]> granicus.if.org Git - shadow/blob - src/login.c
[svn-upgrade] Integrating new upstream version, shadow (4.0.12)
[shadow] / src / login.c
1 /*
2  * Copyright 1989 - 1994, Julianne Frances Haugh
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #include <config.h>
31
32 #include "rcsid.h"
33 RCSID (PKG_VER "$Id: login.c,v 1.67 2005/08/11 11:26:11 kloczek Exp $")
34 #include "prototypes.h"
35 #include "defines.h"
36 #include <sys/stat.h>
37 #include <stdio.h>
38 #include <errno.h>
39 #include <pwd.h>
40 #include <grp.h>
41 #include <signal.h>
42 #include <lastlog.h>
43 #include "faillog.h"
44 #include "failure.h"
45 #include "pwauth.h"
46 #include "getdef.h"
47 #ifdef UT_ADDR
48 #include <netdb.h>
49 #endif
50 #ifdef USE_PAM
51 #include "pam_defs.h"
52 static const struct pam_conv conv = {
53         misc_conv,
54         NULL
55 };
56
57 static pam_handle_t *pamh = NULL;
58
59 #define PAM_FAIL_CHECK if (retcode != PAM_SUCCESS) { \
60         fprintf(stderr,"\n%s\n",pam_strerror(pamh, retcode)); \
61         SYSLOG((LOG_ERR,"%s",pam_strerror(pamh, retcode))); \
62         pam_end(pamh, retcode); exit(1); \
63    }
64 #define PAM_END { retcode = pam_close_session(pamh,0); \
65                 pam_end(pamh,retcode); }
66
67 #endif                          /* USE_PAM */
68
69 /*
70  * Needed for MkLinux DR1/2/2.1 - J.
71  */
72 #ifndef LASTLOG_FILE
73 #define LASTLOG_FILE "/var/log/lastlog"
74 #endif
75
76 const char *hostname = "";
77
78 static struct passwd pwent;
79
80 #if HAVE_UTMPX_H
81 extern struct utmpx utxent;
82 struct utmpx failent;
83 #else
84 struct utmp failent;
85 #endif
86 extern struct utmp utent;
87
88 struct lastlog lastlog;
89 static int pflg = 0;
90 static int fflg = 0;
91
92 #ifdef RLOGIN
93 static int rflg = 0;
94 #else
95 #define rflg 0
96 #endif
97 static int hflg = 0;
98 static int preauth_flag = 0;
99
100 /*
101  * Global variables.
102  */
103
104 static char *Prog;
105 static int amroot;
106 static int timeout;
107
108 /*
109  * External identifiers.
110  */
111
112 extern char **newenvp;
113 extern size_t newenvc;
114
115 extern void dolastlog (struct lastlog *, const struct passwd *,
116                        const char *, const char *);
117
118 extern char **environ;
119
120 #ifndef ALARM
121 #define ALARM   60
122 #endif
123
124 #ifndef RETRIES
125 #define RETRIES 3
126 #endif
127
128 /* local function prototypes */
129 static void usage (void);
130 static void setup_tty (void);
131 static void check_flags (int, char *const *);
132
133 #ifndef USE_PAM
134 extern int login_access (const char *, const char *);
135
136 static struct faillog faillog;
137
138 static void bad_time_notify (void);
139 static void check_nologin (void);
140 #endif
141
142 static void init_env (void);
143 static RETSIGTYPE alarm_handler (int);
144
145 /*
146  * usage - print login command usage and exit
147  *
148  * login [ name ]
149  * login -r hostname    (for rlogind)
150  * login -h hostname    (for telnetd, etc.)
151  * login -f name        (for pre-authenticated login: datakit, xterm, etc.)
152  */
153
154 static void usage (void)
155 {
156         fprintf (stderr, _("Usage: %s [-p] [name]\n"), Prog);
157         if (!amroot)
158                 exit (1);
159         fprintf (stderr, _("       %s [-p] [-h host] [-f name]\n"), Prog);
160 #ifdef RLOGIN
161         fprintf (stderr, _("       %s [-p] -r host\n"), Prog);
162 #endif
163         exit (1);
164 }
165
166 static void setup_tty (void)
167 {
168         TERMIO termio;
169
170         GTTY (0, &termio);      /* get terminal characteristics */
171
172         /*
173          * Add your favorite terminal modes here ...
174          */
175
176         termio.c_lflag |= ISIG | ICANON | ECHO | ECHOE;
177         termio.c_iflag |= ICRNL;
178
179         /* leave these values unchanged if not specified in login.defs */
180         termio.c_cc[VERASE] = getdef_num ("ERASECHAR", termio.c_cc[VERASE]);
181         termio.c_cc[VKILL] = getdef_num ("KILLCHAR", termio.c_cc[VKILL]);
182
183         /*
184          * ttymon invocation prefers this, but these settings won't come into
185          * effect after the first username login 
186          */
187
188         STTY (0, &termio);
189 }
190
191
192 #ifndef USE_PAM
193 /*
194  * Tell the user that this is not the right time to login at this tty
195  */
196 static void bad_time_notify (void)
197 {
198         printf (_("Invalid login time\n"));
199         fflush (stdout);
200 }
201
202 static void check_nologin (void)
203 {
204         char *fname;
205
206         /*
207          * Check to see if system is turned off for non-root users.
208          * This would be useful to prevent users from logging in
209          * during system maintenance. We make sure the message comes
210          * out for root so she knows to remove the file if she's
211          * forgotten about it ...
212          */
213
214         fname = getdef_str ("NOLOGINS_FILE");
215         if (fname != NULL && access (fname, F_OK) == 0) {
216                 FILE *nlfp;
217                 int c;
218
219                 /*
220                  * Cat the file if it can be opened, otherwise just
221                  * print a default message
222                  */
223
224                 if ((nlfp = fopen (fname, "r"))) {
225                         while ((c = getc (nlfp)) != EOF) {
226                                 if (c == '\n')
227                                         putchar ('\r');
228
229                                 putchar (c);
230                         }
231                         fflush (stdout);
232                         fclose (nlfp);
233                 } else
234                         printf (_("\nSystem closed for routine maintenance\n"));
235                 /*
236                  * Non-root users must exit. Root gets the message, but
237                  * gets to login.
238                  */
239
240                 if (pwent.pw_uid != 0) {
241                         closelog ();
242                         exit (0);
243                 }
244                 printf (_("\n[Disconnect bypassed -- root login allowed.]\n"));
245         }
246 }
247 #endif                          /* !USE_PAM */
248
249 static void check_flags (int argc, char *const *argv)
250 {
251         int arg;
252
253         /*
254          * Check the flags for proper form. Every argument starting with
255          * "-" must be exactly two characters long. This closes all the
256          * clever rlogin, telnet, and getty holes.
257          */
258         for (arg = 1; arg < argc; arg++) {
259                 if (argv[arg][0] == '-' && strlen (argv[arg]) > 2)
260                         usage ();
261         }
262 }
263
264
265 static void init_env (void)
266 {
267         char *cp, *tmp;
268
269         if ((tmp = getenv ("LANG"))) {
270                 addenv ("LANG", tmp);
271         }
272
273         /*
274          * Add the timezone environmental variable so that time functions
275          * work correctly.
276          */
277
278         if ((tmp = getenv ("TZ"))) {
279                 addenv ("TZ", tmp);
280         } 
281 #ifndef USE_PAM
282                 else if ((cp = getdef_str ("ENV_TZ")))
283                 addenv (*cp == '/' ? tz (cp) : cp, NULL);
284 #endif /* !USE_PAM */
285         /* 
286          * Add the clock frequency so that profiling commands work
287          * correctly.
288          */
289
290         if ((tmp = getenv ("HZ"))) {
291                 addenv ("HZ", tmp);
292         } 
293 #ifndef USE_PAM
294                 else if ((cp = getdef_str ("ENV_HZ")))
295                 addenv (cp, NULL);
296 #endif /* !USE_PAM */
297 }
298
299
300 static RETSIGTYPE alarm_handler (int sig)
301 {
302         fprintf (stderr, _("\nLogin timed out after %d seconds.\n"), timeout);
303         exit (0);
304 }
305
306
307 /*
308  * login - create a new login session for a user
309  *
310  *      login is typically called by getty as the second step of a
311  *      new user session. getty is responsible for setting the line
312  *      characteristics to a reasonable set of values and getting
313  *      the name of the user to be logged in. login may also be
314  *      called to create a new user session on a pty for a variety
315  *      of reasons, such as X servers or network logins.
316  *
317  *      the flags which login supports are
318  *      
319  *      -p - preserve the environment
320  *      -r - perform autologin protocol for rlogin
321  *      -f - do not perform authentication, user is preauthenticated
322  *      -h - the name of the remote host
323  */
324
325 int main (int argc, char **argv)
326 {
327         char username[32];
328         char tty[BUFSIZ];
329
330 #ifdef RLOGIN
331         char term[128] = "";
332 #endif
333 #if defined(HAVE_STRFTIME) && !defined(USE_PAM)
334         char ptime[80];
335 #endif
336         int reason = PW_LOGIN;
337         int delay;
338         int retries;
339         int failed;
340         int flag;
341         int subroot = 0;
342         int is_console;
343         const char *cp;
344         char *tmp;
345         char fromhost[512];
346         struct passwd *pwd;
347         char **envp = environ;
348         static char temp_pw[2];
349         static char temp_shell[] = "/bin/sh";
350
351 #ifdef USE_PAM
352         int retcode;
353         pid_t child;
354         char *pam_user;
355 #else
356         struct spwd *spwd = NULL;
357 #endif
358         /*
359          * Some quick initialization.
360          */
361
362         sanitize_env ();
363
364         setlocale (LC_ALL, "");
365         bindtextdomain (PACKAGE, LOCALEDIR);
366         textdomain (PACKAGE);
367
368         initenv ();
369
370         username[0] = '\0';
371         amroot = (getuid () == 0);
372         Prog = Basename (argv[0]);
373
374         check_flags (argc, argv);
375
376         while ((flag = getopt (argc, argv, "d:f::h:pr:")) != EOF) {
377                 switch (flag) {
378                 case 'd':
379                         /* "-d device" ignored for compatibility */
380                         break;
381                 case 'f':
382                         /*
383                          * username must be a separate token
384                          * (-f root, *not* -froot).  --marekm
385                          *
386                          * if -f has an arg, use that, else use the
387                          * normal user name passed after all options
388                          * --benc
389                          */
390                         if (optarg != NULL && optarg != argv[optind - 1])
391                                 usage ();
392                         fflg++;
393                         if (optarg)
394                                 STRFCPY (username, optarg);
395                         break;
396                 case 'h':
397                         hflg++;
398                         hostname = optarg;
399                         reason = PW_TELNET;
400                         break;
401 #ifdef  RLOGIN
402                 case 'r':
403                         rflg++;
404                         hostname = optarg;
405                         reason = PW_RLOGIN;
406                         break;
407 #endif
408                 case 'p':
409                         pflg++;
410                         break;
411                 default:
412                         usage ();
413                 }
414         }
415
416 #ifdef RLOGIN
417         /*
418          * Neither -h nor -f should be combined with -r.
419          */
420
421         if (rflg && (hflg || fflg))
422                 usage ();
423 #endif
424
425         /*
426          * Allow authentication bypass only if real UID is zero.
427          */
428
429         if ((rflg || fflg || hflg) && !amroot) {
430                 fprintf (stderr, _("%s: Permission denied.\n"), Prog);
431                 exit (1);
432         }
433
434         if (!isatty (0) || !isatty (1) || !isatty (2))
435                 exit (1);       /* must be a terminal */
436
437 #if 0
438         /*
439          * Get the utmp file entry and get the tty name from it. The
440          * current process ID must match the process ID in the utmp
441          * file if there are no additional flags on the command line.
442          */
443         checkutmp (!rflg && !fflg && !hflg);
444 #else
445         /*
446          * Be picky if run by normal users (possible if installed setuid
447          * root), but not if run by root. This way it still allows logins
448          * even if your getty is broken, or if something corrupts utmp,
449          * but users must "exec login" which will use the existing utmp
450          * entry (will not overwrite remote hostname).  --marekm
451          */
452         checkutmp (!amroot);
453 #endif
454         STRFCPY (tty, utent.ut_line);
455         is_console = console (tty);
456
457         if (rflg || hflg) {
458 #ifdef UT_ADDR
459                 struct hostent *he;
460
461                 /*
462                  * Fill in the ut_addr field (remote login IP address). XXX
463                  * - login from util-linux does it, but this is not the
464                  * right place to do it. The program that starts login
465                  * (telnetd, rlogind) knows the IP address, so it should
466                  * create the utmp entry and fill in ut_addr. 
467                  * gethostbyname() is not 100% reliable (the remote host may
468                  * be unknown, etc.).  --marekm
469                  */
470                 if ((he = gethostbyname (hostname))) {
471                         utent.ut_addr = *((int32_t *) (he->h_addr_list[0]));
472 #endif
473 #ifdef UT_HOST
474                         strncpy (utent.ut_host, hostname,
475                                  sizeof (utent.ut_host));
476 #endif
477 #if HAVE_UTMPX_H
478                         strncpy (utxent.ut_host, hostname,
479                                  sizeof (utxent.ut_host));
480 #endif
481                         /*
482                          * Add remote hostname to the environment. I think
483                          * (not sure) I saw it once on Irix.  --marekm
484                          */
485                         addenv ("REMOTEHOST", hostname);
486                 }
487 #ifdef __linux__
488                 /*
489                  * workaround for init/getty leaving junk in ut_host at least in
490                  * some version of RedHat.  --marekm
491                  */
492                 else if (amroot)
493                         memzero (utent.ut_host, sizeof utent.ut_host);
494 #endif
495                 if (fflg)
496                         preauth_flag++;
497                 if (hflg)
498                         reason = PW_RLOGIN;
499 #ifdef RLOGIN
500                 if (rflg
501                     && do_rlogin (hostname, username, sizeof username,
502                                   term, sizeof term))
503                         preauth_flag++;
504 #endif
505
506                 OPENLOG ("login");
507
508                 setup_tty ();
509
510 #ifndef USE_PAM
511                 umask (getdef_num ("UMASK", 077));
512
513                 {
514                         /* 
515                          * Use the ULIMIT in the login.defs file, and if
516                          * there isn't one, use the default value. The
517                          * user may have one for themselves, but otherwise,
518                          * just take what you get.
519                          */
520
521                         long limit = getdef_long ("ULIMIT", -1L);
522
523                         if (limit != -1)
524                                 set_filesize_limit (limit);
525                 }
526
527 #endif
528                 /*
529                  * The entire environment will be preserved if the -p flag
530                  * is used.
531                  */
532
533                 if (pflg)
534                         while (*envp)   /* add inherited environment, */
535                                 addenv (*envp++, NULL); /* some variables change later */
536
537 #ifdef RLOGIN
538                 if (term[0] != '\0')
539                         addenv ("TERM", term);
540                 else
541 #endif
542                         /* preserve TERM from getty */
543                 if (!pflg && (tmp = getenv ("TERM")))
544                         addenv ("TERM", tmp);
545
546                 init_env ();
547
548                 if (optind < argc) {    /* get the user name */
549                         if (rflg || (fflg && username[0]))
550                                 usage ();
551
552                         STRFCPY (username, argv[optind]);
553                         strzero (argv[optind]);
554                         ++optind;
555                 }
556                 if (optind < argc)      /* now set command line variables */
557                         set_env (argc - optind, &argv[optind]);
558
559                 if (rflg || hflg)
560                         cp = hostname;
561                 else
562 #ifdef  UT_HOST
563                 if (utent.ut_host[0])
564                         cp = utent.ut_host;
565                 else
566 #endif
567 #if HAVE_UTMPX_H
568                 if (utxent.ut_host[0])
569                         cp = utxent.ut_host;
570                 else
571 #endif
572                         cp = "";
573
574                 if (*cp)
575                         snprintf (fromhost, sizeof fromhost,
576                                   _(" on `%.100s' from `%.200s'"), tty, cp);
577                 else
578                         snprintf (fromhost, sizeof fromhost,
579                                   _(" on `%.100s'"), tty);
580
581               top:
582                 /* only allow ALARM sec. for login */
583                 signal (SIGALRM, alarm_handler);
584                 timeout = getdef_num ("LOGIN_TIMEOUT", ALARM);
585                 if (timeout > 0)
586                         alarm (timeout);
587
588                 environ = newenvp;      /* make new environment active */
589                 delay = getdef_num ("FAIL_DELAY", 1);
590                 retries = getdef_num ("LOGIN_RETRIES", RETRIES);
591
592 #ifdef USE_PAM
593                 retcode = pam_start ("login", username, &conv, &pamh);
594                 if (retcode != PAM_SUCCESS) {
595                         fprintf (stderr,
596                                  "login: PAM Failure, aborting: %s\n",
597                                  pam_strerror (pamh, retcode));
598                         SYSLOG ((LOG_ERR, "Couldn't initialize PAM: %s",
599                                 pam_strerror (pamh, retcode)));
600                         exit (99);
601                 }
602                 /*
603                  * hostname & tty are either set to NULL or their correct values,
604                  * depending on how much we know. We also set PAM's fail delay to
605                  * ours.
606                  */
607                 retcode = pam_set_item (pamh, PAM_RHOST, hostname);
608                 PAM_FAIL_CHECK;
609                 retcode = pam_set_item (pamh, PAM_TTY, tty);
610                 PAM_FAIL_CHECK;
611 #ifdef HAVE_PAM_FAIL_DELAY
612                 retcode = pam_fail_delay (pamh, 1000000 * delay);
613                 PAM_FAIL_CHECK;
614 #endif
615                 /* if fflg == 1, then the user has already been authenticated */
616                 if (!fflg || (getuid () != 0)) {
617                         int failcount = 0;
618                         char hostn[256];
619                         char login_prompt[256]; /* That's one hell of a prompt :) */
620
621                         /* Make the login prompt look like we want it */
622                         if (!gethostname (hostn, sizeof (hostn)))
623                                 snprintf (login_prompt,
624                                           sizeof (login_prompt),
625                                           "%s login: ", hostn);
626                         else
627                                 snprintf (login_prompt,
628                                           sizeof (login_prompt), "login: ");
629
630                         retcode =
631                             pam_set_item (pamh, PAM_USER_PROMPT, login_prompt);
632                         PAM_FAIL_CHECK;
633
634                         /* if we didn't get a user on the command line,
635                            set it to NULL */
636                         pam_get_item (pamh, PAM_USER,
637                                       (const void **) &pam_user);
638                         if (pam_user[0] == '\0')
639                                 pam_set_item (pamh, PAM_USER, NULL);
640
641                         /*
642                          * There may be better ways to deal with some of
643                          * these conditions, but at least this way I don't
644                          * think we'll be giving away information. Perhaps
645                          * someday we can trust that all PAM modules will
646                          * pay attention to failure count and get rid of
647                          * MAX_LOGIN_TRIES?
648                          */
649
650                         retcode = pam_authenticate (pamh, 0);
651                         while ((failcount++ < retries) &&
652                                ((retcode == PAM_AUTH_ERR) ||
653                                 (retcode == PAM_USER_UNKNOWN) ||
654                                 (retcode == PAM_CRED_INSUFFICIENT) ||
655                                 (retcode == PAM_AUTHINFO_UNAVAIL))) {
656                                 pam_get_item (pamh, PAM_USER,
657                                               (const void **) &pam_user);
658                                 SYSLOG ((LOG_NOTICE,
659                                         "FAILED LOGIN %d FROM %s FOR %s, %s",
660                                         failcount, hostname, pam_user,
661                                         pam_strerror (pamh, retcode)));
662 #ifdef HAVE_PAM_FAIL_DELAY
663                                 pam_fail_delay (pamh, 1000000 * delay);
664 #endif
665                                 fprintf (stderr, "Login incorrect\n\n");
666                                 pam_set_item (pamh, PAM_USER, NULL);
667                                 retcode = pam_authenticate (pamh, 0);
668                         }
669
670                         if (retcode != PAM_SUCCESS) {
671                                 pam_get_item (pamh, PAM_USER,
672                                               (const void **) &pam_user);
673
674                                 if (retcode == PAM_MAXTRIES)
675                                         SYSLOG ((LOG_NOTICE,
676                                                 "TOO MANY LOGIN TRIES (%d) FROM %s FOR %s, %s",
677                                                 failcount, hostname,
678                                                 pam_user,
679                                                 pam_strerror (pamh, retcode)));
680                                 else
681                                         SYSLOG ((LOG_NOTICE,
682                                                 "FAILED LOGIN SESSION FROM %s FOR %s, %s",
683                                                 hostname, pam_user,
684                                                 pam_strerror (pamh, retcode)));
685
686                                 fprintf (stderr, "\nLogin incorrect\n");
687                                 pam_end (pamh, retcode);
688                                 exit (0);
689                         }
690
691                         retcode = pam_acct_mgmt (pamh, 0);
692
693                         if (retcode == PAM_NEW_AUTHTOK_REQD) {
694                                 retcode =
695                                     pam_chauthtok (pamh,
696                                                    PAM_CHANGE_EXPIRED_AUTHTOK);
697                         }
698
699                         PAM_FAIL_CHECK;
700                 }
701
702                 /* Grab the user information out of the password file for future usage
703                    First get the username that we are actually using, though.
704                  */
705                 retcode =
706                     pam_get_item (pamh, PAM_USER, (const void **) &pam_user);
707                 setpwent ();
708                 pwd = getpwnam (pam_user);
709
710                 if (fflg) {
711                         retcode = pam_acct_mgmt (pamh, 0);
712                         PAM_FAIL_CHECK;
713                 }
714
715                 if (!pwd || setup_groups (pwd))
716                         exit (1);
717                 else
718                         pwent = *pwd;
719
720                 retcode = pam_setcred (pamh, PAM_ESTABLISH_CRED);
721                 PAM_FAIL_CHECK;
722
723                 retcode = pam_open_session (pamh,
724                                             hushed (&pwent) ? PAM_SILENT : 0);
725                 PAM_FAIL_CHECK;
726
727 #else                           /* ! USE_PAM */
728                 while (1) {     /* repeatedly get login/password pairs */
729                         failed = 0;     /* haven't failed authentication yet */
730                         if (!username[0]) {     /* need to get a login id */
731                                 if (subroot) {
732                                         closelog ();
733                                         exit (1);
734                                 }
735                                 preauth_flag = 0;
736                                 login_prompt (_("\n%s login: "), username,
737                                               sizeof username);
738                                 continue;
739                         }
740 #endif                          /* ! USE_PAM */
741
742 #ifdef USE_PAM
743                 if (!(pwd = getpwnam (pam_user))) {
744                         pwent.pw_name = pam_user;
745 #else
746                 if (!(pwd = getpwnam (username))) {
747                         pwent.pw_name = username;
748 #endif
749                         strcpy (temp_pw, "!");
750                         pwent.pw_passwd = temp_pw;
751                         pwent.pw_shell = temp_shell;
752
753                         preauth_flag = 0;
754                         failed = 1;
755                 } else {
756                         pwent = *pwd;
757                 }
758 #ifndef USE_PAM
759                 spwd = NULL;
760                 if (pwd && strcmp (pwd->pw_passwd, SHADOW_PASSWD_STRING) == 0) {
761                         spwd = getspnam (username);
762                         if (spwd)
763                                 pwent.pw_passwd = spwd->sp_pwdp;
764                         else
765                                 SYSLOG ((LOG_WARN,
766                                          "no shadow password for `%s'%s",
767                                          username, fromhost));
768                 }
769
770                 /*
771                  * If the encrypted password begins with a "!", the account
772                  * is locked and the user cannot login, even if they have
773                  * been "pre-authenticated."
774                  */
775                 if (pwent.pw_passwd[0] == '!' || pwent.pw_passwd[0] == '*')
776                         failed = 1;
777
778                 /*
779                  * The -r and -f flags provide a name which has already
780                  * been authenticated by some server.
781                  */
782                 if (preauth_flag)
783                         goto auth_ok;
784
785                 if (pw_auth
786                     (pwent.pw_passwd, username, reason, (char *) 0) == 0)
787                         goto auth_ok;
788
789                 /*
790                  * Don't log unknown usernames - I mistyped the password for
791                  * username at least once. Should probably use LOG_AUTHPRIV
792                  * for those who really want to log them.  --marekm
793                  */
794                 SYSLOG ((LOG_WARN, "invalid password for `%s' %s",
795                          (pwd
796                           || getdef_bool ("LOG_UNKFAIL_ENAB")) ?
797                          username : "UNKNOWN", fromhost));
798                 failed = 1;
799
800               auth_ok:
801                 /*
802                  * This is the point where all authenticated users wind up.
803                  * If you reach this far, your password has been
804                  * authenticated and so on.
805                  */
806
807                 if (!failed && pwent.pw_name && pwent.pw_uid == 0
808                     && !is_console) {
809                         SYSLOG ((LOG_CRIT, "ILLEGAL ROOT LOGIN %s", fromhost));
810                         failed = 1;
811                 }
812                 if (!failed
813                     && !login_access (username, *hostname ? hostname : tty)) {
814                         SYSLOG ((LOG_WARN, "LOGIN `%s' REFUSED %s",
815                                  username, fromhost));
816                         failed = 1;
817                 }
818                 if (pwd && getdef_bool ("FAILLOG_ENAB") &&
819                     !failcheck (pwent.pw_uid, &faillog, failed)) {
820                         SYSLOG ((LOG_CRIT,
821                                  "exceeded failure limit for `%s' %s",
822                                  username, fromhost));
823                         failed = 1;
824                 }
825                 if (!failed)
826                         break;
827
828                 /* don't log non-existent users */
829                 if (pwd && getdef_bool ("FAILLOG_ENAB"))
830                         failure (pwent.pw_uid, tty, &faillog);
831                 if (getdef_str ("FTMP_FILE") != NULL) {
832                         const char *failent_user;
833
834 #if HAVE_UTMPX_H
835                         failent = utxent;
836                         if (sizeof (failent.ut_tv) == sizeof (struct timeval))
837                                 gettimeofday ((struct timeval *)
838                                               &failent.ut_tv, NULL);
839                         else {
840                                 struct timeval tv;
841
842                                 gettimeofday (&tv, NULL);
843                                 failent.ut_tv.tv_sec = tv.tv_sec;
844                                 failent.ut_tv.tv_usec = tv.tv_usec;
845                         }
846 #else
847                         failent = utent;
848                         failent.ut_time = time (NULL);
849 #endif
850                         if (pwd) {
851                                 failent_user = pwent.pw_name;
852                         } else {
853                                 if (getdef_bool ("LOG_UNKFAIL_ENAB"))
854                                         failent_user = username;
855                                 else
856                                         failent_user = "UNKNOWN";
857                         }
858                         strncpy (failent.ut_user, failent_user,
859                                  sizeof (failent.ut_user));
860 #ifdef USER_PROCESS
861                         failent.ut_type = USER_PROCESS;
862 #endif
863                         failtmp (&failent);
864                 }
865                 memzero (username, sizeof username);
866
867                 if (--retries <= 0)
868                         SYSLOG ((LOG_CRIT, "REPEATED login failures%s",
869                                  fromhost));
870 #if 1
871                 /*
872                  * If this was a passwordless account and we get here, login
873                  * was denied (securetty, faillog, etc.). There was no
874                  * password prompt, so do it now (will always fail - the bad
875                  * guys won't see that the passwordless account exists at
876                  * all).  --marekm
877                  */
878
879                 if (pwent.pw_passwd[0] == '\0')
880                         pw_auth ("!", username, reason, (char *) 0);
881 #endif
882                 /*
883                  * Wait a while (a la SVR4 /usr/bin/login) before attempting
884                  * to login the user again. If the earlier alarm occurs
885                  * before the sleep() below completes, login will exit.
886                  */
887
888                 if (delay > 0)
889                         sleep (delay);
890
891                 puts (_("Login incorrect"));
892
893                 /* allow only one attempt with -r or -f */
894                 if (rflg || fflg || retries <= 0) {
895                         closelog ();
896                         exit (1);
897                 }
898         }                       /* while (1) */
899 #endif                          /* ! USE_PAM */
900         alarm (0);              /* turn off alarm clock */
901 #ifndef USE_PAM                 /* PAM does this */
902         /*
903          * porttime checks moved here, after the user has been
904          * authenticated. now prints a message, as suggested
905          * by Ivan Nejgebauer <ian@unsux.ns.ac.yu>.  --marekm
906          */
907         if (getdef_bool ("PORTTIME_CHECKS_ENAB") &&
908             !isttytime (pwent.pw_name, tty, time ((time_t *) 0))) {
909                 SYSLOG ((LOG_WARN, "invalid login time for `%s'%s",
910                          username, fromhost));
911                 closelog ();
912                 bad_time_notify ();
913                 exit (1);
914         }
915
916         check_nologin ();
917 #endif
918
919         if (getenv ("IFS"))     /* don't export user IFS ... */
920                 addenv ("IFS= \t\n", NULL);     /* ... instead, set a safe IFS */
921
922 #ifdef USE_PAM
923         setutmp (pam_user, tty, hostname);      /* make entry in utmp & wtmp files */
924 #else
925         setutmp (username, tty, hostname);      /* make entry in utmp & wtmp files */
926 #endif
927         if (pwent.pw_shell[0] == '*') { /* subsystem root */
928                 pwent.pw_shell++;       /* skip the '*' */
929                 subsystem (&pwent);     /* figure out what to execute */
930                 subroot++;      /* say i was here again */
931                 endpwent ();    /* close all of the file which were */
932                 endgrent ();    /* open in the original rooted file */
933                 endspent ();    /* system. they will be re-opened */
934 #ifdef  SHADOWGRP
935                 endsgent ();    /* in the new rooted file system */
936 #endif
937                 goto top;       /* go do all this all over again */
938         }
939 #ifndef USE_PAM                 /* pam_lastlog handles this */
940         if (getdef_bool ("LASTLOG_ENAB"))       /* give last login and log this one */
941                 dolastlog (&lastlog, &pwent, utent.ut_line, hostname);
942 #endif
943
944 #ifndef USE_PAM                 /* PAM handles this as well */
945         /*
946          * Have to do this while we still have root privileges, otherwise we
947          * don't have access to /etc/shadow. expire() closes password files,
948          * and changes to the user in the child before executing the passwd
949          * program.  --marekm
950          */
951         if (spwd) {             /* check for age of password */
952                 if (expire (&pwent, spwd)) {
953                         pwd = getpwnam (username);
954                         spwd = getspnam (username);
955                         if (pwd)
956                                 pwent = *pwd;
957                 }
958         }
959         setup_limits (&pwent);  /* nice, ulimit etc. */
960 #endif                          /* ! USE_PAM */
961         chown_tty (tty, &pwent);
962
963 #ifdef USE_PAM
964         /*
965          * We must fork before setuid() because we need to call
966          * pam_close_session() as root.
967          */
968         signal (SIGINT, SIG_IGN);
969         child = fork ();
970         if (child < 0) {
971                 /* error in fork() */
972                 fprintf (stderr, "login: failure forking: %s",
973                          strerror (errno));
974                 PAM_END;
975                 exit (0);
976         } else if (child) {
977                 /*
978                  * parent - wait for child to finish, then cleanup
979                  * session
980                  */
981                 wait (NULL);
982                 PAM_END;
983                 exit (0);
984         }
985         /* child */
986 #endif
987
988         /* We call set_groups() above because this clobbers pam_groups.so */
989 #ifndef USE_PAM
990         if (setup_uid_gid (&pwent, is_console))
991 #else
992         if (change_uid (&pwent))
993 #endif
994                 exit (1);
995
996         setup_env (&pwent);     /* set env vars, cd to the home dir */
997
998 #ifdef USE_PAM
999         {
1000                 const char *const *env;
1001
1002                 env = (const char *const *) pam_getenvlist (pamh);
1003                 while (env && *env) {
1004                         addenv (*env, NULL);
1005                         env++;
1006                 }
1007         }
1008 #endif
1009
1010         setlocale (LC_ALL, "");
1011         bindtextdomain (PACKAGE, LOCALEDIR);
1012         textdomain (PACKAGE);
1013
1014         if (!hushed (&pwent)) {
1015                 addenv ("HUSHLOGIN=FALSE", NULL);
1016                 /*
1017                  * pam_unix, pam_mail and pam_lastlog should take care of
1018                  * this
1019                  */
1020 #ifndef USE_PAM
1021                 motd ();        /* print the message of the day */
1022                 if (getdef_bool ("FAILLOG_ENAB")
1023                     && faillog.fail_cnt != 0) {
1024                         failprint (&faillog);
1025                         /* Reset the lockout times if logged in */
1026                         if (faillog.fail_max &&
1027                             faillog.fail_cnt >= faillog.fail_max) {
1028                                 puts (_
1029                                       ("Warning: login re-enabled after temporary lockout.\n"));
1030                                 SYSLOG ((LOG_WARN,
1031                                          "login `%s' re-enabled after temporary lockout (%d failures)",
1032                                          username, (int) faillog.fail_cnt));
1033                         }
1034                 }
1035                 if (getdef_bool ("LASTLOG_ENAB")
1036                     && lastlog.ll_time != 0) {
1037                         time_t ll_time = lastlog.ll_time;
1038
1039 #ifdef HAVE_STRFTIME
1040                         strftime (ptime, sizeof (ptime),
1041                                   "%a %b %e %H:%M:%S %z %Y",
1042                                   localtime (&ll_time));
1043                         printf (_("Last login: %s on %s"),
1044                                 ptime, lastlog.ll_line);
1045 #else
1046                         printf (_("Last login: %.19s on %s"),
1047                                 ctime (&ll_time), lastlog.ll_line);
1048 #endif
1049 #ifdef HAVE_LL_HOST             /* __linux__ || SUN4 */
1050                         if (lastlog.ll_host[0])
1051                                 printf (_(" from %.*s"),
1052                                         (int) sizeof lastlog.
1053                                         ll_host, lastlog.ll_host);
1054 #endif
1055                         printf (".\n");
1056                 }
1057                 agecheck (&pwent, spwd);
1058
1059                 mailcheck ();   /* report on the status of mail */
1060 #endif                          /* !USE_PAM */
1061         } else
1062                 addenv ("HUSHLOGIN=TRUE", NULL);
1063
1064         if (getdef_str ("TTYTYPE_FILE") != NULL && getenv ("TERM") == NULL)
1065                 ttytype (tty);
1066
1067         signal (SIGQUIT, SIG_DFL);      /* default quit signal */
1068         signal (SIGTERM, SIG_DFL);      /* default terminate signal */
1069         signal (SIGALRM, SIG_DFL);      /* default alarm signal */
1070         signal (SIGHUP, SIG_DFL);       /* added this.  --marekm */
1071         signal (SIGINT, SIG_DFL);       /* default interrupt signal */
1072
1073         endpwent ();            /* stop access to password file */
1074         endgrent ();            /* stop access to group file */
1075         endspent ();            /* stop access to shadow passwd file */
1076 #ifdef  SHADOWGRP
1077         endsgent ();            /* stop access to shadow group file */
1078 #endif
1079         if (pwent.pw_uid == 0)
1080                 SYSLOG ((LOG_NOTICE, "ROOT LOGIN %s", fromhost));
1081         else if (getdef_bool ("LOG_OK_LOGINS"))
1082 #ifdef USE_PAM
1083                 SYSLOG ((LOG_INFO, "`%s' logged in %s", pam_user, fromhost));
1084 #else
1085                 SYSLOG ((LOG_INFO, "`%s' logged in %s", username, fromhost));
1086 #endif
1087         closelog ();
1088         if ((tmp = getdef_str ("FAKE_SHELL")) != NULL) {
1089                 shell (tmp, pwent.pw_shell);    /* fake shell */
1090         }
1091         shell (pwent.pw_shell, (char *) 0);     /* exec the shell finally. */
1092         /* NOT REACHED */
1093         return 0;
1094 }