2 * Copyright (c) 1989 - 1994, Julianne Frances Haugh
3 * Copyright (c) 1996 - 2001, Marek Michałkiewicz
4 * Copyright (c) 2001 - 2006, Tomasz Kłoczko
5 * Copyright (c) 2007 - 2012, Nicolas François
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the copyright holders or contributors may not be used to
17 * endorse or promote products derived from this software without
18 * specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
46 #include <sys/ioctl.h>
52 #include "prototypes.h"
55 #include "exitcodes.h"
60 static pam_handle_t *pamh = NULL;
62 #define PAM_FAIL_CHECK if (retcode != PAM_SUCCESS) { \
63 fprintf(stderr,"\n%s\n",pam_strerror(pamh, retcode)); \
64 SYSLOG((LOG_ERR,"%s",pam_strerror(pamh, retcode))); \
65 (void) pam_end(pamh, retcode); \
68 #define PAM_END { retcode = pam_close_session(pamh,0); \
69 (void) pam_end(pamh,retcode); }
75 * Needed for MkLinux DR1/2/2.1 - J.
78 #define LASTLOG_FILE "/var/log/lastlog"
87 static const char *hostname = "";
88 static /*@null@*/ /*@only@*/char *username = NULL;
89 static int reason = PW_LOGIN;
92 static struct lastlog ll;
94 static bool pflg = false;
95 static bool fflg = false;
98 static bool rflg = false;
102 static bool hflg = false;
103 static bool preauth_flag = false;
106 static char tmsg[256];
109 * External identifiers.
112 extern char **newenvp;
113 extern size_t newenvc;
114 extern char **environ;
124 /* local function prototypes */
125 static void usage (void);
126 static void setup_tty (void);
127 static void process_flags (int argc, char *const *argv);
128 static /*@observer@*/const char *get_failent_user (/*@returned@*/const char *user);
129 static void update_utmp (const char *user,
133 /*@null@*/const struct utmpx *utent
135 /*@null@*/const struct utmp *utent
140 static struct faillog faillog;
142 static void bad_time_notify (void);
143 static void check_nologin (bool login_to_root);
145 static void get_pam_user (char **ptr_pam_user);
148 static void init_env (void);
149 static RETSIGTYPE alarm_handler (int);
152 * usage - print login command usage and exit
155 * login -r hostname (for rlogind)
156 * login -h hostname (for telnetd, etc.)
157 * login -f name (for pre-authenticated login: datakit, xterm, etc.)
159 static void usage (void)
161 fprintf (stderr, _("Usage: %s [-p] [name]\n"), Prog);
165 fprintf (stderr, _(" %s [-p] [-h host] [-f name]\n"), Prog);
167 fprintf (stderr, _(" %s [-p] -r host\n"), Prog);
172 static void setup_tty (void)
176 if (GTTY (0, &termio) == 0) { /* get terminal characteristics */
181 * Add your favorite terminal modes here ...
183 termio.c_lflag |= ISIG | ICANON | ECHO | ECHOE;
184 termio.c_iflag |= ICRNL;
186 #if defined(ECHOKE) && defined(ECHOCTL)
187 termio.c_lflag |= ECHOKE | ECHOCTL;
189 #if defined(ECHOPRT) && defined(NOFLSH) && defined(TOSTOP)
190 termio.c_lflag &= ~(ECHOPRT | NOFLSH | TOSTOP);
193 termio.c_oflag |= ONLCR;
196 /* leave these values unchanged if not specified in login.defs */
197 erasechar = getdef_num ("ERASECHAR", (int) termio.c_cc[VERASE]);
198 killchar = getdef_num ("KILLCHAR", (int) termio.c_cc[VKILL]);
199 termio.c_cc[VERASE] = (cc_t) erasechar;
200 termio.c_cc[VKILL] = (cc_t) killchar;
201 /* Make sure the values were valid.
202 * getdef_num cannot validate this.
204 if (erasechar != (int) termio.c_cc[VERASE]) {
206 _("configuration error - cannot parse %s value: '%d'"),
207 "ERASECHAR", erasechar);
210 if (killchar != (int) termio.c_cc[VKILL]) {
212 _("configuration error - cannot parse %s value: '%d'"),
213 "KILLCHAR", killchar);
218 * ttymon invocation prefers this, but these settings
219 * won't come into effect after the first username login
221 (void) STTY (0, &termio);
228 * Tell the user that this is not the right time to login at this tty
230 static void bad_time_notify (void)
232 (void) puts (_("Invalid login time"));
233 (void) fflush (stdout);
236 static void check_nologin (bool login_to_root)
241 * Check to see if system is turned off for non-root users.
242 * This would be useful to prevent users from logging in
243 * during system maintenance. We make sure the message comes
244 * out for root so she knows to remove the file if she's
245 * forgotten about it ...
247 fname = getdef_str ("NOLOGINS_FILE");
248 if ((NULL != fname) && (access (fname, F_OK) == 0)) {
252 * Cat the file if it can be opened, otherwise just
253 * print a default message
255 nlfp = fopen (fname, "r");
258 while ((c = getc (nlfp)) != EOF) {
260 (void) putchar ('\r');
265 (void) fflush (stdout);
266 (void) fclose (nlfp);
268 (void) puts (_("\nSystem closed for routine maintenance"));
271 * Non-root users must exit. Root gets the message, but
275 if (!login_to_root) {
279 (void) puts (_("\n[Disconnect bypassed -- root login allowed.]"));
282 #endif /* !USE_PAM */
284 static void process_flags (int argc, char *const *argv)
290 * Check the flags for proper form. Every argument starting with
291 * "-" must be exactly two characters long. This closes all the
292 * clever rlogin, telnet, and getty holes.
294 for (arg = 1; arg < argc; arg++) {
295 if (argv[arg][0] == '-' && strlen (argv[arg]) > 2) {
298 if (strcmp(argv[arg], "--") == 0) {
299 break; /* stop checking on a "--" */
306 while ((flag = getopt (argc, argv, "d:fh:pr:")) != EOF) {
309 /* "-d device" ignored for compatibility */
336 * Neither -h nor -f should be combined with -r.
339 if (rflg && (hflg || fflg)) {
345 * Allow authentication bypass only if real UID is zero.
348 if ((rflg || fflg || hflg) && !amroot) {
349 fprintf (stderr, _("%s: Permission denied.\n"), Prog);
357 assert (NULL == username);
358 username = xstrdup (argv[optind]);
359 strzero (argv[optind]);
364 if (rflg && (NULL != username)) {
368 if (fflg && (NULL == username)) {
375 static void init_env (void)
382 tmp = getenv ("LANG");
384 addenv ("LANG", tmp);
388 * Add the timezone environmental variable so that time functions
397 cp = getdef_str ("ENV_TZ");
399 addenv (('/' == *cp) ? tz (cp) : cp, NULL);
402 #endif /* !USE_PAM */
404 * Add the clock frequency so that profiling commands work
413 cp = getdef_str ("ENV_HZ");
418 #endif /* !USE_PAM */
422 static RETSIGTYPE alarm_handler (unused int sig)
424 write (STDERR_FILENO, tmsg, strlen (tmsg));
430 * get_pam_user - Get the username according to PAM
432 * ptr_pam_user shall point to a malloc'ed string (or NULL).
434 static void get_pam_user (char **ptr_pam_user)
439 assert (NULL != ptr_pam_user);
441 retcode = pam_get_item (pamh, PAM_USER, (const void **)&ptr_user);
444 if (NULL != *ptr_pam_user) {
445 free (*ptr_pam_user);
447 if (NULL != ptr_user) {
448 *ptr_pam_user = xstrdup ((const char *)ptr_user);
450 *ptr_pam_user = NULL;
456 * get_failent_user - Return a string that can be used to log failure
459 * This will be either the user argument, or "UNKNOWN".
461 * It is quite common to mistyped the password for username, and passwords
462 * should not be logged.
464 static /*@observer@*/const char *get_failent_user (/*@returned@*/const char *user)
466 const char *failent_user = "UNKNOWN";
467 bool log_unkfail_enab = getdef_bool("LOG_UNKFAIL_ENAB");
469 if ((NULL != user) && ('\0' != user[0])) {
470 if ( log_unkfail_enab
471 || (getpwnam (user) != NULL)) {
480 * update_utmp - Update or create an utmp entry in utmp, wtmp, utmpw, and
483 * utent should be the utmp entry returned by get_current_utmp (or
486 static void update_utmp (const char *user,
490 /*@null@*/const struct utmpx *utent
492 /*@null@*/const struct utmp *utent
497 struct utmpx *utx = prepare_utmpx (user, tty, host, utent);
499 struct utmp *ut = prepare_utmp (user, tty, host, utent);
500 #endif /* USE_UTMPX */
503 (void) setutmp (ut); /* make entry in the utmp & wtmp files */
506 (void) setutmpx (utx); /* make entry in the utmpx & wtmpx files */
508 #endif /* USE_UTMPX */
512 * login - create a new login session for a user
514 * login is typically called by getty as the second step of a
515 * new user session. getty is responsible for setting the line
516 * characteristics to a reasonable set of values and getting
517 * the name of the user to be logged in. login may also be
518 * called to create a new user session on a pty for a variety
519 * of reasons, such as X servers or network logins.
521 * the flags which login supports are
523 * -p - preserve the environment
524 * -r - perform autologin protocol for rlogin
525 * -f - do not perform authentication, user is preauthenticated
526 * -h - the name of the remote host
528 int main (int argc, char **argv)
536 #if defined(HAVE_STRFTIME) && !defined(USE_PAM)
540 unsigned int retries;
541 bool subroot = false;
546 unsigned int timeout;
550 struct passwd *pwd = NULL;
551 char **envp = environ;
552 const char *failent_user;
554 /*@null@*/struct utmpx *utent;
556 /*@null@*/struct utmp *utent;
562 char *pam_user = NULL;
564 struct spwd *spwd = NULL;
567 * Some quick initialization.
572 (void) setlocale (LC_ALL, "");
573 (void) bindtextdomain (PACKAGE, LOCALEDIR);
574 (void) textdomain (PACKAGE);
578 amroot = (getuid () == 0);
579 Prog = Basename (argv[0]);
581 if (geteuid() != 0) {
582 fprintf (stderr, _("%s: Cannot possibly work without effective root\n"), Prog);
586 process_flags (argc, argv);
588 if ((isatty (0) == 0) || (isatty (1) == 0) || (isatty (2) == 0)) {
589 exit (1); /* must be a terminal */
592 utent = get_current_utmp ();
594 * Be picky if run by normal users (possible if installed setuid
595 * root), but not if run by root. This way it still allows logins
596 * even if your getty is broken, or if something corrupts utmp,
597 * but users must "exec login" which will use the existing utmp
598 * entry (will not overwrite remote hostname). --marekm
600 if (!amroot && (NULL == utent)) {
601 (void) puts (_("No utmp entry. You must exec \"login\" from the lowest level \"sh\""));
604 /* NOTE: utent might be NULL afterwards */
606 tmptty = ttyname (0);
607 if (NULL == tmptty) {
610 STRFCPY (tty, tmptty);
613 is_console = console (tty);
618 * Add remote hostname to the environment. I think
619 * (not sure) I saw it once on Irix. --marekm
621 addenv ("REMOTEHOST", hostname);
631 assert (NULL == username);
632 username = xmalloc (USER_NAME_MAX_LENGTH + 1);
633 username[USER_NAME_MAX_LENGTH] = '\0';
634 if (do_rlogin (hostname, username, USER_NAME_MAX_LENGTH, term, sizeof term)) {
648 (void) umask (getdef_num ("UMASK", GETDEF_DEFAULT_UMASK));
652 * Use the ULIMIT in the login.defs file, and if
653 * there isn't one, use the default value. The
654 * user may have one for themselves, but otherwise,
655 * just take what you get.
657 long limit = getdef_long ("ULIMIT", -1L);
660 set_filesize_limit (limit);
666 * The entire environment will be preserved if the -p flag
670 while (NULL != *envp) { /* add inherited environment, */
671 addenv (*envp, NULL); /* some variables change later */
677 if (term[0] != '\0') {
678 addenv ("TERM", term);
682 /* preserve TERM from getty */
684 tmp = getenv ("TERM");
686 addenv ("TERM", tmp);
693 if (optind < argc) { /* now set command line variables */
694 set_env (argc - optind, &argv[optind]);
699 #if defined(HAVE_STRUCT_UTMP_UT_HOST) || defined(USE_UTMPX)
700 } else if ((NULL != utent) && ('\0' != utent->ut_host[0])) {
702 #endif /* HAVE_STRUCT_UTMP_UT_HOST */
708 snprintf (fromhost, sizeof fromhost,
709 " on '%.100s' from '%.200s'", tty, cp);
711 snprintf (fromhost, sizeof fromhost,
712 " on '%.100s'", tty);
716 /* only allow ALARM sec. for login */
717 timeout = getdef_unum ("LOGIN_TIMEOUT", ALARM);
718 snprintf (tmsg, sizeof tmsg,
719 _("\nLogin timed out after %u seconds.\n"), timeout);
720 (void) signal (SIGALRM, alarm_handler);
722 (void) alarm (timeout);
725 environ = newenvp; /* make new environment active */
726 delay = getdef_unum ("FAIL_DELAY", 1);
727 retries = getdef_unum ("LOGIN_RETRIES", RETRIES);
730 retcode = pam_start ("login", username, &conv, &pamh);
731 if (retcode != PAM_SUCCESS) {
733 _("login: PAM Failure, aborting: %s\n"),
734 pam_strerror (pamh, retcode));
735 SYSLOG ((LOG_ERR, "Couldn't initialize PAM: %s",
736 pam_strerror (pamh, retcode)));
741 * hostname & tty are either set to NULL or their correct values,
742 * depending on how much we know. We also set PAM's fail delay to
745 * PAM_RHOST and PAM_TTY are used for authentication, only use
746 * information coming from login or from the caller (e.g. no utmp)
748 retcode = pam_set_item (pamh, PAM_RHOST, hostname);
750 retcode = pam_set_item (pamh, PAM_TTY, tty);
752 #ifdef HAS_PAM_FAIL_DELAY
753 retcode = pam_fail_delay (pamh, 1000000 * delay);
756 /* if fflg, then the user has already been authenticated */
758 unsigned int failcount = 0;
760 char loginprompt[256]; /* That's one hell of a prompt :) */
762 /* Make the login prompt look like we want it */
763 if (gethostname (hostn, sizeof (hostn)) == 0) {
764 snprintf (loginprompt,
765 sizeof (loginprompt),
766 _("%s login: "), hostn);
768 strncpy (loginprompt, _("login: "),
769 sizeof (loginprompt));
772 retcode = pam_set_item (pamh, PAM_USER_PROMPT, loginprompt);
775 /* if we didn't get a user on the command line,
777 get_pam_user (&pam_user);
778 if ((NULL != pam_user) && ('\0' == pam_user[0])) {
779 retcode = pam_set_item (pamh, PAM_USER, NULL);
784 * There may be better ways to deal with some of
785 * these conditions, but at least this way I don't
786 * think we'll be giving away information. Perhaps
787 * someday we can trust that all PAM modules will
788 * pay attention to failure count and get rid of
796 #ifdef HAS_PAM_FAIL_DELAY
798 retcode = pam_fail_delay(pamh, 1000000*delay);
803 retcode = pam_authenticate (pamh, 0);
805 get_pam_user (&pam_user);
806 failent_user = get_failent_user (pam_user);
808 if (retcode == PAM_MAXTRIES) {
810 "TOO MANY LOGIN TRIES (%u)%s FOR '%s'",
811 failcount, fromhost, failent_user));
813 _("Maximum number of tries exceeded (%u)\n"),
817 } else if (retcode == PAM_ABORT) {
818 /* Serious problems, quit now */
819 (void) fputs (_("login: abort requested by PAM\n"), stderr);
820 SYSLOG ((LOG_ERR,"PAM_ABORT returned from pam_authenticate()"));
823 } else if (retcode != PAM_SUCCESS) {
824 SYSLOG ((LOG_NOTICE,"FAILED LOGIN (%u)%s FOR '%s', %s",
825 failcount, fromhost, failent_user,
826 pam_strerror (pamh, retcode)));
835 audit_fd = audit_open ();
836 audit_log_acct_message (audit_fd,
838 NULL, /* Prog. name */
847 #endif /* WITH_AUDIT */
850 (void) puts (_("Login incorrect"));
852 if (failcount >= retries) {
854 "TOO MANY LOGIN TRIES (%u)%s FOR '%s'",
855 failcount, fromhost, failent_user));
857 _("Maximum number of tries exceeded (%u)\n"),
864 * Let's give it another go around.
865 * Even if a username was given on the command
866 * line, prompt again for the username.
868 retcode = pam_set_item (pamh, PAM_USER, NULL);
872 /* We don't get here unless they were authenticated above */
876 /* Check the account validity */
877 retcode = pam_acct_mgmt (pamh, 0);
878 if (retcode == PAM_NEW_AUTHTOK_REQD) {
879 retcode = pam_chauthtok (pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
883 /* Open the PAM session */
884 get_pam_user (&pam_user);
885 retcode = pam_open_session (pamh, hushed (pam_user) ? PAM_SILENT : 0);
888 /* Grab the user information out of the password file for future usage
889 * First get the username that we are actually using, though.
891 * From now on, we will discard changes of the user (PAM_USER) by
894 get_pam_user (&pam_user);
895 if (NULL != username) {
898 username = xstrdup (pam_user);
899 failent_user = get_failent_user (username);
901 pwd = xgetpwnam (username);
903 SYSLOG ((LOG_ERR, "cannot find user %s", failent_user));
905 _("Cannot find user (%s)\n"),
910 /* This set up the process credential (group) and initialize the
911 * supplementary group access list.
912 * This has to be done before pam_setcred
914 if (setup_groups (pwd) != 0) {
918 retcode = pam_setcred (pamh, PAM_ESTABLISH_CRED);
920 /* NOTE: If pam_setcred changes PAM_USER, this will not be taken
924 #else /* ! USE_PAM */
925 while (true) { /* repeatedly get login/password pairs */
927 /* user_passwd is always a pointer to this constant string
928 * or a passwd or shadow password that will be memzero by
929 * pw_free / spw_free.
930 * Do not free() user_passwd. */
931 const char *user_passwd = "!";
933 /* Do some cleanup to avoid keeping entries we do not need
944 failed = false; /* haven't failed authentication yet */
945 if (NULL == username) { /* need to get a login id */
950 preauth_flag = false;
951 username = xmalloc (USER_NAME_MAX_LENGTH + 1);
952 username[USER_NAME_MAX_LENGTH] = '\0';
953 login_prompt (_("\n%s login: "), username, USER_NAME_MAX_LENGTH);
955 if ('\0' == username[0]) {
956 /* Prompt for a new login */
962 /* Get the username to be used to log failures */
963 failent_user = get_failent_user (username);
965 pwd = xgetpwnam (username);
967 preauth_flag = false;
970 user_passwd = pwd->pw_passwd;
972 * If the encrypted password begins with a "!",
973 * the account is locked and the user cannot
974 * login, even if they have been
975 * "pre-authenticated."
977 if ( ('!' == user_passwd[0])
978 || ('*' == user_passwd[0])) {
983 if (strcmp (user_passwd, SHADOW_PASSWD_STRING) == 0) {
984 spwd = xgetspnam (username);
986 user_passwd = spwd->sp_pwdp;
988 /* The user exists in passwd, but not in
989 * shadow. SHADOW_PASSWD_STRING indicates
990 * that the password shall be in shadow.
993 "no shadow password for '%s'%s",
994 username, fromhost));
999 * The -r and -f flags provide a name which has already
1000 * been authenticated by some server.
1006 if (pw_auth (user_passwd, username, reason, (char *) 0) == 0) {
1010 SYSLOG ((LOG_WARN, "invalid password for '%s' %s",
1011 failent_user, fromhost));
1016 * This is the point where all authenticated users wind up.
1017 * If you reach this far, your password has been
1018 * authenticated and so on.
1022 && (0 == pwd->pw_uid)
1024 SYSLOG ((LOG_CRIT, "ILLEGAL ROOT LOGIN %s", fromhost));
1028 && !login_access (username, ('\0' != *hostname) ? hostname : tty)) {
1029 SYSLOG ((LOG_WARN, "LOGIN '%s' REFUSED %s",
1030 username, fromhost));
1034 && getdef_bool ("FAILLOG_ENAB")
1035 && !failcheck (pwd->pw_uid, &faillog, failed)) {
1037 "exceeded failure limit for '%s' %s",
1038 username, fromhost));
1045 /* don't log non-existent users */
1046 if ((NULL != pwd) && getdef_bool ("FAILLOG_ENAB")) {
1047 failure (pwd->pw_uid, tty, &faillog);
1049 if (getdef_str ("FTMP_FILE") != NULL) {
1051 struct utmpx *failent =
1052 prepare_utmpx (failent_user,
1054 /* FIXME: or fromhost? */hostname,
1056 #else /* !USE_UTMPX */
1057 struct utmp *failent =
1058 prepare_utmp (failent_user,
1062 #endif /* !USE_UTMPX */
1063 failtmp (failent_user, failent);
1069 SYSLOG ((LOG_CRIT, "REPEATED login failures%s",
1074 * If this was a passwordless account and we get here, login
1075 * was denied (securetty, faillog, etc.). There was no
1076 * password prompt, so do it now (will always fail - the bad
1077 * guys won't see that the passwordless account exists at
1080 if (user_passwd[0] == '\0') {
1081 pw_auth ("!", username, reason, (char *) 0);
1085 * Authentication of this user failed.
1086 * The username must be confirmed in the next try.
1092 * Wait a while (a la SVR4 /usr/bin/login) before attempting
1093 * to login the user again. If the earlier alarm occurs
1094 * before the sleep() below completes, login will exit.
1097 (void) sleep (delay);
1100 (void) puts (_("Login incorrect"));
1102 /* allow only one attempt with -r or -f */
1103 if (rflg || fflg || (retries <= 0)) {
1107 } /* while (true) */
1108 #endif /* ! USE_PAM */
1109 assert (NULL != username);
1110 assert (NULL != pwd);
1112 (void) alarm (0); /* turn off alarm clock */
1114 #ifndef USE_PAM /* PAM does this */
1116 * porttime checks moved here, after the user has been
1117 * authenticated. now prints a message, as suggested
1118 * by Ivan Nejgebauer <ian@unsux.ns.ac.yu>. --marekm
1120 if ( getdef_bool ("PORTTIME_CHECKS_ENAB")
1121 && !isttytime (username, tty, time ((time_t *) 0))) {
1122 SYSLOG ((LOG_WARN, "invalid login time for '%s'%s",
1123 username, fromhost));
1129 check_nologin (pwd->pw_uid == 0);
1132 if (getenv ("IFS")) { /* don't export user IFS ... */
1133 addenv ("IFS= \t\n", NULL); /* ... instead, set a safe IFS */
1136 if (pwd->pw_shell[0] == '*') { /* subsystem root */
1137 pwd->pw_shell++; /* skip the '*' */
1138 subsystem (pwd); /* figure out what to execute */
1139 subroot = true; /* say I was here again */
1140 endpwent (); /* close all of the file which were */
1141 endgrent (); /* open in the original rooted file */
1142 endspent (); /* system. they will be re-opened */
1144 endsgent (); /* in the new rooted file system */
1146 goto top; /* go do all this all over again */
1150 audit_fd = audit_open ();
1151 audit_log_acct_message (audit_fd,
1153 NULL, /* Prog. name */
1162 #endif /* WITH_AUDIT */
1164 #ifndef USE_PAM /* pam_lastlog handles this */
1165 if ( getdef_bool ("LASTLOG_ENAB")
1166 && pwd->pw_uid <= (uid_t) getdef_ulong ("LASTLOG_UID_MAX", 0xFFFFFFFFUL)) {
1167 /* give last login and log this one */
1168 dolastlog (&ll, pwd, tty, hostname);
1172 #ifndef USE_PAM /* PAM handles this as well */
1174 * Have to do this while we still have root privileges, otherwise we
1175 * don't have access to /etc/shadow.
1177 if (NULL != spwd) { /* check for age of password */
1178 if (expire (pwd, spwd)) {
1179 /* The user updated her password, get the new
1181 * Use the x variants because we need to keep the
1182 * entry for a long time, and there might be other
1183 * getxxyyy in between.
1186 pwd = xgetpwnam (username);
1189 "cannot find user %s after update of expired password",
1194 spwd = xgetspnam (username);
1197 setup_limits (pwd); /* nice, ulimit etc. */
1198 #endif /* ! USE_PAM */
1203 * We must fork before setuid() because we need to call
1204 * pam_close_session() as root.
1206 (void) signal (SIGINT, SIG_IGN);
1209 /* error in fork() */
1210 fprintf (stderr, _("%s: failure forking: %s"),
1211 Prog, strerror (errno));
1214 } else if (child != 0) {
1216 * parent - wait for child to finish, then cleanup
1226 /* If we were init, we need to start a new session */
1227 if (getppid() == 1) {
1229 if (ioctl(0, TIOCSCTTY, 1) != 0) {
1230 fprintf (stderr, _("TIOCSCTTY failed on %s"), tty);
1235 * The utmp entry needs to be updated to indicate the new status
1236 * of the session, the new PID and SID.
1238 update_utmp (username, tty, hostname, utent);
1240 /* The pwd and spwd entries for the user have been copied.
1242 * Close all the files so that unauthorized access won't occur.
1244 endpwent (); /* stop access to password file */
1245 endgrent (); /* stop access to group file */
1246 endspent (); /* stop access to shadow passwd file */
1248 endsgent (); /* stop access to shadow group file */
1251 /* Drop root privileges */
1253 if (setup_uid_gid (pwd, is_console))
1255 /* The group privileges were already dropped.
1256 * See setup_groups() above.
1258 if (change_uid (pwd))
1264 setup_env (pwd); /* set env vars, cd to the home dir */
1268 const char *const *env;
1270 env = (const char *const *) pam_getenvlist (pamh);
1271 while ((NULL != env) && (NULL != *env)) {
1272 addenv (*env, NULL);
1278 (void) setlocale (LC_ALL, "");
1279 (void) bindtextdomain (PACKAGE, LOCALEDIR);
1280 (void) textdomain (PACKAGE);
1282 if (!hushed (username)) {
1283 addenv ("HUSHLOGIN=FALSE", NULL);
1285 * pam_unix, pam_mail and pam_lastlog should take care of
1289 motd (); /* print the message of the day */
1290 if ( getdef_bool ("FAILLOG_ENAB")
1291 && (0 != faillog.fail_cnt)) {
1292 failprint (&faillog);
1293 /* Reset the lockout times if logged in */
1294 if ( (0 != faillog.fail_max)
1295 && (faillog.fail_cnt >= faillog.fail_max)) {
1296 (void) puts (_("Warning: login re-enabled after temporary lockout."));
1298 "login '%s' re-enabled after temporary lockout (%d failures)",
1299 username, (int) faillog.fail_cnt));
1302 if ( getdef_bool ("LASTLOG_ENAB")
1303 && pwd->pw_uid <= (uid_t) getdef_ulong ("LASTLOG_UID_MAX", 0xFFFFFFFFUL)
1304 && (ll.ll_time != 0)) {
1305 time_t ll_time = ll.ll_time;
1307 #ifdef HAVE_STRFTIME
1308 (void) strftime (ptime, sizeof (ptime),
1309 "%a %b %e %H:%M:%S %z %Y",
1310 localtime (&ll_time));
1311 printf (_("Last login: %s on %s"),
1314 printf (_("Last login: %.19s on %s"),
1315 ctime (&ll_time), ll.ll_line);
1317 #ifdef HAVE_LL_HOST /* __linux__ || SUN4 */
1318 if ('\0' != ll.ll_host[0]) {
1319 printf (_(" from %.*s"),
1320 (int) sizeof ll.ll_host, ll.ll_host);
1327 mailcheck (); /* report on the status of mail */
1328 #endif /* !USE_PAM */
1330 addenv ("HUSHLOGIN=TRUE", NULL);
1335 (void) signal (SIGQUIT, SIG_DFL); /* default quit signal */
1336 (void) signal (SIGTERM, SIG_DFL); /* default terminate signal */
1337 (void) signal (SIGALRM, SIG_DFL); /* default alarm signal */
1338 (void) signal (SIGHUP, SIG_DFL); /* added this. --marekm */
1339 (void) signal (SIGINT, SIG_DFL); /* default interrupt signal */
1341 if (0 == pwd->pw_uid) {
1342 SYSLOG ((LOG_NOTICE, "ROOT LOGIN %s", fromhost));
1343 } else if (getdef_bool ("LOG_OK_LOGINS")) {
1344 SYSLOG ((LOG_INFO, "'%s' logged in %s", username, fromhost));
1347 tmp = getdef_str ("FAKE_SHELL");
1349 err = shell (tmp, pwd->pw_shell, newenvp); /* fake shell */
1351 /* exec the shell finally */
1352 err = shell (pwd->pw_shell, (char *) 0, newenvp);
1355 return ((err == ENOENT) ? E_CMD_NOTFOUND : E_CMD_NOEXEC);