7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /* ONC_PLUS EXTRACT START */
28 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
29 /* All Rights Reserved */
30
31 /*
32 * University Copyright- Copyright (c) 1982, 1986, 1988
33 * The Regents of the University of California
34 * All Rights Reserved
35 *
36 * University Acknowledgment- Portions of this document are derived from
37 * software developed by the University of California, Berkeley, and its
38 * contributors.
39 */
40
41 /* Copyright (c) 1987, 1988 Microsoft Corporation */
42 /* All Rights Reserved */
43
44 /* ONC_PLUS EXTRACT END */
45
46 /*
47 * For a complete reference to login(1), see the manual page. However,
48 * login has accreted some intentionally undocumented options, which are
49 * explained here:
50 *
51 * -a: This legacy flag appears to be unused.
52 *
53 * -f <username>: This flag was introduced by PSARC 1995/039 in support
54 * of Kerberos. But it's not used by Sun's Kerberos implementation.
55 * It is however employed by zlogin(1), since it allows one to tell
56 * login: "This user is authenticated." In the case of zlogin that's
57 * true because the zone always trusts the global zone.
58 *
59 * -z <zonename>: This flag is passed to login when zlogin(1) executes a
60 * zone login. This tells login(1) to skip it's normal CONSOLE check
61 * (i.e. that the root login must be on /dev/console) and tells us the
62 * name of the zone from which the login is occurring.
63 */
64
65 #include <sys/types.h>
149 #define ENVSTRNCAT(to, from) {int deflen; deflen = strlen(to); \
150 (void) strncpy((to)+ deflen, (from), sizeof (to) - (1 + deflen)); }
151
152 /*
153 * Other macros
154 */
155 #define NMAX sizeof (((struct utmpx *)0)->ut_name)
156 #define HMAX sizeof (((struct utmpx *)0)->ut_host)
157 #define min(a, b) (((a) < (b)) ? (a) : (b))
158
159 /*
160 * Various useful files and string constants
161 */
162 #define SHELL "/usr/bin/sh"
163 #define SHELL2 "/sbin/sh"
164 #define SUBLOGIN "<!sublogin>"
165 #define LASTLOG "/var/adm/lastlog"
166 #define PROG_NAME "login"
167 #define HUSHLOGIN ".hushlogin"
168
169 /* ONC_PLUS EXTRACT START */
170 /*
171 * Array and Buffer sizes
172 */
173 #define PBUFSIZE 8 /* max significant characters in a password */
174 /* ONC_PLUS EXTRACT END */
175 #define MAXARGS 63 /* change value below if changing this */
176 #define MAXARGSWIDTH 2 /* log10(MAXARGS) */
177 #define MAXENV 1024
178 #define MAXLINE 2048
179
180 /*
181 * Miscellaneous constants
182 */
183 #define ROOTUID 0
184 #define ERROR 1
185 #define OK 0
186 #define LOG_ERROR 1
187 #define DONT_LOG_ERROR 0
188 #define TRUE 1
189 #define FALSE 0
190
191 /*
192 * Counters for counting the number of failed login attempts
193 */
194 static int trys = 0;
195 static int count = 1;
196
197 /*
198 * error value for login_exit() audit output (0 == no audit record)
199 */
200 static int audit_error = 0;
201
202 /*
203 * Externs a plenty
204 */
205 /* ONC_PLUS EXTRACT START */
206 extern int getsecretkey();
207 /* ONC_PLUS EXTRACT START */
208
209 /*
210 * The current user name
211 */
212 static char user_name[NMAX];
213 static char minusnam[16] = "-";
214
215 /*
216 * login_pid, used to find utmpx entry to update.
217 */
218 static pid_t login_pid;
219
220 /*
221 * locale environments to be passed to shells.
222 */
223 static char *localeenv[] = {
224 "LANG",
225 "LC_CTYPE", "LC_NUMERIC", "LC_TIME", "LC_COLLATE",
226 "LC_MONETARY", "LC_MESSAGES", "LC_ALL", 0};
227 static int locale_envmatch(char *, char *);
247 #endif
248 extern char **environ;
249 static char inputline[MAXLINE];
250
251 #define MAX_ID_LEN 256
252 #define MAX_REPOSITORY_LEN 256
253 #define MAX_PAMSERVICE_LEN 256
254
255 static char identity[MAX_ID_LEN];
256 static char repository[MAX_REPOSITORY_LEN];
257 static char progname[MAX_PAMSERVICE_LEN];
258
259
260 /*
261 * Strings used to prompt the user.
262 */
263 static char loginmsg[] = "login: ";
264 static char passwdmsg[] = "Password:";
265 static char incorrectmsg[] = "Login incorrect\n";
266
267 /* ONC_PLUS EXTRACT START */
268 /*
269 * Password file support
270 */
271 static struct passwd *pwd = NULL;
272 static char remote_host[HMAX];
273 static char zone_name[ZONENAME_MAX];
274
275 /*
276 * Illegal passwd entries.
277 */
278 static struct passwd nouser = { "", "no:password", (uid_t)-1 };
279 /* ONC_PLUS EXTRACT END */
280
281 /*
282 * Log file support
283 */
284 static char *log_entry[LOGTRYS];
285 static int writelog = 0;
286 static int lastlogok = 0;
287 static struct lastlog ll;
288 static int dosyslog = 0;
289 static int flogin = MAXTRYS; /* flag for SYSLOG_FAILED_LOGINS */
290
291 /*
292 * Default file toggles
293 */
294 static char *Pndefault = "/etc/default/login";
295 static char *Altshell = NULL;
296 static char *Console = NULL;
297 static int Passreqflag = 0;
298
299 #define DEFUMASK 022
326 /*
327 * Pass inherited environment. Used by telnetd in support of the telnet
328 * ENVIRON option.
329 */
330 static boolean_t pflag = B_FALSE;
331 static boolean_t uflag = B_FALSE;
332 static boolean_t Rflag = B_FALSE;
333 static boolean_t sflag = B_FALSE;
334 static boolean_t Uflag = B_FALSE;
335 static boolean_t tflag = B_FALSE;
336 static boolean_t hflag = B_FALSE;
337 static boolean_t rflag = B_FALSE;
338 static boolean_t zflag = B_FALSE;
339
340 /*
341 * Remote login support
342 */
343 static char rusername[NMAX+1], lusername[NMAX+1];
344 static char terminal[MAXPATHLEN];
345
346 /* ONC_PLUS EXTRACT START */
347 /*
348 * Pre-authentication flag support
349 */
350 static int fflag;
351
352 static char ** getargs(char *);
353
354 static int login_conv(int, struct pam_message **,
355 struct pam_response **, void *);
356
357 static struct pam_conv pam_conv = {login_conv, NULL};
358 static pam_handle_t *pamh; /* Authentication handle */
359 /* ONC_PLUS EXTRACT END */
360
361 /*
362 * Function declarations
363 */
364 static void turn_on_logging(void);
365 static void defaults(void);
366 static void usage(void);
367 static void process_rlogin(void);
368 /* ONC_PLUS EXTRACT START */
369 static void login_authenticate();
370 static void setup_credentials(void);
371 /* ONC_PLUS EXTRACT END */
372 static void adjust_nice(void);
373 static void update_utmpx_entry(int);
374 static void establish_user_environment(char **);
375 static void print_banner(void);
376 static void display_last_login_time(void);
377 static void exec_the_shell(void);
378 static int process_chroot_logins(void);
379 static void chdir_to_dir_user(void);
380 static void check_log(void);
381 static void validate_account(void);
382 static void doremoteterm(char *);
383 static int get_options(int, char **);
384 static void getstr(char *, int, char *);
385 static int legalenvvar(char *);
386 static void check_for_console(void);
387 static void check_for_dueling_unix(char *);
388 static void get_user_name(void);
389 static uint_t get_audit_id(void);
390 static void login_exit(int)__NORETURN;
391 static int logins_disabled(char *);
392 static void log_bad_attempts(void);
393 static int is_number(char *);
394
395 /* ONC_PLUS EXTRACT START */
396 /*
397 * *** main ***
398 *
399 * The primary flow of control is directed in this routine.
400 * Control moves in line from top to bottom calling subfunctions
401 * which perform the bulk of the work. Many of these calls exit
402 * when a fatal error is encountered and do not return to main.
403 *
404 *
405 */
406
407 int
408 main(int argc, char *argv[], char **renvp)
409 {
410 /* ONC_PLUS EXTRACT END */
411 int sublogin;
412 int pam_rc;
413
414 login_pid = getpid();
415
416 /*
417 * Set up Defaults and flags
418 */
419 defaults();
420 SCPYL(progname, PROG_NAME);
421
422 /*
423 * Set up default umask
424 */
425 if (Umask > ((mode_t)0777))
426 Umask = DEFUMASK;
427 (void) umask(Umask);
428
429 /*
430 * Set up default timeouts and delays
452 sublogin = 1;
453
454 /*
455 * Parse Arguments
456 */
457 if (get_options(argc, argv) == -1) {
458 usage();
459 audit_error = ADT_FAIL_VALUE_BAD_CMD;
460 login_exit(1);
461 }
462
463 /*
464 * if devicename is not passed as argument, call ttyname(0)
465 */
466 if (ttyn == NULL) {
467 ttyn = ttyname(0);
468 if (ttyn == NULL)
469 ttyn = "/dev/???";
470 }
471
472 /* ONC_PLUS EXTRACT START */
473 /*
474 * Call pam_start to initiate a PAM authentication operation
475 */
476
477 if ((pam_rc = pam_start(progname, user_name, &pam_conv, &pamh))
478 != PAM_SUCCESS) {
479 audit_error = ADT_FAIL_PAM + pam_rc;
480 login_exit(1);
481 }
482 if ((pam_rc = pam_set_item(pamh, PAM_TTY, ttyn)) != PAM_SUCCESS) {
483 audit_error = ADT_FAIL_PAM + pam_rc;
484 login_exit(1);
485 }
486 if ((pam_rc = pam_set_item(pamh, PAM_RHOST, remote_host)) !=
487 PAM_SUCCESS) {
488 audit_error = ADT_FAIL_PAM + pam_rc;
489 login_exit(1);
490 }
491
492 /*
493 * We currently only support special handling of the KRB5 PAM repository
494 */
495 if ((Rflag && strlen(repository)) &&
496 strcmp(repository, KRB5_REPOSITORY_NAME) == 0 &&
497 (uflag && strlen(identity))) {
498 krb5_repository_data_t krb5_data;
499 pam_repository_t pam_rep_data;
500
501 krb5_data.principal = identity;
502 krb5_data.flags = SUNW_PAM_KRB5_ALREADY_AUTHENTICATED;
503
504 pam_rep_data.type = repository;
505 pam_rep_data.scope = (void *)&krb5_data;
506 pam_rep_data.scope_len = sizeof (krb5_data);
507
508 (void) pam_set_item(pamh, PAM_REPOSITORY,
509 (void *)&pam_rep_data);
510 }
511 /* ONC_PLUS EXTRACT END */
512
513 /*
514 * Open the log file which contains a record of successful and failed
515 * login attempts
516 */
517 turn_on_logging();
518
519 /*
520 * say "hi" to syslogd ..
521 */
522 openlog("login", 0, LOG_AUTH);
523
524 /*
525 * Do special processing for -r (rlogin) flag
526 */
527 if (rflag)
528 process_rlogin();
529
530 /* ONC_PLUS EXTRACT START */
531 /*
532 * validate user
533 */
534 /* we are already authenticated. fill in what we must, then continue */
535 if (fflag) {
536 /* ONC_PLUS EXTRACT END */
537 if ((pwd = getpwnam(user_name)) == NULL) {
538 audit_error = ADT_FAIL_VALUE_USERNAME;
539
540 log_bad_attempts();
541 (void) printf("Login failed: unknown user '%s'.\n",
542 user_name);
543 login_exit(1);
544 }
545 /* ONC_PLUS EXTRACT START */
546 } else {
547 /*
548 * Perform the primary login authentication activity.
549 */
550 login_authenticate();
551 }
552 /* ONC_PLUS EXTRACT END */
553
554 /* change root login, then we exec another login and try again */
555 if (process_chroot_logins() != OK)
556 login_exit(1);
557
558 /*
559 * If root login and not on system console then call exit(2)
560 */
561 check_for_console();
562
563 /*
564 * Check to see if a shutdown is in progress, if it is and
565 * we are not root then throw the user off the system
566 */
567 if (logins_disabled(user_name) == TRUE) {
568 audit_error = ADT_FAIL_VALUE_LOGIN_DISABLED;
569 login_exit(1);
570 }
571
572 if (pwd->pw_uid == 0) {
585 * We only get here if we've been authenticated.
586 */
587
588 /*
589 * Now we set up the environment for the new user, which includes
590 * the users ulimit, nice value, ownership of this tty, uid, gid,
591 * and environment variables.
592 */
593 if (Def_ulimit > 0L && ulimit(SET_FSIZ, Def_ulimit) < 0L)
594 (void) printf("Could not set ULIMIT to %ld\n", Def_ulimit);
595
596 /* di_devperm_login() sends detailed errors to syslog */
597 if (di_devperm_login((const char *)ttyn, pwd->pw_uid, pwd->pw_gid,
598 NULL) == -1) {
599 (void) fprintf(stderr, "error processing /etc/logindevperm,"
600 " see syslog for more details\n");
601 }
602
603 adjust_nice(); /* passwd file can specify nice value */
604
605 /* ONC_PLUS EXTRACT START */
606 setup_credentials(); /* Set user credentials - exits on failure */
607
608 /*
609 * NOTE: telnetd and rlogind rely upon this updating of utmpx
610 * to indicate that the authentication completed successfully,
611 * pam_open_session was called and therefore they are required to
612 * call pam_close_session.
613 */
614 update_utmpx_entry(sublogin);
615
616 /* set the real (and effective) UID */
617 if (setuid(pwd->pw_uid) == -1) {
618 login_exit(1);
619 }
620
621 /*
622 * Set up the basic environment for the exec. This includes
623 * HOME, PATH, LOGNAME, SHELL, TERM, TZ, HZ, and MAIL.
624 */
625 chdir_to_dir_user();
626
627 establish_user_environment(renvp);
628
629 (void) pam_end(pamh, PAM_SUCCESS); /* Done using PAM */
630 pamh = NULL;
631 /* ONC_PLUS EXTRACT END */
632
633 if (pwd->pw_uid == 0) {
634 if (dosyslog) {
635 if (remote_host[0]) {
636 syslog(LOG_NOTICE, "ROOT LOGIN %s FROM %.*s",
637 ttyn, HMAX, remote_host);
638 } else
639 syslog(LOG_NOTICE, "ROOT LOGIN %s", ttyn);
640 }
641 }
642 closelog();
643
644 (void) signal(SIGQUIT, SIG_DFL);
645 (void) signal(SIGINT, SIG_DFL);
646
647 /*
648 * Display some useful information to the new user like the banner
649 * and last login time if not a quiet login.
650 */
651
665
666 /*
667 * Now fire off the shell of choice
668 */
669 exec_the_shell();
670
671 /*
672 * All done
673 */
674 login_exit(1);
675 return (0);
676 }
677
678
679 /*
680 * *** Utility functions ***
681 */
682
683
684
685 /* ONC_PLUS EXTRACT START */
686 /*
687 * donothing & catch - Signal catching functions
688 */
689
690 /*ARGSUSED*/
691 static void
692 donothing(int sig)
693 {
694 if (pamh)
695 (void) pam_end(pamh, PAM_ABORT);
696 }
697 /* ONC_PLUS EXTRACT END */
698
699 #ifdef notdef
700 static int intrupt;
701
702 /*ARGSUSED*/
703 static void
704 catch(int sig)
705 {
706 ++intrupt;
707 }
708 #endif
709
710 /*
711 * *** Bad login logging support ***
712 */
713
714 /*
715 * badlogin() - log to the log file 'trys'
716 * unsuccessful attempts
717 */
798
799 static void
800 turn_on_logging(void)
801 {
802 struct stat dbuf;
803 int i;
804
805 if (stat(LOGINLOG, &dbuf) == 0) {
806 writelog = 1;
807 for (i = 0; i < LOGTRYS; i++) {
808 if (!(log_entry[i] = malloc((size_t)ENT_SIZE))) {
809 writelog = 0;
810 break;
811 }
812 *log_entry[i] = '\0';
813 }
814 }
815 }
816
817
818 /* ONC_PLUS EXTRACT START */
819 /*
820 * login_conv():
821 * This is the conv (conversation) function called from
822 * a PAM authentication module to print error messages
823 * or garner information from the user.
824 */
825 /*ARGSUSED*/
826 static int
827 login_conv(int num_msg, struct pam_message **msg,
828 struct pam_response **response, void *appdata_ptr)
829 {
830 struct pam_message *m;
831 struct pam_response *r;
832 char *temp;
833 int k, i;
834
835 if (num_msg <= 0)
836 return (PAM_CONV_ERR);
837
838 *response = calloc(num_msg, sizeof (struct pam_response));
964 * PAM authenticates the user for us.
965 */
966 error = pam_authenticate(pamh, flag);
967
968 /* get the user_name from the pam handle */
969 (void) pam_get_item(pamh, PAM_USER, (void**)&user);
970
971 if (user == NULL || *user == '\0')
972 return (PAM_SYSTEM_ERR);
973
974 SCPYL(user_name, user);
975 check_for_dueling_unix(user_name);
976
977 if (((pwd = getpwnam(user_name)) == NULL) &&
978 (error != PAM_USER_UNKNOWN)) {
979 return (PAM_SYSTEM_ERR);
980 }
981
982 return (error);
983 }
984 /* ONC_PLUS EXTRACT END */
985
986 /*
987 * quotec - Called by getargs
988 */
989
990 static int
991 quotec(void)
992 {
993 int c, i, num;
994
995 switch (c = getc(stdin)) {
996
997 case 'n':
998 c = '\n';
999 break;
1000
1001 case 'r':
1002 c = '\r';
1003 break;
1004
1771 "LOGIN FAILURES ON %s FROM %.*s ",
1772 " %.*s", ttyn, HMAX,
1773 remote_host, NMAX, pwd->pw_name);
1774 } else {
1775 syslog(LOG_CRIT,
1776 "LOGIN FAILURES ON %s, %.*s",
1777 ttyn, NMAX, pwd->pw_name);
1778 }
1779 }
1780 closelog();
1781 (void) sleep(Disabletime);
1782 exit(1);
1783 } else {
1784 (void) printf("No directory! Logging in with home=/\n");
1785 pwd->pw_dir = "/";
1786 }
1787 }
1788 }
1789
1790
1791 /* ONC_PLUS EXTRACT START */
1792 /*
1793 * login_authenticate - Performs the main authentication work
1794 * 1. Prints the login prompt
1795 * 2. Requests and verifys the password
1796 * 3. Checks the port password
1797 */
1798
1799 static void
1800 login_authenticate(void)
1801 {
1802 char *user;
1803 int err;
1804 int login_successful = 0;
1805
1806 do {
1807 /* if scheme broken, then nothing to do but quit */
1808 if (pam_get_item(pamh, PAM_USER, (void **)&user) != PAM_SUCCESS)
1809 exit(1);
1810
1811 /*
1950 if ((user_name[0] == '\0') ||
1951 (initgroups(user_name, pwd->pw_gid) == -1)) {
1952 audit_error = ADT_FAIL_VALUE_PROGRAM;
1953 login_exit(1);
1954 }
1955
1956 if ((error = pam_setcred(pamh, zflag ? PAM_REINITIALIZE_CRED :
1957 PAM_ESTABLISH_CRED)) != PAM_SUCCESS) {
1958 audit_error = ADT_FAIL_PAM + error;
1959 login_exit(error);
1960 }
1961
1962 /*
1963 * Record successful login and fork process that records logout.
1964 * We have to do this after setting credentials because pam_setcred()
1965 * loads key audit info into the cred, but before setuid() so audit
1966 * system calls will work.
1967 */
1968 audit_success(get_audit_id(), pwd, zone_name);
1969 }
1970 /* ONC_PLUS EXTRACT END */
1971
1972 static uint_t
1973 get_audit_id(void)
1974 {
1975 if (rflag)
1976 return (ADT_rlogin);
1977 else if (hflag)
1978 return (ADT_telnet);
1979 else if (zflag)
1980 return (ADT_zlogin);
1981
1982 return (ADT_login);
1983 }
1984
1985 /*
1986 *
1987 * *** Routines to get a new user set up and running ***
1988 *
1989 * Things to do when starting up a new user:
1990 * adjust_nice
2010 if (strncmp("pri=", pwd->pw_gecos, 4) == 0) {
2011 pri = 0;
2012 mflg = 0;
2013 i = 4;
2014
2015 if (pwd->pw_gecos[i] == '-') {
2016 mflg++;
2017 i++;
2018 }
2019
2020 while (pwd->pw_gecos[i] >= '0' && pwd->pw_gecos[i] <= '9')
2021 pri = (pri * 10) + pwd->pw_gecos[i++] - '0';
2022
2023 if (mflg)
2024 pri = -pri;
2025
2026 (void) nice(pri);
2027 }
2028 }
2029
2030 /* ONC_PLUS EXTRACT START */
2031 /*
2032 * update_utmpx_entry - Searchs for the correct utmpx entry, making an
2033 * entry there if it finds one, otherwise exits.
2034 */
2035
2036 static void
2037 update_utmpx_entry(int sublogin)
2038 {
2039 int err;
2040 char *user;
2041 static char *errmsg = "No utmpx entry. "
2042 "You must exec \"login\" from the lowest level \"shell\".";
2043 int tmplen;
2044 struct utmpx *u = (struct utmpx *)0;
2045 struct utmpx utmpx;
2046 char *ttyntail;
2047
2048 /*
2049 * If we're not a sublogin then
2050 * we'll get an error back if our PID doesn't match the PID of the
2051 * entry we are updating, otherwise if its a sublogin the flags
2052 * field is set to 0, which means we just write a matching entry
2053 * (without checking the pid), or a new entry if an entry doesn't
2054 * exist.
2055 */
2056
2057 if ((err = pam_open_session(pamh, 0)) != PAM_SUCCESS) {
2058 audit_error = ADT_FAIL_PAM + err;
2059 login_exit(1);
2060 }
2061
2062 if ((err = pam_get_item(pamh, PAM_USER, (void **) &user)) !=
2063 PAM_SUCCESS) {
2064 audit_error = ADT_FAIL_PAM + err;
2065 login_exit(1);
2066 }
2067 /* ONC_PLUS EXTRACT END */
2068
2069 (void) memset((void *)&utmpx, 0, sizeof (utmpx));
2070 (void) time(&utmpx.ut_tv.tv_sec);
2071 utmpx.ut_pid = getpid();
2072
2073 if (rflag || hflag) {
2074 SCPYN(utmpx.ut_host, remote_host);
2075 tmplen = strlen(remote_host) + 1;
2076 if (tmplen < sizeof (utmpx.ut_host))
2077 utmpx.ut_syslen = tmplen;
2078 else
2079 utmpx.ut_syslen = sizeof (utmpx.ut_host);
2080 } else if (zflag) {
2081 /*
2082 * If this is a login from another zone, put the
2083 * zone:<zonename> string in the utmpx entry.
2084 */
2085 SCPYN(utmpx.ut_host, zone_name);
2086 tmplen = strlen(zone_name) + 1;
2087 if (tmplen < sizeof (utmpx.ut_host))
2115 }
2116 endutxent();
2117
2118 if (u == (struct utmpx *)NULL) {
2119 if (!sublogin) {
2120 /*
2121 * no utmpx entry already setup
2122 * (init or rlogind/telnetd)
2123 */
2124 (void) puts(errmsg);
2125
2126 audit_error = ADT_FAIL_VALUE_PROGRAM;
2127 login_exit(1);
2128 }
2129 } else {
2130 /* Now attempt to write out this entry to the wtmp file if */
2131 /* we were successful in getting it from the utmpx file and */
2132 /* the wtmp file exists. */
2133 updwtmpx(WTMPX_FILE, &utmpx);
2134 }
2135 /* ONC_PLUS EXTRACT START */
2136 }
2137
2138
2139
2140 /*
2141 * process_chroot_logins - Chroots to the specified subdirectory and
2142 * re executes login.
2143 */
2144
2145 static int
2146 process_chroot_logins(void)
2147 {
2148 /*
2149 * If the shell field starts with a '*', do a chroot to the home
2150 * directory and perform a new login.
2151 */
2152
2153 if (*pwd->pw_shell == '*') {
2154 (void) pam_end(pamh, PAM_SUCCESS); /* Done using PAM */
2155 pamh = NULL; /* really done */
2156 if (chroot(pwd->pw_dir) < 0) {
2157 (void) printf("No Root Directory\n");
2158
2159 audit_failure(get_audit_id(),
2160 ADT_FAIL_VALUE_CHDIR_FAILED,
2161 pwd, remote_host, ttyn, zone_name);
2162
2163 return (ERROR);
2164 }
2165 /*
2166 * Set the environment flag <!sublogin> so that the next login
2167 * knows that it is a sublogin.
2168 */
2169 /* ONC_PLUS EXTRACT END */
2170 envinit[0] = SUBLOGIN;
2171 envinit[1] = (char *)NULL;
2172 (void) printf("Subsystem root: %s\n", pwd->pw_dir);
2173 (void) execle("/usr/bin/login", "login", (char *)0,
2174 &envinit[0]);
2175 (void) execle("/etc/login", "login", (char *)0, &envinit[0]);
2176 (void) printf("No /usr/bin/login or /etc/login on root\n");
2177
2178 audit_error = ADT_FAIL_VALUE_PROGRAM;
2179
2180 login_exit(1);
2181 }
2182 return (OK);
2183 /* ONC_PLUS EXTRACT START */
2184 }
2185
2186 /*
2187 * establish_user_environment - Set up the new users enviornment
2188 */
2189
2190 static void
2191 establish_user_environment(char **renvp)
2192 {
2193 int i, j, k, l_index, length, idx = 0;
2194 char *endptr;
2195 char **lenvp;
2196 char **pam_env;
2197
2198 lenvp = environ;
2199 while (*lenvp++)
2200 ;
2201
2202 /* count the number of PAM environment variables set by modules */
2203 if ((pam_env = pam_getenvlist(pamh)) != 0) {
2211 (void) printf("Calloc failed - out of swap space.\n");
2212 login_exit(8);
2213 }
2214
2215 /*
2216 * add PAM environment variables first so they
2217 * can be overwritten at login's discretion.
2218 * check for illegal environment variables.
2219 */
2220 idx = 0; basicenv = 0;
2221 if (pam_env != 0) {
2222 while (pam_env[idx] != 0) {
2223 if (legalenvvar(pam_env[idx])) {
2224 envinit[basicenv] = pam_env[idx];
2225 basicenv++;
2226 }
2227 idx++;
2228 }
2229 }
2230 (void) memcpy(&envinit[basicenv], newenv, sizeof (newenv));
2231 /* ONC_PLUS EXTRACT END */
2232
2233 /* Set up environment */
2234 if (rflag) {
2235 ENVSTRNCAT(term, terminal);
2236 } else if (hflag) {
2237 if (strlen(terminal)) {
2238 ENVSTRNCAT(term, terminal);
2239 }
2240 } else {
2241 char *tp = getenv("TERM");
2242
2243 if ((tp != NULL) && (*tp != '\0'))
2244 ENVSTRNCAT(term, tp);
2245 }
2246
2247 ENVSTRNCAT(logname, pwd->pw_name);
2248
2249 /*
2250 * There are three places to get timezone info. init.c sets
2251 * TZ if the file /etc/TIMEZONE contains a value for TZ.
|
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
29
30 /*
31 * University Copyright- Copyright (c) 1982, 1986, 1988
32 * The Regents of the University of California
33 * All Rights Reserved
34 *
35 * University Acknowledgment- Portions of this document are derived from
36 * software developed by the University of California, Berkeley, and its
37 * contributors.
38 */
39
40 /* Copyright (c) 1987, 1988 Microsoft Corporation */
41 /* All Rights Reserved */
42
43 /*
44 * For a complete reference to login(1), see the manual page. However,
45 * login has accreted some intentionally undocumented options, which are
46 * explained here:
47 *
48 * -a: This legacy flag appears to be unused.
49 *
50 * -f <username>: This flag was introduced by PSARC 1995/039 in support
51 * of Kerberos. But it's not used by Sun's Kerberos implementation.
52 * It is however employed by zlogin(1), since it allows one to tell
53 * login: "This user is authenticated." In the case of zlogin that's
54 * true because the zone always trusts the global zone.
55 *
56 * -z <zonename>: This flag is passed to login when zlogin(1) executes a
57 * zone login. This tells login(1) to skip it's normal CONSOLE check
58 * (i.e. that the root login must be on /dev/console) and tells us the
59 * name of the zone from which the login is occurring.
60 */
61
62 #include <sys/types.h>
146 #define ENVSTRNCAT(to, from) {int deflen; deflen = strlen(to); \
147 (void) strncpy((to)+ deflen, (from), sizeof (to) - (1 + deflen)); }
148
149 /*
150 * Other macros
151 */
152 #define NMAX sizeof (((struct utmpx *)0)->ut_name)
153 #define HMAX sizeof (((struct utmpx *)0)->ut_host)
154 #define min(a, b) (((a) < (b)) ? (a) : (b))
155
156 /*
157 * Various useful files and string constants
158 */
159 #define SHELL "/usr/bin/sh"
160 #define SHELL2 "/sbin/sh"
161 #define SUBLOGIN "<!sublogin>"
162 #define LASTLOG "/var/adm/lastlog"
163 #define PROG_NAME "login"
164 #define HUSHLOGIN ".hushlogin"
165
166 /*
167 * Array and Buffer sizes
168 */
169 #define PBUFSIZE 8 /* max significant characters in a password */
170 #define MAXARGS 63 /* change value below if changing this */
171 #define MAXARGSWIDTH 2 /* log10(MAXARGS) */
172 #define MAXENV 1024
173 #define MAXLINE 2048
174
175 /*
176 * Miscellaneous constants
177 */
178 #define ROOTUID 0
179 #define ERROR 1
180 #define OK 0
181 #define LOG_ERROR 1
182 #define DONT_LOG_ERROR 0
183 #define TRUE 1
184 #define FALSE 0
185
186 /*
187 * Counters for counting the number of failed login attempts
188 */
189 static int trys = 0;
190 static int count = 1;
191
192 /*
193 * error value for login_exit() audit output (0 == no audit record)
194 */
195 static int audit_error = 0;
196
197 /*
198 * Externs a plenty
199 */
200 extern int getsecretkey();
201
202 /*
203 * The current user name
204 */
205 static char user_name[NMAX];
206 static char minusnam[16] = "-";
207
208 /*
209 * login_pid, used to find utmpx entry to update.
210 */
211 static pid_t login_pid;
212
213 /*
214 * locale environments to be passed to shells.
215 */
216 static char *localeenv[] = {
217 "LANG",
218 "LC_CTYPE", "LC_NUMERIC", "LC_TIME", "LC_COLLATE",
219 "LC_MONETARY", "LC_MESSAGES", "LC_ALL", 0};
220 static int locale_envmatch(char *, char *);
240 #endif
241 extern char **environ;
242 static char inputline[MAXLINE];
243
244 #define MAX_ID_LEN 256
245 #define MAX_REPOSITORY_LEN 256
246 #define MAX_PAMSERVICE_LEN 256
247
248 static char identity[MAX_ID_LEN];
249 static char repository[MAX_REPOSITORY_LEN];
250 static char progname[MAX_PAMSERVICE_LEN];
251
252
253 /*
254 * Strings used to prompt the user.
255 */
256 static char loginmsg[] = "login: ";
257 static char passwdmsg[] = "Password:";
258 static char incorrectmsg[] = "Login incorrect\n";
259
260 /*
261 * Password file support
262 */
263 static struct passwd *pwd = NULL;
264 static char remote_host[HMAX];
265 static char zone_name[ZONENAME_MAX];
266
267 /*
268 * Illegal passwd entries.
269 */
270 static struct passwd nouser = { "", "no:password", (uid_t)-1 };
271
272 /*
273 * Log file support
274 */
275 static char *log_entry[LOGTRYS];
276 static int writelog = 0;
277 static int lastlogok = 0;
278 static struct lastlog ll;
279 static int dosyslog = 0;
280 static int flogin = MAXTRYS; /* flag for SYSLOG_FAILED_LOGINS */
281
282 /*
283 * Default file toggles
284 */
285 static char *Pndefault = "/etc/default/login";
286 static char *Altshell = NULL;
287 static char *Console = NULL;
288 static int Passreqflag = 0;
289
290 #define DEFUMASK 022
317 /*
318 * Pass inherited environment. Used by telnetd in support of the telnet
319 * ENVIRON option.
320 */
321 static boolean_t pflag = B_FALSE;
322 static boolean_t uflag = B_FALSE;
323 static boolean_t Rflag = B_FALSE;
324 static boolean_t sflag = B_FALSE;
325 static boolean_t Uflag = B_FALSE;
326 static boolean_t tflag = B_FALSE;
327 static boolean_t hflag = B_FALSE;
328 static boolean_t rflag = B_FALSE;
329 static boolean_t zflag = B_FALSE;
330
331 /*
332 * Remote login support
333 */
334 static char rusername[NMAX+1], lusername[NMAX+1];
335 static char terminal[MAXPATHLEN];
336
337 /*
338 * Pre-authentication flag support
339 */
340 static int fflag;
341
342 static char ** getargs(char *);
343
344 static int login_conv(int, struct pam_message **,
345 struct pam_response **, void *);
346
347 static struct pam_conv pam_conv = {login_conv, NULL};
348 static pam_handle_t *pamh; /* Authentication handle */
349
350 /*
351 * Function declarations
352 */
353 static void turn_on_logging(void);
354 static void defaults(void);
355 static void usage(void);
356 static void process_rlogin(void);
357 static void login_authenticate();
358 static void setup_credentials(void);
359 static void adjust_nice(void);
360 static void update_utmpx_entry(int);
361 static void establish_user_environment(char **);
362 static void print_banner(void);
363 static void display_last_login_time(void);
364 static void exec_the_shell(void);
365 static int process_chroot_logins(void);
366 static void chdir_to_dir_user(void);
367 static void check_log(void);
368 static void validate_account(void);
369 static void doremoteterm(char *);
370 static int get_options(int, char **);
371 static void getstr(char *, int, char *);
372 static int legalenvvar(char *);
373 static void check_for_console(void);
374 static void check_for_dueling_unix(char *);
375 static void get_user_name(void);
376 static uint_t get_audit_id(void);
377 static void login_exit(int)__NORETURN;
378 static int logins_disabled(char *);
379 static void log_bad_attempts(void);
380 static int is_number(char *);
381
382 /*
383 * *** main ***
384 *
385 * The primary flow of control is directed in this routine.
386 * Control moves in line from top to bottom calling subfunctions
387 * which perform the bulk of the work. Many of these calls exit
388 * when a fatal error is encountered and do not return to main.
389 *
390 *
391 */
392
393 int
394 main(int argc, char *argv[], char **renvp)
395 {
396 int sublogin;
397 int pam_rc;
398
399 login_pid = getpid();
400
401 /*
402 * Set up Defaults and flags
403 */
404 defaults();
405 SCPYL(progname, PROG_NAME);
406
407 /*
408 * Set up default umask
409 */
410 if (Umask > ((mode_t)0777))
411 Umask = DEFUMASK;
412 (void) umask(Umask);
413
414 /*
415 * Set up default timeouts and delays
437 sublogin = 1;
438
439 /*
440 * Parse Arguments
441 */
442 if (get_options(argc, argv) == -1) {
443 usage();
444 audit_error = ADT_FAIL_VALUE_BAD_CMD;
445 login_exit(1);
446 }
447
448 /*
449 * if devicename is not passed as argument, call ttyname(0)
450 */
451 if (ttyn == NULL) {
452 ttyn = ttyname(0);
453 if (ttyn == NULL)
454 ttyn = "/dev/???";
455 }
456
457 /*
458 * Call pam_start to initiate a PAM authentication operation
459 */
460
461 if ((pam_rc = pam_start(progname, user_name, &pam_conv, &pamh))
462 != PAM_SUCCESS) {
463 audit_error = ADT_FAIL_PAM + pam_rc;
464 login_exit(1);
465 }
466 if ((pam_rc = pam_set_item(pamh, PAM_TTY, ttyn)) != PAM_SUCCESS) {
467 audit_error = ADT_FAIL_PAM + pam_rc;
468 login_exit(1);
469 }
470 if ((pam_rc = pam_set_item(pamh, PAM_RHOST, remote_host)) !=
471 PAM_SUCCESS) {
472 audit_error = ADT_FAIL_PAM + pam_rc;
473 login_exit(1);
474 }
475
476 /*
477 * We currently only support special handling of the KRB5 PAM repository
478 */
479 if ((Rflag && strlen(repository)) &&
480 strcmp(repository, KRB5_REPOSITORY_NAME) == 0 &&
481 (uflag && strlen(identity))) {
482 krb5_repository_data_t krb5_data;
483 pam_repository_t pam_rep_data;
484
485 krb5_data.principal = identity;
486 krb5_data.flags = SUNW_PAM_KRB5_ALREADY_AUTHENTICATED;
487
488 pam_rep_data.type = repository;
489 pam_rep_data.scope = (void *)&krb5_data;
490 pam_rep_data.scope_len = sizeof (krb5_data);
491
492 (void) pam_set_item(pamh, PAM_REPOSITORY,
493 (void *)&pam_rep_data);
494 }
495
496 /*
497 * Open the log file which contains a record of successful and failed
498 * login attempts
499 */
500 turn_on_logging();
501
502 /*
503 * say "hi" to syslogd ..
504 */
505 openlog("login", 0, LOG_AUTH);
506
507 /*
508 * Do special processing for -r (rlogin) flag
509 */
510 if (rflag)
511 process_rlogin();
512
513 /*
514 * validate user
515 */
516 /* we are already authenticated. fill in what we must, then continue */
517 if (fflag) {
518 if ((pwd = getpwnam(user_name)) == NULL) {
519 audit_error = ADT_FAIL_VALUE_USERNAME;
520
521 log_bad_attempts();
522 (void) printf("Login failed: unknown user '%s'.\n",
523 user_name);
524 login_exit(1);
525 }
526 } else {
527 /*
528 * Perform the primary login authentication activity.
529 */
530 login_authenticate();
531 }
532
533 /* change root login, then we exec another login and try again */
534 if (process_chroot_logins() != OK)
535 login_exit(1);
536
537 /*
538 * If root login and not on system console then call exit(2)
539 */
540 check_for_console();
541
542 /*
543 * Check to see if a shutdown is in progress, if it is and
544 * we are not root then throw the user off the system
545 */
546 if (logins_disabled(user_name) == TRUE) {
547 audit_error = ADT_FAIL_VALUE_LOGIN_DISABLED;
548 login_exit(1);
549 }
550
551 if (pwd->pw_uid == 0) {
564 * We only get here if we've been authenticated.
565 */
566
567 /*
568 * Now we set up the environment for the new user, which includes
569 * the users ulimit, nice value, ownership of this tty, uid, gid,
570 * and environment variables.
571 */
572 if (Def_ulimit > 0L && ulimit(SET_FSIZ, Def_ulimit) < 0L)
573 (void) printf("Could not set ULIMIT to %ld\n", Def_ulimit);
574
575 /* di_devperm_login() sends detailed errors to syslog */
576 if (di_devperm_login((const char *)ttyn, pwd->pw_uid, pwd->pw_gid,
577 NULL) == -1) {
578 (void) fprintf(stderr, "error processing /etc/logindevperm,"
579 " see syslog for more details\n");
580 }
581
582 adjust_nice(); /* passwd file can specify nice value */
583
584 setup_credentials(); /* Set user credentials - exits on failure */
585
586 /*
587 * NOTE: telnetd and rlogind rely upon this updating of utmpx
588 * to indicate that the authentication completed successfully,
589 * pam_open_session was called and therefore they are required to
590 * call pam_close_session.
591 */
592 update_utmpx_entry(sublogin);
593
594 /* set the real (and effective) UID */
595 if (setuid(pwd->pw_uid) == -1) {
596 login_exit(1);
597 }
598
599 /*
600 * Set up the basic environment for the exec. This includes
601 * HOME, PATH, LOGNAME, SHELL, TERM, TZ, HZ, and MAIL.
602 */
603 chdir_to_dir_user();
604
605 establish_user_environment(renvp);
606
607 (void) pam_end(pamh, PAM_SUCCESS); /* Done using PAM */
608 pamh = NULL;
609
610 if (pwd->pw_uid == 0) {
611 if (dosyslog) {
612 if (remote_host[0]) {
613 syslog(LOG_NOTICE, "ROOT LOGIN %s FROM %.*s",
614 ttyn, HMAX, remote_host);
615 } else
616 syslog(LOG_NOTICE, "ROOT LOGIN %s", ttyn);
617 }
618 }
619 closelog();
620
621 (void) signal(SIGQUIT, SIG_DFL);
622 (void) signal(SIGINT, SIG_DFL);
623
624 /*
625 * Display some useful information to the new user like the banner
626 * and last login time if not a quiet login.
627 */
628
642
643 /*
644 * Now fire off the shell of choice
645 */
646 exec_the_shell();
647
648 /*
649 * All done
650 */
651 login_exit(1);
652 return (0);
653 }
654
655
656 /*
657 * *** Utility functions ***
658 */
659
660
661
662 /*
663 * donothing & catch - Signal catching functions
664 */
665
666 /*ARGSUSED*/
667 static void
668 donothing(int sig)
669 {
670 if (pamh)
671 (void) pam_end(pamh, PAM_ABORT);
672 }
673
674 #ifdef notdef
675 static int intrupt;
676
677 /*ARGSUSED*/
678 static void
679 catch(int sig)
680 {
681 ++intrupt;
682 }
683 #endif
684
685 /*
686 * *** Bad login logging support ***
687 */
688
689 /*
690 * badlogin() - log to the log file 'trys'
691 * unsuccessful attempts
692 */
773
774 static void
775 turn_on_logging(void)
776 {
777 struct stat dbuf;
778 int i;
779
780 if (stat(LOGINLOG, &dbuf) == 0) {
781 writelog = 1;
782 for (i = 0; i < LOGTRYS; i++) {
783 if (!(log_entry[i] = malloc((size_t)ENT_SIZE))) {
784 writelog = 0;
785 break;
786 }
787 *log_entry[i] = '\0';
788 }
789 }
790 }
791
792
793 /*
794 * login_conv():
795 * This is the conv (conversation) function called from
796 * a PAM authentication module to print error messages
797 * or garner information from the user.
798 */
799 /*ARGSUSED*/
800 static int
801 login_conv(int num_msg, struct pam_message **msg,
802 struct pam_response **response, void *appdata_ptr)
803 {
804 struct pam_message *m;
805 struct pam_response *r;
806 char *temp;
807 int k, i;
808
809 if (num_msg <= 0)
810 return (PAM_CONV_ERR);
811
812 *response = calloc(num_msg, sizeof (struct pam_response));
938 * PAM authenticates the user for us.
939 */
940 error = pam_authenticate(pamh, flag);
941
942 /* get the user_name from the pam handle */
943 (void) pam_get_item(pamh, PAM_USER, (void**)&user);
944
945 if (user == NULL || *user == '\0')
946 return (PAM_SYSTEM_ERR);
947
948 SCPYL(user_name, user);
949 check_for_dueling_unix(user_name);
950
951 if (((pwd = getpwnam(user_name)) == NULL) &&
952 (error != PAM_USER_UNKNOWN)) {
953 return (PAM_SYSTEM_ERR);
954 }
955
956 return (error);
957 }
958
959 /*
960 * quotec - Called by getargs
961 */
962
963 static int
964 quotec(void)
965 {
966 int c, i, num;
967
968 switch (c = getc(stdin)) {
969
970 case 'n':
971 c = '\n';
972 break;
973
974 case 'r':
975 c = '\r';
976 break;
977
1744 "LOGIN FAILURES ON %s FROM %.*s ",
1745 " %.*s", ttyn, HMAX,
1746 remote_host, NMAX, pwd->pw_name);
1747 } else {
1748 syslog(LOG_CRIT,
1749 "LOGIN FAILURES ON %s, %.*s",
1750 ttyn, NMAX, pwd->pw_name);
1751 }
1752 }
1753 closelog();
1754 (void) sleep(Disabletime);
1755 exit(1);
1756 } else {
1757 (void) printf("No directory! Logging in with home=/\n");
1758 pwd->pw_dir = "/";
1759 }
1760 }
1761 }
1762
1763
1764 /*
1765 * login_authenticate - Performs the main authentication work
1766 * 1. Prints the login prompt
1767 * 2. Requests and verifys the password
1768 * 3. Checks the port password
1769 */
1770
1771 static void
1772 login_authenticate(void)
1773 {
1774 char *user;
1775 int err;
1776 int login_successful = 0;
1777
1778 do {
1779 /* if scheme broken, then nothing to do but quit */
1780 if (pam_get_item(pamh, PAM_USER, (void **)&user) != PAM_SUCCESS)
1781 exit(1);
1782
1783 /*
1922 if ((user_name[0] == '\0') ||
1923 (initgroups(user_name, pwd->pw_gid) == -1)) {
1924 audit_error = ADT_FAIL_VALUE_PROGRAM;
1925 login_exit(1);
1926 }
1927
1928 if ((error = pam_setcred(pamh, zflag ? PAM_REINITIALIZE_CRED :
1929 PAM_ESTABLISH_CRED)) != PAM_SUCCESS) {
1930 audit_error = ADT_FAIL_PAM + error;
1931 login_exit(error);
1932 }
1933
1934 /*
1935 * Record successful login and fork process that records logout.
1936 * We have to do this after setting credentials because pam_setcred()
1937 * loads key audit info into the cred, but before setuid() so audit
1938 * system calls will work.
1939 */
1940 audit_success(get_audit_id(), pwd, zone_name);
1941 }
1942
1943 static uint_t
1944 get_audit_id(void)
1945 {
1946 if (rflag)
1947 return (ADT_rlogin);
1948 else if (hflag)
1949 return (ADT_telnet);
1950 else if (zflag)
1951 return (ADT_zlogin);
1952
1953 return (ADT_login);
1954 }
1955
1956 /*
1957 *
1958 * *** Routines to get a new user set up and running ***
1959 *
1960 * Things to do when starting up a new user:
1961 * adjust_nice
1981 if (strncmp("pri=", pwd->pw_gecos, 4) == 0) {
1982 pri = 0;
1983 mflg = 0;
1984 i = 4;
1985
1986 if (pwd->pw_gecos[i] == '-') {
1987 mflg++;
1988 i++;
1989 }
1990
1991 while (pwd->pw_gecos[i] >= '0' && pwd->pw_gecos[i] <= '9')
1992 pri = (pri * 10) + pwd->pw_gecos[i++] - '0';
1993
1994 if (mflg)
1995 pri = -pri;
1996
1997 (void) nice(pri);
1998 }
1999 }
2000
2001 /*
2002 * update_utmpx_entry - Searchs for the correct utmpx entry, making an
2003 * entry there if it finds one, otherwise exits.
2004 */
2005
2006 static void
2007 update_utmpx_entry(int sublogin)
2008 {
2009 int err;
2010 char *user;
2011 static char *errmsg = "No utmpx entry. "
2012 "You must exec \"login\" from the lowest level \"shell\".";
2013 int tmplen;
2014 struct utmpx *u = (struct utmpx *)0;
2015 struct utmpx utmpx;
2016 char *ttyntail;
2017
2018 /*
2019 * If we're not a sublogin then
2020 * we'll get an error back if our PID doesn't match the PID of the
2021 * entry we are updating, otherwise if its a sublogin the flags
2022 * field is set to 0, which means we just write a matching entry
2023 * (without checking the pid), or a new entry if an entry doesn't
2024 * exist.
2025 */
2026
2027 if ((err = pam_open_session(pamh, 0)) != PAM_SUCCESS) {
2028 audit_error = ADT_FAIL_PAM + err;
2029 login_exit(1);
2030 }
2031
2032 if ((err = pam_get_item(pamh, PAM_USER, (void **) &user)) !=
2033 PAM_SUCCESS) {
2034 audit_error = ADT_FAIL_PAM + err;
2035 login_exit(1);
2036 }
2037
2038 (void) memset((void *)&utmpx, 0, sizeof (utmpx));
2039 (void) time(&utmpx.ut_tv.tv_sec);
2040 utmpx.ut_pid = getpid();
2041
2042 if (rflag || hflag) {
2043 SCPYN(utmpx.ut_host, remote_host);
2044 tmplen = strlen(remote_host) + 1;
2045 if (tmplen < sizeof (utmpx.ut_host))
2046 utmpx.ut_syslen = tmplen;
2047 else
2048 utmpx.ut_syslen = sizeof (utmpx.ut_host);
2049 } else if (zflag) {
2050 /*
2051 * If this is a login from another zone, put the
2052 * zone:<zonename> string in the utmpx entry.
2053 */
2054 SCPYN(utmpx.ut_host, zone_name);
2055 tmplen = strlen(zone_name) + 1;
2056 if (tmplen < sizeof (utmpx.ut_host))
2084 }
2085 endutxent();
2086
2087 if (u == (struct utmpx *)NULL) {
2088 if (!sublogin) {
2089 /*
2090 * no utmpx entry already setup
2091 * (init or rlogind/telnetd)
2092 */
2093 (void) puts(errmsg);
2094
2095 audit_error = ADT_FAIL_VALUE_PROGRAM;
2096 login_exit(1);
2097 }
2098 } else {
2099 /* Now attempt to write out this entry to the wtmp file if */
2100 /* we were successful in getting it from the utmpx file and */
2101 /* the wtmp file exists. */
2102 updwtmpx(WTMPX_FILE, &utmpx);
2103 }
2104 }
2105
2106
2107
2108 /*
2109 * process_chroot_logins - Chroots to the specified subdirectory and
2110 * re executes login.
2111 */
2112
2113 static int
2114 process_chroot_logins(void)
2115 {
2116 /*
2117 * If the shell field starts with a '*', do a chroot to the home
2118 * directory and perform a new login.
2119 */
2120
2121 if (*pwd->pw_shell == '*') {
2122 (void) pam_end(pamh, PAM_SUCCESS); /* Done using PAM */
2123 pamh = NULL; /* really done */
2124 if (chroot(pwd->pw_dir) < 0) {
2125 (void) printf("No Root Directory\n");
2126
2127 audit_failure(get_audit_id(),
2128 ADT_FAIL_VALUE_CHDIR_FAILED,
2129 pwd, remote_host, ttyn, zone_name);
2130
2131 return (ERROR);
2132 }
2133 /*
2134 * Set the environment flag <!sublogin> so that the next login
2135 * knows that it is a sublogin.
2136 */
2137 envinit[0] = SUBLOGIN;
2138 envinit[1] = (char *)NULL;
2139 (void) printf("Subsystem root: %s\n", pwd->pw_dir);
2140 (void) execle("/usr/bin/login", "login", (char *)0,
2141 &envinit[0]);
2142 (void) execle("/etc/login", "login", (char *)0, &envinit[0]);
2143 (void) printf("No /usr/bin/login or /etc/login on root\n");
2144
2145 audit_error = ADT_FAIL_VALUE_PROGRAM;
2146
2147 login_exit(1);
2148 }
2149 return (OK);
2150 }
2151
2152 /*
2153 * establish_user_environment - Set up the new users enviornment
2154 */
2155
2156 static void
2157 establish_user_environment(char **renvp)
2158 {
2159 int i, j, k, l_index, length, idx = 0;
2160 char *endptr;
2161 char **lenvp;
2162 char **pam_env;
2163
2164 lenvp = environ;
2165 while (*lenvp++)
2166 ;
2167
2168 /* count the number of PAM environment variables set by modules */
2169 if ((pam_env = pam_getenvlist(pamh)) != 0) {
2177 (void) printf("Calloc failed - out of swap space.\n");
2178 login_exit(8);
2179 }
2180
2181 /*
2182 * add PAM environment variables first so they
2183 * can be overwritten at login's discretion.
2184 * check for illegal environment variables.
2185 */
2186 idx = 0; basicenv = 0;
2187 if (pam_env != 0) {
2188 while (pam_env[idx] != 0) {
2189 if (legalenvvar(pam_env[idx])) {
2190 envinit[basicenv] = pam_env[idx];
2191 basicenv++;
2192 }
2193 idx++;
2194 }
2195 }
2196 (void) memcpy(&envinit[basicenv], newenv, sizeof (newenv));
2197
2198 /* Set up environment */
2199 if (rflag) {
2200 ENVSTRNCAT(term, terminal);
2201 } else if (hflag) {
2202 if (strlen(terminal)) {
2203 ENVSTRNCAT(term, terminal);
2204 }
2205 } else {
2206 char *tp = getenv("TERM");
2207
2208 if ((tp != NULL) && (*tp != '\0'))
2209 ENVSTRNCAT(term, tp);
2210 }
2211
2212 ENVSTRNCAT(logname, pwd->pw_name);
2213
2214 /*
2215 * There are three places to get timezone info. init.c sets
2216 * TZ if the file /etc/TIMEZONE contains a value for TZ.
|