]> granicus.if.org Git - shadow/blob - src/login.c
* src/login.c: Ignore the return value of puts(), fputs(),
[shadow] / src / login.c
1 /*
2  * Copyright (c) 1989 - 1994, Julianne Frances Haugh
3  * Copyright (c) 1996 - 2001, Marek Michałkiewicz
4  * Copyright (c) 2001 - 2006, Tomasz Kłoczko
5  * Copyright (c) 2007 - 2009, Nicolas François
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. The name of the copyright holders or contributors may not be used to
17  *    endorse or promote products derived from this software without
18  *    specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23  * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT
24  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include <config.h>
34
35 #ident "$Id$"
36
37 #include <errno.h>
38 #include <grp.h>
39 #ifndef USE_PAM
40 #include <lastlog.h>
41 #endif                          /* !USE_PAM */
42 #include <pwd.h>
43 #include <signal.h>
44 #include <stdio.h>
45 #include <sys/stat.h>
46 #include <sys/ioctl.h>
47 #include <assert.h>
48 #include "defines.h"
49 #include "faillog.h"
50 #include "failure.h"
51 #include "getdef.h"
52 #include "prototypes.h"
53 #include "pwauth.h"
54 #include "exitcodes.h"
55 #ifdef USE_PAM
56 #include "pam_defs.h"
57
58 static pam_handle_t *pamh = NULL;
59
60 #define PAM_FAIL_CHECK if (retcode != PAM_SUCCESS) { \
61         fprintf(stderr,"\n%s\n",pam_strerror(pamh, retcode)); \
62         SYSLOG((LOG_ERR,"%s",pam_strerror(pamh, retcode))); \
63         (void) pam_end(pamh, retcode); \
64         exit(1); \
65    }
66 #define PAM_END { retcode = pam_close_session(pamh,0); \
67                 (void) pam_end(pamh,retcode); }
68
69 #endif                          /* USE_PAM */
70
71 #ifndef USE_PAM
72 /*
73  * Needed for MkLinux DR1/2/2.1 - J.
74  */
75 #ifndef LASTLOG_FILE
76 #define LASTLOG_FILE "/var/log/lastlog"
77 #endif
78 #endif                          /* !USE_PAM */
79
80 /*
81  * Global variables
82  */
83 char *Prog;
84
85 static const char *hostname = "";
86 static char *username = NULL;
87 static int reason = PW_LOGIN;
88
89 #ifndef USE_PAM
90 static struct lastlog ll;
91 #endif                          /* !USE_PAM */
92 static bool pflg = false;
93 static bool fflg = false;
94
95 #ifdef RLOGIN
96 static bool rflg = false;
97 #else                           /* RLOGIN */
98 #define rflg false
99 #endif                          /* !RLOGIN */
100 static bool hflg = false;
101 static bool preauth_flag = false;
102
103 static bool amroot;
104 static unsigned int timeout;
105
106 /*
107  * External identifiers.
108  */
109
110 extern char **newenvp;
111 extern size_t newenvc;
112 extern char **environ;
113
114 #ifndef ALARM
115 #define ALARM   60
116 #endif
117
118 #ifndef RETRIES
119 #define RETRIES 3
120 #endif
121
122 /* local function prototypes */
123 static void usage (void);
124 static void setup_tty (void);
125 static void process_flags (int, char *const *);
126 static const char *get_failent_user (const char *user);
127 static void update_utmp (const char *username,
128                          const char *tty,
129                          const char *hostname,
130                          const struct utmp *utent);
131
132 #ifndef USE_PAM
133 static struct faillog faillog;
134
135 static void bad_time_notify (void);
136 static void check_nologin (bool login_to_root);
137 #else
138 static void get_pam_user (char **ptr_pam_user);
139 #endif
140
141 static void init_env (void);
142 static RETSIGTYPE alarm_handler (int);
143
144 /*
145  * usage - print login command usage and exit
146  *
147  * login [ name ]
148  * login -r hostname    (for rlogind)
149  * login -h hostname    (for telnetd, etc.)
150  * login -f name        (for pre-authenticated login: datakit, xterm, etc.)
151  */
152 static void usage (void)
153 {
154         fprintf (stderr, _("Usage: %s [-p] [name]\n"), Prog);
155         if (!amroot) {
156                 exit (1);
157         }
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                          /* RLOGIN */
162         exit (1);
163 }
164
165 static void setup_tty (void)
166 {
167         TERMIO termio;
168         int erasechar;
169         int killchar;
170
171         if (GTTY (0, &termio) == 0) {   /* get terminal characteristics */
172
173         /*
174          * Add your favorite terminal modes here ...
175          */
176         termio.c_lflag |= ISIG | ICANON | ECHO | ECHOE;
177         termio.c_iflag |= ICRNL;
178
179 #if defined(ECHOKE) && defined(ECHOCTL)
180         termio.c_lflag |= ECHOKE | ECHOCTL;
181 #endif
182 #if defined(ECHOPRT) && defined(NOFLSH) && defined(TOSTOP)
183         termio.c_lflag &= ~(ECHOPRT | NOFLSH | TOSTOP);
184 #endif
185 #ifdef ONLCR
186         termio.c_oflag |= ONLCR;
187 #endif
188
189         /* leave these values unchanged if not specified in login.defs */
190         erasechar = getdef_num ("ERASECHAR", (int) termio.c_cc[VERASE]);
191         killchar = getdef_num ("KILLCHAR", (int) termio.c_cc[VKILL]);
192         termio.c_cc[VERASE] = (cc_t) erasechar;
193         termio.c_cc[VKILL] = (cc_t) killchar;
194         /* Make sure the values were valid.
195          * getdef_num cannot validate this.
196          */
197         if (erasechar != termio.c_cc[VERASE]) {
198                 fprintf (stderr,
199                          _("configuration error - cannot parse %s value: '%d'"),
200                          "ERASECHAR", erasechar);
201                 exit (1);
202         }
203         if (killchar != termio.c_cc[VKILL]) {
204                 fprintf (stderr,
205                          _("configuration error - cannot parse %s value: '%d'"),
206                          "KILLCHAR", killchar);
207                 exit (1);
208         }
209
210         /*
211          * ttymon invocation prefers this, but these settings won't come into
212          * effect after the first username login 
213          */
214         (void) STTY (0, &termio);
215         }
216 }
217
218
219 #ifndef USE_PAM
220 /*
221  * Tell the user that this is not the right time to login at this tty
222  */
223 static void bad_time_notify (void)
224 {
225         (void) puts (_("Invalid login time"));
226         (void) fflush (stdout);
227 }
228
229 static void check_nologin (bool login_to_root)
230 {
231         char *fname;
232
233         /*
234          * Check to see if system is turned off for non-root users.
235          * This would be useful to prevent users from logging in
236          * during system maintenance. We make sure the message comes
237          * out for root so she knows to remove the file if she's
238          * forgotten about it ...
239          */
240         fname = getdef_str ("NOLOGINS_FILE");
241         if ((NULL != fname) && (access (fname, F_OK) == 0)) {
242                 FILE *nlfp;
243                 int c;
244
245                 /*
246                  * Cat the file if it can be opened, otherwise just
247                  * print a default message
248                  */
249                 nlfp = fopen (fname, "r");
250                 if (NULL != nlfp) {
251                         while ((c = getc (nlfp)) != EOF) {
252                                 if (c == '\n') {
253                                         (void) putchar ('\r');
254                                 }
255
256                                 (void) putchar (c);
257                         }
258                         (void) fflush (stdout);
259                         (void) fclose (nlfp);
260                 } else {
261                         (void) puts (_("\nSystem closed for routine maintenance"));
262                 }
263                 /*
264                  * Non-root users must exit. Root gets the message, but
265                  * gets to login.
266                  */
267
268                 if (!login_to_root) {
269                         closelog ();
270                         exit (0);
271                 }
272                 (void) puts (_("\n[Disconnect bypassed -- root login allowed.]"));
273         }
274 }
275 #endif                          /* !USE_PAM */
276
277 static void process_flags (int argc, char *const *argv)
278 {
279         int arg;
280         int flag;
281
282         /*
283          * Check the flags for proper form. Every argument starting with
284          * "-" must be exactly two characters long. This closes all the
285          * clever rlogin, telnet, and getty holes.
286          */
287         for (arg = 1; arg < argc; arg++) {
288                 if (argv[arg][0] == '-' && strlen (argv[arg]) > 2) {
289                         usage ();
290                 }
291                 if (strcmp(argv[arg], "--") == 0) {
292                         break; /* stop checking on a "--" */
293                 }
294         }
295
296         /*
297          * Process options.
298          */
299         while ((flag = getopt (argc, argv, "d:fh:pr:")) != EOF) {
300                 switch (flag) {
301                 case 'd':
302                         /* "-d device" ignored for compatibility */
303                         break;
304                 case 'f':
305                         fflg = true;
306                         break;
307                 case 'h':
308                         hflg = true;
309                         hostname = optarg;
310                         reason = PW_TELNET;
311                         break;
312 #ifdef  RLOGIN
313                 case 'r':
314                         rflg = true;
315                         hostname = optarg;
316                         reason = PW_RLOGIN;
317                         break;
318 #endif                          /* RLOGIN */
319                 case 'p':
320                         pflg = true;
321                         break;
322                 default:
323                         usage ();
324                 }
325         }
326
327 #ifdef RLOGIN
328         /*
329          * Neither -h nor -f should be combined with -r.
330          */
331
332         if (rflg && (hflg || fflg)) {
333                 usage ();
334         }
335 #endif                          /* RLOGIN */
336
337         /*
338          * Allow authentication bypass only if real UID is zero.
339          */
340
341         if ((rflg || fflg || hflg) && !amroot) {
342                 fprintf (stderr, _("%s: Permission denied.\n"), Prog);
343                 exit (1);
344         }
345
346         /*
347          *  Get the user name.
348          */
349         if (optind < argc) {
350                 username = xstrdup (argv[optind]);
351                 strzero (argv[optind]);
352                 ++optind;
353         }
354
355 #ifdef  RLOGIN
356         if (rflg && (NULL != username)) {
357                 usage ();
358         }
359 #endif                          /* RLOGIN */
360         if (fflg && (NULL == username)) {
361                 usage ();
362         }
363
364 }
365
366
367 static void init_env (void)
368 {
369 #ifndef USE_PAM
370         char *cp;
371 #endif
372         char *tmp;
373
374         tmp = getenv ("LANG");
375         if (NULL != tmp) {
376                 addenv ("LANG", tmp);
377         }
378
379         /*
380          * Add the timezone environmental variable so that time functions
381          * work correctly.
382          */
383         tmp = getenv ("TZ");
384         if (NULL != tmp) {
385                 addenv ("TZ", tmp);
386         }
387 #ifndef USE_PAM
388         else {
389                 cp = getdef_str ("ENV_TZ");
390                 if (NULL != cp) {
391                         addenv (('/' == *cp) ? tz (cp) : cp, NULL);
392                 }
393         }
394 #endif                          /* !USE_PAM */
395         /* 
396          * Add the clock frequency so that profiling commands work
397          * correctly.
398          */
399         tmp = getenv ("HZ");
400         if (NULL != tmp) {
401                 addenv ("HZ", tmp);
402         }
403 #ifndef USE_PAM
404         else {
405                 cp = getdef_str ("ENV_HZ");
406                 if (NULL != cp) {
407                         addenv (cp, NULL);
408                 }
409         }
410 #endif                          /* !USE_PAM */
411 }
412
413
414 static RETSIGTYPE alarm_handler (unused int sig)
415 {
416         fprintf (stderr, _("\nLogin timed out after %u seconds.\n"), timeout);
417         exit (0);
418 }
419
420 #ifdef USE_PAM
421 /*
422  * get_pam_user - Get the username according to PAM
423  *
424  * ptr_pam_user shall point to a malloc'ed string (or NULL).
425  */
426 static void get_pam_user (char **ptr_pam_user)
427 {
428         int retcode;
429         void *ptr_user;
430
431         assert (NULL != ptr_pam_user);
432
433         retcode = pam_get_item (pamh, PAM_USER, (const void **)&ptr_user);
434         PAM_FAIL_CHECK;
435
436         if (NULL != *ptr_pam_user) {
437                 free (*ptr_pam_user);
438         }
439         if (NULL != ptr_user) {
440                 *ptr_pam_user = xstrdup ((const char *)ptr_user);
441         } else {
442                 *ptr_pam_user = NULL;
443         }
444 }
445 #endif
446
447 /*
448  * get_failent_user - Return a string that can be used to log failure
449  *                    from an user.
450  *
451  * This will be either the user argument, or "UNKNOWN".
452  *
453  * It is quite common to mistyped the password for username, and passwords
454  * should not be logged.
455  */
456 static const char *get_failent_user (const char *user)
457 {
458         const char *failent_user = "UNKNOWN";
459         bool log_unkfail_enab = getdef_bool("LOG_UNKFAIL_ENAB");
460
461         if ((NULL != user) && ('\0' != user[0])) {
462                 if (   log_unkfail_enab
463                     || (getpwnam (user) != NULL)) {
464                         failent_user = user;
465                 }
466         }
467
468         return failent_user;
469 }
470
471 /*
472  * update_utmp - Update or create an utmp entry in utmp, wtmp, utmpw, and
473  *               wtmpx
474  *
475  *      utent should be the utmp entry returned by get_current_utmp (or
476  *      NULL).
477  */
478 static void update_utmp (const char *username,
479                          const char *tty,
480                          const char *hostname,
481                          /*@null@*/const struct utmp *utent)
482 {
483         struct utmp  *ut  = prepare_utmp  (username, tty, hostname, utent);
484 #ifdef HAVE_UTMPX_H
485         struct utmpx *utx = prepare_utmpx (username, tty, hostname, utent);
486 #endif                          /* HAVE_UTMPX_H */
487
488         (void) setutmp  (ut);   /* make entry in the utmp & wtmp files */
489         free (ut);
490
491 #ifdef HAVE_UTMPX_H
492         (void) setutmpx (utx);  /* make entry in the utmpx & wtmpx files */
493         free (utx);
494 #endif                          /* HAVE_UTMPX_H */
495 }
496
497 /*
498  * login - create a new login session for a user
499  *
500  *      login is typically called by getty as the second step of a
501  *      new user session. getty is responsible for setting the line
502  *      characteristics to a reasonable set of values and getting
503  *      the name of the user to be logged in. login may also be
504  *      called to create a new user session on a pty for a variety
505  *      of reasons, such as X servers or network logins.
506  *
507  *      the flags which login supports are
508  *      
509  *      -p - preserve the environment
510  *      -r - perform autologin protocol for rlogin
511  *      -f - do not perform authentication, user is preauthenticated
512  *      -h - the name of the remote host
513  */
514 int main (int argc, char **argv)
515 {
516         const char *tmptty;
517         char tty[BUFSIZ];
518
519 #ifdef RLOGIN
520         char term[128] = "";
521 #endif                          /* RLOGIN */
522 #if defined(HAVE_STRFTIME) && !defined(USE_PAM)
523         char ptime[80];
524 #endif
525         unsigned int delay;
526         unsigned int retries;
527         bool failed;
528         bool subroot = false;
529 #ifndef USE_PAM
530         bool is_console;
531 #endif
532         int err;
533         const char *cp;
534         char *tmp;
535         char fromhost[512];
536         struct passwd *pwd = NULL;
537         char **envp = environ;
538         const char *failent_user;
539         struct utmp *utent;
540
541 #ifdef USE_PAM
542         int retcode;
543         pid_t child;
544         char *pam_user = NULL;
545 #else
546         struct spwd *spwd = NULL;
547 #endif
548         /*
549          * Some quick initialization.
550          */
551
552         sanitize_env ();
553
554         (void) setlocale (LC_ALL, "");
555         (void) bindtextdomain (PACKAGE, LOCALEDIR);
556         (void) textdomain (PACKAGE);
557
558         initenv ();
559
560         amroot = (getuid () == 0);
561         Prog = Basename (argv[0]);
562
563         if (geteuid() != 0) {
564                 fprintf (stderr, _("%s: Cannot possibly work without effective root\n"), Prog);
565                 exit (1);
566         }
567
568         process_flags (argc, argv);
569
570         if ((isatty (0) == 0) || (isatty (1) == 0) || (isatty (2) == 0)) {
571                 exit (1);       /* must be a terminal */
572         }
573
574         utent = get_current_utmp ();
575         /*
576          * Be picky if run by normal users (possible if installed setuid
577          * root), but not if run by root. This way it still allows logins
578          * even if your getty is broken, or if something corrupts utmp,
579          * but users must "exec login" which will use the existing utmp
580          * entry (will not overwrite remote hostname).  --marekm
581          */
582         if (!amroot && (NULL == utent)) {
583                 (void) puts (_("No utmp entry.  You must exec \"login\" from the lowest level \"sh\""));
584                 exit (1);
585         }
586         /* NOTE: utent might be NULL afterwards */
587
588         tmptty = ttyname (0);
589         if (NULL == tmptty) {
590                 tmptty = "UNKNOWN";
591         }
592         STRFCPY (tty, tmptty);
593
594 #ifndef USE_PAM
595         is_console = console (tty);
596 #endif
597
598         if (rflg || hflg) {
599                 /*
600                  * Add remote hostname to the environment. I think
601                  * (not sure) I saw it once on Irix.  --marekm
602                  */
603                 addenv ("REMOTEHOST", hostname);
604         }
605         if (fflg) {
606                 preauth_flag = true;
607         }
608         if (hflg) {
609                 reason = PW_RLOGIN;
610         }
611 #ifdef RLOGIN
612         if (rflg) {
613                 username = malloc (32 * sizeof (char));
614                 if (do_rlogin (hostname, username, 32, term, sizeof term)) {
615                         preauth_flag = true;
616                 } else {
617                         free (username);
618                         username = NULL;
619                 }
620         }
621 #endif                          /* RLOGIN */
622
623         OPENLOG ("login");
624
625         setup_tty ();
626
627 #ifndef USE_PAM
628         (void) umask (getdef_num ("UMASK", GETDEF_DEFAULT_UMASK));
629
630         {
631                 /* 
632                  * Use the ULIMIT in the login.defs file, and if
633                  * there isn't one, use the default value. The
634                  * user may have one for themselves, but otherwise,
635                  * just take what you get.
636                  */
637                 long limit = getdef_long ("ULIMIT", -1L);
638
639                 if (limit != -1) {
640                         set_filesize_limit (limit);
641                 }
642         }
643
644 #endif
645         /*
646          * The entire environment will be preserved if the -p flag
647          * is used.
648          */
649         if (pflg) {
650                 while (NULL != *envp) { /* add inherited environment, */
651                         addenv (*envp, NULL); /* some variables change later */
652                         envp++;
653                 }
654         }
655
656 #ifdef RLOGIN
657         if (term[0] != '\0') {
658                 addenv ("TERM", term);
659         } else
660 #endif                          /* RLOGIN */
661         {
662                 /* preserve TERM from getty */
663                 if (!pflg) {
664                         tmp = getenv ("TERM");
665                         if (NULL != tmp) {
666                                 addenv ("TERM", tmp);
667                         }
668                 }
669         }
670
671         init_env ();
672
673         if (optind < argc) {    /* now set command line variables */
674                 set_env (argc - optind, &argv[optind]);
675         }
676
677         if (rflg || hflg) {
678                 cp = hostname;
679 #ifdef  HAVE_STRUCT_UTMP_UT_HOST
680         } else if ((NULL != utent) && ('\0' != utent->ut_host[0])) {
681                 cp = utent->ut_host;
682 #endif                          /* HAVE_STRUCT_UTMP_UT_HOST */
683         } else {
684                 cp = "";
685         }
686
687         if ('\0' != *cp) {
688                 snprintf (fromhost, sizeof fromhost,
689                           " on '%.100s' from '%.200s'", tty, cp);
690         } else {
691                 snprintf (fromhost, sizeof fromhost,
692                           " on '%.100s'", tty);
693         }
694
695       top:
696         /* only allow ALARM sec. for login */
697         (void) signal (SIGALRM, alarm_handler);
698         timeout = getdef_unum ("LOGIN_TIMEOUT", ALARM);
699         if (timeout > 0) {
700                 (void) alarm (timeout);
701         }
702
703         environ = newenvp;      /* make new environment active */
704         delay   = getdef_unum ("FAIL_DELAY", 1);
705         retries = getdef_unum ("LOGIN_RETRIES", RETRIES);
706
707 #ifdef USE_PAM
708         retcode = pam_start ("login", username, &conv, &pamh);
709         if (retcode != PAM_SUCCESS) {
710                 fprintf (stderr,
711                          _("login: PAM Failure, aborting: %s\n"),
712                          pam_strerror (pamh, retcode));
713                 SYSLOG ((LOG_ERR, "Couldn't initialize PAM: %s",
714                          pam_strerror (pamh, retcode)));
715                 exit (99);
716         }
717
718         /*
719          * hostname & tty are either set to NULL or their correct values,
720          * depending on how much we know. We also set PAM's fail delay to
721          * ours.
722          *
723          * PAM_RHOST and PAM_TTY are used for authentication, only use
724          * information coming from login or from the caller (e.g. no utmp)
725          */
726         retcode = pam_set_item (pamh, PAM_RHOST, hostname);
727         PAM_FAIL_CHECK;
728         retcode = pam_set_item (pamh, PAM_TTY, tty);
729         PAM_FAIL_CHECK;
730 #ifdef HAS_PAM_FAIL_DELAY
731         retcode = pam_fail_delay (pamh, 1000000 * delay);
732         PAM_FAIL_CHECK;
733 #endif
734         /* if fflg, then the user has already been authenticated */
735         if (!fflg) {
736                 int failcount = 0;
737                 char hostn[256];
738                 char loginprompt[256];  /* That's one hell of a prompt :) */
739
740                 /* Make the login prompt look like we want it */
741                 if (gethostname (hostn, sizeof (hostn)) == 0) {
742                         snprintf (loginprompt,
743                                   sizeof (loginprompt),
744                                   _("%s login: "), hostn);
745                 } else {
746                         snprintf (loginprompt,
747                                   sizeof (loginprompt), _("login: "));
748                 }
749
750                 retcode = pam_set_item (pamh, PAM_USER_PROMPT, loginprompt);
751                 PAM_FAIL_CHECK;
752
753                 /* if we didn't get a user on the command line,
754                    set it to NULL */
755                 get_pam_user (&pam_user);
756                 if ((NULL != pam_user) && ('\0' == pam_user[0])) {
757                         retcode = pam_set_item (pamh, PAM_USER, NULL);
758                         PAM_FAIL_CHECK;
759                 }
760
761                 /*
762                  * There may be better ways to deal with some of
763                  * these conditions, but at least this way I don't
764                  * think we'll be giving away information. Perhaps
765                  * someday we can trust that all PAM modules will
766                  * pay attention to failure count and get rid of
767                  * MAX_LOGIN_TRIES?
768                  */
769                 failcount = 0;
770                 while (true) {
771                         failed = false;
772
773                         failcount++;
774 #ifdef HAS_PAM_FAIL_DELAY
775                         if (delay > 0) {
776                                 retcode = pam_fail_delay(pamh, 1000000*delay);
777                                 PAM_FAIL_CHECK;
778                         }
779 #endif
780
781                         retcode = pam_authenticate (pamh, 0);
782
783                         get_pam_user (&pam_user);
784                         failent_user = get_failent_user (pam_user);
785
786                         if (retcode == PAM_MAXTRIES) {
787                                 SYSLOG ((LOG_NOTICE,
788                                          "TOO MANY LOGIN TRIES (%d)%s FOR '%s'",
789                                          failcount, fromhost, failent_user));
790                                 fprintf(stderr,
791                                         _("Maximum number of tries exceeded (%d)\n"),
792                                         failcount);
793                                 PAM_END;
794                                 exit(0);
795                         } else if (retcode == PAM_ABORT) {
796                                 /* Serious problems, quit now */
797                                 (void) fputs (_("login: abort requested by PAM\n"), stderr);
798                                 SYSLOG ((LOG_ERR,"PAM_ABORT returned from pam_authenticate()"));
799                                 PAM_END;
800                                 exit(99);
801                         } else if (retcode != PAM_SUCCESS) {
802                                 SYSLOG ((LOG_NOTICE,"FAILED LOGIN (%d)%s FOR '%s', %s",
803                                          failcount, fromhost, failent_user,
804                                          pam_strerror (pamh, retcode)));
805                                 failed = true;
806                         }
807
808                         if (!failed) {
809                                 break;
810                         }
811
812 #ifdef WITH_AUDIT
813                         audit_fd = audit_open ();
814                         audit_log_acct_message (audit_fd,
815                                                 AUDIT_USER_LOGIN,
816                                                 NULL,    /* Prog. name */
817                                                 "login",
818                                                 failent_user,
819                                                 AUDIT_NO_ID,
820                                                 hostname,
821                                                 NULL,    /* addr */
822                                                 tty,
823                                                 0);      /* result */
824                         close (audit_fd);
825 #endif                          /* WITH_AUDIT */
826
827                         fprintf (stderr, "\nLogin incorrect\n");
828
829                         if (failcount >= retries) {
830                                 SYSLOG ((LOG_NOTICE,
831                                          "TOO MANY LOGIN TRIES (%d)%s FOR '%s'",
832                                          failcount, fromhost, failent_user));
833                                 fprintf(stderr,
834                                         _("Maximum number of tries exceeded (%d)\n"),
835                                         failcount);
836                                 PAM_END;
837                                 exit(0);
838                         }
839
840                         /*
841                          * Let's give it another go around.
842                          * Even if a username was given on the command
843                          * line, prompt again for the username.
844                          */
845                         retcode = pam_set_item (pamh, PAM_USER, NULL);
846                         PAM_FAIL_CHECK;
847                 }
848
849                 /* We don't get here unless they were authenticated above */
850                 (void) alarm (0);
851         }
852
853         /* Check the account validity */
854         retcode = pam_acct_mgmt (pamh, 0);
855         if (retcode == PAM_NEW_AUTHTOK_REQD) {
856                 retcode = pam_chauthtok (pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
857         }
858         PAM_FAIL_CHECK;
859
860         /* Open the PAM session */
861         get_pam_user (&pam_user);
862         retcode = pam_open_session (pamh, hushed (pam_user) ? PAM_SILENT : 0);
863         PAM_FAIL_CHECK;
864
865         /* Grab the user information out of the password file for future usage
866          * First get the username that we are actually using, though.
867          *
868          * From now on, we will discard changes of the user (PAM_USER) by
869          * PAM APIs.
870          */
871         get_pam_user (&pam_user);
872         if (NULL != username) {
873                 free (username);
874         }
875         username = pam_user;
876         failent_user = get_failent_user (username);
877
878         pwd = xgetpwnam (username);
879         if (NULL == pwd) {
880                 SYSLOG ((LOG_ERR, "cannot find user %s", failent_user));
881                 exit (1);
882         }
883
884         /* This set up the process credential (group) and initialize the
885          * supplementary group access list.
886          * This has to be done before pam_setcred
887          */
888         if (setup_groups (pwd) != 0) {
889                 exit (1);
890         }
891
892         retcode = pam_setcred (pamh, PAM_ESTABLISH_CRED);
893         PAM_FAIL_CHECK;
894         /* NOTE: If pam_setcred changes PAM_USER, this will not be taken
895          * into account.
896          */
897
898 #else                           /* ! USE_PAM */
899         while (true) {  /* repeatedly get login/password pairs */
900                 /* user_passwd is always a pointer to this constant string
901                  * or a passwd or shadow password that will be memzero by
902                  * pw_free / spw_free.
903                  * Do not free() user_passwd. */
904                 const char *user_passwd = "!";
905
906                 /* Do some cleanup to avoid keeping entries we do not need
907                  * anymore. */
908                 if (NULL != pwd) {
909                         pw_free (pwd);
910                 }
911                 if (NULL != spwd) {
912                         spw_free (spwd);
913                         spwd = NULL;
914                 }
915
916                 failed = false; /* haven't failed authentication yet */
917                 if (NULL == username) { /* need to get a login id */
918                         if (subroot) {
919                                 closelog ();
920                                 exit (1);
921                         }
922                         preauth_flag = false;
923                         username = malloc (32);
924                         login_prompt (_("\n%s login: "), username, 32);
925
926                         if ('\0' == username) {
927                                 /* Prompt for a new login */
928                                 free (username);
929                                 username = NULL;
930                                 continue;
931                         }
932                 }
933                 /* Get the username to be used to log failures */
934                 failent_user = get_failent_user (username);
935
936                 pwd = xgetpwnam (username);
937                 if (NULL == pwd) {
938                         preauth_flag = false;
939                         failed = true;
940                 } else {
941                         user_passwd = pwd->pw_passwd;
942                         /*
943                          * If the encrypted password begins with a "!",
944                          * the account is locked and the user cannot
945                          * login, even if they have been
946                          * "pre-authenticated."
947                          */
948                         if (   ('!' == user_passwd[0])
949                             || ('*' == user_passwd[0])) {
950                                 failed = true;
951                         }
952                 }
953
954                 if (strcmp (user_passwd, SHADOW_PASSWD_STRING) == 0) {
955                         spwd = xgetspnam (username);
956                         if (NULL != spwd) {
957                                 user_passwd = spwd->sp_pwdp;
958                         } else {
959                                 /* The user exists in passwd, but not in
960                                  * shadow. SHADOW_PASSWD_STRING indicates
961                                  * that the password shall be in shadow.
962                                  */
963                                 SYSLOG ((LOG_WARN,
964                                          "no shadow password for '%s'%s",
965                                          username, fromhost));
966                         }
967                 }
968
969                 /*
970                  * The -r and -f flags provide a name which has already
971                  * been authenticated by some server.
972                  */
973                 if (preauth_flag) {
974                         goto auth_ok;
975                 }
976
977                 if (pw_auth (user_passwd, username, reason, (char *) 0) == 0) {
978                         goto auth_ok;
979                 }
980
981                 SYSLOG ((LOG_WARN, "invalid password for '%s' %s",
982                          failent_user, fromhost));
983                 failed = true;
984
985               auth_ok:
986                 /*
987                  * This is the point where all authenticated users wind up.
988                  * If you reach this far, your password has been
989                  * authenticated and so on.
990                  */
991                 if (   !failed
992                     && (NULL != pwd)
993                     && (0 == pwd->pw_uid)
994                     && !is_console) {
995                         SYSLOG ((LOG_CRIT, "ILLEGAL ROOT LOGIN %s", fromhost));
996                         failed = true;
997                 }
998                 if (   !failed
999                     && !login_access (username, *hostname ? hostname : tty)) {
1000                         SYSLOG ((LOG_WARN, "LOGIN '%s' REFUSED %s",
1001                                  username, fromhost));
1002                         failed = true;
1003                 }
1004                 if (   (NULL != pwd)
1005                     && getdef_bool ("FAILLOG_ENAB")
1006                     && !failcheck (pwd->pw_uid, &faillog, failed)) {
1007                         SYSLOG ((LOG_CRIT,
1008                                  "exceeded failure limit for '%s' %s",
1009                                  username, fromhost));
1010                         failed = true;
1011                 }
1012                 if (!failed) {
1013                         break;
1014                 }
1015
1016                 /* don't log non-existent users */
1017                 if ((NULL != pwd) && getdef_bool ("FAILLOG_ENAB")) {
1018                         failure (pwd->pw_uid, tty, &faillog);
1019                 }
1020                 if (getdef_str ("FTMP_FILE") != NULL) {
1021 #ifdef HAVE_UTMPX_H
1022                         struct utmpx *failent =
1023                                 prepare_utmpx (failent_user,
1024                                                tty,
1025                         /* FIXME: or fromhost? */hostname,
1026                                                utent);
1027 #else
1028                         struct utmp *failent =
1029                                 prepare_utmp (failent_user,
1030                                               tty,
1031                                               hostname,
1032                                               utent);
1033 #endif
1034                         failtmp (failent_user, failent);
1035                         free (failent);
1036                 }
1037
1038                 retries--;
1039                 if (retries <= 0) {
1040                         SYSLOG ((LOG_CRIT, "REPEATED login failures%s",
1041                                  fromhost));
1042                 }
1043
1044                 /*
1045                  * If this was a passwordless account and we get here, login
1046                  * was denied (securetty, faillog, etc.). There was no
1047                  * password prompt, so do it now (will always fail - the bad
1048                  * guys won't see that the passwordless account exists at
1049                  * all).  --marekm
1050                  */
1051                 if (user_passwd[0] == '\0') {
1052                         pw_auth ("!", username, reason, (char *) 0);
1053                 }
1054
1055                 /*
1056                  * Authentication of this user failed.
1057                  * The username must be confirmed in the next try.
1058                  */
1059                 free (username);
1060                 username = NULL;
1061
1062                 /*
1063                  * Wait a while (a la SVR4 /usr/bin/login) before attempting
1064                  * to login the user again. If the earlier alarm occurs
1065                  * before the sleep() below completes, login will exit.
1066                  */
1067                 if (delay > 0) {
1068                         (void) sleep (delay);
1069                 }
1070
1071                 (void) puts (_("Login incorrect"));
1072
1073                 /* allow only one attempt with -r or -f */
1074                 if (rflg || fflg || (retries <= 0)) {
1075                         closelog ();
1076                         exit (1);
1077                 }
1078         }                       /* while (true) */
1079 #endif                          /* ! USE_PAM */
1080
1081         (void) alarm (0);               /* turn off alarm clock */
1082
1083 #ifndef USE_PAM                 /* PAM does this */
1084         /*
1085          * porttime checks moved here, after the user has been
1086          * authenticated. now prints a message, as suggested
1087          * by Ivan Nejgebauer <ian@unsux.ns.ac.yu>.  --marekm
1088          */
1089         if (   getdef_bool ("PORTTIME_CHECKS_ENAB")
1090             && !isttytime (username, tty, time ((time_t *) 0))) {
1091                 SYSLOG ((LOG_WARN, "invalid login time for '%s'%s",
1092                          username, fromhost));
1093                 closelog ();
1094                 bad_time_notify ();
1095                 exit (1);
1096         }
1097
1098         check_nologin (pwd->pw_uid == 0);
1099 #endif
1100
1101         if (getenv ("IFS")) {   /* don't export user IFS ... */
1102                 addenv ("IFS= \t\n", NULL);     /* ... instead, set a safe IFS */
1103         }
1104
1105         update_utmp (username, tty, hostname, utent);
1106
1107         if (pwd->pw_shell[0] == '*') {  /* subsystem root */
1108                 pwd->pw_shell++;        /* skip the '*' */
1109                 subsystem (pwd);        /* figure out what to execute */
1110                 subroot = true; /* say I was here again */
1111                 endpwent ();    /* close all of the file which were */
1112                 endgrent ();    /* open in the original rooted file */
1113                 endspent ();    /* system. they will be re-opened */
1114 #ifdef  SHADOWGRP
1115                 endsgent ();    /* in the new rooted file system */
1116 #endif
1117                 goto top;       /* go do all this all over again */
1118         }
1119
1120 #ifdef WITH_AUDIT
1121         audit_fd = audit_open ();
1122         audit_log_acct_message (audit_fd,
1123                                 AUDIT_USER_LOGIN,
1124                                 NULL,    /* Prog. name */
1125                                 "login",
1126                                 username,
1127                                 AUDIT_NO_ID,
1128                                 hostname,
1129                                 NULL,    /* addr */
1130                                 tty,
1131                                 1);      /* result */
1132         close (audit_fd);
1133 #endif                          /* WITH_AUDIT */
1134
1135 #ifndef USE_PAM                 /* pam_lastlog handles this */
1136         if (getdef_bool ("LASTLOG_ENAB")) {     /* give last login and log this one */
1137                 dolastlog (&ll, pwd, tty, hostname);
1138         }
1139 #endif
1140
1141 #ifndef USE_PAM                 /* PAM handles this as well */
1142         /*
1143          * Have to do this while we still have root privileges, otherwise we
1144          * don't have access to /etc/shadow.
1145          */
1146         if (NULL != spwd) {             /* check for age of password */
1147                 if (expire (pwd, spwd)) {
1148                         /* The user updated her password, get the new
1149                          * entries.
1150                          * Use the x variants because we need to keep the
1151                          * entry for a long time, and there might be other
1152                          * getxxyy in between.
1153                          */
1154                         pw_free (pwd);
1155                         pwd = xgetpwnam (username);
1156                         if (NULL == pwd) {
1157                                 SYSLOG ((LOG_ERR,
1158                                          "cannot find user %s after update of expired password",
1159                                          username));
1160                                 exit (1);
1161                         }
1162                         spw_free (spwd);
1163                         spwd = xgetspnam (username);
1164                 }
1165         }
1166         setup_limits (pwd);     /* nice, ulimit etc. */
1167 #endif                          /* ! USE_PAM */
1168         chown_tty (pwd);
1169
1170 #ifdef USE_PAM
1171         /*
1172          * We must fork before setuid() because we need to call
1173          * pam_close_session() as root.
1174          */
1175         (void) signal (SIGINT, SIG_IGN);
1176         child = fork ();
1177         if (child < 0) {
1178                 /* error in fork() */
1179                 fprintf (stderr, _("%s: failure forking: %s"),
1180                          Prog, strerror (errno));
1181                 PAM_END;
1182                 exit (0);
1183         } else if (child != 0) {
1184                 /*
1185                  * parent - wait for child to finish, then cleanup
1186                  * session
1187                  */
1188                 wait (NULL);
1189                 PAM_END;
1190                 exit (0);
1191         }
1192         /* child */
1193 #endif
1194         /* If we were init, we need to start a new session */
1195         if (getppid() == 1) {
1196                 setsid();
1197                 if (ioctl(0, TIOCSCTTY, 1) != 0) {
1198                         fprintf (stderr, _("TIOCSCTTY failed on %s"), tty);
1199                 }
1200         }
1201
1202
1203         /* The pwd and spwd entries for the user have been copied.
1204          *
1205          * Close all the files so that unauthorized access won't occur.
1206          */
1207         endpwent ();            /* stop access to password file */
1208         endgrent ();            /* stop access to group file */
1209         endspent ();            /* stop access to shadow passwd file */
1210 #ifdef  SHADOWGRP
1211         endsgent ();            /* stop access to shadow group file */
1212 #endif
1213
1214         /* Drop root privileges */
1215 #ifndef USE_PAM
1216         if (setup_uid_gid (pwd, is_console))
1217 #else
1218         /* The group privileges were already dropped.
1219          * See setup_groups() above.
1220          */
1221         if (change_uid (pwd))
1222 #endif
1223         {
1224                 exit (1);
1225         }
1226
1227         setup_env (pwd);        /* set env vars, cd to the home dir */
1228
1229 #ifdef USE_PAM
1230         {
1231                 const char *const *env;
1232
1233                 env = (const char *const *) pam_getenvlist (pamh);
1234                 while ((NULL != env) && (NULL != *env)) {
1235                         addenv (*env, NULL);
1236                         env++;
1237                 }
1238         }
1239 #endif
1240
1241         (void) setlocale (LC_ALL, "");
1242         (void) bindtextdomain (PACKAGE, LOCALEDIR);
1243         (void) textdomain (PACKAGE);
1244
1245         if (!hushed (username)) {
1246                 addenv ("HUSHLOGIN=FALSE", NULL);
1247                 /*
1248                  * pam_unix, pam_mail and pam_lastlog should take care of
1249                  * this
1250                  */
1251 #ifndef USE_PAM
1252                 motd ();        /* print the message of the day */
1253                 if (   getdef_bool ("FAILLOG_ENAB")
1254                     && (0 != faillog.fail_cnt)) {
1255                         failprint (&faillog);
1256                         /* Reset the lockout times if logged in */
1257                         if (   (0 != faillog.fail_max)
1258                             && (faillog.fail_cnt >= faillog.fail_max)) {
1259                                 (void) puts (_("Warning: login re-enabled after temporary lockout."));
1260                                 SYSLOG ((LOG_WARN,
1261                                          "login '%s' re-enabled after temporary lockout (%d failures)",
1262                                          username, (int) faillog.fail_cnt));
1263                         }
1264                 }
1265                 if (   getdef_bool ("LASTLOG_ENAB")
1266                     && (ll.ll_time != 0)) {
1267                         time_t ll_time = ll.ll_time;
1268
1269 #ifdef HAVE_STRFTIME
1270                         (void) strftime (ptime, sizeof (ptime),
1271                                          "%a %b %e %H:%M:%S %z %Y",
1272                                          localtime (&ll_time));
1273                         printf (_("Last login: %s on %s"),
1274                                 ptime, ll.ll_line);
1275 #else
1276                         printf (_("Last login: %.19s on %s"),
1277                                 ctime (&ll_time), ll.ll_line);
1278 #endif
1279 #ifdef HAVE_LL_HOST             /* __linux__ || SUN4 */
1280                         if ('\0' != ll.ll_host[0]) {
1281                                 printf (_(" from %.*s"),
1282                                         (int) sizeof ll.ll_host, ll.ll_host);
1283                         }
1284 #endif
1285                         printf (".\n");
1286                 }
1287                 agecheck (spwd);
1288
1289                 mailcheck ();   /* report on the status of mail */
1290 #endif                          /* !USE_PAM */
1291         } else {
1292                 addenv ("HUSHLOGIN=TRUE", NULL);
1293         }
1294
1295         ttytype (tty);
1296
1297         (void) signal (SIGQUIT, SIG_DFL);       /* default quit signal */
1298         (void) signal (SIGTERM, SIG_DFL);       /* default terminate signal */
1299         (void) signal (SIGALRM, SIG_DFL);       /* default alarm signal */
1300         (void) signal (SIGHUP, SIG_DFL);        /* added this.  --marekm */
1301         (void) signal (SIGINT, SIG_DFL);        /* default interrupt signal */
1302
1303         if (0 == pwd->pw_uid) {
1304                 SYSLOG ((LOG_NOTICE, "ROOT LOGIN %s", fromhost));
1305         } else if (getdef_bool ("LOG_OK_LOGINS")) {
1306                 SYSLOG ((LOG_INFO, "'%s' logged in %s", username, fromhost));
1307         }
1308         closelog ();
1309         tmp = getdef_str ("FAKE_SHELL");
1310         if (NULL != tmp) {
1311                 err = shell (tmp, pwd->pw_shell, newenvp); /* fake shell */
1312         } else {
1313                 /* exec the shell finally */
1314                 err = shell (pwd->pw_shell, (char *) 0, newenvp);
1315         }
1316         exit (err == ENOENT ? E_CMD_NOTFOUND : E_CMD_NOEXEC);
1317         /* NOT REACHED */
1318         return 0;
1319 }
1320