2 * Copyright 1989 - 1994, Julianne Frances Haugh
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 #include <sys/ioctl.h>
49 #include "prototypes.h"
51 #include "exitcodes.h"
55 static pam_handle_t *pamh = NULL;
57 #define PAM_FAIL_CHECK if (retcode != PAM_SUCCESS) { \
58 fprintf(stderr,"\n%s\n",pam_strerror(pamh, retcode)); \
59 SYSLOG((LOG_ERR,"%s",pam_strerror(pamh, retcode))); \
60 pam_end(pamh, retcode); exit(1); \
62 #define PAM_END { retcode = pam_close_session(pamh,0); \
63 pam_end(pamh,retcode); }
68 * Needed for MkLinux DR1/2/2.1 - J.
71 #define LASTLOG_FILE "/var/log/lastlog"
77 const char *hostname = "";
79 static struct passwd pwent;
82 extern struct utmpx utxent;
87 extern struct utmp utent;
89 struct lastlog lastlog;
99 static int preauth_flag = 0;
110 * External identifiers.
113 extern char **newenvp;
114 extern size_t newenvc;
115 extern char **environ;
125 /* local function prototypes */
126 static void usage (void);
127 static void setup_tty (void);
128 static void check_flags (int, char *const *);
131 static struct faillog faillog;
133 static void bad_time_notify (void);
134 static void check_nologin (void);
137 static void init_env (void);
138 static RETSIGTYPE alarm_handler (int);
141 * usage - print login command usage and exit
144 * login -r hostname (for rlogind)
145 * login -h hostname (for telnetd, etc.)
146 * login -f name (for pre-authenticated login: datakit, xterm, etc.)
148 static void usage (void)
150 fprintf (stderr, _("Usage: %s [-p] [name]\n"), Prog);
153 fprintf (stderr, _(" %s [-p] [-h host] [-f name]\n"), Prog);
155 fprintf (stderr, _(" %s [-p] -r host\n"), Prog);
160 static void setup_tty (void)
164 GTTY (0, &termio); /* get terminal characteristics */
167 * Add your favorite terminal modes here ...
169 termio.c_lflag |= ISIG | ICANON | ECHO | ECHOE;
170 termio.c_iflag |= ICRNL;
172 /* leave these values unchanged if not specified in login.defs */
173 termio.c_cc[VERASE] = getdef_num ("ERASECHAR", termio.c_cc[VERASE]);
174 termio.c_cc[VKILL] = getdef_num ("KILLCHAR", termio.c_cc[VKILL]);
177 * ttymon invocation prefers this, but these settings won't come into
178 * effect after the first username login
186 * Tell the user that this is not the right time to login at this tty
188 static void bad_time_notify (void)
190 puts (_("Invalid login time"));
194 static void check_nologin (void)
199 * Check to see if system is turned off for non-root users.
200 * This would be useful to prevent users from logging in
201 * during system maintenance. We make sure the message comes
202 * out for root so she knows to remove the file if she's
203 * forgotten about it ...
205 fname = getdef_str ("NOLOGINS_FILE");
206 if (fname != NULL && access (fname, F_OK) == 0) {
211 * Cat the file if it can be opened, otherwise just
212 * print a default message
214 if ((nlfp = fopen (fname, "r"))) {
215 while ((c = getc (nlfp)) != EOF) {
224 puts (_("\nSystem closed for routine maintenance"));
226 * Non-root users must exit. Root gets the message, but
230 if (pwent.pw_uid != 0) {
234 puts (_("\n[Disconnect bypassed -- root login allowed.]"));
237 #endif /* !USE_PAM */
239 static void check_flags (int argc, char *const *argv)
244 * Check the flags for proper form. Every argument starting with
245 * "-" must be exactly two characters long. This closes all the
246 * clever rlogin, telnet, and getty holes.
248 for (arg = 1; arg < argc; arg++) {
249 if (argv[arg][0] == '-' && strlen (argv[arg]) > 2)
255 static void init_env (void)
262 if ((tmp = getenv ("LANG"))) {
263 addenv ("LANG", tmp);
267 * Add the timezone environmental variable so that time functions
270 if ((tmp = getenv ("TZ"))) {
274 else if ((cp = getdef_str ("ENV_TZ")))
275 addenv (*cp == '/' ? tz (cp) : cp, NULL);
276 #endif /* !USE_PAM */
278 * Add the clock frequency so that profiling commands work
281 if ((tmp = getenv ("HZ"))) {
285 else if ((cp = getdef_str ("ENV_HZ")))
287 #endif /* !USE_PAM */
291 static RETSIGTYPE alarm_handler (unused int sig)
293 fprintf (stderr, _("\nLogin timed out after %d seconds.\n"), timeout);
299 * login - create a new login session for a user
301 * login is typically called by getty as the second step of a
302 * new user session. getty is responsible for setting the line
303 * characteristics to a reasonable set of values and getting
304 * the name of the user to be logged in. login may also be
305 * called to create a new user session on a pty for a variety
306 * of reasons, such as X servers or network logins.
308 * the flags which login supports are
310 * -p - preserve the environment
311 * -r - perform autologin protocol for rlogin
312 * -f - do not perform authentication, user is preauthenticated
313 * -h - the name of the remote host
315 int main (int argc, char **argv)
323 #if defined(HAVE_STRFTIME) && !defined(USE_PAM)
326 int reason = PW_LOGIN;
340 char **envp = environ;
341 static char temp_pw[2];
342 static char temp_shell[] = "/bin/sh";
348 char **ptr_pam_user = &pam_user;
350 struct spwd *spwd = NULL;
353 * Some quick initialization.
358 setlocale (LC_ALL, "");
359 bindtextdomain (PACKAGE, LOCALEDIR);
360 textdomain (PACKAGE);
365 amroot = (getuid () == 0);
366 Prog = Basename (argv[0]);
368 check_flags (argc, argv);
370 while ((flag = getopt (argc, argv, "d:f::h:pr:")) != EOF) {
373 /* "-d device" ignored for compatibility */
377 * username must be a separate token
378 * (-f root, *not* -froot). --marekm
380 * if -f has an arg, use that, else use the
381 * normal user name passed after all options
384 if (optarg != NULL && optarg != argv[optind - 1])
388 STRFCPY (username, optarg);
412 * Neither -h nor -f should be combined with -r.
415 if (rflg && (hflg || fflg))
420 * Allow authentication bypass only if real UID is zero.
423 if ((rflg || fflg || hflg) && !amroot) {
424 fprintf (stderr, _("%s: Permission denied.\n"), Prog);
428 if (!isatty (0) || !isatty (1) || !isatty (2))
429 exit (1); /* must be a terminal */
432 * Be picky if run by normal users (possible if installed setuid
433 * root), but not if run by root. This way it still allows logins
434 * even if your getty is broken, or if something corrupts utmp,
435 * but users must "exec login" which will use the existing utmp
436 * entry (will not overwrite remote hostname). --marekm
439 STRFCPY (tty, utent.ut_line);
441 is_console = console (tty);
449 * Fill in the ut_addr field (remote login IP address). XXX
450 * - login from util-linux does it, but this is not the
451 * right place to do it. The program that starts login
452 * (telnetd, rlogind) knows the IP address, so it should
453 * create the utmp entry and fill in ut_addr.
454 * gethostbyname() is not 100% reliable (the remote host may
455 * be unknown, etc.). --marekm
457 if ((he = gethostbyname (hostname))) {
458 utent.ut_addr = *((int32_t *) (he->h_addr_list[0]));
461 strncpy (utent.ut_host, hostname,
462 sizeof (utent.ut_host));
465 strncpy (utxent.ut_host, hostname,
466 sizeof (utxent.ut_host));
469 * Add remote hostname to the environment. I think
470 * (not sure) I saw it once on Irix. --marekm
472 addenv ("REMOTEHOST", hostname);
476 * workaround for init/getty leaving junk in ut_host at least in
477 * some version of RedHat. --marekm
480 memzero (utent.ut_host, sizeof utent.ut_host);
488 && do_rlogin (hostname, username, sizeof username,
498 umask (getdef_num ("UMASK", GETDEF_DEFAULT_UMASK));
502 * Use the ULIMIT in the login.defs file, and if
503 * there isn't one, use the default value. The
504 * user may have one for themselves, but otherwise,
505 * just take what you get.
507 long limit = getdef_long ("ULIMIT", -1L);
510 set_filesize_limit (limit);
515 * The entire environment will be preserved if the -p flag
519 while (*envp) /* add inherited environment, */
520 addenv (*envp++, NULL); /* some variables change later */
524 addenv ("TERM", term);
527 /* preserve TERM from getty */
528 if (!pflg && (tmp = getenv ("TERM")))
529 addenv ("TERM", tmp);
533 if (optind < argc) { /* get the user name */
534 if (rflg || (fflg && username[0]))
537 STRFCPY (username, argv[optind]);
538 strzero (argv[optind]);
541 if (optind < argc) /* now set command line variables */
542 set_env (argc - optind, &argv[optind]);
548 if (utent.ut_host[0])
553 if (utxent.ut_host[0])
560 snprintf (fromhost, sizeof fromhost,
561 " on '%.100s' from '%.200s'", tty, cp);
563 snprintf (fromhost, sizeof fromhost,
564 " on '%.100s'", tty);
567 /* only allow ALARM sec. for login */
568 signal (SIGALRM, alarm_handler);
569 timeout = getdef_num ("LOGIN_TIMEOUT", ALARM);
573 environ = newenvp; /* make new environment active */
574 delay = getdef_num ("FAIL_DELAY", 1);
575 retries = getdef_num ("LOGIN_RETRIES", RETRIES);
578 retcode = pam_start ("login", username, &conv, &pamh);
579 if (retcode != PAM_SUCCESS) {
581 _("login: PAM Failure, aborting: %s\n"),
582 pam_strerror (pamh, retcode));
583 SYSLOG ((LOG_ERR, "Couldn't initialize PAM: %s",
584 pam_strerror (pamh, retcode)));
589 * hostname & tty are either set to NULL or their correct values,
590 * depending on how much we know. We also set PAM's fail delay to
593 retcode = pam_set_item (pamh, PAM_RHOST, hostname);
595 retcode = pam_set_item (pamh, PAM_TTY, tty);
597 #ifdef HAVE_PAM_FAIL_DELAY
598 retcode = pam_fail_delay (pamh, 1000000 * delay);
601 /* if fflg == 1, then the user has already been authenticated */
602 if (!fflg || (getuid () != 0)) {
605 char loginprompt[256]; /* That's one hell of a prompt :) */
607 /* Make the login prompt look like we want it */
608 if (!gethostname (hostn, sizeof (hostn)))
609 snprintf (loginprompt,
610 sizeof (loginprompt),
611 _("%s login: "), hostn);
613 snprintf (loginprompt,
614 sizeof (loginprompt), _("login: "));
617 pam_set_item (pamh, PAM_USER_PROMPT, loginprompt);
620 /* if we didn't get a user on the command line,
622 pam_get_item (pamh, PAM_USER,
623 (const void **)ptr_pam_user);
624 if (pam_user[0] == '\0')
625 pam_set_item (pamh, PAM_USER, NULL);
628 * There may be better ways to deal with some of
629 * these conditions, but at least this way I don't
630 * think we'll be giving away information. Perhaps
631 * someday we can trust that all PAM modules will
632 * pay attention to failure count and get rid of
637 const char *failent_user;
642 retcode = pam_fail_delay(pamh, 1000000*delay);
644 retcode = pam_authenticate (pamh, 0);
646 pam_get_item (pamh, PAM_USER,
647 (const void **) ptr_pam_user);
649 if (pam_user && pam_user[0]) {
650 pwd = xgetpwnam(pam_user);
653 failent_user = pwent.pw_name;
655 if (getdef_bool("LOG_UNKFAIL_ENAB") && pam_user)
656 failent_user = pam_user;
658 failent_user = "UNKNOWN";
662 failent_user = "UNKNOWN";
665 if (retcode == PAM_MAXTRIES || failcount >= retries) {
667 "TOO MANY LOGIN TRIES (%d)%s FOR `%s'",
668 failcount, fromhost, failent_user));
670 _("Maximum number of tries exceeded (%d)\n"),
674 } else if (retcode == PAM_ABORT) {
675 /* Serious problems, quit now */
676 fputs (_("login: abort requested by PAM\n"),stderr);
677 SYSLOG ((LOG_ERR,"PAM_ABORT returned from pam_authenticate()"));
680 } else if (retcode != PAM_SUCCESS) {
681 SYSLOG ((LOG_NOTICE,"FAILED LOGIN (%d)%s FOR `%s', %s",
682 failcount, fromhost, failent_user,
683 pam_strerror (pamh, retcode)));
695 audit_fd = audit_open ();
696 /* local, no need for xgetpwnam */
697 pw = getpwnam (username);
699 snprintf (buf, sizeof (buf),
700 "uid=%d", pw->pw_uid);
701 audit_log_user_message
702 (audit_fd, AUDIT_USER_LOGIN,
706 snprintf (buf, sizeof (buf),
707 "acct=%s", username);
708 audit_log_user_message
709 (audit_fd, AUDIT_USER_LOGIN,
715 #endif /* WITH_AUDIT */
717 fprintf(stderr,"\nLogin incorrect\n");
719 /* Let's give it another go around */
720 pam_set_item(pamh,PAM_USER,NULL);
723 /* We don't get here unless they were authenticated above */
725 retcode = pam_acct_mgmt (pamh, 0);
727 if (retcode == PAM_NEW_AUTHTOK_REQD) {
730 PAM_CHANGE_EXPIRED_AUTHTOK);
736 /* Grab the user information out of the password file for future usage
737 First get the username that we are actually using, though.
740 pam_get_item (pamh, PAM_USER, (const void **)ptr_pam_user);
741 pwd = xgetpwnam (pam_user);
743 SYSLOG ((LOG_ERR, "xgetpwnam(%s) failed",
744 getdef_bool ("LOG_UNKFAIL_ENAB") ?
745 pam_user : "UNKNOWN"));
750 retcode = pam_acct_mgmt (pamh, 0);
754 if (setup_groups (pwd))
759 retcode = pam_setcred (pamh, PAM_ESTABLISH_CRED);
762 retcode = pam_open_session (pamh,
763 hushed (&pwent) ? PAM_SILENT : 0);
766 #else /* ! USE_PAM */
767 while (1) { /* repeatedly get login/password pairs */
768 failed = 0; /* haven't failed authentication yet */
769 if (!username[0]) { /* need to get a login id */
775 login_prompt (_("\n%s login: "), username,
779 #endif /* ! USE_PAM */
782 if (!(pwd = xgetpwnam (pam_user))) {
783 pwent.pw_name = pam_user;
785 if (!(pwd = xgetpwnam (username))) {
786 pwent.pw_name = username;
788 strcpy (temp_pw, "!");
789 pwent.pw_passwd = temp_pw;
790 pwent.pw_shell = temp_shell;
799 if (pwd && strcmp (pwd->pw_passwd, SHADOW_PASSWD_STRING) == 0) {
800 /* !USE_PAM, no need for xgetspnam */
801 spwd = getspnam (username);
803 pwent.pw_passwd = spwd->sp_pwdp;
806 "no shadow password for `%s'%s",
807 username, fromhost));
811 * If the encrypted password begins with a "!", the account
812 * is locked and the user cannot login, even if they have
813 * been "pre-authenticated."
815 if (pwent.pw_passwd[0] == '!' || pwent.pw_passwd[0] == '*')
819 * The -r and -f flags provide a name which has already
820 * been authenticated by some server.
826 (pwent.pw_passwd, username, reason, (char *) 0) == 0)
830 * Don't log unknown usernames - I mistyped the password for
831 * username at least once. Should probably use LOG_AUTHPRIV
832 * for those who really want to log them. --marekm
834 SYSLOG ((LOG_WARN, "invalid password for `%s' %s",
836 || getdef_bool ("LOG_UNKFAIL_ENAB")) ?
837 username : "UNKNOWN", fromhost));
842 * This is the point where all authenticated users wind up.
843 * If you reach this far, your password has been
844 * authenticated and so on.
846 if (!failed && pwent.pw_name && pwent.pw_uid == 0
848 SYSLOG ((LOG_CRIT, "ILLEGAL ROOT LOGIN %s", fromhost));
852 && !login_access (username, *hostname ? hostname : tty)) {
853 SYSLOG ((LOG_WARN, "LOGIN `%s' REFUSED %s",
854 username, fromhost));
857 if (pwd && getdef_bool ("FAILLOG_ENAB") &&
858 !failcheck (pwent.pw_uid, &faillog, failed)) {
860 "exceeded failure limit for `%s' %s",
861 username, fromhost));
867 /* don't log non-existent users */
868 if (pwd && getdef_bool ("FAILLOG_ENAB"))
869 failure (pwent.pw_uid, tty, &faillog);
870 if (getdef_str ("FTMP_FILE") != NULL) {
871 const char *failent_user;
875 if (sizeof (failent.ut_tv) == sizeof (struct timeval))
876 gettimeofday ((struct timeval *)
877 &failent.ut_tv, NULL);
881 gettimeofday (&tv, NULL);
882 failent.ut_tv.tv_sec = tv.tv_sec;
883 failent.ut_tv.tv_usec = tv.tv_usec;
887 failent.ut_time = time (NULL);
890 failent_user = pwent.pw_name;
892 if (getdef_bool ("LOG_UNKFAIL_ENAB"))
893 failent_user = username;
895 failent_user = "UNKNOWN";
897 strncpy (failent.ut_user, failent_user,
898 sizeof (failent.ut_user));
899 failent.ut_type = USER_PROCESS;
902 memzero (username, sizeof username);
905 SYSLOG ((LOG_CRIT, "REPEATED login failures%s",
908 * If this was a passwordless account and we get here, login
909 * was denied (securetty, faillog, etc.). There was no
910 * password prompt, so do it now (will always fail - the bad
911 * guys won't see that the passwordless account exists at
914 if (pwent.pw_passwd[0] == '\0')
915 pw_auth ("!", username, reason, (char *) 0);
918 * Wait a while (a la SVR4 /usr/bin/login) before attempting
919 * to login the user again. If the earlier alarm occurs
920 * before the sleep() below completes, login will exit.
925 puts (_("Login incorrect"));
927 /* allow only one attempt with -r or -f */
928 if (rflg || fflg || retries <= 0) {
933 #endif /* ! USE_PAM */
934 alarm (0); /* turn off alarm clock */
935 #ifndef USE_PAM /* PAM does this */
937 * porttime checks moved here, after the user has been
938 * authenticated. now prints a message, as suggested
939 * by Ivan Nejgebauer <ian@unsux.ns.ac.yu>. --marekm
941 if (getdef_bool ("PORTTIME_CHECKS_ENAB") &&
942 !isttytime (pwent.pw_name, tty, time ((time_t *) 0))) {
943 SYSLOG ((LOG_WARN, "invalid login time for `%s'%s",
944 username, fromhost));
953 if (getenv ("IFS")) /* don't export user IFS ... */
954 addenv ("IFS= \t\n", NULL); /* ... instead, set a safe IFS */
957 setutmp (pam_user, tty, hostname); /* make entry in utmp & wtmp files */
959 setutmp (username, tty, hostname); /* make entry in utmp & wtmp files */
961 if (pwent.pw_shell[0] == '*') { /* subsystem root */
962 pwent.pw_shell++; /* skip the '*' */
963 subsystem (&pwent); /* figure out what to execute */
964 subroot++; /* say I was here again */
965 endpwent (); /* close all of the file which were */
966 endgrent (); /* open in the original rooted file */
967 endspent (); /* system. they will be re-opened */
969 endsgent (); /* in the new rooted file system */
971 goto top; /* go do all this all over again */
978 audit_fd = audit_open ();
979 snprintf (buf, sizeof (buf), "uid=%d", pwd->pw_uid);
980 audit_log_user_message (audit_fd, AUDIT_USER_LOGIN,
981 buf, hostname, NULL, tty, 1);
984 #endif /* WITH_AUDIT */
986 #ifndef USE_PAM /* pam_lastlog handles this */
987 if (getdef_bool ("LASTLOG_ENAB")) /* give last login and log this one */
988 dolastlog (&lastlog, &pwent, utent.ut_line, hostname);
991 #ifndef USE_PAM /* PAM handles this as well */
993 * Have to do this while we still have root privileges, otherwise we
994 * don't have access to /etc/shadow. expire() closes password files,
995 * and changes to the user in the child before executing the passwd
998 if (spwd) { /* check for age of password */
999 if (expire (&pwent, spwd)) {
1000 /* !USE_PAM, no need for xgetpwnam */
1001 pwd = getpwnam (username);
1002 /* !USE_PAM, no need for xgetspnam */
1003 spwd = getspnam (username);
1008 setup_limits (&pwent); /* nice, ulimit etc. */
1009 #endif /* ! USE_PAM */
1010 chown_tty (tty, &pwent);
1014 * We must fork before setuid() because we need to call
1015 * pam_close_session() as root.
1017 signal (SIGINT, SIG_IGN);
1020 /* error in fork() */
1021 fprintf (stderr, _("%s: failure forking: %s"),
1022 Prog, strerror (errno));
1027 * parent - wait for child to finish, then cleanup
1036 /* If we were init, we need to start a new session */
1037 if (getppid() == 1) {
1039 if (ioctl(0, TIOCSCTTY, 1))
1040 fprintf(stderr,_("TIOCSCTTY failed on %s"),tty);
1043 /* We call set_groups() above because this clobbers pam_groups.so */
1045 if (setup_uid_gid (&pwent, is_console))
1047 if (change_uid (&pwent))
1051 setup_env (&pwent); /* set env vars, cd to the home dir */
1055 const char *const *env;
1057 env = (const char *const *) pam_getenvlist (pamh);
1058 while (env && *env) {
1059 addenv (*env, NULL);
1065 setlocale (LC_ALL, "");
1066 bindtextdomain (PACKAGE, LOCALEDIR);
1067 textdomain (PACKAGE);
1069 if (!hushed (&pwent)) {
1070 addenv ("HUSHLOGIN=FALSE", NULL);
1072 * pam_unix, pam_mail and pam_lastlog should take care of
1076 motd (); /* print the message of the day */
1077 if (getdef_bool ("FAILLOG_ENAB")
1078 && faillog.fail_cnt != 0) {
1079 failprint (&faillog);
1080 /* Reset the lockout times if logged in */
1081 if (faillog.fail_max &&
1082 faillog.fail_cnt >= faillog.fail_max) {
1084 ("Warning: login re-enabled after temporary lockout."));
1086 "login `%s' re-enabled after temporary lockout (%d failures)",
1087 username, (int) faillog.fail_cnt));
1090 if (getdef_bool ("LASTLOG_ENAB")
1091 && lastlog.ll_time != 0) {
1092 time_t ll_time = lastlog.ll_time;
1094 #ifdef HAVE_STRFTIME
1095 strftime (ptime, sizeof (ptime),
1096 "%a %b %e %H:%M:%S %z %Y",
1097 localtime (&ll_time));
1098 printf (_("Last login: %s on %s"),
1099 ptime, lastlog.ll_line);
1101 printf (_("Last login: %.19s on %s"),
1102 ctime (&ll_time), lastlog.ll_line);
1104 #ifdef HAVE_LL_HOST /* __linux__ || SUN4 */
1105 if (lastlog.ll_host[0])
1106 printf (_(" from %.*s"),
1107 (int) sizeof lastlog.
1108 ll_host, lastlog.ll_host);
1112 agecheck (&pwent, spwd);
1114 mailcheck (); /* report on the status of mail */
1115 #endif /* !USE_PAM */
1117 addenv ("HUSHLOGIN=TRUE", NULL);
1119 if (getdef_str ("TTYTYPE_FILE") != NULL && getenv ("TERM") == NULL)
1122 signal (SIGQUIT, SIG_DFL); /* default quit signal */
1123 signal (SIGTERM, SIG_DFL); /* default terminate signal */
1124 signal (SIGALRM, SIG_DFL); /* default alarm signal */
1125 signal (SIGHUP, SIG_DFL); /* added this. --marekm */
1126 signal (SIGINT, SIG_DFL); /* default interrupt signal */
1128 endpwent (); /* stop access to password file */
1129 endgrent (); /* stop access to group file */
1130 endspent (); /* stop access to shadow passwd file */
1132 endsgent (); /* stop access to shadow group file */
1134 if (pwent.pw_uid == 0)
1135 SYSLOG ((LOG_NOTICE, "ROOT LOGIN %s", fromhost));
1136 else if (getdef_bool ("LOG_OK_LOGINS"))
1138 SYSLOG ((LOG_INFO, "`%s' logged in %s", pam_user, fromhost));
1140 SYSLOG ((LOG_INFO, "`%s' logged in %s", username, fromhost));
1143 if ((tmp = getdef_str ("FAKE_SHELL")) != NULL)
1144 err = shell (tmp, pwent.pw_shell, newenvp); /* fake shell */
1146 /* exec the shell finally */
1147 err = shell (pwent.pw_shell, (char *) 0, newenvp);
1148 exit (err == ENOENT ? E_CMD_NOTFOUND : E_CMD_NOEXEC);