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