]> granicus.if.org Git - shadow/blob - src/login.c
* src/login.c: Reuse a string and avoid an untranslated message
[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 /*@null@*/ /*@only@*/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 argc, char *const *argv);
126 static /*@observer@*/const char *get_failent_user (/*@returned@*/const char *user);
127 static void update_utmp (const char *user,
128                          const char *tty,
129                          const char *host,
130                          /*@null@*/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 != (int) 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 != (int) 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
212                  * won't come into 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                 assert (NULL == username);
351                 username = xstrdup (argv[optind]);
352                 strzero (argv[optind]);
353                 ++optind;
354         }
355
356 #ifdef  RLOGIN
357         if (rflg && (NULL != username)) {
358                 usage ();
359         }
360 #endif                          /* RLOGIN */
361         if (fflg && (NULL == username)) {
362                 usage ();
363         }
364
365 }
366
367
368 static void init_env (void)
369 {
370 #ifndef USE_PAM
371         char *cp;
372 #endif
373         char *tmp;
374
375         tmp = getenv ("LANG");
376         if (NULL != tmp) {
377                 addenv ("LANG", tmp);
378         }
379
380         /*
381          * Add the timezone environmental variable so that time functions
382          * work correctly.
383          */
384         tmp = getenv ("TZ");
385         if (NULL != tmp) {
386                 addenv ("TZ", tmp);
387         }
388 #ifndef USE_PAM
389         else {
390                 cp = getdef_str ("ENV_TZ");
391                 if (NULL != cp) {
392                         addenv (('/' == *cp) ? tz (cp) : cp, NULL);
393                 }
394         }
395 #endif                          /* !USE_PAM */
396         /* 
397          * Add the clock frequency so that profiling commands work
398          * correctly.
399          */
400         tmp = getenv ("HZ");
401         if (NULL != tmp) {
402                 addenv ("HZ", tmp);
403         }
404 #ifndef USE_PAM
405         else {
406                 cp = getdef_str ("ENV_HZ");
407                 if (NULL != cp) {
408                         addenv (cp, NULL);
409                 }
410         }
411 #endif                          /* !USE_PAM */
412 }
413
414
415 static RETSIGTYPE alarm_handler (unused int sig)
416 {
417         fprintf (stderr, _("\nLogin timed out after %u seconds.\n"), timeout);
418         exit (0);
419 }
420
421 #ifdef USE_PAM
422 /*
423  * get_pam_user - Get the username according to PAM
424  *
425  * ptr_pam_user shall point to a malloc'ed string (or NULL).
426  */
427 static void get_pam_user (char **ptr_pam_user)
428 {
429         int retcode;
430         void *ptr_user;
431
432         assert (NULL != ptr_pam_user);
433
434         retcode = pam_get_item (pamh, PAM_USER, (const void **)&ptr_user);
435         PAM_FAIL_CHECK;
436
437         if (NULL != *ptr_pam_user) {
438                 free (*ptr_pam_user);
439         }
440         if (NULL != ptr_user) {
441                 *ptr_pam_user = xstrdup ((const char *)ptr_user);
442         } else {
443                 *ptr_pam_user = NULL;
444         }
445 }
446 #endif
447
448 /*
449  * get_failent_user - Return a string that can be used to log failure
450  *                    from an user.
451  *
452  * This will be either the user argument, or "UNKNOWN".
453  *
454  * It is quite common to mistyped the password for username, and passwords
455  * should not be logged.
456  */
457 static /*@observer@*/const char *get_failent_user (/*@returned@*/const char *user)
458 {
459         const char *failent_user = "UNKNOWN";
460         bool log_unkfail_enab = getdef_bool("LOG_UNKFAIL_ENAB");
461
462         if ((NULL != user) && ('\0' != user[0])) {
463                 if (   log_unkfail_enab
464                     || (getpwnam (user) != NULL)) {
465                         failent_user = user;
466                 }
467         }
468
469         return failent_user;
470 }
471
472 /*
473  * update_utmp - Update or create an utmp entry in utmp, wtmp, utmpw, and
474  *               wtmpx
475  *
476  *      utent should be the utmp entry returned by get_current_utmp (or
477  *      NULL).
478  */
479 static void update_utmp (const char *user,
480                          const char *tty,
481                          const char *host,
482                          /*@null@*/const struct utmp *utent)
483 {
484         struct utmp  *ut  = prepare_utmp  (user, tty, host, utent);
485 #ifdef USE_UTMPX
486         struct utmpx *utx = prepare_utmpx (user, tty, host, utent);
487 #endif                          /* USE_UTMPX */
488
489         (void) setutmp  (ut);   /* make entry in the utmp & wtmp files */
490         free (ut);
491
492 #ifdef USE_UTMPX
493         (void) setutmpx (utx);  /* make entry in the utmpx & wtmpx files */
494         free (utx);
495 #endif                          /* USE_UTMPX */
496 }
497
498 /*
499  * login - create a new login session for a user
500  *
501  *      login is typically called by getty as the second step of a
502  *      new user session. getty is responsible for setting the line
503  *      characteristics to a reasonable set of values and getting
504  *      the name of the user to be logged in. login may also be
505  *      called to create a new user session on a pty for a variety
506  *      of reasons, such as X servers or network logins.
507  *
508  *      the flags which login supports are
509  *      
510  *      -p - preserve the environment
511  *      -r - perform autologin protocol for rlogin
512  *      -f - do not perform authentication, user is preauthenticated
513  *      -h - the name of the remote host
514  */
515 int main (int argc, char **argv)
516 {
517         const char *tmptty;
518         char tty[BUFSIZ];
519
520 #ifdef RLOGIN
521         char term[128] = "";
522 #endif                          /* RLOGIN */
523 #if defined(HAVE_STRFTIME) && !defined(USE_PAM)
524         char ptime[80];
525 #endif
526         unsigned int delay;
527         unsigned int retries;
528         bool failed;
529         bool subroot = false;
530 #ifndef USE_PAM
531         bool is_console;
532 #endif
533         int err;
534         const char *cp;
535         char *tmp;
536         char fromhost[512];
537         struct passwd *pwd = NULL;
538         char **envp = environ;
539         const char *failent_user;
540         /*@null@*/struct utmp *utent;
541
542 #ifdef USE_PAM
543         int retcode;
544         pid_t child;
545         char *pam_user = NULL;
546 #else
547         struct spwd *spwd = NULL;
548 #endif
549         /*
550          * Some quick initialization.
551          */
552
553         sanitize_env ();
554
555         (void) setlocale (LC_ALL, "");
556         (void) bindtextdomain (PACKAGE, LOCALEDIR);
557         (void) textdomain (PACKAGE);
558
559         initenv ();
560
561         amroot = (getuid () == 0);
562         Prog = Basename (argv[0]);
563
564         if (geteuid() != 0) {
565                 fprintf (stderr, _("%s: Cannot possibly work without effective root\n"), Prog);
566                 exit (1);
567         }
568
569         process_flags (argc, argv);
570
571         if ((isatty (0) == 0) || (isatty (1) == 0) || (isatty (2) == 0)) {
572                 exit (1);       /* must be a terminal */
573         }
574
575         utent = get_current_utmp ();
576         /*
577          * Be picky if run by normal users (possible if installed setuid
578          * root), but not if run by root. This way it still allows logins
579          * even if your getty is broken, or if something corrupts utmp,
580          * but users must "exec login" which will use the existing utmp
581          * entry (will not overwrite remote hostname).  --marekm
582          */
583         if (!amroot && (NULL == utent)) {
584                 (void) puts (_("No utmp entry.  You must exec \"login\" from the lowest level \"sh\""));
585                 exit (1);
586         }
587         /* NOTE: utent might be NULL afterwards */
588
589         tmptty = ttyname (0);
590         if (NULL == tmptty) {
591                 tmptty = "UNKNOWN";
592         }
593         STRFCPY (tty, tmptty);
594
595 #ifndef USE_PAM
596         is_console = console (tty);
597 #endif
598
599         if (rflg || hflg) {
600                 /*
601                  * Add remote hostname to the environment. I think
602                  * (not sure) I saw it once on Irix.  --marekm
603                  */
604                 addenv ("REMOTEHOST", hostname);
605         }
606         if (fflg) {
607                 preauth_flag = true;
608         }
609         if (hflg) {
610                 reason = PW_RLOGIN;
611         }
612 #ifdef RLOGIN
613         if (rflg) {
614                 assert (NULL == username);
615                 username = xmalloc (USER_NAME_MAX_LENGTH + 1);
616                 username[USER_NAME_MAX_LENGTH] = '\0';
617                 if (do_rlogin (hostname, username, USER_NAME_MAX_LENGTH, term, sizeof term)) {
618                         preauth_flag = true;
619                 } else {
620                         free (username);
621                         username = NULL;
622                 }
623         }
624 #endif                          /* RLOGIN */
625
626         OPENLOG ("login");
627
628         setup_tty ();
629
630 #ifndef USE_PAM
631         (void) umask (getdef_num ("UMASK", GETDEF_DEFAULT_UMASK));
632
633         {
634                 /* 
635                  * Use the ULIMIT in the login.defs file, and if
636                  * there isn't one, use the default value. The
637                  * user may have one for themselves, but otherwise,
638                  * just take what you get.
639                  */
640                 long limit = getdef_long ("ULIMIT", -1L);
641
642                 if (limit != -1) {
643                         set_filesize_limit (limit);
644                 }
645         }
646
647 #endif
648         /*
649          * The entire environment will be preserved if the -p flag
650          * is used.
651          */
652         if (pflg) {
653                 while (NULL != *envp) { /* add inherited environment, */
654                         addenv (*envp, NULL); /* some variables change later */
655                         envp++;
656                 }
657         }
658
659 #ifdef RLOGIN
660         if (term[0] != '\0') {
661                 addenv ("TERM", term);
662         } else
663 #endif                          /* RLOGIN */
664         {
665                 /* preserve TERM from getty */
666                 if (!pflg) {
667                         tmp = getenv ("TERM");
668                         if (NULL != tmp) {
669                                 addenv ("TERM", tmp);
670                         }
671                 }
672         }
673
674         init_env ();
675
676         if (optind < argc) {    /* now set command line variables */
677                 set_env (argc - optind, &argv[optind]);
678         }
679
680         if (rflg || hflg) {
681                 cp = hostname;
682 #ifdef  HAVE_STRUCT_UTMP_UT_HOST
683         } else if ((NULL != utent) && ('\0' != utent->ut_host[0])) {
684                 cp = utent->ut_host;
685 #endif                          /* HAVE_STRUCT_UTMP_UT_HOST */
686         } else {
687                 cp = "";
688         }
689
690         if ('\0' != *cp) {
691                 snprintf (fromhost, sizeof fromhost,
692                           " on '%.100s' from '%.200s'", tty, cp);
693         } else {
694                 snprintf (fromhost, sizeof fromhost,
695                           " on '%.100s'", tty);
696         }
697
698       top:
699         /* only allow ALARM sec. for login */
700         (void) signal (SIGALRM, alarm_handler);
701         timeout = getdef_unum ("LOGIN_TIMEOUT", ALARM);
702         if (timeout > 0) {
703                 (void) alarm (timeout);
704         }
705
706         environ = newenvp;      /* make new environment active */
707         delay   = getdef_unum ("FAIL_DELAY", 1);
708         retries = getdef_unum ("LOGIN_RETRIES", RETRIES);
709
710 #ifdef USE_PAM
711         retcode = pam_start ("login", username, &conv, &pamh);
712         if (retcode != PAM_SUCCESS) {
713                 fprintf (stderr,
714                          _("login: PAM Failure, aborting: %s\n"),
715                          pam_strerror (pamh, retcode));
716                 SYSLOG ((LOG_ERR, "Couldn't initialize PAM: %s",
717                          pam_strerror (pamh, retcode)));
718                 exit (99);
719         }
720
721         /*
722          * hostname & tty are either set to NULL or their correct values,
723          * depending on how much we know. We also set PAM's fail delay to
724          * ours.
725          *
726          * PAM_RHOST and PAM_TTY are used for authentication, only use
727          * information coming from login or from the caller (e.g. no utmp)
728          */
729         retcode = pam_set_item (pamh, PAM_RHOST, hostname);
730         PAM_FAIL_CHECK;
731         retcode = pam_set_item (pamh, PAM_TTY, tty);
732         PAM_FAIL_CHECK;
733 #ifdef HAS_PAM_FAIL_DELAY
734         retcode = pam_fail_delay (pamh, 1000000 * delay);
735         PAM_FAIL_CHECK;
736 #endif
737         /* if fflg, then the user has already been authenticated */
738         if (!fflg) {
739                 int failcount = 0;
740                 char hostn[256];
741                 char loginprompt[256];  /* That's one hell of a prompt :) */
742
743                 /* Make the login prompt look like we want it */
744                 if (gethostname (hostn, sizeof (hostn)) == 0) {
745                         snprintf (loginprompt,
746                                   sizeof (loginprompt),
747                                   _("%s login: "), hostn);
748                 } else {
749                         snprintf (loginprompt,
750                                   sizeof (loginprompt), _("login: "));
751                 }
752
753                 retcode = pam_set_item (pamh, PAM_USER_PROMPT, loginprompt);
754                 PAM_FAIL_CHECK;
755
756                 /* if we didn't get a user on the command line,
757                    set it to NULL */
758                 get_pam_user (&pam_user);
759                 if ((NULL != pam_user) && ('\0' == pam_user[0])) {
760                         retcode = pam_set_item (pamh, PAM_USER, NULL);
761                         PAM_FAIL_CHECK;
762                 }
763
764                 /*
765                  * There may be better ways to deal with some of
766                  * these conditions, but at least this way I don't
767                  * think we'll be giving away information. Perhaps
768                  * someday we can trust that all PAM modules will
769                  * pay attention to failure count and get rid of
770                  * MAX_LOGIN_TRIES?
771                  */
772                 failcount = 0;
773                 while (true) {
774                         failed = false;
775
776                         failcount++;
777 #ifdef HAS_PAM_FAIL_DELAY
778                         if (delay > 0) {
779                                 retcode = pam_fail_delay(pamh, 1000000*delay);
780                                 PAM_FAIL_CHECK;
781                         }
782 #endif
783
784                         retcode = pam_authenticate (pamh, 0);
785
786                         get_pam_user (&pam_user);
787                         failent_user = get_failent_user (pam_user);
788
789                         if (retcode == PAM_MAXTRIES) {
790                                 SYSLOG ((LOG_NOTICE,
791                                          "TOO MANY LOGIN TRIES (%d)%s FOR '%s'",
792                                          failcount, fromhost, failent_user));
793                                 fprintf(stderr,
794                                         _("Maximum number of tries exceeded (%d)\n"),
795                                         failcount);
796                                 PAM_END;
797                                 exit(0);
798                         } else if (retcode == PAM_ABORT) {
799                                 /* Serious problems, quit now */
800                                 (void) fputs (_("login: abort requested by PAM\n"), stderr);
801                                 SYSLOG ((LOG_ERR,"PAM_ABORT returned from pam_authenticate()"));
802                                 PAM_END;
803                                 exit(99);
804                         } else if (retcode != PAM_SUCCESS) {
805                                 SYSLOG ((LOG_NOTICE,"FAILED LOGIN (%d)%s FOR '%s', %s",
806                                          failcount, fromhost, failent_user,
807                                          pam_strerror (pamh, retcode)));
808                                 failed = true;
809                         }
810
811                         if (!failed) {
812                                 break;
813                         }
814
815 #ifdef WITH_AUDIT
816                         audit_fd = audit_open ();
817                         audit_log_acct_message (audit_fd,
818                                                 AUDIT_USER_LOGIN,
819                                                 NULL,    /* Prog. name */
820                                                 "login",
821                                                 failent_user,
822                                                 AUDIT_NO_ID,
823                                                 hostname,
824                                                 NULL,    /* addr */
825                                                 tty,
826                                                 0);      /* result */
827                         close (audit_fd);
828 #endif                          /* WITH_AUDIT */
829
830                         (void) puts ("");
831                         (void) puts (_("Login incorrect"));
832
833                         if (failcount >= retries) {
834                                 SYSLOG ((LOG_NOTICE,
835                                          "TOO MANY LOGIN TRIES (%d)%s FOR '%s'",
836                                          failcount, fromhost, failent_user));
837                                 fprintf(stderr,
838                                         _("Maximum number of tries exceeded (%d)\n"),
839                                         failcount);
840                                 PAM_END;
841                                 exit(0);
842                         }
843
844                         /*
845                          * Let's give it another go around.
846                          * Even if a username was given on the command
847                          * line, prompt again for the username.
848                          */
849                         retcode = pam_set_item (pamh, PAM_USER, NULL);
850                         PAM_FAIL_CHECK;
851                 }
852
853                 /* We don't get here unless they were authenticated above */
854                 (void) alarm (0);
855         }
856
857         /* Check the account validity */
858         retcode = pam_acct_mgmt (pamh, 0);
859         if (retcode == PAM_NEW_AUTHTOK_REQD) {
860                 retcode = pam_chauthtok (pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
861         }
862         PAM_FAIL_CHECK;
863
864         /* Open the PAM session */
865         get_pam_user (&pam_user);
866         retcode = pam_open_session (pamh, hushed (pam_user) ? PAM_SILENT : 0);
867         PAM_FAIL_CHECK;
868
869         /* Grab the user information out of the password file for future usage
870          * First get the username that we are actually using, though.
871          *
872          * From now on, we will discard changes of the user (PAM_USER) by
873          * PAM APIs.
874          */
875         get_pam_user (&pam_user);
876         if (NULL != username) {
877                 free (username);
878         }
879         username = pam_user;
880         failent_user = get_failent_user (username);
881
882         pwd = xgetpwnam (username);
883         if (NULL == pwd) {
884                 SYSLOG ((LOG_ERR, "cannot find user %s", failent_user));
885                 exit (1);
886         }
887
888         /* This set up the process credential (group) and initialize the
889          * supplementary group access list.
890          * This has to be done before pam_setcred
891          */
892         if (setup_groups (pwd) != 0) {
893                 exit (1);
894         }
895
896         retcode = pam_setcred (pamh, PAM_ESTABLISH_CRED);
897         PAM_FAIL_CHECK;
898         /* NOTE: If pam_setcred changes PAM_USER, this will not be taken
899          * into account.
900          */
901
902 #else                           /* ! USE_PAM */
903         while (true) {  /* repeatedly get login/password pairs */
904                 /* user_passwd is always a pointer to this constant string
905                  * or a passwd or shadow password that will be memzero by
906                  * pw_free / spw_free.
907                  * Do not free() user_passwd. */
908                 const char *user_passwd = "!";
909
910                 /* Do some cleanup to avoid keeping entries we do not need
911                  * anymore. */
912                 if (NULL != pwd) {
913                         pw_free (pwd);
914                 }
915                 if (NULL != spwd) {
916                         spw_free (spwd);
917                         spwd = NULL;
918                 }
919
920                 failed = false; /* haven't failed authentication yet */
921                 if (NULL == username) { /* need to get a login id */
922                         if (subroot) {
923                                 closelog ();
924                                 exit (1);
925                         }
926                         preauth_flag = false;
927                         username = xmalloc (USER_NAME_MAX_LENGTH + 1);
928                         username[USER_NAME_MAX_LENGTH] = '\0';
929                         login_prompt (_("\n%s login: "), username, USER_NAME_MAX_LENGTH);
930
931                         if ('\0' == username[0]) {
932                                 /* Prompt for a new login */
933                                 free (username);
934                                 username = NULL;
935                                 continue;
936                         }
937                 }
938                 /* Get the username to be used to log failures */
939                 failent_user = get_failent_user (username);
940
941                 pwd = xgetpwnam (username);
942                 if (NULL == pwd) {
943                         preauth_flag = false;
944                         failed = true;
945                 } else {
946                         user_passwd = pwd->pw_passwd;
947                         /*
948                          * If the encrypted password begins with a "!",
949                          * the account is locked and the user cannot
950                          * login, even if they have been
951                          * "pre-authenticated."
952                          */
953                         if (   ('!' == user_passwd[0])
954                             || ('*' == user_passwd[0])) {
955                                 failed = true;
956                         }
957                 }
958
959                 if (strcmp (user_passwd, SHADOW_PASSWD_STRING) == 0) {
960                         spwd = xgetspnam (username);
961                         if (NULL != spwd) {
962                                 user_passwd = spwd->sp_pwdp;
963                         } else {
964                                 /* The user exists in passwd, but not in
965                                  * shadow. SHADOW_PASSWD_STRING indicates
966                                  * that the password shall be in shadow.
967                                  */
968                                 SYSLOG ((LOG_WARN,
969                                          "no shadow password for '%s'%s",
970                                          username, fromhost));
971                         }
972                 }
973
974                 /*
975                  * The -r and -f flags provide a name which has already
976                  * been authenticated by some server.
977                  */
978                 if (preauth_flag) {
979                         goto auth_ok;
980                 }
981
982                 if (pw_auth (user_passwd, username, reason, (char *) 0) == 0) {
983                         goto auth_ok;
984                 }
985
986                 SYSLOG ((LOG_WARN, "invalid password for '%s' %s",
987                          failent_user, fromhost));
988                 failed = true;
989
990               auth_ok:
991                 /*
992                  * This is the point where all authenticated users wind up.
993                  * If you reach this far, your password has been
994                  * authenticated and so on.
995                  */
996                 if (   !failed
997                     && (NULL != pwd)
998                     && (0 == pwd->pw_uid)
999                     && !is_console) {
1000                         SYSLOG ((LOG_CRIT, "ILLEGAL ROOT LOGIN %s", fromhost));
1001                         failed = true;
1002                 }
1003                 if (   !failed
1004                     && !login_access (username, ('\0' != *hostname) ? hostname : tty)) {
1005                         SYSLOG ((LOG_WARN, "LOGIN '%s' REFUSED %s",
1006                                  username, fromhost));
1007                         failed = true;
1008                 }
1009                 if (   (NULL != pwd)
1010                     && getdef_bool ("FAILLOG_ENAB")
1011                     && !failcheck (pwd->pw_uid, &faillog, failed)) {
1012                         SYSLOG ((LOG_CRIT,
1013                                  "exceeded failure limit for '%s' %s",
1014                                  username, fromhost));
1015                         failed = true;
1016                 }
1017                 if (!failed) {
1018                         break;
1019                 }
1020
1021                 /* don't log non-existent users */
1022                 if ((NULL != pwd) && getdef_bool ("FAILLOG_ENAB")) {
1023                         failure (pwd->pw_uid, tty, &faillog);
1024                 }
1025                 if (getdef_str ("FTMP_FILE") != NULL) {
1026 #ifdef USE_UTMPX
1027                         struct utmpx *failent =
1028                                 prepare_utmpx (failent_user,
1029                                                tty,
1030                         /* FIXME: or fromhost? */hostname,
1031                                                utent);
1032 #else                           /* !USE_UTMPX */
1033                         struct utmp *failent =
1034                                 prepare_utmp (failent_user,
1035                                               tty,
1036                                               hostname,
1037                                               utent);
1038 #endif                          /* !USE_UTMPX */
1039                         failtmp (failent_user, failent);
1040                         free (failent);
1041                 }
1042
1043                 retries--;
1044                 if (retries <= 0) {
1045                         SYSLOG ((LOG_CRIT, "REPEATED login failures%s",
1046                                  fromhost));
1047                 }
1048
1049                 /*
1050                  * If this was a passwordless account and we get here, login
1051                  * was denied (securetty, faillog, etc.). There was no
1052                  * password prompt, so do it now (will always fail - the bad
1053                  * guys won't see that the passwordless account exists at
1054                  * all).  --marekm
1055                  */
1056                 if (user_passwd[0] == '\0') {
1057                         pw_auth ("!", username, reason, (char *) 0);
1058                 }
1059
1060                 /*
1061                  * Authentication of this user failed.
1062                  * The username must be confirmed in the next try.
1063                  */
1064                 free (username);
1065                 username = NULL;
1066
1067                 /*
1068                  * Wait a while (a la SVR4 /usr/bin/login) before attempting
1069                  * to login the user again. If the earlier alarm occurs
1070                  * before the sleep() below completes, login will exit.
1071                  */
1072                 if (delay > 0) {
1073                         (void) sleep (delay);
1074                 }
1075
1076                 (void) puts (_("Login incorrect"));
1077
1078                 /* allow only one attempt with -r or -f */
1079                 if (rflg || fflg || (retries <= 0)) {
1080                         closelog ();
1081                         exit (1);
1082                 }
1083         }                       /* while (true) */
1084 #endif                          /* ! USE_PAM */
1085         assert (NULL != username);
1086         assert (NULL != pwd);
1087
1088         (void) alarm (0);               /* turn off alarm clock */
1089
1090 #ifndef USE_PAM                 /* PAM does this */
1091         /*
1092          * porttime checks moved here, after the user has been
1093          * authenticated. now prints a message, as suggested
1094          * by Ivan Nejgebauer <ian@unsux.ns.ac.yu>.  --marekm
1095          */
1096         if (   getdef_bool ("PORTTIME_CHECKS_ENAB")
1097             && !isttytime (username, tty, time ((time_t *) 0))) {
1098                 SYSLOG ((LOG_WARN, "invalid login time for '%s'%s",
1099                          username, fromhost));
1100                 closelog ();
1101                 bad_time_notify ();
1102                 exit (1);
1103         }
1104
1105         check_nologin (pwd->pw_uid == 0);
1106 #endif
1107
1108         if (getenv ("IFS")) {   /* don't export user IFS ... */
1109                 addenv ("IFS= \t\n", NULL);     /* ... instead, set a safe IFS */
1110         }
1111
1112         update_utmp (username, tty, hostname, utent);
1113
1114         if (pwd->pw_shell[0] == '*') {  /* subsystem root */
1115                 pwd->pw_shell++;        /* skip the '*' */
1116                 subsystem (pwd);        /* figure out what to execute */
1117                 subroot = true; /* say I was here again */
1118                 endpwent ();    /* close all of the file which were */
1119                 endgrent ();    /* open in the original rooted file */
1120                 endspent ();    /* system. they will be re-opened */
1121 #ifdef  SHADOWGRP
1122                 endsgent ();    /* in the new rooted file system */
1123 #endif
1124                 goto top;       /* go do all this all over again */
1125         }
1126
1127 #ifdef WITH_AUDIT
1128         audit_fd = audit_open ();
1129         audit_log_acct_message (audit_fd,
1130                                 AUDIT_USER_LOGIN,
1131                                 NULL,    /* Prog. name */
1132                                 "login",
1133                                 username,
1134                                 AUDIT_NO_ID,
1135                                 hostname,
1136                                 NULL,    /* addr */
1137                                 tty,
1138                                 1);      /* result */
1139         close (audit_fd);
1140 #endif                          /* WITH_AUDIT */
1141
1142 #ifndef USE_PAM                 /* pam_lastlog handles this */
1143         if (getdef_bool ("LASTLOG_ENAB")) {     /* give last login and log this one */
1144                 dolastlog (&ll, pwd, tty, hostname);
1145         }
1146 #endif
1147
1148 #ifndef USE_PAM                 /* PAM handles this as well */
1149         /*
1150          * Have to do this while we still have root privileges, otherwise we
1151          * don't have access to /etc/shadow.
1152          */
1153         if (NULL != spwd) {             /* check for age of password */
1154                 if (expire (pwd, spwd)) {
1155                         /* The user updated her password, get the new
1156                          * entries.
1157                          * Use the x variants because we need to keep the
1158                          * entry for a long time, and there might be other
1159                          * getxxyy in between.
1160                          */
1161                         pw_free (pwd);
1162                         pwd = xgetpwnam (username);
1163                         if (NULL == pwd) {
1164                                 SYSLOG ((LOG_ERR,
1165                                          "cannot find user %s after update of expired password",
1166                                          username));
1167                                 exit (1);
1168                         }
1169                         spw_free (spwd);
1170                         spwd = xgetspnam (username);
1171                 }
1172         }
1173         setup_limits (pwd);     /* nice, ulimit etc. */
1174 #endif                          /* ! USE_PAM */
1175         chown_tty (pwd);
1176
1177 #ifdef USE_PAM
1178         /*
1179          * We must fork before setuid() because we need to call
1180          * pam_close_session() as root.
1181          */
1182         (void) signal (SIGINT, SIG_IGN);
1183         child = fork ();
1184         if (child < 0) {
1185                 /* error in fork() */
1186                 fprintf (stderr, _("%s: failure forking: %s"),
1187                          Prog, strerror (errno));
1188                 PAM_END;
1189                 exit (0);
1190         } else if (child != 0) {
1191                 /*
1192                  * parent - wait for child to finish, then cleanup
1193                  * session
1194                  */
1195                 wait (NULL);
1196                 PAM_END;
1197                 exit (0);
1198         }
1199         /* child */
1200 #endif
1201         /* If we were init, we need to start a new session */
1202         if (getppid() == 1) {
1203                 setsid();
1204                 if (ioctl(0, TIOCSCTTY, 1) != 0) {
1205                         fprintf (stderr, _("TIOCSCTTY failed on %s"), tty);
1206                 }
1207         }
1208
1209
1210         /* The pwd and spwd entries for the user have been copied.
1211          *
1212          * Close all the files so that unauthorized access won't occur.
1213          */
1214         endpwent ();            /* stop access to password file */
1215         endgrent ();            /* stop access to group file */
1216         endspent ();            /* stop access to shadow passwd file */
1217 #ifdef  SHADOWGRP
1218         endsgent ();            /* stop access to shadow group file */
1219 #endif
1220
1221         /* Drop root privileges */
1222 #ifndef USE_PAM
1223         if (setup_uid_gid (pwd, is_console))
1224 #else
1225         /* The group privileges were already dropped.
1226          * See setup_groups() above.
1227          */
1228         if (change_uid (pwd))
1229 #endif
1230         {
1231                 exit (1);
1232         }
1233
1234         setup_env (pwd);        /* set env vars, cd to the home dir */
1235
1236 #ifdef USE_PAM
1237         {
1238                 const char *const *env;
1239
1240                 env = (const char *const *) pam_getenvlist (pamh);
1241                 while ((NULL != env) && (NULL != *env)) {
1242                         addenv (*env, NULL);
1243                         env++;
1244                 }
1245         }
1246 #endif
1247
1248         (void) setlocale (LC_ALL, "");
1249         (void) bindtextdomain (PACKAGE, LOCALEDIR);
1250         (void) textdomain (PACKAGE);
1251
1252         if (!hushed (username)) {
1253                 addenv ("HUSHLOGIN=FALSE", NULL);
1254                 /*
1255                  * pam_unix, pam_mail and pam_lastlog should take care of
1256                  * this
1257                  */
1258 #ifndef USE_PAM
1259                 motd ();        /* print the message of the day */
1260                 if (   getdef_bool ("FAILLOG_ENAB")
1261                     && (0 != faillog.fail_cnt)) {
1262                         failprint (&faillog);
1263                         /* Reset the lockout times if logged in */
1264                         if (   (0 != faillog.fail_max)
1265                             && (faillog.fail_cnt >= faillog.fail_max)) {
1266                                 (void) puts (_("Warning: login re-enabled after temporary lockout."));
1267                                 SYSLOG ((LOG_WARN,
1268                                          "login '%s' re-enabled after temporary lockout (%d failures)",
1269                                          username, (int) faillog.fail_cnt));
1270                         }
1271                 }
1272                 if (   getdef_bool ("LASTLOG_ENAB")
1273                     && (ll.ll_time != 0)) {
1274                         time_t ll_time = ll.ll_time;
1275
1276 #ifdef HAVE_STRFTIME
1277                         (void) strftime (ptime, sizeof (ptime),
1278                                          "%a %b %e %H:%M:%S %z %Y",
1279                                          localtime (&ll_time));
1280                         printf (_("Last login: %s on %s"),
1281                                 ptime, ll.ll_line);
1282 #else
1283                         printf (_("Last login: %.19s on %s"),
1284                                 ctime (&ll_time), ll.ll_line);
1285 #endif
1286 #ifdef HAVE_LL_HOST             /* __linux__ || SUN4 */
1287                         if ('\0' != ll.ll_host[0]) {
1288                                 printf (_(" from %.*s"),
1289                                         (int) sizeof ll.ll_host, ll.ll_host);
1290                         }
1291 #endif
1292                         printf (".\n");
1293                 }
1294                 agecheck (spwd);
1295
1296                 mailcheck ();   /* report on the status of mail */
1297 #endif                          /* !USE_PAM */
1298         } else {
1299                 addenv ("HUSHLOGIN=TRUE", NULL);
1300         }
1301
1302         ttytype (tty);
1303
1304         (void) signal (SIGQUIT, SIG_DFL);       /* default quit signal */
1305         (void) signal (SIGTERM, SIG_DFL);       /* default terminate signal */
1306         (void) signal (SIGALRM, SIG_DFL);       /* default alarm signal */
1307         (void) signal (SIGHUP, SIG_DFL);        /* added this.  --marekm */
1308         (void) signal (SIGINT, SIG_DFL);        /* default interrupt signal */
1309
1310         if (0 == pwd->pw_uid) {
1311                 SYSLOG ((LOG_NOTICE, "ROOT LOGIN %s", fromhost));
1312         } else if (getdef_bool ("LOG_OK_LOGINS")) {
1313                 SYSLOG ((LOG_INFO, "'%s' logged in %s", username, fromhost));
1314         }
1315         closelog ();
1316         tmp = getdef_str ("FAKE_SHELL");
1317         if (NULL != tmp) {
1318                 err = shell (tmp, pwd->pw_shell, newenvp); /* fake shell */
1319         } else {
1320                 /* exec the shell finally */
1321                 err = shell (pwd->pw_shell, (char *) 0, newenvp);
1322         }
1323         exit (err == ENOENT ? E_CMD_NOTFOUND : E_CMD_NOEXEC);
1324         /* NOT REACHED */
1325         return 0;
1326 }
1327