]> granicus.if.org Git - shadow/blob - src/login.c
a2c2e77c543264d62f4cdcb2a19b4255cd68a36a
[shadow] / src / login.c
1 /*
2  * Copyright 1989 - 1994, Julianne Frances Haugh
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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.
16  *
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
27  * SUCH DAMAGE.
28  */
29
30 #include <config.h>
31
32 #ident "$Id: login.c,v 1.86 2006/07/10 04:11:32 kloczek Exp $"
33
34 #include <errno.h>
35 #include <grp.h>
36 #include <lastlog.h>
37 #ifdef UT_ADDR
38 #include <netdb.h>
39 #endif
40 #include <pwd.h>
41 #include <signal.h>
42 #include <stdio.h>
43 #include <sys/stat.h>
44 #include "defines.h"
45 #include "faillog.h"
46 #include "failure.h"
47 #include "getdef.h"
48 #include "prototypes.h"
49 #include "pwauth.h"
50 #include "exitcodes.h"
51 #ifdef USE_PAM
52 #include "pam_defs.h"
53
54 static pam_handle_t *pamh = NULL;
55
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); \
60    }
61 #define PAM_END { retcode = pam_close_session(pamh,0); \
62                 pam_end(pamh,retcode); }
63
64 #endif                          /* USE_PAM */
65
66 /*
67  * Needed for MkLinux DR1/2/2.1 - J.
68  */
69 #ifndef LASTLOG_FILE
70 #define LASTLOG_FILE "/var/log/lastlog"
71 #endif
72
73 /*
74  * Global variables
75  */
76 const char *hostname = "";
77
78 static struct passwd pwent;
79
80 #if HAVE_UTMPX_H
81 extern struct utmpx utxent;
82 struct utmpx failent;
83 #else
84 struct utmp failent;
85 #endif
86 extern struct utmp utent;
87
88 struct lastlog lastlog;
89 static int pflg = 0;
90 static int fflg = 0;
91
92 #ifdef RLOGIN
93 static int rflg = 0;
94 #else
95 #define rflg 0
96 #endif
97 static int hflg = 0;
98 static int preauth_flag = 0;
99
100 /*
101  * Global variables.
102  */
103
104 static char *Prog;
105 static int amroot;
106 static int timeout;
107
108 /*
109  * External identifiers.
110  */
111
112 extern char **newenvp;
113 extern size_t newenvc;
114
115 extern void dolastlog (struct lastlog *, const struct passwd *,
116                        const char *, const char *);
117
118 extern char **environ;
119
120 #ifndef ALARM
121 #define ALARM   60
122 #endif
123
124 #ifndef RETRIES
125 #define RETRIES 3
126 #endif
127
128 /* local function prototypes */
129 static void usage (void);
130 static void setup_tty (void);
131 static void check_flags (int, char *const *);
132
133 #ifndef USE_PAM
134 extern int login_access (const char *, const char *);
135
136 static struct faillog faillog;
137
138 static void bad_time_notify (void);
139 static void check_nologin (void);
140 #endif
141
142 static void init_env (void);
143 static RETSIGTYPE alarm_handler (int);
144
145 /*
146  * usage - print login command usage and exit
147  *
148  * login [ name ]
149  * login -r hostname    (for rlogind)
150  * login -h hostname    (for telnetd, etc.)
151  * login -f name        (for pre-authenticated login: datakit, xterm, etc.)
152  */
153 static void usage (void)
154 {
155         fprintf (stderr, _("Usage: %s [-p] [name]\n"), Prog);
156         if (!amroot)
157                 exit (1);
158         fprintf (stderr, _("       %s [-p] [-h host] [-f name]\n"), Prog);
159 #ifdef RLOGIN
160         fprintf (stderr, _("       %s [-p] -r host\n"), Prog);
161 #endif
162         exit (1);
163 }
164
165 static void setup_tty (void)
166 {
167         TERMIO termio;
168
169         GTTY (0, &termio);      /* get terminal characteristics */
170
171         /*
172          * Add your favorite terminal modes here ...
173          */
174         termio.c_lflag |= ISIG | ICANON | ECHO | ECHOE;
175         termio.c_iflag |= ICRNL;
176
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]);
180
181         /*
182          * ttymon invocation prefers this, but these settings won't come into
183          * effect after the first username login 
184          */
185         STTY (0, &termio);
186 }
187
188
189 #ifndef USE_PAM
190 /*
191  * Tell the user that this is not the right time to login at this tty
192  */
193 static void bad_time_notify (void)
194 {
195         printf (_("Invalid login time\n"));
196         fflush (stdout);
197 }
198
199 static void check_nologin (void)
200 {
201         char *fname;
202
203         /*
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 ...
209          */
210         fname = getdef_str ("NOLOGINS_FILE");
211         if (fname != NULL && access (fname, F_OK) == 0) {
212                 FILE *nlfp;
213                 int c;
214
215                 /*
216                  * Cat the file if it can be opened, otherwise just
217                  * print a default message
218                  */
219                 if ((nlfp = fopen (fname, "r"))) {
220                         while ((c = getc (nlfp)) != EOF) {
221                                 if (c == '\n')
222                                         putchar ('\r');
223
224                                 putchar (c);
225                         }
226                         fflush (stdout);
227                         fclose (nlfp);
228                 } else
229                         printf (_("\nSystem closed for routine maintenance\n"));
230                 /*
231                  * Non-root users must exit. Root gets the message, but
232                  * gets to login.
233                  */
234
235                 if (pwent.pw_uid != 0) {
236                         closelog ();
237                         exit (0);
238                 }
239                 printf (_("\n[Disconnect bypassed -- root login allowed.]\n"));
240         }
241 }
242 #endif                          /* !USE_PAM */
243
244 static void check_flags (int argc, char *const *argv)
245 {
246         int arg;
247
248         /*
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.
252          */
253         for (arg = 1; arg < argc; arg++) {
254                 if (argv[arg][0] == '-' && strlen (argv[arg]) > 2)
255                         usage ();
256         }
257 }
258
259
260 static void init_env (void)
261 {
262 #ifndef USE_PAM
263         char *cp;
264 #endif
265         char *tmp;
266
267         if ((tmp = getenv ("LANG"))) {
268                 addenv ("LANG", tmp);
269         }
270
271         /*
272          * Add the timezone environmental variable so that time functions
273          * work correctly.
274          */
275         if ((tmp = getenv ("TZ"))) {
276                 addenv ("TZ", tmp);
277         }
278 #ifndef USE_PAM
279         else if ((cp = getdef_str ("ENV_TZ")))
280                 addenv (*cp == '/' ? tz (cp) : cp, NULL);
281 #endif                          /* !USE_PAM */
282         /* 
283          * Add the clock frequency so that profiling commands work
284          * correctly.
285          */
286         if ((tmp = getenv ("HZ"))) {
287                 addenv ("HZ", tmp);
288         }
289 #ifndef USE_PAM
290         else if ((cp = getdef_str ("ENV_HZ")))
291                 addenv (cp, NULL);
292 #endif                          /* !USE_PAM */
293 }
294
295
296 static RETSIGTYPE alarm_handler (int sig)
297 {
298         fprintf (stderr, _("\nLogin timed out after %d seconds.\n"), timeout);
299         exit (0);
300 }
301
302
303 /*
304  * login - create a new login session for a user
305  *
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.
312  *
313  *      the flags which login supports are
314  *      
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
319  */
320 int main (int argc, char **argv)
321 {
322         char username[32];
323         char tty[BUFSIZ];
324
325 #ifdef RLOGIN
326         char term[128] = "";
327 #endif
328 #if defined(HAVE_STRFTIME) && !defined(USE_PAM)
329         char ptime[80];
330 #endif
331         int reason = PW_LOGIN;
332         int delay;
333         int retries;
334         int failed;
335         int flag;
336         int subroot = 0;
337         int is_console;
338         int err;
339         const char *cp;
340         char *tmp;
341         char fromhost[512];
342         struct passwd *pwd;
343         char **envp = environ;
344         static char temp_pw[2];
345         static char temp_shell[] = "/bin/sh";
346
347 #ifdef USE_PAM
348         int retcode;
349         pid_t child;
350         char *pam_user;
351 #else
352         struct spwd *spwd = NULL;
353 #endif
354         /*
355          * Some quick initialization.
356          */
357
358         sanitize_env ();
359
360         setlocale (LC_ALL, "");
361         bindtextdomain (PACKAGE, LOCALEDIR);
362         textdomain (PACKAGE);
363
364         initenv ();
365
366         username[0] = '\0';
367         amroot = (getuid () == 0);
368         Prog = Basename (argv[0]);
369
370         check_flags (argc, argv);
371
372         while ((flag = getopt (argc, argv, "d:f::h:pr:")) != EOF) {
373                 switch (flag) {
374                 case 'd':
375                         /* "-d device" ignored for compatibility */
376                         break;
377                 case 'f':
378                         /*
379                          * username must be a separate token
380                          * (-f root, *not* -froot).  --marekm
381                          *
382                          * if -f has an arg, use that, else use the
383                          * normal user name passed after all options
384                          * --benc
385                          */
386                         if (optarg != NULL && optarg != argv[optind - 1])
387                                 usage ();
388                         fflg++;
389                         if (optarg)
390                                 STRFCPY (username, optarg);
391                         break;
392                 case 'h':
393                         hflg++;
394                         hostname = optarg;
395                         reason = PW_TELNET;
396                         break;
397 #ifdef  RLOGIN
398                 case 'r':
399                         rflg++;
400                         hostname = optarg;
401                         reason = PW_RLOGIN;
402                         break;
403 #endif
404                 case 'p':
405                         pflg++;
406                         break;
407                 default:
408                         usage ();
409                 }
410         }
411
412 #ifdef RLOGIN
413         /*
414          * Neither -h nor -f should be combined with -r.
415          */
416
417         if (rflg && (hflg || fflg))
418                 usage ();
419 #endif
420
421         /*
422          * Allow authentication bypass only if real UID is zero.
423          */
424
425         if ((rflg || fflg || hflg) && !amroot) {
426                 fprintf (stderr, _("%s: Permission denied.\n"), Prog);
427                 exit (1);
428         }
429
430         if (!isatty (0) || !isatty (1) || !isatty (2))
431                 exit (1);       /* must be a terminal */
432
433         /*
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
439          */
440         checkutmp (!amroot);
441         STRFCPY (tty, utent.ut_line);
442         is_console = console (tty);
443
444         if (rflg || hflg) {
445 #ifdef UT_ADDR
446                 struct hostent *he;
447
448                 /*
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
456                  */
457                 if ((he = gethostbyname (hostname))) {
458                         utent.ut_addr = *((int32_t *) (he->h_addr_list[0]));
459 #endif
460 #ifdef UT_HOST
461                         strncpy (utent.ut_host, hostname,
462                                  sizeof (utent.ut_host));
463 #endif
464 #if HAVE_UTMPX_H
465                         strncpy (utxent.ut_host, hostname,
466                                  sizeof (utxent.ut_host));
467 #endif
468                         /*
469                          * Add remote hostname to the environment. I think
470                          * (not sure) I saw it once on Irix.  --marekm
471                          */
472                         addenv ("REMOTEHOST", hostname);
473                 }
474 #ifdef __linux__
475                 /*
476                  * workaround for init/getty leaving junk in ut_host at least in
477                  * some version of RedHat.  --marekm
478                  */
479                 else if (amroot)
480                         memzero (utent.ut_host, sizeof utent.ut_host);
481 #endif
482                 if (fflg)
483                         preauth_flag++;
484                 if (hflg)
485                         reason = PW_RLOGIN;
486 #ifdef RLOGIN
487                 if (rflg
488                     && do_rlogin (hostname, username, sizeof username,
489                                   term, sizeof term))
490                         preauth_flag++;
491 #endif
492
493                 OPENLOG ("login");
494
495                 setup_tty ();
496
497 #ifndef USE_PAM
498                 umask (getdef_num ("UMASK", GETDEF_DEFAULT_UMASK));
499
500                 {
501                         /* 
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.
506                          */
507                         long limit = getdef_long ("ULIMIT", -1L);
508
509                         if (limit != -1)
510                                 set_filesize_limit (limit);
511                 }
512
513 #endif
514                 /*
515                  * The entire environment will be preserved if the -p flag
516                  * is used.
517                  */
518                 if (pflg)
519                         while (*envp)   /* add inherited environment, */
520                                 addenv (*envp++, NULL); /* some variables change later */
521
522 #ifdef RLOGIN
523                 if (term[0] != '\0')
524                         addenv ("TERM", term);
525                 else
526 #endif
527                         /* preserve TERM from getty */
528                 if (!pflg && (tmp = getenv ("TERM")))
529                         addenv ("TERM", tmp);
530
531                 init_env ();
532
533                 if (optind < argc) {    /* get the user name */
534                         if (rflg || (fflg && username[0]))
535                                 usage ();
536
537                         STRFCPY (username, argv[optind]);
538                         strzero (argv[optind]);
539                         ++optind;
540                 }
541                 if (optind < argc)      /* now set command line variables */
542                         set_env (argc - optind, &argv[optind]);
543
544                 if (rflg || hflg)
545                         cp = hostname;
546                 else
547 #ifdef  UT_HOST
548                 if (utent.ut_host[0])
549                         cp = utent.ut_host;
550                 else
551 #endif
552 #if HAVE_UTMPX_H
553                 if (utxent.ut_host[0])
554                         cp = utxent.ut_host;
555                 else
556 #endif
557                         cp = "";
558
559                 if (*cp)
560                         snprintf (fromhost, sizeof fromhost,
561                                   _(" on '%.100s' from '%.200s'"), tty, cp);
562                 else
563                         snprintf (fromhost, sizeof fromhost,
564                                   _(" on '%.100s'"), tty);
565
566               top:
567                 /* only allow ALARM sec. for login */
568                 signal (SIGALRM, alarm_handler);
569                 timeout = getdef_num ("LOGIN_TIMEOUT", ALARM);
570                 if (timeout > 0)
571                         alarm (timeout);
572
573                 environ = newenvp;      /* make new environment active */
574                 delay = getdef_num ("FAIL_DELAY", 1);
575                 retries = getdef_num ("LOGIN_RETRIES", RETRIES);
576
577 #ifdef USE_PAM
578                 retcode = pam_start ("login", username, &conv, &pamh);
579                 if (retcode != PAM_SUCCESS) {
580                         fprintf (stderr,
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)));
585                         exit (99);
586                 }
587
588                 /*
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
591                  * ours.
592                  */
593                 retcode = pam_set_item (pamh, PAM_RHOST, hostname);
594                 PAM_FAIL_CHECK;
595                 retcode = pam_set_item (pamh, PAM_TTY, tty);
596                 PAM_FAIL_CHECK;
597 #ifdef HAVE_PAM_FAIL_DELAY
598                 retcode = pam_fail_delay (pamh, 1000000 * delay);
599                 PAM_FAIL_CHECK;
600 #endif
601                 /* if fflg == 1, then the user has already been authenticated */
602                 if (!fflg || (getuid () != 0)) {
603                         int failcount = 0;
604                         char hostn[256];
605                         char login_prompt[256]; /* That's one hell of a prompt :) */
606
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);
612                         else
613                                 snprintf (login_prompt,
614                                           sizeof (login_prompt), _("login: "));
615
616                         retcode =
617                             pam_set_item (pamh, PAM_USER_PROMPT, login_prompt);
618                         PAM_FAIL_CHECK;
619
620                         /* if we didn't get a user on the command line,
621                            set it to NULL */
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);
626
627                         /*
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
633                          * MAX_LOGIN_TRIES?
634                          */
635                         failcount = 0;
636                         while (1) {
637                           const char *failent_user;
638                           failed = 0;
639
640                           failcount++;
641                           if (delay > 0)
642                             retcode = pam_fail_delay(pamh, 1000000*delay);
643
644                           retcode = pam_authenticate (pamh, 0);
645
646                           pam_get_item (pamh, PAM_USER,
647                                         (const void **) &pam_user);
648
649                           if (pam_user && pam_user[0]) {
650                             pwd = getpwnam(pam_user);
651                             if (pwd) {
652                               pwent = *pwd;
653                               failent_user = pwent.pw_name;
654                             } else {
655                               if (getdef_bool("LOG_UNKFAIL_ENAB") && pam_user)
656                                 failent_user = pam_user;
657                               else
658                                 failent_user = "UNKNOWN";
659                             }
660                           } else {
661                             pwd = NULL;
662                             failent_user = "UNKNOWN";
663                           }
664
665                           if (retcode == PAM_MAXTRIES || failcount >= retries) {
666                             SYSLOG ((LOG_NOTICE,
667                                     "TOO MANY LOGIN TRIES (%d)%s FOR `%s'",
668                                     failcount, fromhost, failent_user));
669                             fprintf(stderr,
670                                     _("Maximum number of tries exceeded (%d)\n"),
671                                     failcount);
672                             PAM_END;
673                             exit(0);
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()"));
678                             PAM_END;
679                             exit(99);
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)));
684                             failed = 1;
685                           }
686
687                           if (!failed)
688                             break;
689
690 #ifdef WITH_AUDIT
691                                 {
692                                         struct passwd *pw;
693                                         char buf[64];
694
695                                         audit_fd = audit_open ();
696                                         pw = getpwnam (username);
697                                         if (pw) {
698                                                 snprintf (buf, sizeof (buf),
699                                                   "uid=%d", pw->pw_uid);
700                                                 audit_log_user_message
701                                                     (audit_fd, AUDIT_USER_LOGIN,
702                                                      buf, hostname, NULL,
703                                                      tty, 0);
704                                         } else {
705                                                 snprintf (buf, sizeof (buf),
706                                                           "acct=%s", username);
707                                                 audit_log_user_message
708                                                     (audit_fd, AUDIT_USER_LOGIN,
709                                                      buf, hostname, NULL,
710                                                      tty, 0);
711                                         }
712                                         close (audit_fd);
713                                 }
714 #endif                          /* WITH_AUDIT */
715
716                           fprintf(stderr,"\nLogin incorrect\n");
717
718                           /* Let's give it another go around */
719                           pam_set_item(pamh,PAM_USER,NULL);
720                         }
721
722                         /* We don't get here unless they were authenticated above */
723                         alarm (0);
724                         retcode = pam_acct_mgmt (pamh, 0);
725
726                         if (retcode == PAM_NEW_AUTHTOK_REQD) {
727                                 retcode =
728                                     pam_chauthtok (pamh,
729                                                    PAM_CHANGE_EXPIRED_AUTHTOK);
730                         }
731
732                         PAM_FAIL_CHECK;
733                 }
734
735                 /* Grab the user information out of the password file for future usage
736                    First get the username that we are actually using, though.
737                  */
738                 retcode =
739                     pam_get_item (pamh, PAM_USER, (const void **) &pam_user);
740                 setpwent ();
741                 pwd = getpwnam (pam_user);
742
743                 if (fflg) {
744                         retcode = pam_acct_mgmt (pamh, 0);
745                         PAM_FAIL_CHECK;
746                 }
747
748                 if (!pwd || setup_groups (pwd))
749                         exit (1);
750                 else
751                         pwent = *pwd;
752
753                 retcode = pam_setcred (pamh, PAM_ESTABLISH_CRED);
754                 PAM_FAIL_CHECK;
755
756                 retcode = pam_open_session (pamh,
757                                             hushed (&pwent) ? PAM_SILENT : 0);
758                 PAM_FAIL_CHECK;
759
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 */
764                                 if (subroot) {
765                                         closelog ();
766                                         exit (1);
767                                 }
768                                 preauth_flag = 0;
769                                 login_prompt (_("\n%s login: "), username,
770                                               sizeof username);
771                                 continue;
772                         }
773 #endif                          /* ! USE_PAM */
774
775 #ifdef USE_PAM
776                 if (!(pwd = getpwnam (pam_user))) {
777                         pwent.pw_name = pam_user;
778 #else
779                 if (!(pwd = getpwnam (username))) {
780                         pwent.pw_name = username;
781 #endif
782                         strcpy (temp_pw, "!");
783                         pwent.pw_passwd = temp_pw;
784                         pwent.pw_shell = temp_shell;
785
786                         preauth_flag = 0;
787                         failed = 1;
788                 } else {
789                         pwent = *pwd;
790                 }
791 #ifndef USE_PAM
792                 spwd = NULL;
793                 if (pwd && strcmp (pwd->pw_passwd, SHADOW_PASSWD_STRING) == 0) {
794                         spwd = getspnam (username);
795                         if (spwd)
796                                 pwent.pw_passwd = spwd->sp_pwdp;
797                         else
798                                 SYSLOG ((LOG_WARN,
799                                          "no shadow password for `%s'%s",
800                                          username, fromhost));
801                 }
802
803                 /*
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."
807                  */
808                 if (pwent.pw_passwd[0] == '!' || pwent.pw_passwd[0] == '*')
809                         failed = 1;
810
811                 /*
812                  * The -r and -f flags provide a name which has already
813                  * been authenticated by some server.
814                  */
815                 if (preauth_flag)
816                         goto auth_ok;
817
818                 if (pw_auth
819                     (pwent.pw_passwd, username, reason, (char *) 0) == 0)
820                         goto auth_ok;
821
822                 /*
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
826                  */
827                 SYSLOG ((LOG_WARN, "invalid password for `%s' %s",
828                          (pwd
829                           || getdef_bool ("LOG_UNKFAIL_ENAB")) ?
830                          username : "UNKNOWN", fromhost));
831                 failed = 1;
832
833               auth_ok:
834                 /*
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.
838                  */
839                 if (!failed && pwent.pw_name && pwent.pw_uid == 0
840                     && !is_console) {
841                         SYSLOG ((LOG_CRIT, "ILLEGAL ROOT LOGIN %s", fromhost));
842                         failed = 1;
843                 }
844                 if (!failed
845                     && !login_access (username, *hostname ? hostname : tty)) {
846                         SYSLOG ((LOG_WARN, "LOGIN `%s' REFUSED %s",
847                                  username, fromhost));
848                         failed = 1;
849                 }
850                 if (pwd && getdef_bool ("FAILLOG_ENAB") &&
851                     !failcheck (pwent.pw_uid, &faillog, failed)) {
852                         SYSLOG ((LOG_CRIT,
853                                  "exceeded failure limit for `%s' %s",
854                                  username, fromhost));
855                         failed = 1;
856                 }
857                 if (!failed)
858                         break;
859
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;
865
866 #if HAVE_UTMPX_H
867                         failent = utxent;
868                         if (sizeof (failent.ut_tv) == sizeof (struct timeval))
869                                 gettimeofday ((struct timeval *)
870                                               &failent.ut_tv, NULL);
871                         else {
872                                 struct timeval tv;
873
874                                 gettimeofday (&tv, NULL);
875                                 failent.ut_tv.tv_sec = tv.tv_sec;
876                                 failent.ut_tv.tv_usec = tv.tv_usec;
877                         }
878 #else
879                         failent = utent;
880                         failent.ut_time = time (NULL);
881 #endif
882                         if (pwd) {
883                                 failent_user = pwent.pw_name;
884                         } else {
885                                 if (getdef_bool ("LOG_UNKFAIL_ENAB"))
886                                         failent_user = username;
887                                 else
888                                         failent_user = "UNKNOWN";
889                         }
890                         strncpy (failent.ut_user, failent_user,
891                                  sizeof (failent.ut_user));
892                         failent.ut_type = USER_PROCESS;
893                         failtmp (&failent);
894                 }
895                 memzero (username, sizeof username);
896
897                 if (--retries <= 0)
898                         SYSLOG ((LOG_CRIT, "REPEATED login failures%s",
899                                  fromhost));
900                 /*
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
905                  * all).  --marekm
906                  */
907                 if (pwent.pw_passwd[0] == '\0')
908                         pw_auth ("!", username, reason, (char *) 0);
909
910                 /*
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.
914                  */
915                 if (delay > 0)
916                         sleep (delay);
917
918                 puts (_("Login incorrect"));
919
920                 /* allow only one attempt with -r or -f */
921                 if (rflg || fflg || retries <= 0) {
922                         closelog ();
923                         exit (1);
924                 }
925         }                       /* while (1) */
926 #endif                          /* ! USE_PAM */
927         alarm (0);              /* turn off alarm clock */
928 #ifndef USE_PAM                 /* PAM does this */
929         /*
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
933          */
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));
938                 closelog ();
939                 bad_time_notify ();
940                 exit (1);
941         }
942
943         check_nologin ();
944 #endif
945
946         if (getenv ("IFS"))     /* don't export user IFS ... */
947                 addenv ("IFS= \t\n", NULL);     /* ... instead, set a safe IFS */
948
949 #ifdef USE_PAM
950         setutmp (pam_user, tty, hostname);      /* make entry in utmp & wtmp files */
951 #else
952         setutmp (username, tty, hostname);      /* make entry in utmp & wtmp files */
953 #endif
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 */
961 #ifdef  SHADOWGRP
962                 endsgent ();    /* in the new rooted file system */
963 #endif
964                 goto top;       /* go do all this all over again */
965         }
966
967 #ifdef WITH_AUDIT
968         {
969                 char buf[32];
970
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);
975                 close (audit_fd);
976         }
977 #endif                          /* WITH_AUDIT */
978
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);
982 #endif
983
984 #ifndef USE_PAM                 /* PAM handles this as well */
985         /*
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
989          * program.  --marekm
990          */
991         if (spwd) {             /* check for age of password */
992                 if (expire (&pwent, spwd)) {
993                         pwd = getpwnam (username);
994                         spwd = getspnam (username);
995                         if (pwd)
996                                 pwent = *pwd;
997                 }
998         }
999         setup_limits (&pwent);  /* nice, ulimit etc. */
1000 #endif                          /* ! USE_PAM */
1001         chown_tty (tty, &pwent);
1002
1003 #ifdef USE_PAM
1004         /*
1005          * We must fork before setuid() because we need to call
1006          * pam_close_session() as root.
1007          */
1008         signal (SIGINT, SIG_IGN);
1009         child = fork ();
1010         if (child < 0) {
1011                 /* error in fork() */
1012                 fprintf (stderr, _("%s: failure forking: %s"),
1013                          Prog, strerror (errno));
1014                 PAM_END;
1015                 exit (0);
1016         } else if (child) {
1017                 /*
1018                  * parent - wait for child to finish, then cleanup
1019                  * session
1020                  */
1021                 wait (NULL);
1022                 PAM_END;
1023                 exit (0);
1024         }
1025         /* child */
1026 #endif
1027
1028         /* We call set_groups() above because this clobbers pam_groups.so */
1029 #ifndef USE_PAM
1030         if (setup_uid_gid (&pwent, is_console))
1031 #else
1032         if (change_uid (&pwent))
1033 #endif
1034                 exit (1);
1035
1036         setup_env (&pwent);     /* set env vars, cd to the home dir */
1037
1038 #ifdef USE_PAM
1039         {
1040                 const char *const *env;
1041
1042                 env = (const char *const *) pam_getenvlist (pamh);
1043                 while (env && *env) {
1044                         addenv (*env, NULL);
1045                         env++;
1046                 }
1047         }
1048 #endif
1049
1050         setlocale (LC_ALL, "");
1051         bindtextdomain (PACKAGE, LOCALEDIR);
1052         textdomain (PACKAGE);
1053
1054         if (!hushed (&pwent)) {
1055                 addenv ("HUSHLOGIN=FALSE", NULL);
1056                 /*
1057                  * pam_unix, pam_mail and pam_lastlog should take care of
1058                  * this
1059                  */
1060 #ifndef USE_PAM
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) {
1068                                 puts (_
1069                                       ("Warning: login re-enabled after temporary lockout.\n"));
1070                                 SYSLOG ((LOG_WARN,
1071                                          "login `%s' re-enabled after temporary lockout (%d failures)",
1072                                          username, (int) faillog.fail_cnt));
1073                         }
1074                 }
1075                 if (getdef_bool ("LASTLOG_ENAB")
1076                     && lastlog.ll_time != 0) {
1077                         time_t ll_time = lastlog.ll_time;
1078
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);
1085 #else
1086                         printf (_("Last login: %.19s on %s"),
1087                                 ctime (&ll_time), lastlog.ll_line);
1088 #endif
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);
1094 #endif
1095                         printf (".\n");
1096                 }
1097                 agecheck (&pwent, spwd);
1098
1099                 mailcheck ();   /* report on the status of mail */
1100 #endif                          /* !USE_PAM */
1101         } else
1102                 addenv ("HUSHLOGIN=TRUE", NULL);
1103
1104         if (getdef_str ("TTYTYPE_FILE") != NULL && getenv ("TERM") == NULL)
1105                 ttytype (tty);
1106
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 */
1112
1113         endpwent ();            /* stop access to password file */
1114         endgrent ();            /* stop access to group file */
1115         endspent ();            /* stop access to shadow passwd file */
1116 #ifdef  SHADOWGRP
1117         endsgent ();            /* stop access to shadow group file */
1118 #endif
1119         if (pwent.pw_uid == 0)
1120                 SYSLOG ((LOG_NOTICE, "ROOT LOGIN %s", fromhost));
1121         else if (getdef_bool ("LOG_OK_LOGINS"))
1122 #ifdef USE_PAM
1123                 SYSLOG ((LOG_INFO, "`%s' logged in %s", pam_user, fromhost));
1124 #else
1125                 SYSLOG ((LOG_INFO, "`%s' logged in %s", username, fromhost));
1126 #endif
1127         closelog ();
1128         if ((tmp = getdef_str ("FAKE_SHELL")) != NULL)
1129                 err = shell (tmp, pwent.pw_shell, newenvp); /* fake shell */
1130         else
1131                 /* exec the shell finally */
1132                 err = shell (pwent.pw_shell, (char *) 0, newenvp);
1133         exit (err == ENOENT ? E_CMD_NOTFOUND : E_CMD_NOEXEC);
1134         /* NOT REACHED */
1135         return 0;
1136 }