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);
742 pwd = xgetpwnam (pam_user);
744 SYSLOG ((LOG_ERR, "xgetpwnam(%s) failed",
745 getdef_bool ("LOG_UNKFAIL_ENAB") ?
746 pam_user : "UNKNOWN"));
751 retcode = pam_acct_mgmt (pamh, 0);
755 if (setup_groups (pwd))
760 retcode = pam_setcred (pamh, PAM_ESTABLISH_CRED);
763 retcode = pam_open_session (pamh,
764 hushed (&pwent) ? PAM_SILENT : 0);
767 #else /* ! USE_PAM */
768 while (1) { /* repeatedly get login/password pairs */
769 failed = 0; /* haven't failed authentication yet */
770 if (!username[0]) { /* need to get a login id */
776 login_prompt (_("\n%s login: "), username,
780 #endif /* ! USE_PAM */
783 if (!(pwd = xgetpwnam (pam_user))) {
784 pwent.pw_name = pam_user;
786 if (!(pwd = xgetpwnam (username))) {
787 pwent.pw_name = username;
789 strcpy (temp_pw, "!");
790 pwent.pw_passwd = temp_pw;
791 pwent.pw_shell = temp_shell;
800 if (pwd && strcmp (pwd->pw_passwd, SHADOW_PASSWD_STRING) == 0) {
801 /* !USE_PAM, no need for xgetspnam */
802 spwd = getspnam (username);
804 pwent.pw_passwd = spwd->sp_pwdp;
807 "no shadow password for `%s'%s",
808 username, fromhost));
812 * If the encrypted password begins with a "!", the account
813 * is locked and the user cannot login, even if they have
814 * been "pre-authenticated."
816 if (pwent.pw_passwd[0] == '!' || pwent.pw_passwd[0] == '*')
820 * The -r and -f flags provide a name which has already
821 * been authenticated by some server.
827 (pwent.pw_passwd, username, reason, (char *) 0) == 0)
831 * Don't log unknown usernames - I mistyped the password for
832 * username at least once. Should probably use LOG_AUTHPRIV
833 * for those who really want to log them. --marekm
835 SYSLOG ((LOG_WARN, "invalid password for `%s' %s",
837 || getdef_bool ("LOG_UNKFAIL_ENAB")) ?
838 username : "UNKNOWN", fromhost));
843 * This is the point where all authenticated users wind up.
844 * If you reach this far, your password has been
845 * authenticated and so on.
847 if (!failed && pwent.pw_name && pwent.pw_uid == 0
849 SYSLOG ((LOG_CRIT, "ILLEGAL ROOT LOGIN %s", fromhost));
853 && !login_access (username, *hostname ? hostname : tty)) {
854 SYSLOG ((LOG_WARN, "LOGIN `%s' REFUSED %s",
855 username, fromhost));
858 if (pwd && getdef_bool ("FAILLOG_ENAB") &&
859 !failcheck (pwent.pw_uid, &faillog, failed)) {
861 "exceeded failure limit for `%s' %s",
862 username, fromhost));
868 /* don't log non-existent users */
869 if (pwd && getdef_bool ("FAILLOG_ENAB"))
870 failure (pwent.pw_uid, tty, &faillog);
871 if (getdef_str ("FTMP_FILE") != NULL) {
872 const char *failent_user;
876 if (sizeof (failent.ut_tv) == sizeof (struct timeval))
877 gettimeofday ((struct timeval *)
878 &failent.ut_tv, NULL);
882 gettimeofday (&tv, NULL);
883 failent.ut_tv.tv_sec = tv.tv_sec;
884 failent.ut_tv.tv_usec = tv.tv_usec;
888 failent.ut_time = time (NULL);
891 failent_user = pwent.pw_name;
893 if (getdef_bool ("LOG_UNKFAIL_ENAB"))
894 failent_user = username;
896 failent_user = "UNKNOWN";
898 strncpy (failent.ut_user, failent_user,
899 sizeof (failent.ut_user));
900 failent.ut_type = USER_PROCESS;
903 memzero (username, sizeof username);
906 SYSLOG ((LOG_CRIT, "REPEATED login failures%s",
909 * If this was a passwordless account and we get here, login
910 * was denied (securetty, faillog, etc.). There was no
911 * password prompt, so do it now (will always fail - the bad
912 * guys won't see that the passwordless account exists at
915 if (pwent.pw_passwd[0] == '\0')
916 pw_auth ("!", username, reason, (char *) 0);
919 * Wait a while (a la SVR4 /usr/bin/login) before attempting
920 * to login the user again. If the earlier alarm occurs
921 * before the sleep() below completes, login will exit.
926 puts (_("Login incorrect"));
928 /* allow only one attempt with -r or -f */
929 if (rflg || fflg || retries <= 0) {
934 #endif /* ! USE_PAM */
935 alarm (0); /* turn off alarm clock */
936 #ifndef USE_PAM /* PAM does this */
938 * porttime checks moved here, after the user has been
939 * authenticated. now prints a message, as suggested
940 * by Ivan Nejgebauer <ian@unsux.ns.ac.yu>. --marekm
942 if (getdef_bool ("PORTTIME_CHECKS_ENAB") &&
943 !isttytime (pwent.pw_name, tty, time ((time_t *) 0))) {
944 SYSLOG ((LOG_WARN, "invalid login time for `%s'%s",
945 username, fromhost));
954 if (getenv ("IFS")) /* don't export user IFS ... */
955 addenv ("IFS= \t\n", NULL); /* ... instead, set a safe IFS */
958 setutmp (pam_user, tty, hostname); /* make entry in utmp & wtmp files */
960 setutmp (username, tty, hostname); /* make entry in utmp & wtmp files */
962 if (pwent.pw_shell[0] == '*') { /* subsystem root */
963 pwent.pw_shell++; /* skip the '*' */
964 subsystem (&pwent); /* figure out what to execute */
965 subroot++; /* say i was here again */
966 endpwent (); /* close all of the file which were */
967 endgrent (); /* open in the original rooted file */
968 endspent (); /* system. they will be re-opened */
970 endsgent (); /* in the new rooted file system */
972 goto top; /* go do all this all over again */
979 audit_fd = audit_open ();
980 snprintf (buf, sizeof (buf), "uid=%d", pwd->pw_uid);
981 audit_log_user_message (audit_fd, AUDIT_USER_LOGIN,
982 buf, hostname, NULL, tty, 1);
985 #endif /* WITH_AUDIT */
987 #ifndef USE_PAM /* pam_lastlog handles this */
988 if (getdef_bool ("LASTLOG_ENAB")) /* give last login and log this one */
989 dolastlog (&lastlog, &pwent, utent.ut_line, hostname);
992 #ifndef USE_PAM /* PAM handles this as well */
994 * Have to do this while we still have root privileges, otherwise we
995 * don't have access to /etc/shadow. expire() closes password files,
996 * and changes to the user in the child before executing the passwd
999 if (spwd) { /* check for age of password */
1000 if (expire (&pwent, spwd)) {
1001 /* !USE_PAM, no need for xgetpwnam */
1002 pwd = getpwnam (username);
1003 /* !USE_PAM, no need for xgetspnam */
1004 spwd = getspnam (username);
1009 setup_limits (&pwent); /* nice, ulimit etc. */
1010 #endif /* ! USE_PAM */
1011 chown_tty (tty, &pwent);
1015 * We must fork before setuid() because we need to call
1016 * pam_close_session() as root.
1018 signal (SIGINT, SIG_IGN);
1021 /* error in fork() */
1022 fprintf (stderr, _("%s: failure forking: %s"),
1023 Prog, strerror (errno));
1028 * parent - wait for child to finish, then cleanup
1037 /* If we were init, we need to start a new session */
1038 if (getppid() == 1) {
1040 if (ioctl(0, TIOCSCTTY, 1))
1041 fprintf(stderr,_("TIOCSCTTY failed on %s"),tty);
1044 /* We call set_groups() above because this clobbers pam_groups.so */
1046 if (setup_uid_gid (&pwent, is_console))
1048 if (change_uid (&pwent))
1052 setup_env (&pwent); /* set env vars, cd to the home dir */
1056 const char *const *env;
1058 env = (const char *const *) pam_getenvlist (pamh);
1059 while (env && *env) {
1060 addenv (*env, NULL);
1066 setlocale (LC_ALL, "");
1067 bindtextdomain (PACKAGE, LOCALEDIR);
1068 textdomain (PACKAGE);
1070 if (!hushed (&pwent)) {
1071 addenv ("HUSHLOGIN=FALSE", NULL);
1073 * pam_unix, pam_mail and pam_lastlog should take care of
1077 motd (); /* print the message of the day */
1078 if (getdef_bool ("FAILLOG_ENAB")
1079 && faillog.fail_cnt != 0) {
1080 failprint (&faillog);
1081 /* Reset the lockout times if logged in */
1082 if (faillog.fail_max &&
1083 faillog.fail_cnt >= faillog.fail_max) {
1085 ("Warning: login re-enabled after temporary lockout."));
1087 "login `%s' re-enabled after temporary lockout (%d failures)",
1088 username, (int) faillog.fail_cnt));
1091 if (getdef_bool ("LASTLOG_ENAB")
1092 && lastlog.ll_time != 0) {
1093 time_t ll_time = lastlog.ll_time;
1095 #ifdef HAVE_STRFTIME
1096 strftime (ptime, sizeof (ptime),
1097 "%a %b %e %H:%M:%S %z %Y",
1098 localtime (&ll_time));
1099 printf (_("Last login: %s on %s"),
1100 ptime, lastlog.ll_line);
1102 printf (_("Last login: %.19s on %s"),
1103 ctime (&ll_time), lastlog.ll_line);
1105 #ifdef HAVE_LL_HOST /* __linux__ || SUN4 */
1106 if (lastlog.ll_host[0])
1107 printf (_(" from %.*s"),
1108 (int) sizeof lastlog.
1109 ll_host, lastlog.ll_host);
1113 agecheck (&pwent, spwd);
1115 mailcheck (); /* report on the status of mail */
1116 #endif /* !USE_PAM */
1118 addenv ("HUSHLOGIN=TRUE", NULL);
1120 if (getdef_str ("TTYTYPE_FILE") != NULL && getenv ("TERM") == NULL)
1123 signal (SIGQUIT, SIG_DFL); /* default quit signal */
1124 signal (SIGTERM, SIG_DFL); /* default terminate signal */
1125 signal (SIGALRM, SIG_DFL); /* default alarm signal */
1126 signal (SIGHUP, SIG_DFL); /* added this. --marekm */
1127 signal (SIGINT, SIG_DFL); /* default interrupt signal */
1129 endpwent (); /* stop access to password file */
1130 endgrent (); /* stop access to group file */
1131 endspent (); /* stop access to shadow passwd file */
1133 endsgent (); /* stop access to shadow group file */
1135 if (pwent.pw_uid == 0)
1136 SYSLOG ((LOG_NOTICE, "ROOT LOGIN %s", fromhost));
1137 else if (getdef_bool ("LOG_OK_LOGINS"))
1139 SYSLOG ((LOG_INFO, "`%s' logged in %s", pam_user, fromhost));
1141 SYSLOG ((LOG_INFO, "`%s' logged in %s", username, fromhost));
1144 if ((tmp = getdef_str ("FAKE_SHELL")) != NULL)
1145 err = shell (tmp, pwent.pw_shell, newenvp); /* fake shell */
1147 /* exec the shell finally */
1148 err = shell (pwent.pw_shell, (char *) 0, newenvp);
1149 exit (err == ENOENT ? E_CMD_NOTFOUND : E_CMD_NOEXEC);