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 - 2009, 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"
54 #include "exitcodes.h"
58 static pam_handle_t *pamh = NULL;
60 #define PAM_FAIL_CHECK if (retcode != PAM_SUCCESS) { \
61 fprintf(stderr,"\n%s\n",pam_strerror(pamh, retcode)); \
62 SYSLOG((LOG_ERR,"%s",pam_strerror(pamh, retcode))); \
63 (void) pam_end(pamh, retcode); \
66 #define PAM_END { retcode = pam_close_session(pamh,0); \
67 (void) pam_end(pamh,retcode); }
73 * Needed for MkLinux DR1/2/2.1 - J.
76 #define LASTLOG_FILE "/var/log/lastlog"
85 static const char *hostname = "";
86 static char *username = NULL;
87 static int reason = PW_LOGIN;
90 static struct lastlog ll;
92 static bool pflg = false;
93 static bool fflg = false;
96 static bool rflg = false;
100 static bool hflg = false;
101 static bool preauth_flag = false;
104 static unsigned int timeout;
107 * External identifiers.
110 extern char **newenvp;
111 extern size_t newenvc;
112 extern char **environ;
122 /* local function prototypes */
123 static void usage (void);
124 static void setup_tty (void);
125 static void process_flags (int, char *const *);
126 static const char *get_failent_user (const char *user);
127 static void update_utmp (const char *username,
129 const char *hostname,
130 const struct utmp *utent);
133 static struct faillog faillog;
135 static void bad_time_notify (void);
136 static void check_nologin (bool login_to_root);
138 static void get_pam_user (char **ptr_pam_user);
141 static void init_env (void);
142 static RETSIGTYPE alarm_handler (int);
145 * usage - print login command usage and exit
148 * login -r hostname (for rlogind)
149 * login -h hostname (for telnetd, etc.)
150 * login -f name (for pre-authenticated login: datakit, xterm, etc.)
152 static void usage (void)
154 fprintf (stderr, _("Usage: %s [-p] [name]\n"), Prog);
158 fprintf (stderr, _(" %s [-p] [-h host] [-f name]\n"), Prog);
160 fprintf (stderr, _(" %s [-p] -r host\n"), Prog);
165 static void setup_tty (void)
171 if (GTTY (0, &termio) == 0) { /* get terminal characteristics */
174 * Add your favorite terminal modes here ...
176 termio.c_lflag |= ISIG | ICANON | ECHO | ECHOE;
177 termio.c_iflag |= ICRNL;
179 #if defined(ECHOKE) && defined(ECHOCTL)
180 termio.c_lflag |= ECHOKE | ECHOCTL;
182 #if defined(ECHOPRT) && defined(NOFLSH) && defined(TOSTOP)
183 termio.c_lflag &= ~(ECHOPRT | NOFLSH | TOSTOP);
186 termio.c_oflag |= ONLCR;
189 /* leave these values unchanged if not specified in login.defs */
190 erasechar = getdef_num ("ERASECHAR", (int) termio.c_cc[VERASE]);
191 killchar = getdef_num ("KILLCHAR", (int) termio.c_cc[VKILL]);
192 termio.c_cc[VERASE] = (cc_t) erasechar;
193 termio.c_cc[VKILL] = (cc_t) killchar;
194 /* Make sure the values were valid.
195 * getdef_num cannot validate this.
197 if (erasechar != termio.c_cc[VERASE]) {
199 _("configuration error - cannot parse %s value: '%d'"),
200 "ERASECHAR", erasechar);
203 if (killchar != termio.c_cc[VKILL]) {
205 _("configuration error - cannot parse %s value: '%d'"),
206 "KILLCHAR", killchar);
211 * ttymon invocation prefers this, but these settings won't come into
212 * effect after the first username login
214 (void) STTY (0, &termio);
221 * Tell the user that this is not the right time to login at this tty
223 static void bad_time_notify (void)
225 (void) puts (_("Invalid login time"));
226 (void) fflush (stdout);
229 static void check_nologin (bool login_to_root)
234 * Check to see if system is turned off for non-root users.
235 * This would be useful to prevent users from logging in
236 * during system maintenance. We make sure the message comes
237 * out for root so she knows to remove the file if she's
238 * forgotten about it ...
240 fname = getdef_str ("NOLOGINS_FILE");
241 if ((NULL != fname) && (access (fname, F_OK) == 0)) {
246 * Cat the file if it can be opened, otherwise just
247 * print a default message
249 nlfp = fopen (fname, "r");
251 while ((c = getc (nlfp)) != EOF) {
253 (void) putchar ('\r');
258 (void) fflush (stdout);
259 (void) fclose (nlfp);
261 (void) puts (_("\nSystem closed for routine maintenance"));
264 * Non-root users must exit. Root gets the message, but
268 if (!login_to_root) {
272 (void) puts (_("\n[Disconnect bypassed -- root login allowed.]"));
275 #endif /* !USE_PAM */
277 static void process_flags (int argc, char *const *argv)
283 * Check the flags for proper form. Every argument starting with
284 * "-" must be exactly two characters long. This closes all the
285 * clever rlogin, telnet, and getty holes.
287 for (arg = 1; arg < argc; arg++) {
288 if (argv[arg][0] == '-' && strlen (argv[arg]) > 2) {
291 if (strcmp(argv[arg], "--") == 0) {
292 break; /* stop checking on a "--" */
299 while ((flag = getopt (argc, argv, "d:fh:pr:")) != EOF) {
302 /* "-d device" ignored for compatibility */
329 * Neither -h nor -f should be combined with -r.
332 if (rflg && (hflg || fflg)) {
338 * Allow authentication bypass only if real UID is zero.
341 if ((rflg || fflg || hflg) && !amroot) {
342 fprintf (stderr, _("%s: Permission denied.\n"), Prog);
350 username = xstrdup (argv[optind]);
351 strzero (argv[optind]);
356 if (rflg && (NULL != username)) {
360 if (fflg && (NULL == username)) {
367 static void init_env (void)
374 tmp = getenv ("LANG");
376 addenv ("LANG", tmp);
380 * Add the timezone environmental variable so that time functions
389 cp = getdef_str ("ENV_TZ");
391 addenv (('/' == *cp) ? tz (cp) : cp, NULL);
394 #endif /* !USE_PAM */
396 * Add the clock frequency so that profiling commands work
405 cp = getdef_str ("ENV_HZ");
410 #endif /* !USE_PAM */
414 static RETSIGTYPE alarm_handler (unused int sig)
416 fprintf (stderr, _("\nLogin timed out after %u seconds.\n"), timeout);
422 * get_pam_user - Get the username according to PAM
424 * ptr_pam_user shall point to a malloc'ed string (or NULL).
426 static void get_pam_user (char **ptr_pam_user)
431 assert (NULL != ptr_pam_user);
433 retcode = pam_get_item (pamh, PAM_USER, (const void **)&ptr_user);
436 if (NULL != *ptr_pam_user) {
437 free (*ptr_pam_user);
439 if (NULL != ptr_user) {
440 *ptr_pam_user = xstrdup ((const char *)ptr_user);
442 *ptr_pam_user = NULL;
448 * get_failent_user - Return a string that can be used to log failure
451 * This will be either the user argument, or "UNKNOWN".
453 * It is quite common to mistyped the password for username, and passwords
454 * should not be logged.
456 static const char *get_failent_user (const char *user)
458 const char *failent_user = "UNKNOWN";
459 bool log_unkfail_enab = getdef_bool("LOG_UNKFAIL_ENAB");
461 if ((NULL != user) && ('\0' != user[0])) {
462 if ( log_unkfail_enab
463 || (getpwnam (user) != NULL)) {
472 * update_utmp - Update or create an utmp entry in utmp, wtmp, utmpw, and
475 * utent should be the utmp entry returned by get_current_utmp (or
478 static void update_utmp (const char *username,
480 const char *hostname,
481 /*@null@*/const struct utmp *utent)
483 struct utmp *ut = prepare_utmp (username, tty, hostname, utent);
485 struct utmpx *utx = prepare_utmpx (username, tty, hostname, utent);
486 #endif /* HAVE_UTMPX_H */
488 (void) setutmp (ut); /* make entry in the utmp & wtmp files */
492 (void) setutmpx (utx); /* make entry in the utmpx & wtmpx files */
494 #endif /* HAVE_UTMPX_H */
498 * login - create a new login session for a user
500 * login is typically called by getty as the second step of a
501 * new user session. getty is responsible for setting the line
502 * characteristics to a reasonable set of values and getting
503 * the name of the user to be logged in. login may also be
504 * called to create a new user session on a pty for a variety
505 * of reasons, such as X servers or network logins.
507 * the flags which login supports are
509 * -p - preserve the environment
510 * -r - perform autologin protocol for rlogin
511 * -f - do not perform authentication, user is preauthenticated
512 * -h - the name of the remote host
514 int main (int argc, char **argv)
522 #if defined(HAVE_STRFTIME) && !defined(USE_PAM)
526 unsigned int retries;
528 bool subroot = false;
536 struct passwd *pwd = NULL;
537 char **envp = environ;
538 const char *failent_user;
544 char *pam_user = NULL;
546 struct spwd *spwd = NULL;
549 * Some quick initialization.
554 (void) setlocale (LC_ALL, "");
555 (void) bindtextdomain (PACKAGE, LOCALEDIR);
556 (void) textdomain (PACKAGE);
560 amroot = (getuid () == 0);
561 Prog = Basename (argv[0]);
563 if (geteuid() != 0) {
564 fprintf (stderr, _("%s: Cannot possibly work without effective root\n"), Prog);
568 process_flags (argc, argv);
570 if ((isatty (0) == 0) || (isatty (1) == 0) || (isatty (2) == 0)) {
571 exit (1); /* must be a terminal */
574 utent = get_current_utmp ();
576 * Be picky if run by normal users (possible if installed setuid
577 * root), but not if run by root. This way it still allows logins
578 * even if your getty is broken, or if something corrupts utmp,
579 * but users must "exec login" which will use the existing utmp
580 * entry (will not overwrite remote hostname). --marekm
582 if (!amroot && (NULL == utent)) {
583 (void) puts (_("No utmp entry. You must exec \"login\" from the lowest level \"sh\""));
586 /* NOTE: utent might be NULL afterwards */
588 tmptty = ttyname (0);
589 if (NULL == tmptty) {
592 STRFCPY (tty, tmptty);
595 is_console = console (tty);
600 * Add remote hostname to the environment. I think
601 * (not sure) I saw it once on Irix. --marekm
603 addenv ("REMOTEHOST", hostname);
613 username = malloc (32 * sizeof (char));
614 if (do_rlogin (hostname, username, 32, term, sizeof term)) {
628 (void) umask (getdef_num ("UMASK", GETDEF_DEFAULT_UMASK));
632 * Use the ULIMIT in the login.defs file, and if
633 * there isn't one, use the default value. The
634 * user may have one for themselves, but otherwise,
635 * just take what you get.
637 long limit = getdef_long ("ULIMIT", -1L);
640 set_filesize_limit (limit);
646 * The entire environment will be preserved if the -p flag
650 while (NULL != *envp) { /* add inherited environment, */
651 addenv (*envp, NULL); /* some variables change later */
657 if (term[0] != '\0') {
658 addenv ("TERM", term);
662 /* preserve TERM from getty */
664 tmp = getenv ("TERM");
666 addenv ("TERM", tmp);
673 if (optind < argc) { /* now set command line variables */
674 set_env (argc - optind, &argv[optind]);
679 #ifdef HAVE_STRUCT_UTMP_UT_HOST
680 } else if ((NULL != utent) && ('\0' != utent->ut_host[0])) {
682 #endif /* HAVE_STRUCT_UTMP_UT_HOST */
688 snprintf (fromhost, sizeof fromhost,
689 " on '%.100s' from '%.200s'", tty, cp);
691 snprintf (fromhost, sizeof fromhost,
692 " on '%.100s'", tty);
696 /* only allow ALARM sec. for login */
697 (void) signal (SIGALRM, alarm_handler);
698 timeout = getdef_unum ("LOGIN_TIMEOUT", ALARM);
700 (void) alarm (timeout);
703 environ = newenvp; /* make new environment active */
704 delay = getdef_unum ("FAIL_DELAY", 1);
705 retries = getdef_unum ("LOGIN_RETRIES", RETRIES);
708 retcode = pam_start ("login", username, &conv, &pamh);
709 if (retcode != PAM_SUCCESS) {
711 _("login: PAM Failure, aborting: %s\n"),
712 pam_strerror (pamh, retcode));
713 SYSLOG ((LOG_ERR, "Couldn't initialize PAM: %s",
714 pam_strerror (pamh, retcode)));
719 * hostname & tty are either set to NULL or their correct values,
720 * depending on how much we know. We also set PAM's fail delay to
723 * PAM_RHOST and PAM_TTY are used for authentication, only use
724 * information coming from login or from the caller (e.g. no utmp)
726 retcode = pam_set_item (pamh, PAM_RHOST, hostname);
728 retcode = pam_set_item (pamh, PAM_TTY, tty);
730 #ifdef HAS_PAM_FAIL_DELAY
731 retcode = pam_fail_delay (pamh, 1000000 * delay);
734 /* if fflg, then the user has already been authenticated */
738 char loginprompt[256]; /* That's one hell of a prompt :) */
740 /* Make the login prompt look like we want it */
741 if (gethostname (hostn, sizeof (hostn)) == 0) {
742 snprintf (loginprompt,
743 sizeof (loginprompt),
744 _("%s login: "), hostn);
746 snprintf (loginprompt,
747 sizeof (loginprompt), _("login: "));
750 retcode = pam_set_item (pamh, PAM_USER_PROMPT, loginprompt);
753 /* if we didn't get a user on the command line,
755 get_pam_user (&pam_user);
756 if ((NULL != pam_user) && ('\0' == pam_user[0])) {
757 retcode = pam_set_item (pamh, PAM_USER, NULL);
762 * There may be better ways to deal with some of
763 * these conditions, but at least this way I don't
764 * think we'll be giving away information. Perhaps
765 * someday we can trust that all PAM modules will
766 * pay attention to failure count and get rid of
774 #ifdef HAS_PAM_FAIL_DELAY
776 retcode = pam_fail_delay(pamh, 1000000*delay);
781 retcode = pam_authenticate (pamh, 0);
783 get_pam_user (&pam_user);
784 failent_user = get_failent_user (pam_user);
786 if (retcode == PAM_MAXTRIES) {
788 "TOO MANY LOGIN TRIES (%d)%s FOR '%s'",
789 failcount, fromhost, failent_user));
791 _("Maximum number of tries exceeded (%d)\n"),
795 } else if (retcode == PAM_ABORT) {
796 /* Serious problems, quit now */
797 (void) fputs (_("login: abort requested by PAM\n"), stderr);
798 SYSLOG ((LOG_ERR,"PAM_ABORT returned from pam_authenticate()"));
801 } else if (retcode != PAM_SUCCESS) {
802 SYSLOG ((LOG_NOTICE,"FAILED LOGIN (%d)%s FOR '%s', %s",
803 failcount, fromhost, failent_user,
804 pam_strerror (pamh, retcode)));
813 audit_fd = audit_open ();
814 audit_log_acct_message (audit_fd,
816 NULL, /* Prog. name */
825 #endif /* WITH_AUDIT */
827 fprintf (stderr, "\nLogin incorrect\n");
829 if (failcount >= retries) {
831 "TOO MANY LOGIN TRIES (%d)%s FOR '%s'",
832 failcount, fromhost, failent_user));
834 _("Maximum number of tries exceeded (%d)\n"),
841 * Let's give it another go around.
842 * Even if a username was given on the command
843 * line, prompt again for the username.
845 retcode = pam_set_item (pamh, PAM_USER, NULL);
849 /* We don't get here unless they were authenticated above */
853 /* Check the account validity */
854 retcode = pam_acct_mgmt (pamh, 0);
855 if (retcode == PAM_NEW_AUTHTOK_REQD) {
856 retcode = pam_chauthtok (pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
860 /* Open the PAM session */
861 get_pam_user (&pam_user);
862 retcode = pam_open_session (pamh, hushed (pam_user) ? PAM_SILENT : 0);
865 /* Grab the user information out of the password file for future usage
866 * First get the username that we are actually using, though.
868 * From now on, we will discard changes of the user (PAM_USER) by
871 get_pam_user (&pam_user);
872 if (NULL != username) {
876 failent_user = get_failent_user (username);
878 pwd = xgetpwnam (username);
880 SYSLOG ((LOG_ERR, "cannot find user %s", failent_user));
884 /* This set up the process credential (group) and initialize the
885 * supplementary group access list.
886 * This has to be done before pam_setcred
888 if (setup_groups (pwd) != 0) {
892 retcode = pam_setcred (pamh, PAM_ESTABLISH_CRED);
894 /* NOTE: If pam_setcred changes PAM_USER, this will not be taken
898 #else /* ! USE_PAM */
899 while (true) { /* repeatedly get login/password pairs */
900 /* user_passwd is always a pointer to this constant string
901 * or a passwd or shadow password that will be memzero by
902 * pw_free / spw_free.
903 * Do not free() user_passwd. */
904 const char *user_passwd = "!";
906 /* Do some cleanup to avoid keeping entries we do not need
916 failed = false; /* haven't failed authentication yet */
917 if (NULL == username) { /* need to get a login id */
922 preauth_flag = false;
923 username = malloc (32);
924 login_prompt (_("\n%s login: "), username, 32);
926 if ('\0' == username) {
927 /* Prompt for a new login */
933 /* Get the username to be used to log failures */
934 failent_user = get_failent_user (username);
936 pwd = xgetpwnam (username);
938 preauth_flag = false;
941 user_passwd = pwd->pw_passwd;
943 * If the encrypted password begins with a "!",
944 * the account is locked and the user cannot
945 * login, even if they have been
946 * "pre-authenticated."
948 if ( ('!' == user_passwd[0])
949 || ('*' == user_passwd[0])) {
954 if (strcmp (user_passwd, SHADOW_PASSWD_STRING) == 0) {
955 spwd = xgetspnam (username);
957 user_passwd = spwd->sp_pwdp;
959 /* The user exists in passwd, but not in
960 * shadow. SHADOW_PASSWD_STRING indicates
961 * that the password shall be in shadow.
964 "no shadow password for '%s'%s",
965 username, fromhost));
970 * The -r and -f flags provide a name which has already
971 * been authenticated by some server.
977 if (pw_auth (user_passwd, username, reason, (char *) 0) == 0) {
981 SYSLOG ((LOG_WARN, "invalid password for '%s' %s",
982 failent_user, fromhost));
987 * This is the point where all authenticated users wind up.
988 * If you reach this far, your password has been
989 * authenticated and so on.
993 && (0 == pwd->pw_uid)
995 SYSLOG ((LOG_CRIT, "ILLEGAL ROOT LOGIN %s", fromhost));
999 && !login_access (username, *hostname ? hostname : tty)) {
1000 SYSLOG ((LOG_WARN, "LOGIN '%s' REFUSED %s",
1001 username, fromhost));
1005 && getdef_bool ("FAILLOG_ENAB")
1006 && !failcheck (pwd->pw_uid, &faillog, failed)) {
1008 "exceeded failure limit for '%s' %s",
1009 username, fromhost));
1016 /* don't log non-existent users */
1017 if ((NULL != pwd) && getdef_bool ("FAILLOG_ENAB")) {
1018 failure (pwd->pw_uid, tty, &faillog);
1020 if (getdef_str ("FTMP_FILE") != NULL) {
1022 struct utmpx *failent =
1023 prepare_utmpx (failent_user,
1025 /* FIXME: or fromhost? */hostname,
1028 struct utmp *failent =
1029 prepare_utmp (failent_user,
1034 failtmp (failent_user, failent);
1040 SYSLOG ((LOG_CRIT, "REPEATED login failures%s",
1045 * If this was a passwordless account and we get here, login
1046 * was denied (securetty, faillog, etc.). There was no
1047 * password prompt, so do it now (will always fail - the bad
1048 * guys won't see that the passwordless account exists at
1051 if (user_passwd[0] == '\0') {
1052 pw_auth ("!", username, reason, (char *) 0);
1056 * Authentication of this user failed.
1057 * The username must be confirmed in the next try.
1063 * Wait a while (a la SVR4 /usr/bin/login) before attempting
1064 * to login the user again. If the earlier alarm occurs
1065 * before the sleep() below completes, login will exit.
1068 (void) sleep (delay);
1071 (void) puts (_("Login incorrect"));
1073 /* allow only one attempt with -r or -f */
1074 if (rflg || fflg || (retries <= 0)) {
1078 } /* while (true) */
1079 #endif /* ! USE_PAM */
1081 (void) alarm (0); /* turn off alarm clock */
1083 #ifndef USE_PAM /* PAM does this */
1085 * porttime checks moved here, after the user has been
1086 * authenticated. now prints a message, as suggested
1087 * by Ivan Nejgebauer <ian@unsux.ns.ac.yu>. --marekm
1089 if ( getdef_bool ("PORTTIME_CHECKS_ENAB")
1090 && !isttytime (username, tty, time ((time_t *) 0))) {
1091 SYSLOG ((LOG_WARN, "invalid login time for '%s'%s",
1092 username, fromhost));
1098 check_nologin (pwd->pw_uid == 0);
1101 if (getenv ("IFS")) { /* don't export user IFS ... */
1102 addenv ("IFS= \t\n", NULL); /* ... instead, set a safe IFS */
1105 update_utmp (username, tty, hostname, utent);
1107 if (pwd->pw_shell[0] == '*') { /* subsystem root */
1108 pwd->pw_shell++; /* skip the '*' */
1109 subsystem (pwd); /* figure out what to execute */
1110 subroot = true; /* say I was here again */
1111 endpwent (); /* close all of the file which were */
1112 endgrent (); /* open in the original rooted file */
1113 endspent (); /* system. they will be re-opened */
1115 endsgent (); /* in the new rooted file system */
1117 goto top; /* go do all this all over again */
1121 audit_fd = audit_open ();
1122 audit_log_acct_message (audit_fd,
1124 NULL, /* Prog. name */
1133 #endif /* WITH_AUDIT */
1135 #ifndef USE_PAM /* pam_lastlog handles this */
1136 if (getdef_bool ("LASTLOG_ENAB")) { /* give last login and log this one */
1137 dolastlog (&ll, pwd, tty, hostname);
1141 #ifndef USE_PAM /* PAM handles this as well */
1143 * Have to do this while we still have root privileges, otherwise we
1144 * don't have access to /etc/shadow.
1146 if (NULL != spwd) { /* check for age of password */
1147 if (expire (pwd, spwd)) {
1148 /* The user updated her password, get the new
1150 * Use the x variants because we need to keep the
1151 * entry for a long time, and there might be other
1152 * getxxyy in between.
1155 pwd = xgetpwnam (username);
1158 "cannot find user %s after update of expired password",
1163 spwd = xgetspnam (username);
1166 setup_limits (pwd); /* nice, ulimit etc. */
1167 #endif /* ! USE_PAM */
1172 * We must fork before setuid() because we need to call
1173 * pam_close_session() as root.
1175 (void) signal (SIGINT, SIG_IGN);
1178 /* error in fork() */
1179 fprintf (stderr, _("%s: failure forking: %s"),
1180 Prog, strerror (errno));
1183 } else if (child != 0) {
1185 * parent - wait for child to finish, then cleanup
1194 /* If we were init, we need to start a new session */
1195 if (getppid() == 1) {
1197 if (ioctl(0, TIOCSCTTY, 1) != 0) {
1198 fprintf (stderr, _("TIOCSCTTY failed on %s"), tty);
1203 /* The pwd and spwd entries for the user have been copied.
1205 * Close all the files so that unauthorized access won't occur.
1207 endpwent (); /* stop access to password file */
1208 endgrent (); /* stop access to group file */
1209 endspent (); /* stop access to shadow passwd file */
1211 endsgent (); /* stop access to shadow group file */
1214 /* Drop root privileges */
1216 if (setup_uid_gid (pwd, is_console))
1218 /* The group privileges were already dropped.
1219 * See setup_groups() above.
1221 if (change_uid (pwd))
1227 setup_env (pwd); /* set env vars, cd to the home dir */
1231 const char *const *env;
1233 env = (const char *const *) pam_getenvlist (pamh);
1234 while ((NULL != env) && (NULL != *env)) {
1235 addenv (*env, NULL);
1241 (void) setlocale (LC_ALL, "");
1242 (void) bindtextdomain (PACKAGE, LOCALEDIR);
1243 (void) textdomain (PACKAGE);
1245 if (!hushed (username)) {
1246 addenv ("HUSHLOGIN=FALSE", NULL);
1248 * pam_unix, pam_mail and pam_lastlog should take care of
1252 motd (); /* print the message of the day */
1253 if ( getdef_bool ("FAILLOG_ENAB")
1254 && (0 != faillog.fail_cnt)) {
1255 failprint (&faillog);
1256 /* Reset the lockout times if logged in */
1257 if ( (0 != faillog.fail_max)
1258 && (faillog.fail_cnt >= faillog.fail_max)) {
1259 (void) puts (_("Warning: login re-enabled after temporary lockout."));
1261 "login '%s' re-enabled after temporary lockout (%d failures)",
1262 username, (int) faillog.fail_cnt));
1265 if ( getdef_bool ("LASTLOG_ENAB")
1266 && (ll.ll_time != 0)) {
1267 time_t ll_time = ll.ll_time;
1269 #ifdef HAVE_STRFTIME
1270 (void) strftime (ptime, sizeof (ptime),
1271 "%a %b %e %H:%M:%S %z %Y",
1272 localtime (&ll_time));
1273 printf (_("Last login: %s on %s"),
1276 printf (_("Last login: %.19s on %s"),
1277 ctime (&ll_time), ll.ll_line);
1279 #ifdef HAVE_LL_HOST /* __linux__ || SUN4 */
1280 if ('\0' != ll.ll_host[0]) {
1281 printf (_(" from %.*s"),
1282 (int) sizeof ll.ll_host, ll.ll_host);
1289 mailcheck (); /* report on the status of mail */
1290 #endif /* !USE_PAM */
1292 addenv ("HUSHLOGIN=TRUE", NULL);
1297 (void) signal (SIGQUIT, SIG_DFL); /* default quit signal */
1298 (void) signal (SIGTERM, SIG_DFL); /* default terminate signal */
1299 (void) signal (SIGALRM, SIG_DFL); /* default alarm signal */
1300 (void) signal (SIGHUP, SIG_DFL); /* added this. --marekm */
1301 (void) signal (SIGINT, SIG_DFL); /* default interrupt signal */
1303 if (0 == pwd->pw_uid) {
1304 SYSLOG ((LOG_NOTICE, "ROOT LOGIN %s", fromhost));
1305 } else if (getdef_bool ("LOG_OK_LOGINS")) {
1306 SYSLOG ((LOG_INFO, "'%s' logged in %s", username, fromhost));
1309 tmp = getdef_str ("FAKE_SHELL");
1311 err = shell (tmp, pwd->pw_shell, newenvp); /* fake shell */
1313 /* exec the shell finally */
1314 err = shell (pwd->pw_shell, (char *) 0, newenvp);
1316 exit (err == ENOENT ? E_CMD_NOTFOUND : E_CMD_NOEXEC);