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
32 #ident "$Id: login.c,v 1.86 2006/07/10 04:11:32 kloczek Exp $"
48 #include "prototypes.h"
50 #include "exitcodes.h"
54 static pam_handle_t *pamh = NULL;
56 #define PAM_FAIL_CHECK if (retcode != PAM_SUCCESS) { \
57 fprintf(stderr,"\n%s\n",pam_strerror(pamh, retcode)); \
58 SYSLOG((LOG_ERR,"%s",pam_strerror(pamh, retcode))); \
59 pam_end(pamh, retcode); exit(1); \
61 #define PAM_END { retcode = pam_close_session(pamh,0); \
62 pam_end(pamh,retcode); }
67 * Needed for MkLinux DR1/2/2.1 - J.
70 #define LASTLOG_FILE "/var/log/lastlog"
76 const char *hostname = "";
78 static struct passwd pwent;
81 extern struct utmpx utxent;
86 extern struct utmp utent;
88 struct lastlog lastlog;
98 static int preauth_flag = 0;
109 * External identifiers.
112 extern char **newenvp;
113 extern size_t newenvc;
115 extern void dolastlog (struct lastlog *, const struct passwd *,
116 const char *, const char *);
118 extern char **environ;
128 /* local function prototypes */
129 static void usage (void);
130 static void setup_tty (void);
131 static void check_flags (int, char *const *);
134 extern int login_access (const char *, const char *);
136 static struct faillog faillog;
138 static void bad_time_notify (void);
139 static void check_nologin (void);
142 static void init_env (void);
143 static RETSIGTYPE alarm_handler (int);
146 * usage - print login command usage and exit
149 * login -r hostname (for rlogind)
150 * login -h hostname (for telnetd, etc.)
151 * login -f name (for pre-authenticated login: datakit, xterm, etc.)
153 static void usage (void)
155 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 printf (_("Invalid login time\n"));
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 (fname != NULL && access (fname, F_OK) == 0) {
216 * Cat the file if it can be opened, otherwise just
217 * print a default message
219 if ((nlfp = fopen (fname, "r"))) {
220 while ((c = getc (nlfp)) != EOF) {
229 printf (_("\nSystem closed for routine maintenance\n"));
231 * Non-root users must exit. Root gets the message, but
235 if (pwent.pw_uid != 0) {
239 printf (_("\n[Disconnect bypassed -- root login allowed.]\n"));
242 #endif /* !USE_PAM */
244 static void check_flags (int argc, char *const *argv)
249 * Check the flags for proper form. Every argument starting with
250 * "-" must be exactly two characters long. This closes all the
251 * clever rlogin, telnet, and getty holes.
253 for (arg = 1; arg < argc; arg++) {
254 if (argv[arg][0] == '-' && strlen (argv[arg]) > 2)
260 static void init_env (void)
267 if ((tmp = getenv ("LANG"))) {
268 addenv ("LANG", tmp);
272 * Add the timezone environmental variable so that time functions
275 if ((tmp = getenv ("TZ"))) {
279 else if ((cp = getdef_str ("ENV_TZ")))
280 addenv (*cp == '/' ? tz (cp) : cp, NULL);
281 #endif /* !USE_PAM */
283 * Add the clock frequency so that profiling commands work
286 if ((tmp = getenv ("HZ"))) {
290 else if ((cp = getdef_str ("ENV_HZ")))
292 #endif /* !USE_PAM */
296 static RETSIGTYPE alarm_handler (int sig)
298 fprintf (stderr, _("\nLogin timed out after %d seconds.\n"), timeout);
304 * login - create a new login session for a user
306 * login is typically called by getty as the second step of a
307 * new user session. getty is responsible for setting the line
308 * characteristics to a reasonable set of values and getting
309 * the name of the user to be logged in. login may also be
310 * called to create a new user session on a pty for a variety
311 * of reasons, such as X servers or network logins.
313 * the flags which login supports are
315 * -p - preserve the environment
316 * -r - perform autologin protocol for rlogin
317 * -f - do not perform authentication, user is preauthenticated
318 * -h - the name of the remote host
320 int main (int argc, char **argv)
328 #if defined(HAVE_STRFTIME) && !defined(USE_PAM)
331 int reason = PW_LOGIN;
343 char **envp = environ;
344 static char temp_pw[2];
345 static char temp_shell[] = "/bin/sh";
352 struct spwd *spwd = NULL;
355 * Some quick initialization.
360 setlocale (LC_ALL, "");
361 bindtextdomain (PACKAGE, LOCALEDIR);
362 textdomain (PACKAGE);
367 amroot = (getuid () == 0);
368 Prog = Basename (argv[0]);
370 check_flags (argc, argv);
372 while ((flag = getopt (argc, argv, "d:f::h:pr:")) != EOF) {
375 /* "-d device" ignored for compatibility */
379 * username must be a separate token
380 * (-f root, *not* -froot). --marekm
382 * if -f has an arg, use that, else use the
383 * normal user name passed after all options
386 if (optarg != NULL && optarg != argv[optind - 1])
390 STRFCPY (username, optarg);
414 * Neither -h nor -f should be combined with -r.
417 if (rflg && (hflg || fflg))
422 * Allow authentication bypass only if real UID is zero.
425 if ((rflg || fflg || hflg) && !amroot) {
426 fprintf (stderr, _("%s: Permission denied.\n"), Prog);
430 if (!isatty (0) || !isatty (1) || !isatty (2))
431 exit (1); /* must be a terminal */
434 * Be picky if run by normal users (possible if installed setuid
435 * root), but not if run by root. This way it still allows logins
436 * even if your getty is broken, or if something corrupts utmp,
437 * but users must "exec login" which will use the existing utmp
438 * entry (will not overwrite remote hostname). --marekm
441 STRFCPY (tty, utent.ut_line);
442 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 login_prompt[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 (login_prompt,
610 sizeof (login_prompt),
611 _("%s login: "), hostn);
613 snprintf (login_prompt,
614 sizeof (login_prompt), _("login: "));
617 pam_set_item (pamh, PAM_USER_PROMPT, login_prompt);
620 /* if we didn't get a user on the command line,
622 pam_get_item (pamh, PAM_USER,
623 (const void **) &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 **) &pam_user);
649 if (pam_user && pam_user[0]) {
650 pwd = getpwnam(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 fprintf(stderr,_("login: abort requested by PAM\n"));
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 pw = getpwnam (username);
698 snprintf (buf, sizeof (buf),
699 "uid=%d", pw->pw_uid);
700 audit_log_user_message
701 (audit_fd, AUDIT_USER_LOGIN,
705 snprintf (buf, sizeof (buf),
706 "acct=%s", username);
707 audit_log_user_message
708 (audit_fd, AUDIT_USER_LOGIN,
714 #endif /* WITH_AUDIT */
716 fprintf(stderr,"\nLogin incorrect\n");
718 /* Let's give it another go around */
719 pam_set_item(pamh,PAM_USER,NULL);
722 /* We don't get here unless they were authenticated above */
724 retcode = pam_acct_mgmt (pamh, 0);
726 if (retcode == PAM_NEW_AUTHTOK_REQD) {
729 PAM_CHANGE_EXPIRED_AUTHTOK);
735 /* Grab the user information out of the password file for future usage
736 First get the username that we are actually using, though.
739 pam_get_item (pamh, PAM_USER, (const void **) &pam_user);
741 pwd = getpwnam (pam_user);
744 retcode = pam_acct_mgmt (pamh, 0);
748 if (!pwd || setup_groups (pwd))
753 retcode = pam_setcred (pamh, PAM_ESTABLISH_CRED);
756 retcode = pam_open_session (pamh,
757 hushed (&pwent) ? PAM_SILENT : 0);
760 #else /* ! USE_PAM */
761 while (1) { /* repeatedly get login/password pairs */
762 failed = 0; /* haven't failed authentication yet */
763 if (!username[0]) { /* need to get a login id */
769 login_prompt (_("\n%s login: "), username,
773 #endif /* ! USE_PAM */
776 if (!(pwd = getpwnam (pam_user))) {
777 pwent.pw_name = pam_user;
779 if (!(pwd = getpwnam (username))) {
780 pwent.pw_name = username;
782 strcpy (temp_pw, "!");
783 pwent.pw_passwd = temp_pw;
784 pwent.pw_shell = temp_shell;
793 if (pwd && strcmp (pwd->pw_passwd, SHADOW_PASSWD_STRING) == 0) {
794 spwd = getspnam (username);
796 pwent.pw_passwd = spwd->sp_pwdp;
799 "no shadow password for `%s'%s",
800 username, fromhost));
804 * If the encrypted password begins with a "!", the account
805 * is locked and the user cannot login, even if they have
806 * been "pre-authenticated."
808 if (pwent.pw_passwd[0] == '!' || pwent.pw_passwd[0] == '*')
812 * The -r and -f flags provide a name which has already
813 * been authenticated by some server.
819 (pwent.pw_passwd, username, reason, (char *) 0) == 0)
823 * Don't log unknown usernames - I mistyped the password for
824 * username at least once. Should probably use LOG_AUTHPRIV
825 * for those who really want to log them. --marekm
827 SYSLOG ((LOG_WARN, "invalid password for `%s' %s",
829 || getdef_bool ("LOG_UNKFAIL_ENAB")) ?
830 username : "UNKNOWN", fromhost));
835 * This is the point where all authenticated users wind up.
836 * If you reach this far, your password has been
837 * authenticated and so on.
839 if (!failed && pwent.pw_name && pwent.pw_uid == 0
841 SYSLOG ((LOG_CRIT, "ILLEGAL ROOT LOGIN %s", fromhost));
845 && !login_access (username, *hostname ? hostname : tty)) {
846 SYSLOG ((LOG_WARN, "LOGIN `%s' REFUSED %s",
847 username, fromhost));
850 if (pwd && getdef_bool ("FAILLOG_ENAB") &&
851 !failcheck (pwent.pw_uid, &faillog, failed)) {
853 "exceeded failure limit for `%s' %s",
854 username, fromhost));
860 /* don't log non-existent users */
861 if (pwd && getdef_bool ("FAILLOG_ENAB"))
862 failure (pwent.pw_uid, tty, &faillog);
863 if (getdef_str ("FTMP_FILE") != NULL) {
864 const char *failent_user;
868 if (sizeof (failent.ut_tv) == sizeof (struct timeval))
869 gettimeofday ((struct timeval *)
870 &failent.ut_tv, NULL);
874 gettimeofday (&tv, NULL);
875 failent.ut_tv.tv_sec = tv.tv_sec;
876 failent.ut_tv.tv_usec = tv.tv_usec;
880 failent.ut_time = time (NULL);
883 failent_user = pwent.pw_name;
885 if (getdef_bool ("LOG_UNKFAIL_ENAB"))
886 failent_user = username;
888 failent_user = "UNKNOWN";
890 strncpy (failent.ut_user, failent_user,
891 sizeof (failent.ut_user));
892 failent.ut_type = USER_PROCESS;
895 memzero (username, sizeof username);
898 SYSLOG ((LOG_CRIT, "REPEATED login failures%s",
901 * If this was a passwordless account and we get here, login
902 * was denied (securetty, faillog, etc.). There was no
903 * password prompt, so do it now (will always fail - the bad
904 * guys won't see that the passwordless account exists at
907 if (pwent.pw_passwd[0] == '\0')
908 pw_auth ("!", username, reason, (char *) 0);
911 * Wait a while (a la SVR4 /usr/bin/login) before attempting
912 * to login the user again. If the earlier alarm occurs
913 * before the sleep() below completes, login will exit.
918 puts (_("Login incorrect"));
920 /* allow only one attempt with -r or -f */
921 if (rflg || fflg || retries <= 0) {
926 #endif /* ! USE_PAM */
927 alarm (0); /* turn off alarm clock */
928 #ifndef USE_PAM /* PAM does this */
930 * porttime checks moved here, after the user has been
931 * authenticated. now prints a message, as suggested
932 * by Ivan Nejgebauer <ian@unsux.ns.ac.yu>. --marekm
934 if (getdef_bool ("PORTTIME_CHECKS_ENAB") &&
935 !isttytime (pwent.pw_name, tty, time ((time_t *) 0))) {
936 SYSLOG ((LOG_WARN, "invalid login time for `%s'%s",
937 username, fromhost));
946 if (getenv ("IFS")) /* don't export user IFS ... */
947 addenv ("IFS= \t\n", NULL); /* ... instead, set a safe IFS */
950 setutmp (pam_user, tty, hostname); /* make entry in utmp & wtmp files */
952 setutmp (username, tty, hostname); /* make entry in utmp & wtmp files */
954 if (pwent.pw_shell[0] == '*') { /* subsystem root */
955 pwent.pw_shell++; /* skip the '*' */
956 subsystem (&pwent); /* figure out what to execute */
957 subroot++; /* say i was here again */
958 endpwent (); /* close all of the file which were */
959 endgrent (); /* open in the original rooted file */
960 endspent (); /* system. they will be re-opened */
962 endsgent (); /* in the new rooted file system */
964 goto top; /* go do all this all over again */
971 audit_fd = audit_open ();
972 snprintf (buf, sizeof (buf), "uid=%d", pwd->pw_uid);
973 audit_log_user_message (audit_fd, AUDIT_USER_LOGIN,
974 buf, hostname, NULL, tty, 1);
977 #endif /* WITH_AUDIT */
979 #ifndef USE_PAM /* pam_lastlog handles this */
980 if (getdef_bool ("LASTLOG_ENAB")) /* give last login and log this one */
981 dolastlog (&lastlog, &pwent, utent.ut_line, hostname);
984 #ifndef USE_PAM /* PAM handles this as well */
986 * Have to do this while we still have root privileges, otherwise we
987 * don't have access to /etc/shadow. expire() closes password files,
988 * and changes to the user in the child before executing the passwd
991 if (spwd) { /* check for age of password */
992 if (expire (&pwent, spwd)) {
993 pwd = getpwnam (username);
994 spwd = getspnam (username);
999 setup_limits (&pwent); /* nice, ulimit etc. */
1000 #endif /* ! USE_PAM */
1001 chown_tty (tty, &pwent);
1005 * We must fork before setuid() because we need to call
1006 * pam_close_session() as root.
1008 signal (SIGINT, SIG_IGN);
1011 /* error in fork() */
1012 fprintf (stderr, _("%s: failure forking: %s"),
1013 Prog, strerror (errno));
1018 * parent - wait for child to finish, then cleanup
1028 /* We call set_groups() above because this clobbers pam_groups.so */
1030 if (setup_uid_gid (&pwent, is_console))
1032 if (change_uid (&pwent))
1036 setup_env (&pwent); /* set env vars, cd to the home dir */
1040 const char *const *env;
1042 env = (const char *const *) pam_getenvlist (pamh);
1043 while (env && *env) {
1044 addenv (*env, NULL);
1050 setlocale (LC_ALL, "");
1051 bindtextdomain (PACKAGE, LOCALEDIR);
1052 textdomain (PACKAGE);
1054 if (!hushed (&pwent)) {
1055 addenv ("HUSHLOGIN=FALSE", NULL);
1057 * pam_unix, pam_mail and pam_lastlog should take care of
1061 motd (); /* print the message of the day */
1062 if (getdef_bool ("FAILLOG_ENAB")
1063 && faillog.fail_cnt != 0) {
1064 failprint (&faillog);
1065 /* Reset the lockout times if logged in */
1066 if (faillog.fail_max &&
1067 faillog.fail_cnt >= faillog.fail_max) {
1069 ("Warning: login re-enabled after temporary lockout.\n"));
1071 "login `%s' re-enabled after temporary lockout (%d failures)",
1072 username, (int) faillog.fail_cnt));
1075 if (getdef_bool ("LASTLOG_ENAB")
1076 && lastlog.ll_time != 0) {
1077 time_t ll_time = lastlog.ll_time;
1079 #ifdef HAVE_STRFTIME
1080 strftime (ptime, sizeof (ptime),
1081 "%a %b %e %H:%M:%S %z %Y",
1082 localtime (&ll_time));
1083 printf (_("Last login: %s on %s"),
1084 ptime, lastlog.ll_line);
1086 printf (_("Last login: %.19s on %s"),
1087 ctime (&ll_time), lastlog.ll_line);
1089 #ifdef HAVE_LL_HOST /* __linux__ || SUN4 */
1090 if (lastlog.ll_host[0])
1091 printf (_(" from %.*s"),
1092 (int) sizeof lastlog.
1093 ll_host, lastlog.ll_host);
1097 agecheck (&pwent, spwd);
1099 mailcheck (); /* report on the status of mail */
1100 #endif /* !USE_PAM */
1102 addenv ("HUSHLOGIN=TRUE", NULL);
1104 if (getdef_str ("TTYTYPE_FILE") != NULL && getenv ("TERM") == NULL)
1107 signal (SIGQUIT, SIG_DFL); /* default quit signal */
1108 signal (SIGTERM, SIG_DFL); /* default terminate signal */
1109 signal (SIGALRM, SIG_DFL); /* default alarm signal */
1110 signal (SIGHUP, SIG_DFL); /* added this. --marekm */
1111 signal (SIGINT, SIG_DFL); /* default interrupt signal */
1113 endpwent (); /* stop access to password file */
1114 endgrent (); /* stop access to group file */
1115 endspent (); /* stop access to shadow passwd file */
1117 endsgent (); /* stop access to shadow group file */
1119 if (pwent.pw_uid == 0)
1120 SYSLOG ((LOG_NOTICE, "ROOT LOGIN %s", fromhost));
1121 else if (getdef_bool ("LOG_OK_LOGINS"))
1123 SYSLOG ((LOG_INFO, "`%s' logged in %s", pam_user, fromhost));
1125 SYSLOG ((LOG_INFO, "`%s' logged in %s", username, fromhost));
1128 if ((tmp = getdef_str ("FAKE_SHELL")) != NULL)
1129 err = shell (tmp, pwent.pw_shell, newenvp); /* fake shell */
1131 /* exec the shell finally */
1132 err = shell (pwent.pw_shell, (char *) 0, newenvp);
1133 exit (err == ENOENT ? E_CMD_NOTFOUND : E_CMD_NOEXEC);