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
33 RCSID (PKG_VER "$Id: login.c,v 1.67 2005/08/11 11:26:11 kloczek Exp $")
34 #include "prototypes.h"
52 static const struct pam_conv conv = {
57 static pam_handle_t *pamh = NULL;
59 #define PAM_FAIL_CHECK if (retcode != PAM_SUCCESS) { \
60 fprintf(stderr,"\n%s\n",pam_strerror(pamh, retcode)); \
61 SYSLOG((LOG_ERR,"%s",pam_strerror(pamh, retcode))); \
62 pam_end(pamh, retcode); exit(1); \
64 #define PAM_END { retcode = pam_close_session(pamh,0); \
65 pam_end(pamh,retcode); }
70 * Needed for MkLinux DR1/2/2.1 - J.
73 #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.)
154 static void usage (void)
156 fprintf (stderr, _("Usage: %s [-p] [name]\n"), Prog);
159 fprintf (stderr, _(" %s [-p] [-h host] [-f name]\n"), Prog);
161 fprintf (stderr, _(" %s [-p] -r host\n"), Prog);
166 static void setup_tty (void)
170 GTTY (0, &termio); /* get terminal characteristics */
173 * Add your favorite terminal modes here ...
176 termio.c_lflag |= ISIG | ICANON | ECHO | ECHOE;
177 termio.c_iflag |= ICRNL;
179 /* leave these values unchanged if not specified in login.defs */
180 termio.c_cc[VERASE] = getdef_num ("ERASECHAR", termio.c_cc[VERASE]);
181 termio.c_cc[VKILL] = getdef_num ("KILLCHAR", termio.c_cc[VKILL]);
184 * ttymon invocation prefers this, but these settings won't come into
185 * effect after the first username login
194 * Tell the user that this is not the right time to login at this tty
196 static void bad_time_notify (void)
198 printf (_("Invalid login time\n"));
202 static void check_nologin (void)
207 * Check to see if system is turned off for non-root users.
208 * This would be useful to prevent users from logging in
209 * during system maintenance. We make sure the message comes
210 * out for root so she knows to remove the file if she's
211 * forgotten about it ...
214 fname = getdef_str ("NOLOGINS_FILE");
215 if (fname != NULL && access (fname, F_OK) == 0) {
220 * Cat the file if it can be opened, otherwise just
221 * print a default message
224 if ((nlfp = fopen (fname, "r"))) {
225 while ((c = getc (nlfp)) != EOF) {
234 printf (_("\nSystem closed for routine maintenance\n"));
236 * Non-root users must exit. Root gets the message, but
240 if (pwent.pw_uid != 0) {
244 printf (_("\n[Disconnect bypassed -- root login allowed.]\n"));
247 #endif /* !USE_PAM */
249 static void check_flags (int argc, char *const *argv)
254 * Check the flags for proper form. Every argument starting with
255 * "-" must be exactly two characters long. This closes all the
256 * clever rlogin, telnet, and getty holes.
258 for (arg = 1; arg < argc; arg++) {
259 if (argv[arg][0] == '-' && strlen (argv[arg]) > 2)
265 static void init_env (void)
269 if ((tmp = getenv ("LANG"))) {
270 addenv ("LANG", tmp);
274 * Add the timezone environmental variable so that time functions
278 if ((tmp = getenv ("TZ"))) {
282 else if ((cp = getdef_str ("ENV_TZ")))
283 addenv (*cp == '/' ? tz (cp) : cp, NULL);
284 #endif /* !USE_PAM */
286 * Add the clock frequency so that profiling commands work
290 if ((tmp = getenv ("HZ"))) {
294 else if ((cp = getdef_str ("ENV_HZ")))
296 #endif /* !USE_PAM */
300 static RETSIGTYPE alarm_handler (int sig)
302 fprintf (stderr, _("\nLogin timed out after %d seconds.\n"), timeout);
308 * login - create a new login session for a user
310 * login is typically called by getty as the second step of a
311 * new user session. getty is responsible for setting the line
312 * characteristics to a reasonable set of values and getting
313 * the name of the user to be logged in. login may also be
314 * called to create a new user session on a pty for a variety
315 * of reasons, such as X servers or network logins.
317 * the flags which login supports are
319 * -p - preserve the environment
320 * -r - perform autologin protocol for rlogin
321 * -f - do not perform authentication, user is preauthenticated
322 * -h - the name of the remote host
325 int main (int argc, char **argv)
333 #if defined(HAVE_STRFTIME) && !defined(USE_PAM)
336 int reason = PW_LOGIN;
347 char **envp = environ;
348 static char temp_pw[2];
349 static char temp_shell[] = "/bin/sh";
356 struct spwd *spwd = NULL;
359 * Some quick initialization.
364 setlocale (LC_ALL, "");
365 bindtextdomain (PACKAGE, LOCALEDIR);
366 textdomain (PACKAGE);
371 amroot = (getuid () == 0);
372 Prog = Basename (argv[0]);
374 check_flags (argc, argv);
376 while ((flag = getopt (argc, argv, "d:f::h:pr:")) != EOF) {
379 /* "-d device" ignored for compatibility */
383 * username must be a separate token
384 * (-f root, *not* -froot). --marekm
386 * if -f has an arg, use that, else use the
387 * normal user name passed after all options
390 if (optarg != NULL && optarg != argv[optind - 1])
394 STRFCPY (username, optarg);
418 * Neither -h nor -f should be combined with -r.
421 if (rflg && (hflg || fflg))
426 * Allow authentication bypass only if real UID is zero.
429 if ((rflg || fflg || hflg) && !amroot) {
430 fprintf (stderr, _("%s: Permission denied.\n"), Prog);
434 if (!isatty (0) || !isatty (1) || !isatty (2))
435 exit (1); /* must be a terminal */
439 * Get the utmp file entry and get the tty name from it. The
440 * current process ID must match the process ID in the utmp
441 * file if there are no additional flags on the command line.
443 checkutmp (!rflg && !fflg && !hflg);
446 * Be picky if run by normal users (possible if installed setuid
447 * root), but not if run by root. This way it still allows logins
448 * even if your getty is broken, or if something corrupts utmp,
449 * but users must "exec login" which will use the existing utmp
450 * entry (will not overwrite remote hostname). --marekm
454 STRFCPY (tty, utent.ut_line);
455 is_console = console (tty);
462 * Fill in the ut_addr field (remote login IP address). XXX
463 * - login from util-linux does it, but this is not the
464 * right place to do it. The program that starts login
465 * (telnetd, rlogind) knows the IP address, so it should
466 * create the utmp entry and fill in ut_addr.
467 * gethostbyname() is not 100% reliable (the remote host may
468 * be unknown, etc.). --marekm
470 if ((he = gethostbyname (hostname))) {
471 utent.ut_addr = *((int32_t *) (he->h_addr_list[0]));
474 strncpy (utent.ut_host, hostname,
475 sizeof (utent.ut_host));
478 strncpy (utxent.ut_host, hostname,
479 sizeof (utxent.ut_host));
482 * Add remote hostname to the environment. I think
483 * (not sure) I saw it once on Irix. --marekm
485 addenv ("REMOTEHOST", hostname);
489 * workaround for init/getty leaving junk in ut_host at least in
490 * some version of RedHat. --marekm
493 memzero (utent.ut_host, sizeof utent.ut_host);
501 && do_rlogin (hostname, username, sizeof username,
511 umask (getdef_num ("UMASK", 077));
515 * Use the ULIMIT in the login.defs file, and if
516 * there isn't one, use the default value. The
517 * user may have one for themselves, but otherwise,
518 * just take what you get.
521 long limit = getdef_long ("ULIMIT", -1L);
524 set_filesize_limit (limit);
529 * The entire environment will be preserved if the -p flag
534 while (*envp) /* add inherited environment, */
535 addenv (*envp++, NULL); /* some variables change later */
539 addenv ("TERM", term);
542 /* preserve TERM from getty */
543 if (!pflg && (tmp = getenv ("TERM")))
544 addenv ("TERM", tmp);
548 if (optind < argc) { /* get the user name */
549 if (rflg || (fflg && username[0]))
552 STRFCPY (username, argv[optind]);
553 strzero (argv[optind]);
556 if (optind < argc) /* now set command line variables */
557 set_env (argc - optind, &argv[optind]);
563 if (utent.ut_host[0])
568 if (utxent.ut_host[0])
575 snprintf (fromhost, sizeof fromhost,
576 _(" on `%.100s' from `%.200s'"), tty, cp);
578 snprintf (fromhost, sizeof fromhost,
579 _(" on `%.100s'"), tty);
582 /* only allow ALARM sec. for login */
583 signal (SIGALRM, alarm_handler);
584 timeout = getdef_num ("LOGIN_TIMEOUT", ALARM);
588 environ = newenvp; /* make new environment active */
589 delay = getdef_num ("FAIL_DELAY", 1);
590 retries = getdef_num ("LOGIN_RETRIES", RETRIES);
593 retcode = pam_start ("login", username, &conv, &pamh);
594 if (retcode != PAM_SUCCESS) {
596 "login: PAM Failure, aborting: %s\n",
597 pam_strerror (pamh, retcode));
598 SYSLOG ((LOG_ERR, "Couldn't initialize PAM: %s",
599 pam_strerror (pamh, retcode)));
603 * hostname & tty are either set to NULL or their correct values,
604 * depending on how much we know. We also set PAM's fail delay to
607 retcode = pam_set_item (pamh, PAM_RHOST, hostname);
609 retcode = pam_set_item (pamh, PAM_TTY, tty);
611 #ifdef HAVE_PAM_FAIL_DELAY
612 retcode = pam_fail_delay (pamh, 1000000 * delay);
615 /* if fflg == 1, then the user has already been authenticated */
616 if (!fflg || (getuid () != 0)) {
619 char login_prompt[256]; /* That's one hell of a prompt :) */
621 /* Make the login prompt look like we want it */
622 if (!gethostname (hostn, sizeof (hostn)))
623 snprintf (login_prompt,
624 sizeof (login_prompt),
625 "%s login: ", hostn);
627 snprintf (login_prompt,
628 sizeof (login_prompt), "login: ");
631 pam_set_item (pamh, PAM_USER_PROMPT, login_prompt);
634 /* if we didn't get a user on the command line,
636 pam_get_item (pamh, PAM_USER,
637 (const void **) &pam_user);
638 if (pam_user[0] == '\0')
639 pam_set_item (pamh, PAM_USER, NULL);
642 * There may be better ways to deal with some of
643 * these conditions, but at least this way I don't
644 * think we'll be giving away information. Perhaps
645 * someday we can trust that all PAM modules will
646 * pay attention to failure count and get rid of
650 retcode = pam_authenticate (pamh, 0);
651 while ((failcount++ < retries) &&
652 ((retcode == PAM_AUTH_ERR) ||
653 (retcode == PAM_USER_UNKNOWN) ||
654 (retcode == PAM_CRED_INSUFFICIENT) ||
655 (retcode == PAM_AUTHINFO_UNAVAIL))) {
656 pam_get_item (pamh, PAM_USER,
657 (const void **) &pam_user);
659 "FAILED LOGIN %d FROM %s FOR %s, %s",
660 failcount, hostname, pam_user,
661 pam_strerror (pamh, retcode)));
662 #ifdef HAVE_PAM_FAIL_DELAY
663 pam_fail_delay (pamh, 1000000 * delay);
665 fprintf (stderr, "Login incorrect\n\n");
666 pam_set_item (pamh, PAM_USER, NULL);
667 retcode = pam_authenticate (pamh, 0);
670 if (retcode != PAM_SUCCESS) {
671 pam_get_item (pamh, PAM_USER,
672 (const void **) &pam_user);
674 if (retcode == PAM_MAXTRIES)
676 "TOO MANY LOGIN TRIES (%d) FROM %s FOR %s, %s",
679 pam_strerror (pamh, retcode)));
682 "FAILED LOGIN SESSION FROM %s FOR %s, %s",
684 pam_strerror (pamh, retcode)));
686 fprintf (stderr, "\nLogin incorrect\n");
687 pam_end (pamh, retcode);
691 retcode = pam_acct_mgmt (pamh, 0);
693 if (retcode == PAM_NEW_AUTHTOK_REQD) {
696 PAM_CHANGE_EXPIRED_AUTHTOK);
702 /* Grab the user information out of the password file for future usage
703 First get the username that we are actually using, though.
706 pam_get_item (pamh, PAM_USER, (const void **) &pam_user);
708 pwd = getpwnam (pam_user);
711 retcode = pam_acct_mgmt (pamh, 0);
715 if (!pwd || setup_groups (pwd))
720 retcode = pam_setcred (pamh, PAM_ESTABLISH_CRED);
723 retcode = pam_open_session (pamh,
724 hushed (&pwent) ? PAM_SILENT : 0);
727 #else /* ! USE_PAM */
728 while (1) { /* repeatedly get login/password pairs */
729 failed = 0; /* haven't failed authentication yet */
730 if (!username[0]) { /* need to get a login id */
736 login_prompt (_("\n%s login: "), username,
740 #endif /* ! USE_PAM */
743 if (!(pwd = getpwnam (pam_user))) {
744 pwent.pw_name = pam_user;
746 if (!(pwd = getpwnam (username))) {
747 pwent.pw_name = username;
749 strcpy (temp_pw, "!");
750 pwent.pw_passwd = temp_pw;
751 pwent.pw_shell = temp_shell;
760 if (pwd && strcmp (pwd->pw_passwd, SHADOW_PASSWD_STRING) == 0) {
761 spwd = getspnam (username);
763 pwent.pw_passwd = spwd->sp_pwdp;
766 "no shadow password for `%s'%s",
767 username, fromhost));
771 * If the encrypted password begins with a "!", the account
772 * is locked and the user cannot login, even if they have
773 * been "pre-authenticated."
775 if (pwent.pw_passwd[0] == '!' || pwent.pw_passwd[0] == '*')
779 * The -r and -f flags provide a name which has already
780 * been authenticated by some server.
786 (pwent.pw_passwd, username, reason, (char *) 0) == 0)
790 * Don't log unknown usernames - I mistyped the password for
791 * username at least once. Should probably use LOG_AUTHPRIV
792 * for those who really want to log them. --marekm
794 SYSLOG ((LOG_WARN, "invalid password for `%s' %s",
796 || getdef_bool ("LOG_UNKFAIL_ENAB")) ?
797 username : "UNKNOWN", fromhost));
802 * This is the point where all authenticated users wind up.
803 * If you reach this far, your password has been
804 * authenticated and so on.
807 if (!failed && pwent.pw_name && pwent.pw_uid == 0
809 SYSLOG ((LOG_CRIT, "ILLEGAL ROOT LOGIN %s", fromhost));
813 && !login_access (username, *hostname ? hostname : tty)) {
814 SYSLOG ((LOG_WARN, "LOGIN `%s' REFUSED %s",
815 username, fromhost));
818 if (pwd && getdef_bool ("FAILLOG_ENAB") &&
819 !failcheck (pwent.pw_uid, &faillog, failed)) {
821 "exceeded failure limit for `%s' %s",
822 username, fromhost));
828 /* don't log non-existent users */
829 if (pwd && getdef_bool ("FAILLOG_ENAB"))
830 failure (pwent.pw_uid, tty, &faillog);
831 if (getdef_str ("FTMP_FILE") != NULL) {
832 const char *failent_user;
836 if (sizeof (failent.ut_tv) == sizeof (struct timeval))
837 gettimeofday ((struct timeval *)
838 &failent.ut_tv, NULL);
842 gettimeofday (&tv, NULL);
843 failent.ut_tv.tv_sec = tv.tv_sec;
844 failent.ut_tv.tv_usec = tv.tv_usec;
848 failent.ut_time = time (NULL);
851 failent_user = pwent.pw_name;
853 if (getdef_bool ("LOG_UNKFAIL_ENAB"))
854 failent_user = username;
856 failent_user = "UNKNOWN";
858 strncpy (failent.ut_user, failent_user,
859 sizeof (failent.ut_user));
861 failent.ut_type = USER_PROCESS;
865 memzero (username, sizeof username);
868 SYSLOG ((LOG_CRIT, "REPEATED login failures%s",
872 * If this was a passwordless account and we get here, login
873 * was denied (securetty, faillog, etc.). There was no
874 * password prompt, so do it now (will always fail - the bad
875 * guys won't see that the passwordless account exists at
879 if (pwent.pw_passwd[0] == '\0')
880 pw_auth ("!", username, reason, (char *) 0);
883 * Wait a while (a la SVR4 /usr/bin/login) before attempting
884 * to login the user again. If the earlier alarm occurs
885 * before the sleep() below completes, login will exit.
891 puts (_("Login incorrect"));
893 /* allow only one attempt with -r or -f */
894 if (rflg || fflg || retries <= 0) {
899 #endif /* ! USE_PAM */
900 alarm (0); /* turn off alarm clock */
901 #ifndef USE_PAM /* PAM does this */
903 * porttime checks moved here, after the user has been
904 * authenticated. now prints a message, as suggested
905 * by Ivan Nejgebauer <ian@unsux.ns.ac.yu>. --marekm
907 if (getdef_bool ("PORTTIME_CHECKS_ENAB") &&
908 !isttytime (pwent.pw_name, tty, time ((time_t *) 0))) {
909 SYSLOG ((LOG_WARN, "invalid login time for `%s'%s",
910 username, fromhost));
919 if (getenv ("IFS")) /* don't export user IFS ... */
920 addenv ("IFS= \t\n", NULL); /* ... instead, set a safe IFS */
923 setutmp (pam_user, tty, hostname); /* make entry in utmp & wtmp files */
925 setutmp (username, tty, hostname); /* make entry in utmp & wtmp files */
927 if (pwent.pw_shell[0] == '*') { /* subsystem root */
928 pwent.pw_shell++; /* skip the '*' */
929 subsystem (&pwent); /* figure out what to execute */
930 subroot++; /* say i was here again */
931 endpwent (); /* close all of the file which were */
932 endgrent (); /* open in the original rooted file */
933 endspent (); /* system. they will be re-opened */
935 endsgent (); /* in the new rooted file system */
937 goto top; /* go do all this all over again */
939 #ifndef USE_PAM /* pam_lastlog handles this */
940 if (getdef_bool ("LASTLOG_ENAB")) /* give last login and log this one */
941 dolastlog (&lastlog, &pwent, utent.ut_line, hostname);
944 #ifndef USE_PAM /* PAM handles this as well */
946 * Have to do this while we still have root privileges, otherwise we
947 * don't have access to /etc/shadow. expire() closes password files,
948 * and changes to the user in the child before executing the passwd
951 if (spwd) { /* check for age of password */
952 if (expire (&pwent, spwd)) {
953 pwd = getpwnam (username);
954 spwd = getspnam (username);
959 setup_limits (&pwent); /* nice, ulimit etc. */
960 #endif /* ! USE_PAM */
961 chown_tty (tty, &pwent);
965 * We must fork before setuid() because we need to call
966 * pam_close_session() as root.
968 signal (SIGINT, SIG_IGN);
971 /* error in fork() */
972 fprintf (stderr, "login: failure forking: %s",
978 * parent - wait for child to finish, then cleanup
988 /* We call set_groups() above because this clobbers pam_groups.so */
990 if (setup_uid_gid (&pwent, is_console))
992 if (change_uid (&pwent))
996 setup_env (&pwent); /* set env vars, cd to the home dir */
1000 const char *const *env;
1002 env = (const char *const *) pam_getenvlist (pamh);
1003 while (env && *env) {
1004 addenv (*env, NULL);
1010 setlocale (LC_ALL, "");
1011 bindtextdomain (PACKAGE, LOCALEDIR);
1012 textdomain (PACKAGE);
1014 if (!hushed (&pwent)) {
1015 addenv ("HUSHLOGIN=FALSE", NULL);
1017 * pam_unix, pam_mail and pam_lastlog should take care of
1021 motd (); /* print the message of the day */
1022 if (getdef_bool ("FAILLOG_ENAB")
1023 && faillog.fail_cnt != 0) {
1024 failprint (&faillog);
1025 /* Reset the lockout times if logged in */
1026 if (faillog.fail_max &&
1027 faillog.fail_cnt >= faillog.fail_max) {
1029 ("Warning: login re-enabled after temporary lockout.\n"));
1031 "login `%s' re-enabled after temporary lockout (%d failures)",
1032 username, (int) faillog.fail_cnt));
1035 if (getdef_bool ("LASTLOG_ENAB")
1036 && lastlog.ll_time != 0) {
1037 time_t ll_time = lastlog.ll_time;
1039 #ifdef HAVE_STRFTIME
1040 strftime (ptime, sizeof (ptime),
1041 "%a %b %e %H:%M:%S %z %Y",
1042 localtime (&ll_time));
1043 printf (_("Last login: %s on %s"),
1044 ptime, lastlog.ll_line);
1046 printf (_("Last login: %.19s on %s"),
1047 ctime (&ll_time), lastlog.ll_line);
1049 #ifdef HAVE_LL_HOST /* __linux__ || SUN4 */
1050 if (lastlog.ll_host[0])
1051 printf (_(" from %.*s"),
1052 (int) sizeof lastlog.
1053 ll_host, lastlog.ll_host);
1057 agecheck (&pwent, spwd);
1059 mailcheck (); /* report on the status of mail */
1060 #endif /* !USE_PAM */
1062 addenv ("HUSHLOGIN=TRUE", NULL);
1064 if (getdef_str ("TTYTYPE_FILE") != NULL && getenv ("TERM") == NULL)
1067 signal (SIGQUIT, SIG_DFL); /* default quit signal */
1068 signal (SIGTERM, SIG_DFL); /* default terminate signal */
1069 signal (SIGALRM, SIG_DFL); /* default alarm signal */
1070 signal (SIGHUP, SIG_DFL); /* added this. --marekm */
1071 signal (SIGINT, SIG_DFL); /* default interrupt signal */
1073 endpwent (); /* stop access to password file */
1074 endgrent (); /* stop access to group file */
1075 endspent (); /* stop access to shadow passwd file */
1077 endsgent (); /* stop access to shadow group file */
1079 if (pwent.pw_uid == 0)
1080 SYSLOG ((LOG_NOTICE, "ROOT LOGIN %s", fromhost));
1081 else if (getdef_bool ("LOG_OK_LOGINS"))
1083 SYSLOG ((LOG_INFO, "`%s' logged in %s", pam_user, fromhost));
1085 SYSLOG ((LOG_INFO, "`%s' logged in %s", username, fromhost));
1088 if ((tmp = getdef_str ("FAKE_SHELL")) != NULL) {
1089 shell (tmp, pwent.pw_shell); /* fake shell */
1091 shell (pwent.pw_shell, (char *) 0); /* exec the shell finally. */