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 - 2010, 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 unsigned int timeout;
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,
132 /*@null@*/const struct utmp *utent);
135 static struct faillog faillog;
137 static void bad_time_notify (void);
138 static void check_nologin (bool login_to_root);
140 static void get_pam_user (char **ptr_pam_user);
143 static void init_env (void);
144 static RETSIGTYPE alarm_handler (int);
147 * usage - print login command usage and exit
150 * login -r hostname (for rlogind)
151 * login -h hostname (for telnetd, etc.)
152 * login -f name (for pre-authenticated login: datakit, xterm, etc.)
154 static void usage (void)
156 fprintf (stderr, _("Usage: %s [-p] [name]\n"), Prog);
160 fprintf (stderr, _(" %s [-p] [-h host] [-f name]\n"), Prog);
162 fprintf (stderr, _(" %s [-p] -r host\n"), Prog);
167 static void setup_tty (void)
171 if (GTTY (0, &termio) == 0) { /* get terminal characteristics */
176 * Add your favorite terminal modes here ...
178 termio.c_lflag |= ISIG | ICANON | ECHO | ECHOE;
179 termio.c_iflag |= ICRNL;
181 #if defined(ECHOKE) && defined(ECHOCTL)
182 termio.c_lflag |= ECHOKE | ECHOCTL;
184 #if defined(ECHOPRT) && defined(NOFLSH) && defined(TOSTOP)
185 termio.c_lflag &= ~(ECHOPRT | NOFLSH | TOSTOP);
188 termio.c_oflag |= ONLCR;
191 /* leave these values unchanged if not specified in login.defs */
192 erasechar = getdef_num ("ERASECHAR", (int) termio.c_cc[VERASE]);
193 killchar = getdef_num ("KILLCHAR", (int) termio.c_cc[VKILL]);
194 termio.c_cc[VERASE] = (cc_t) erasechar;
195 termio.c_cc[VKILL] = (cc_t) killchar;
196 /* Make sure the values were valid.
197 * getdef_num cannot validate this.
199 if (erasechar != (int) termio.c_cc[VERASE]) {
201 _("configuration error - cannot parse %s value: '%d'"),
202 "ERASECHAR", erasechar);
205 if (killchar != (int) termio.c_cc[VKILL]) {
207 _("configuration error - cannot parse %s value: '%d'"),
208 "KILLCHAR", killchar);
213 * ttymon invocation prefers this, but these settings
214 * won't come into effect after the first username login
216 (void) STTY (0, &termio);
223 * Tell the user that this is not the right time to login at this tty
225 static void bad_time_notify (void)
227 (void) puts (_("Invalid login time"));
228 (void) fflush (stdout);
231 static void check_nologin (bool login_to_root)
236 * Check to see if system is turned off for non-root users.
237 * This would be useful to prevent users from logging in
238 * during system maintenance. We make sure the message comes
239 * out for root so she knows to remove the file if she's
240 * forgotten about it ...
242 fname = getdef_str ("NOLOGINS_FILE");
243 if ((NULL != fname) && (access (fname, F_OK) == 0)) {
247 * Cat the file if it can be opened, otherwise just
248 * print a default message
250 nlfp = fopen (fname, "r");
253 while ((c = getc (nlfp)) != EOF) {
255 (void) putchar ('\r');
260 (void) fflush (stdout);
261 (void) fclose (nlfp);
263 (void) puts (_("\nSystem closed for routine maintenance"));
266 * Non-root users must exit. Root gets the message, but
270 if (!login_to_root) {
274 (void) puts (_("\n[Disconnect bypassed -- root login allowed.]"));
277 #endif /* !USE_PAM */
279 static void process_flags (int argc, char *const *argv)
285 * Check the flags for proper form. Every argument starting with
286 * "-" must be exactly two characters long. This closes all the
287 * clever rlogin, telnet, and getty holes.
289 for (arg = 1; arg < argc; arg++) {
290 if (argv[arg][0] == '-' && strlen (argv[arg]) > 2) {
293 if (strcmp(argv[arg], "--") == 0) {
294 break; /* stop checking on a "--" */
301 while ((flag = getopt (argc, argv, "d:fh:pr:")) != EOF) {
304 /* "-d device" ignored for compatibility */
331 * Neither -h nor -f should be combined with -r.
334 if (rflg && (hflg || fflg)) {
340 * Allow authentication bypass only if real UID is zero.
343 if ((rflg || fflg || hflg) && !amroot) {
344 fprintf (stderr, _("%s: Permission denied.\n"), Prog);
352 assert (NULL == username);
353 username = xstrdup (argv[optind]);
354 strzero (argv[optind]);
359 if (rflg && (NULL != username)) {
363 if (fflg && (NULL == username)) {
370 static void init_env (void)
377 tmp = getenv ("LANG");
379 addenv ("LANG", tmp);
383 * Add the timezone environmental variable so that time functions
392 cp = getdef_str ("ENV_TZ");
394 addenv (('/' == *cp) ? tz (cp) : cp, NULL);
397 #endif /* !USE_PAM */
399 * Add the clock frequency so that profiling commands work
408 cp = getdef_str ("ENV_HZ");
413 #endif /* !USE_PAM */
417 static RETSIGTYPE alarm_handler (unused int sig)
419 fprintf (stderr, _("\nLogin timed out after %u seconds.\n"), timeout);
425 * get_pam_user - Get the username according to PAM
427 * ptr_pam_user shall point to a malloc'ed string (or NULL).
429 static void get_pam_user (char **ptr_pam_user)
434 assert (NULL != ptr_pam_user);
436 retcode = pam_get_item (pamh, PAM_USER, (const void **)&ptr_user);
439 if (NULL != *ptr_pam_user) {
440 free (*ptr_pam_user);
442 if (NULL != ptr_user) {
443 *ptr_pam_user = xstrdup ((const char *)ptr_user);
445 *ptr_pam_user = NULL;
451 * get_failent_user - Return a string that can be used to log failure
454 * This will be either the user argument, or "UNKNOWN".
456 * It is quite common to mistyped the password for username, and passwords
457 * should not be logged.
459 static /*@observer@*/const char *get_failent_user (/*@returned@*/const char *user)
461 const char *failent_user = "UNKNOWN";
462 bool log_unkfail_enab = getdef_bool("LOG_UNKFAIL_ENAB");
464 if ((NULL != user) && ('\0' != user[0])) {
465 if ( log_unkfail_enab
466 || (getpwnam (user) != NULL)) {
475 * update_utmp - Update or create an utmp entry in utmp, wtmp, utmpw, and
478 * utent should be the utmp entry returned by get_current_utmp (or
481 static void update_utmp (const char *user,
484 /*@null@*/const struct utmp *utent)
486 struct utmp *ut = prepare_utmp (user, tty, host, utent);
488 struct utmpx *utx = prepare_utmpx (user, tty, host, utent);
489 #endif /* USE_UTMPX */
491 (void) setutmp (ut); /* make entry in the utmp & wtmp files */
495 (void) setutmpx (utx); /* make entry in the utmpx & wtmpx files */
497 #endif /* USE_UTMPX */
501 * login - create a new login session for a user
503 * login is typically called by getty as the second step of a
504 * new user session. getty is responsible for setting the line
505 * characteristics to a reasonable set of values and getting
506 * the name of the user to be logged in. login may also be
507 * called to create a new user session on a pty for a variety
508 * of reasons, such as X servers or network logins.
510 * the flags which login supports are
512 * -p - preserve the environment
513 * -r - perform autologin protocol for rlogin
514 * -f - do not perform authentication, user is preauthenticated
515 * -h - the name of the remote host
517 int main (int argc, char **argv)
525 #if defined(HAVE_STRFTIME) && !defined(USE_PAM)
529 unsigned int retries;
530 bool subroot = false;
538 struct passwd *pwd = NULL;
539 char **envp = environ;
540 const char *failent_user;
541 /*@null@*/struct utmp *utent;
546 char *pam_user = NULL;
548 struct spwd *spwd = NULL;
551 * Some quick initialization.
556 (void) setlocale (LC_ALL, "");
557 (void) bindtextdomain (PACKAGE, LOCALEDIR);
558 (void) textdomain (PACKAGE);
562 amroot = (getuid () == 0);
563 Prog = Basename (argv[0]);
565 if (geteuid() != 0) {
566 fprintf (stderr, _("%s: Cannot possibly work without effective root\n"), Prog);
570 process_flags (argc, argv);
572 if ((isatty (0) == 0) || (isatty (1) == 0) || (isatty (2) == 0)) {
573 exit (1); /* must be a terminal */
576 utent = get_current_utmp ();
578 * Be picky if run by normal users (possible if installed setuid
579 * root), but not if run by root. This way it still allows logins
580 * even if your getty is broken, or if something corrupts utmp,
581 * but users must "exec login" which will use the existing utmp
582 * entry (will not overwrite remote hostname). --marekm
584 if (!amroot && (NULL == utent)) {
585 (void) puts (_("No utmp entry. You must exec \"login\" from the lowest level \"sh\""));
588 /* NOTE: utent might be NULL afterwards */
590 tmptty = ttyname (0);
591 if (NULL == tmptty) {
594 STRFCPY (tty, tmptty);
597 is_console = console (tty);
602 * Add remote hostname to the environment. I think
603 * (not sure) I saw it once on Irix. --marekm
605 addenv ("REMOTEHOST", hostname);
615 assert (NULL == username);
616 username = xmalloc (USER_NAME_MAX_LENGTH + 1);
617 username[USER_NAME_MAX_LENGTH] = '\0';
618 if (do_rlogin (hostname, username, USER_NAME_MAX_LENGTH, term, sizeof term)) {
632 (void) umask (getdef_num ("UMASK", GETDEF_DEFAULT_UMASK));
636 * Use the ULIMIT in the login.defs file, and if
637 * there isn't one, use the default value. The
638 * user may have one for themselves, but otherwise,
639 * just take what you get.
641 long limit = getdef_long ("ULIMIT", -1L);
644 set_filesize_limit (limit);
650 * The entire environment will be preserved if the -p flag
654 while (NULL != *envp) { /* add inherited environment, */
655 addenv (*envp, NULL); /* some variables change later */
661 if (term[0] != '\0') {
662 addenv ("TERM", term);
666 /* preserve TERM from getty */
668 tmp = getenv ("TERM");
670 addenv ("TERM", tmp);
677 if (optind < argc) { /* now set command line variables */
678 set_env (argc - optind, &argv[optind]);
683 #ifdef HAVE_STRUCT_UTMP_UT_HOST
684 } else if ((NULL != utent) && ('\0' != utent->ut_host[0])) {
686 #endif /* HAVE_STRUCT_UTMP_UT_HOST */
692 snprintf (fromhost, sizeof fromhost,
693 " on '%.100s' from '%.200s'", tty, cp);
695 snprintf (fromhost, sizeof fromhost,
696 " on '%.100s'", tty);
700 /* only allow ALARM sec. for login */
701 (void) signal (SIGALRM, alarm_handler);
702 timeout = getdef_unum ("LOGIN_TIMEOUT", ALARM);
704 (void) alarm (timeout);
707 environ = newenvp; /* make new environment active */
708 delay = getdef_unum ("FAIL_DELAY", 1);
709 retries = getdef_unum ("LOGIN_RETRIES", RETRIES);
712 retcode = pam_start ("login", username, &conv, &pamh);
713 if (retcode != PAM_SUCCESS) {
715 _("login: PAM Failure, aborting: %s\n"),
716 pam_strerror (pamh, retcode));
717 SYSLOG ((LOG_ERR, "Couldn't initialize PAM: %s",
718 pam_strerror (pamh, retcode)));
723 * hostname & tty are either set to NULL or their correct values,
724 * depending on how much we know. We also set PAM's fail delay to
727 * PAM_RHOST and PAM_TTY are used for authentication, only use
728 * information coming from login or from the caller (e.g. no utmp)
730 retcode = pam_set_item (pamh, PAM_RHOST, hostname);
732 retcode = pam_set_item (pamh, PAM_TTY, tty);
734 #ifdef HAS_PAM_FAIL_DELAY
735 retcode = pam_fail_delay (pamh, 1000000 * delay);
738 /* if fflg, then the user has already been authenticated */
740 unsigned int failcount = 0;
742 char loginprompt[256]; /* That's one hell of a prompt :) */
744 /* Make the login prompt look like we want it */
745 if (gethostname (hostn, sizeof (hostn)) == 0) {
746 snprintf (loginprompt,
747 sizeof (loginprompt),
748 _("%s login: "), hostn);
750 strncpy (loginprompt, _("login: "),
751 sizeof (loginprompt));
754 retcode = pam_set_item (pamh, PAM_USER_PROMPT, loginprompt);
757 /* if we didn't get a user on the command line,
759 get_pam_user (&pam_user);
760 if ((NULL != pam_user) && ('\0' == pam_user[0])) {
761 retcode = pam_set_item (pamh, PAM_USER, NULL);
766 * There may be better ways to deal with some of
767 * these conditions, but at least this way I don't
768 * think we'll be giving away information. Perhaps
769 * someday we can trust that all PAM modules will
770 * pay attention to failure count and get rid of
778 #ifdef HAS_PAM_FAIL_DELAY
780 retcode = pam_fail_delay(pamh, 1000000*delay);
785 retcode = pam_authenticate (pamh, 0);
787 get_pam_user (&pam_user);
788 failent_user = get_failent_user (pam_user);
790 if (retcode == PAM_MAXTRIES) {
792 "TOO MANY LOGIN TRIES (%u)%s FOR '%s'",
793 failcount, fromhost, failent_user));
795 _("Maximum number of tries exceeded (%u)\n"),
799 } else if (retcode == PAM_ABORT) {
800 /* Serious problems, quit now */
801 (void) fputs (_("login: abort requested by PAM\n"), stderr);
802 SYSLOG ((LOG_ERR,"PAM_ABORT returned from pam_authenticate()"));
805 } else if (retcode != PAM_SUCCESS) {
806 SYSLOG ((LOG_NOTICE,"FAILED LOGIN (%u)%s FOR '%s', %s",
807 failcount, fromhost, failent_user,
808 pam_strerror (pamh, retcode)));
817 audit_fd = audit_open ();
818 audit_log_acct_message (audit_fd,
820 NULL, /* Prog. name */
829 #endif /* WITH_AUDIT */
832 (void) puts (_("Login incorrect"));
834 if (failcount >= retries) {
836 "TOO MANY LOGIN TRIES (%u)%s FOR '%s'",
837 failcount, fromhost, failent_user));
839 _("Maximum number of tries exceeded (%u)\n"),
846 * Let's give it another go around.
847 * Even if a username was given on the command
848 * line, prompt again for the username.
850 retcode = pam_set_item (pamh, PAM_USER, NULL);
854 /* We don't get here unless they were authenticated above */
858 /* Check the account validity */
859 retcode = pam_acct_mgmt (pamh, 0);
860 if (retcode == PAM_NEW_AUTHTOK_REQD) {
861 retcode = pam_chauthtok (pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
865 /* Open the PAM session */
866 get_pam_user (&pam_user);
867 retcode = pam_open_session (pamh, hushed (pam_user) ? PAM_SILENT : 0);
870 /* Grab the user information out of the password file for future usage
871 * First get the username that we are actually using, though.
873 * From now on, we will discard changes of the user (PAM_USER) by
876 get_pam_user (&pam_user);
877 if (NULL != username) {
881 failent_user = get_failent_user (username);
883 pwd = xgetpwnam (username);
885 SYSLOG ((LOG_ERR, "cannot find user %s", failent_user));
889 /* This set up the process credential (group) and initialize the
890 * supplementary group access list.
891 * This has to be done before pam_setcred
893 if (setup_groups (pwd) != 0) {
897 retcode = pam_setcred (pamh, PAM_ESTABLISH_CRED);
899 /* NOTE: If pam_setcred changes PAM_USER, this will not be taken
903 #else /* ! USE_PAM */
904 while (true) { /* repeatedly get login/password pairs */
906 /* user_passwd is always a pointer to this constant string
907 * or a passwd or shadow password that will be memzero by
908 * pw_free / spw_free.
909 * Do not free() user_passwd. */
910 const char *user_passwd = "!";
912 /* Do some cleanup to avoid keeping entries we do not need
923 failed = false; /* haven't failed authentication yet */
924 if (NULL == username) { /* need to get a login id */
929 preauth_flag = false;
930 username = xmalloc (USER_NAME_MAX_LENGTH + 1);
931 username[USER_NAME_MAX_LENGTH] = '\0';
932 login_prompt (_("\n%s login: "), username, USER_NAME_MAX_LENGTH);
934 if ('\0' == username[0]) {
935 /* Prompt for a new login */
941 /* Get the username to be used to log failures */
942 failent_user = get_failent_user (username);
944 pwd = xgetpwnam (username);
946 preauth_flag = false;
949 user_passwd = pwd->pw_passwd;
951 * If the encrypted password begins with a "!",
952 * the account is locked and the user cannot
953 * login, even if they have been
954 * "pre-authenticated."
956 if ( ('!' == user_passwd[0])
957 || ('*' == user_passwd[0])) {
962 if (strcmp (user_passwd, SHADOW_PASSWD_STRING) == 0) {
963 spwd = xgetspnam (username);
965 user_passwd = spwd->sp_pwdp;
967 /* The user exists in passwd, but not in
968 * shadow. SHADOW_PASSWD_STRING indicates
969 * that the password shall be in shadow.
972 "no shadow password for '%s'%s",
973 username, fromhost));
978 * The -r and -f flags provide a name which has already
979 * been authenticated by some server.
985 if (pw_auth (user_passwd, username, reason, (char *) 0) == 0) {
989 SYSLOG ((LOG_WARN, "invalid password for '%s' %s",
990 failent_user, fromhost));
995 * This is the point where all authenticated users wind up.
996 * If you reach this far, your password has been
997 * authenticated and so on.
1001 && (0 == pwd->pw_uid)
1003 SYSLOG ((LOG_CRIT, "ILLEGAL ROOT LOGIN %s", fromhost));
1007 && !login_access (username, ('\0' != *hostname) ? hostname : tty)) {
1008 SYSLOG ((LOG_WARN, "LOGIN '%s' REFUSED %s",
1009 username, fromhost));
1013 && getdef_bool ("FAILLOG_ENAB")
1014 && !failcheck (pwd->pw_uid, &faillog, failed)) {
1016 "exceeded failure limit for '%s' %s",
1017 username, fromhost));
1024 /* don't log non-existent users */
1025 if ((NULL != pwd) && getdef_bool ("FAILLOG_ENAB")) {
1026 failure (pwd->pw_uid, tty, &faillog);
1028 if (getdef_str ("FTMP_FILE") != NULL) {
1030 struct utmpx *failent =
1031 prepare_utmpx (failent_user,
1033 /* FIXME: or fromhost? */hostname,
1035 #else /* !USE_UTMPX */
1036 struct utmp *failent =
1037 prepare_utmp (failent_user,
1041 #endif /* !USE_UTMPX */
1042 failtmp (failent_user, failent);
1048 SYSLOG ((LOG_CRIT, "REPEATED login failures%s",
1053 * If this was a passwordless account and we get here, login
1054 * was denied (securetty, faillog, etc.). There was no
1055 * password prompt, so do it now (will always fail - the bad
1056 * guys won't see that the passwordless account exists at
1059 if (user_passwd[0] == '\0') {
1060 pw_auth ("!", username, reason, (char *) 0);
1064 * Authentication of this user failed.
1065 * The username must be confirmed in the next try.
1071 * Wait a while (a la SVR4 /usr/bin/login) before attempting
1072 * to login the user again. If the earlier alarm occurs
1073 * before the sleep() below completes, login will exit.
1076 (void) sleep (delay);
1079 (void) puts (_("Login incorrect"));
1081 /* allow only one attempt with -r or -f */
1082 if (rflg || fflg || (retries <= 0)) {
1086 } /* while (true) */
1087 #endif /* ! USE_PAM */
1088 assert (NULL != username);
1089 assert (NULL != pwd);
1091 (void) alarm (0); /* turn off alarm clock */
1093 #ifndef USE_PAM /* PAM does this */
1095 * porttime checks moved here, after the user has been
1096 * authenticated. now prints a message, as suggested
1097 * by Ivan Nejgebauer <ian@unsux.ns.ac.yu>. --marekm
1099 if ( getdef_bool ("PORTTIME_CHECKS_ENAB")
1100 && !isttytime (username, tty, time ((time_t *) 0))) {
1101 SYSLOG ((LOG_WARN, "invalid login time for '%s'%s",
1102 username, fromhost));
1108 check_nologin (pwd->pw_uid == 0);
1111 if (getenv ("IFS")) { /* don't export user IFS ... */
1112 addenv ("IFS= \t\n", NULL); /* ... instead, set a safe IFS */
1115 if (pwd->pw_shell[0] == '*') { /* subsystem root */
1116 pwd->pw_shell++; /* skip the '*' */
1117 subsystem (pwd); /* figure out what to execute */
1118 subroot = true; /* say I was here again */
1119 endpwent (); /* close all of the file which were */
1120 endgrent (); /* open in the original rooted file */
1121 endspent (); /* system. they will be re-opened */
1123 endsgent (); /* in the new rooted file system */
1125 goto top; /* go do all this all over again */
1129 audit_fd = audit_open ();
1130 audit_log_acct_message (audit_fd,
1132 NULL, /* Prog. name */
1141 #endif /* WITH_AUDIT */
1143 #ifndef USE_PAM /* pam_lastlog handles this */
1144 if (getdef_bool ("LASTLOG_ENAB")) { /* give last login and log this one */
1145 dolastlog (&ll, pwd, tty, hostname);
1149 #ifndef USE_PAM /* PAM handles this as well */
1151 * Have to do this while we still have root privileges, otherwise we
1152 * don't have access to /etc/shadow.
1154 if (NULL != spwd) { /* check for age of password */
1155 if (expire (pwd, spwd)) {
1156 /* The user updated her password, get the new
1158 * Use the x variants because we need to keep the
1159 * entry for a long time, and there might be other
1160 * getxxyy in between.
1163 pwd = xgetpwnam (username);
1166 "cannot find user %s after update of expired password",
1171 spwd = xgetspnam (username);
1174 setup_limits (pwd); /* nice, ulimit etc. */
1175 #endif /* ! USE_PAM */
1180 * We must fork before setuid() because we need to call
1181 * pam_close_session() as root.
1183 (void) signal (SIGINT, SIG_IGN);
1186 /* error in fork() */
1187 fprintf (stderr, _("%s: failure forking: %s"),
1188 Prog, strerror (errno));
1191 } else if (child != 0) {
1193 * parent - wait for child to finish, then cleanup
1203 /* If we were init, we need to start a new session */
1204 if (getppid() == 1) {
1206 if (ioctl(0, TIOCSCTTY, 1) != 0) {
1207 fprintf (stderr, _("TIOCSCTTY failed on %s"), tty);
1212 * The utmp entry needs to be updated to indicate the new status
1213 * of the session, the new PID and SID.
1215 update_utmp (username, tty, hostname, utent);
1217 /* The pwd and spwd entries for the user have been copied.
1219 * Close all the files so that unauthorized access won't occur.
1221 endpwent (); /* stop access to password file */
1222 endgrent (); /* stop access to group file */
1223 endspent (); /* stop access to shadow passwd file */
1225 endsgent (); /* stop access to shadow group file */
1228 /* Drop root privileges */
1230 if (setup_uid_gid (pwd, is_console))
1232 /* The group privileges were already dropped.
1233 * See setup_groups() above.
1235 if (change_uid (pwd))
1241 setup_env (pwd); /* set env vars, cd to the home dir */
1245 const char *const *env;
1247 env = (const char *const *) pam_getenvlist (pamh);
1248 while ((NULL != env) && (NULL != *env)) {
1249 addenv (*env, NULL);
1255 (void) setlocale (LC_ALL, "");
1256 (void) bindtextdomain (PACKAGE, LOCALEDIR);
1257 (void) textdomain (PACKAGE);
1259 if (!hushed (username)) {
1260 addenv ("HUSHLOGIN=FALSE", NULL);
1262 * pam_unix, pam_mail and pam_lastlog should take care of
1266 motd (); /* print the message of the day */
1267 if ( getdef_bool ("FAILLOG_ENAB")
1268 && (0 != faillog.fail_cnt)) {
1269 failprint (&faillog);
1270 /* Reset the lockout times if logged in */
1271 if ( (0 != faillog.fail_max)
1272 && (faillog.fail_cnt >= faillog.fail_max)) {
1273 (void) puts (_("Warning: login re-enabled after temporary lockout."));
1275 "login '%s' re-enabled after temporary lockout (%d failures)",
1276 username, (int) faillog.fail_cnt));
1279 if ( getdef_bool ("LASTLOG_ENAB")
1280 && (ll.ll_time != 0)) {
1281 time_t ll_time = ll.ll_time;
1283 #ifdef HAVE_STRFTIME
1284 (void) strftime (ptime, sizeof (ptime),
1285 "%a %b %e %H:%M:%S %z %Y",
1286 localtime (&ll_time));
1287 printf (_("Last login: %s on %s"),
1290 printf (_("Last login: %.19s on %s"),
1291 ctime (&ll_time), ll.ll_line);
1293 #ifdef HAVE_LL_HOST /* __linux__ || SUN4 */
1294 if ('\0' != ll.ll_host[0]) {
1295 printf (_(" from %.*s"),
1296 (int) sizeof ll.ll_host, ll.ll_host);
1303 mailcheck (); /* report on the status of mail */
1304 #endif /* !USE_PAM */
1306 addenv ("HUSHLOGIN=TRUE", NULL);
1311 (void) signal (SIGQUIT, SIG_DFL); /* default quit signal */
1312 (void) signal (SIGTERM, SIG_DFL); /* default terminate signal */
1313 (void) signal (SIGALRM, SIG_DFL); /* default alarm signal */
1314 (void) signal (SIGHUP, SIG_DFL); /* added this. --marekm */
1315 (void) signal (SIGINT, SIG_DFL); /* default interrupt signal */
1317 if (0 == pwd->pw_uid) {
1318 SYSLOG ((LOG_NOTICE, "ROOT LOGIN %s", fromhost));
1319 } else if (getdef_bool ("LOG_OK_LOGINS")) {
1320 SYSLOG ((LOG_INFO, "'%s' logged in %s", username, fromhost));
1323 tmp = getdef_str ("FAKE_SHELL");
1325 err = shell (tmp, pwd->pw_shell, newenvp); /* fake shell */
1327 /* exec the shell finally */
1328 err = shell (pwd->pw_shell, (char *) 0, newenvp);
1331 return ((err == ENOENT) ? E_CMD_NOTFOUND : E_CMD_NOEXEC);