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