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 - 2008, 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.
47 #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); }
72 * Needed for MkLinux DR1/2/2.1 - J.
75 #define LASTLOG_FILE "/var/log/lastlog"
81 const char *hostname = "";
83 static struct passwd pwent;
86 extern struct utmpx utxent;
91 extern struct utmp utent;
93 struct lastlog lastlog;
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;
114 * External identifiers.
117 extern char **newenvp;
118 extern size_t newenvc;
119 extern char **environ;
129 /* local function prototypes */
130 static void usage (void);
131 static void setup_tty (void);
132 static void check_flags (int, char *const *);
135 static struct faillog faillog;
137 static void bad_time_notify (void);
138 static void check_nologin (void);
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)
169 GTTY (0, &termio); /* get terminal characteristics */
172 * Add your favorite terminal modes here ...
174 termio.c_lflag |= ISIG | ICANON | ECHO | ECHOE;
175 termio.c_iflag |= ICRNL;
177 /* leave these values unchanged if not specified in login.defs */
178 termio.c_cc[VERASE] = getdef_num ("ERASECHAR", termio.c_cc[VERASE]);
179 termio.c_cc[VKILL] = getdef_num ("KILLCHAR", termio.c_cc[VKILL]);
182 * ttymon invocation prefers this, but these settings won't come into
183 * effect after the first username login
191 * Tell the user that this is not the right time to login at this tty
193 static void bad_time_notify (void)
195 (void) puts (_("Invalid login time"));
196 (void) fflush (stdout);
199 static void check_nologin (void)
204 * Check to see if system is turned off for non-root users.
205 * This would be useful to prevent users from logging in
206 * during system maintenance. We make sure the message comes
207 * out for root so she knows to remove the file if she's
208 * forgotten about it ...
210 fname = getdef_str ("NOLOGINS_FILE");
211 if ((NULL != fname) && (access (fname, F_OK) == 0)) {
216 * Cat the file if it can be opened, otherwise just
217 * print a default message
219 nlfp = fopen (fname, "r");
221 while ((c = getc (nlfp)) != EOF) {
223 (void) putchar ('\r');
228 (void) fflush (stdout);
229 (void) fclose (nlfp);
231 (void) puts (_("\nSystem closed for routine maintenance"));
234 * Non-root users must exit. Root gets the message, but
238 if (pwent.pw_uid != 0) {
242 puts (_("\n[Disconnect bypassed -- root login allowed.]"));
245 #endif /* !USE_PAM */
247 static void check_flags (int argc, char *const *argv)
252 * Check the flags for proper form. Every argument starting with
253 * "-" must be exactly two characters long. This closes all the
254 * clever rlogin, telnet, and getty holes.
256 for (arg = 1; arg < argc; arg++) {
257 if (argv[arg][0] == '-' && strlen (argv[arg]) > 2) {
260 if (strcmp(argv[arg], "--") == 0) {
261 break; /* stop checking on a "--" */
267 static void init_env (void)
274 tmp = getenv ("LANG");
276 addenv ("LANG", tmp);
280 * Add the timezone environmental variable so that time functions
289 cp = getdef_str ("ENV_TZ");
291 addenv (('/' == *cp) ? tz (cp) : cp, NULL);
294 #endif /* !USE_PAM */
296 * Add the clock frequency so that profiling commands work
305 cp = getdef_str ("ENV_HZ");
310 #endif /* !USE_PAM */
314 static RETSIGTYPE alarm_handler (unused int sig)
316 fprintf (stderr, _("\nLogin timed out after %d seconds.\n"), timeout);
322 * login - create a new login session for a user
324 * login is typically called by getty as the second step of a
325 * new user session. getty is responsible for setting the line
326 * characteristics to a reasonable set of values and getting
327 * the name of the user to be logged in. login may also be
328 * called to create a new user session on a pty for a variety
329 * of reasons, such as X servers or network logins.
331 * the flags which login supports are
333 * -p - preserve the environment
334 * -r - perform autologin protocol for rlogin
335 * -f - do not perform authentication, user is preauthenticated
336 * -h - the name of the remote host
338 int main (int argc, char **argv)
346 #if defined(HAVE_STRFTIME) && !defined(USE_PAM)
349 int reason = PW_LOGIN;
354 bool subroot = false;
363 char **envp = environ;
364 static char temp_pw[2];
365 static char temp_shell[] = "/bin/sh";
371 char **ptr_pam_user = &pam_user;
373 struct spwd *spwd = NULL;
376 * Some quick initialization.
381 (void) setlocale (LC_ALL, "");
382 (void) bindtextdomain (PACKAGE, LOCALEDIR);
383 (void) textdomain (PACKAGE);
388 amroot = (getuid () == 0);
389 Prog = Basename (argv[0]);
391 check_flags (argc, argv);
393 while ((flag = getopt (argc, argv, "d:f::h:pr:")) != EOF) {
396 /* "-d device" ignored for compatibility */
400 * username must be a separate token
401 * (-f root, *not* -froot). --marekm
403 * if -f has an arg, use that, else use the
404 * normal user name passed after all options
407 if (optarg != NULL && optarg != argv[optind - 1]) {
412 STRFCPY (username, optarg);
437 * Neither -h nor -f should be combined with -r.
440 if (rflg && (hflg || fflg)) {
446 * Allow authentication bypass only if real UID is zero.
449 if ((rflg || fflg || hflg) && !amroot) {
450 fprintf (stderr, _("%s: Permission denied.\n"), Prog);
454 if ((isatty (0) == 0) || (isatty (1) == 0) || (isatty (2) == 0)) {
455 exit (1); /* must be a terminal */
459 * Be picky if run by normal users (possible if installed setuid
460 * root), but not if run by root. This way it still allows logins
461 * even if your getty is broken, or if something corrupts utmp,
462 * but users must "exec login" which will use the existing utmp
463 * entry (will not overwrite remote hostname). --marekm
466 STRFCPY (tty, utent.ut_line);
468 is_console = console (tty);
476 * Fill in the ut_addr field (remote login IP address). XXX
477 * - login from util-linux does it, but this is not the
478 * right place to do it. The program that starts login
479 * (telnetd, rlogind) knows the IP address, so it should
480 * create the utmp entry and fill in ut_addr.
481 * gethostbyname() is not 100% reliable (the remote host may
482 * be unknown, etc.). --marekm
484 he = gethostbyname (hostname);
486 utent.ut_addr = *((int32_t *) (he->h_addr_list[0]));
489 strncpy (utent.ut_host, hostname,
490 sizeof (utent.ut_host));
493 strncpy (utxent.ut_host, hostname,
494 sizeof (utxent.ut_host));
497 * Add remote hostname to the environment. I think
498 * (not sure) I saw it once on Irix. --marekm
500 addenv ("REMOTEHOST", hostname);
504 * workaround for init/getty leaving junk in ut_host at least in
505 * some version of RedHat. --marekm
508 memzero (utent.ut_host, sizeof utent.ut_host);
519 && do_rlogin (hostname, username, sizeof username,
520 term, sizeof term)) {
530 umask (getdef_num ("UMASK", GETDEF_DEFAULT_UMASK));
534 * Use the ULIMIT in the login.defs file, and if
535 * there isn't one, use the default value. The
536 * user may have one for themselves, but otherwise,
537 * just take what you get.
539 long limit = getdef_long ("ULIMIT", -1L);
542 set_filesize_limit (limit);
548 * The entire environment will be preserved if the -p flag
552 while (NULL != *envp) { /* add inherited environment, */
553 addenv (*envp, NULL); /* some variables change later */
559 if (term[0] != '\0') {
560 addenv ("TERM", term);
564 /* preserve TERM from getty */
566 tmp = getenv ("TERM");
568 addenv ("TERM", tmp);
575 if (optind < argc) { /* get the user name */
576 if (rflg || (fflg && ('\0' != username[0]))) {
580 STRFCPY (username, argv[optind]);
581 strzero (argv[optind]);
584 if (optind < argc) { /* now set command line variables */
585 set_env (argc - optind, &argv[optind]);
591 /* FIXME: What is the priority:
592 * UT_HOST or HAVE_UTMPX_H? */
594 if ('\0' != utent.ut_host[0]) {
599 if ('\0' != utxent.ut_host[0]) {
609 snprintf (fromhost, sizeof fromhost,
610 " on '%.100s' from '%.200s'", tty, cp);
612 snprintf (fromhost, sizeof fromhost,
613 " on '%.100s'", tty);
617 /* only allow ALARM sec. for login */
618 (void) signal (SIGALRM, alarm_handler);
619 timeout = getdef_num ("LOGIN_TIMEOUT", ALARM);
624 environ = newenvp; /* make new environment active */
625 delay = getdef_num ("FAIL_DELAY", 1);
626 retries = getdef_num ("LOGIN_RETRIES", RETRIES);
629 retcode = pam_start ("login", username, &conv, &pamh);
630 if (retcode != PAM_SUCCESS) {
632 _("login: PAM Failure, aborting: %s\n"),
633 pam_strerror (pamh, retcode));
634 SYSLOG ((LOG_ERR, "Couldn't initialize PAM: %s",
635 pam_strerror (pamh, retcode)));
640 * hostname & tty are either set to NULL or their correct values,
641 * depending on how much we know. We also set PAM's fail delay to
644 retcode = pam_set_item (pamh, PAM_RHOST, hostname);
646 retcode = pam_set_item (pamh, PAM_TTY, tty);
648 #ifdef HAS_PAM_FAIL_DELAY
649 retcode = pam_fail_delay (pamh, 1000000 * delay);
652 /* if fflg, then the user has already been authenticated */
653 if (!fflg || (getuid () != 0)) {
656 char loginprompt[256]; /* That's one hell of a prompt :) */
658 /* Make the login prompt look like we want it */
659 if (gethostname (hostn, sizeof (hostn)) == 0) {
660 snprintf (loginprompt,
661 sizeof (loginprompt),
662 _("%s login: "), hostn);
664 snprintf (loginprompt,
665 sizeof (loginprompt), _("login: "));
669 pam_set_item (pamh, PAM_USER_PROMPT, loginprompt);
672 /* if we didn't get a user on the command line,
674 pam_get_item (pamh, PAM_USER,
675 (const void **)ptr_pam_user);
676 if (pam_user[0] == '\0') {
677 pam_set_item (pamh, PAM_USER, NULL);
681 * There may be better ways to deal with some of
682 * these conditions, but at least this way I don't
683 * think we'll be giving away information. Perhaps
684 * someday we can trust that all PAM modules will
685 * pay attention to failure count and get rid of
690 const char *failent_user;
694 #ifdef HAS_PAM_FAIL_DELAY
696 retcode = pam_fail_delay(pamh, 1000000*delay);
700 retcode = pam_authenticate (pamh, 0);
702 pam_get_item (pamh, PAM_USER,
703 (const void **) ptr_pam_user);
705 if ((NULL != pam_user) && ('\0' != pam_user[0])) {
706 pwd = xgetpwnam(pam_user);
709 failent_user = pwent.pw_name;
711 if ( getdef_bool("LOG_UNKFAIL_ENAB")
712 && (NULL != pam_user)) {
713 failent_user = pam_user;
715 failent_user = "UNKNOWN";
720 failent_user = "UNKNOWN";
723 if (retcode == PAM_MAXTRIES || failcount >= retries) {
725 "TOO MANY LOGIN TRIES (%d)%s FOR '%s'",
726 failcount, fromhost, failent_user));
728 _("Maximum number of tries exceeded (%d)\n"),
732 } else if (retcode == PAM_ABORT) {
733 /* Serious problems, quit now */
734 fputs (_("login: abort requested by PAM\n"),stderr);
735 SYSLOG ((LOG_ERR,"PAM_ABORT returned from pam_authenticate()"));
738 } else if (retcode != PAM_SUCCESS) {
739 SYSLOG ((LOG_NOTICE,"FAILED LOGIN (%d)%s FOR '%s', %s",
740 failcount, fromhost, failent_user,
741 pam_strerror (pamh, retcode)));
750 audit_fd = audit_open ();
751 audit_log_acct_message (audit_fd,
753 NULL, /* Prog. name */
762 #endif /* WITH_AUDIT */
764 fprintf (stderr, "\nLogin incorrect\n");
766 /* Let's give it another go around */
767 pam_set_item (pamh, PAM_USER, NULL);
770 /* We don't get here unless they were authenticated above */
772 retcode = pam_acct_mgmt (pamh, 0);
774 if (retcode == PAM_NEW_AUTHTOK_REQD) {
777 PAM_CHANGE_EXPIRED_AUTHTOK);
783 /* Grab the user information out of the password file for future usage
784 First get the username that we are actually using, though.
787 pam_get_item (pamh, PAM_USER, (const void **)ptr_pam_user);
788 pwd = xgetpwnam (pam_user);
790 SYSLOG ((LOG_ERR, "xgetpwnam(%s) failed",
791 getdef_bool ("LOG_UNKFAIL_ENAB") ?
792 pam_user : "UNKNOWN"));
797 retcode = pam_acct_mgmt (pamh, 0);
801 if (setup_groups (pwd) != 0) {
807 retcode = pam_setcred (pamh, PAM_ESTABLISH_CRED);
810 retcode = pam_open_session (pamh,
811 hushed (&pwent) ? PAM_SILENT : 0);
814 pwd = xgetpwnam (pam_user);
816 pwent.pw_name = pam_user;
817 strcpy (temp_pw, "!");
818 pwent.pw_passwd = temp_pw;
819 pwent.pw_shell = temp_shell;
821 preauth_flag = false;
827 #else /* ! USE_PAM */
828 while (true) { /* repeatedly get login/password pairs */
829 failed = false; /* haven't failed authentication yet */
830 if ('\0' == username[0]) { /* need to get a login id */
835 preauth_flag = false;
836 login_prompt (_("\n%s login: "), username,
841 pwd = xgetpwnam (username);
843 pwent.pw_name = username;
844 strcpy (temp_pw, "!");
845 pwent.pw_passwd = temp_pw;
846 pwent.pw_shell = temp_shell;
848 preauth_flag = false;
856 && (strcmp (pwd->pw_passwd, SHADOW_PASSWD_STRING) == 0)) {
857 /* !USE_PAM, no need for xgetspnam */
858 spwd = getspnam (username);
860 pwent.pw_passwd = spwd->sp_pwdp;
863 "no shadow password for '%s'%s",
864 username, fromhost));
869 * If the encrypted password begins with a "!", the account
870 * is locked and the user cannot login, even if they have
871 * been "pre-authenticated."
873 if ( ('!' == pwent.pw_passwd[0])
874 || ('*' == pwent.pw_passwd[0])) {
879 * The -r and -f flags provide a name which has already
880 * been authenticated by some server.
886 if (pw_auth (pwent.pw_passwd, username,
887 reason, (char *) 0) == 0) {
892 * Don't log unknown usernames - I mistyped the password for
893 * username at least once. Should probably use LOG_AUTHPRIV
894 * for those who really want to log them. --marekm
896 SYSLOG ((LOG_WARN, "invalid password for '%s' %s",
898 || getdef_bool ("LOG_UNKFAIL_ENAB")) ?
899 username : "UNKNOWN", fromhost));
904 * This is the point where all authenticated users wind up.
905 * If you reach this far, your password has been
906 * authenticated and so on.
909 && (NULL != pwent.pw_name)
910 && (0 == pwent.pw_uid)
912 SYSLOG ((LOG_CRIT, "ILLEGAL ROOT LOGIN %s", fromhost));
916 && !login_access (username, *hostname ? hostname : tty)) {
917 SYSLOG ((LOG_WARN, "LOGIN '%s' REFUSED %s",
918 username, fromhost));
922 && getdef_bool ("FAILLOG_ENAB")
923 && !failcheck (pwent.pw_uid, &faillog, failed)) {
925 "exceeded failure limit for '%s' %s",
926 username, fromhost));
933 /* don't log non-existent users */
934 if ((NULL != pwd) && getdef_bool ("FAILLOG_ENAB")) {
935 failure (pwent.pw_uid, tty, &faillog);
937 if (getdef_str ("FTMP_FILE") != NULL) {
938 const char *failent_user;
942 if (sizeof (failent.ut_tv) == sizeof (struct timeval)) {
943 gettimeofday ((struct timeval *) &failent.ut_tv,
948 gettimeofday (&tv, NULL);
949 failent.ut_tv.tv_sec = tv.tv_sec;
950 failent.ut_tv.tv_usec = tv.tv_usec;
954 failent.ut_time = time (NULL);
957 failent_user = pwent.pw_name;
959 if (getdef_bool ("LOG_UNKFAIL_ENAB")) {
960 failent_user = username;
962 failent_user = "UNKNOWN";
965 strncpy (failent.ut_user, failent_user,
966 sizeof (failent.ut_user));
967 failent.ut_type = USER_PROCESS;
970 memzero (username, sizeof username);
974 SYSLOG ((LOG_CRIT, "REPEATED login failures%s",
978 * If this was a passwordless account and we get here, login
979 * was denied (securetty, faillog, etc.). There was no
980 * password prompt, so do it now (will always fail - the bad
981 * guys won't see that the passwordless account exists at
984 if (pwent.pw_passwd[0] == '\0') {
985 pw_auth ("!", username, reason, (char *) 0);
989 * Wait a while (a la SVR4 /usr/bin/login) before attempting
990 * to login the user again. If the earlier alarm occurs
991 * before the sleep() below completes, login will exit.
997 puts (_("Login incorrect"));
999 /* allow only one attempt with -r or -f */
1000 if (rflg || fflg || (retries <= 0)) {
1004 } /* while (true) */
1005 #endif /* ! USE_PAM */
1007 alarm (0); /* turn off alarm clock */
1009 #ifndef USE_PAM /* PAM does this */
1011 * porttime checks moved here, after the user has been
1012 * authenticated. now prints a message, as suggested
1013 * by Ivan Nejgebauer <ian@unsux.ns.ac.yu>. --marekm
1015 if ( getdef_bool ("PORTTIME_CHECKS_ENAB")
1016 && !isttytime (pwent.pw_name, tty, time ((time_t *) 0))) {
1017 SYSLOG ((LOG_WARN, "invalid login time for '%s'%s",
1018 username, fromhost));
1027 if (getenv ("IFS")) { /* don't export user IFS ... */
1028 addenv ("IFS= \t\n", NULL); /* ... instead, set a safe IFS */
1032 setutmp (pam_user, tty, hostname); /* make entry in utmp & wtmp files */
1034 setutmp (username, tty, hostname); /* make entry in utmp & wtmp files */
1036 if (pwent.pw_shell[0] == '*') { /* subsystem root */
1037 pwent.pw_shell++; /* skip the '*' */
1038 subsystem (&pwent); /* figure out what to execute */
1039 subroot = true; /* say I was here again */
1040 endpwent (); /* close all of the file which were */
1041 endgrent (); /* open in the original rooted file */
1042 endspent (); /* system. they will be re-opened */
1044 endsgent (); /* in the new rooted file system */
1046 goto top; /* go do all this all over again */
1050 audit_fd = audit_open ();
1051 audit_log_acct_message (audit_fd,
1053 NULL, /* Prog. name */
1062 #endif /* WITH_AUDIT */
1064 #ifndef USE_PAM /* pam_lastlog handles this */
1065 if (getdef_bool ("LASTLOG_ENAB")) { /* give last login and log this one */
1066 dolastlog (&lastlog, &pwent, utent.ut_line, hostname);
1070 #ifndef USE_PAM /* PAM handles this as well */
1072 * Have to do this while we still have root privileges, otherwise we
1073 * don't have access to /etc/shadow. expire() closes password files,
1074 * and changes to the user in the child before executing the passwd
1077 if (spwd) { /* check for age of password */
1078 if (expire (&pwent, spwd)) {
1079 /* !USE_PAM, no need for xgetpwnam */
1080 pwd = getpwnam (username);
1081 /* !USE_PAM, no need for xgetspnam */
1082 spwd = getspnam (username);
1088 setup_limits (&pwent); /* nice, ulimit etc. */
1089 #endif /* ! USE_PAM */
1090 chown_tty (tty, &pwent);
1094 * We must fork before setuid() because we need to call
1095 * pam_close_session() as root.
1097 (void) signal (SIGINT, SIG_IGN);
1100 /* error in fork() */
1101 fprintf (stderr, _("%s: failure forking: %s"),
1102 Prog, strerror (errno));
1105 } else if (child != 0) {
1107 * parent - wait for child to finish, then cleanup
1116 /* If we were init, we need to start a new session */
1117 if (getppid() == 1) {
1119 if (ioctl(0, TIOCSCTTY, 1) != 0) {
1120 fprintf (stderr,_("TIOCSCTTY failed on %s"),tty);
1124 /* We call set_groups() above because this clobbers pam_groups.so */
1126 if (setup_uid_gid (&pwent, is_console))
1128 if (change_uid (&pwent))
1134 setup_env (&pwent); /* set env vars, cd to the home dir */
1138 const char *const *env;
1140 env = (const char *const *) pam_getenvlist (pamh);
1141 while ((NULL != env) && (NULL != *env)) {
1142 addenv (*env, NULL);
1148 (void) setlocale (LC_ALL, "");
1149 (void) bindtextdomain (PACKAGE, LOCALEDIR);
1150 (void) textdomain (PACKAGE);
1152 if (!hushed (&pwent)) {
1153 addenv ("HUSHLOGIN=FALSE", NULL);
1155 * pam_unix, pam_mail and pam_lastlog should take care of
1159 motd (); /* print the message of the day */
1160 if ( getdef_bool ("FAILLOG_ENAB")
1161 && (0 != faillog.fail_cnt)) {
1162 failprint (&faillog);
1163 /* Reset the lockout times if logged in */
1164 if ( (0 != faillog.fail_max)
1165 && (faillog.fail_cnt >= faillog.fail_max)) {
1167 ("Warning: login re-enabled after temporary lockout."));
1169 "login '%s' re-enabled after temporary lockout (%d failures)",
1170 username, (int) faillog.fail_cnt));
1173 if ( getdef_bool ("LASTLOG_ENAB")
1174 && (lastlog.ll_time != 0)) {
1175 time_t ll_time = lastlog.ll_time;
1177 #ifdef HAVE_STRFTIME
1178 strftime (ptime, sizeof (ptime),
1179 "%a %b %e %H:%M:%S %z %Y",
1180 localtime (&ll_time));
1181 printf (_("Last login: %s on %s"),
1182 ptime, lastlog.ll_line);
1184 printf (_("Last login: %.19s on %s"),
1185 ctime (&ll_time), lastlog.ll_line);
1187 #ifdef HAVE_LL_HOST /* __linux__ || SUN4 */
1188 if ('\0' != lastlog.ll_host[0]) {
1189 printf (_(" from %.*s"),
1190 (int) sizeof lastlog.
1191 ll_host, lastlog.ll_host);
1196 agecheck (&pwent, spwd);
1198 mailcheck (); /* report on the status of mail */
1199 #endif /* !USE_PAM */
1201 addenv ("HUSHLOGIN=TRUE", NULL);
1204 if ( (NULL != getdef_str ("TTYTYPE_FILE"))
1205 && (NULL == getenv ("TERM"))) {
1209 (void) signal (SIGQUIT, SIG_DFL); /* default quit signal */
1210 (void) signal (SIGTERM, SIG_DFL); /* default terminate signal */
1211 (void) signal (SIGALRM, SIG_DFL); /* default alarm signal */
1212 (void) signal (SIGHUP, SIG_DFL); /* added this. --marekm */
1213 (void) signal (SIGINT, SIG_DFL); /* default interrupt signal */
1215 endpwent (); /* stop access to password file */
1216 endgrent (); /* stop access to group file */
1217 endspent (); /* stop access to shadow passwd file */
1219 endsgent (); /* stop access to shadow group file */
1221 if (0 == pwent.pw_uid) {
1222 SYSLOG ((LOG_NOTICE, "ROOT LOGIN %s", fromhost));
1223 } else if (getdef_bool ("LOG_OK_LOGINS")) {
1225 SYSLOG ((LOG_INFO, "'%s' logged in %s", pam_user, fromhost));
1227 SYSLOG ((LOG_INFO, "'%s' logged in %s", username, fromhost));
1231 tmp = getdef_str ("FAKE_SHELL");
1233 err = shell (tmp, pwent.pw_shell, newenvp); /* fake shell */
1235 /* exec the shell finally */
1236 err = shell (pwent.pw_shell, (char *) 0, newenvp);
1238 exit (err == ENOENT ? E_CMD_NOTFOUND : E_CMD_NOEXEC);