Initial import from FreeBSD RELENG_4:
[games.git] / crypto / kerberosIV / appl / bsd / login.c
1 /*-
2  * Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994
3  *      The Regents of the University of California.  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. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 /*
35  * login [ name ]
36  * login -h hostname    (for telnetd, etc.)
37  * login -f name        (for pre-authenticated login: datakit, xterm, etc.)
38  */
39
40 #include "bsd_locl.h"
41 #ifdef HAVE_CAPABILITY_H
42 #include <capability.h>
43 #endif
44 #ifdef HAVE_SYS_CAPABILITY_H
45 #include <sys/capability.h>
46 #endif
47
48 RCSID("$Id: login.c,v 1.125.2.2 2000/06/23 02:33:07 assar Exp $");
49
50 #ifdef OTP
51 #include <otp.h>
52 #endif
53
54 #include "sysv_default.h"
55 #ifdef SYSV_SHADOW
56 #include "sysv_shadow.h"
57 #endif
58
59 static  void     badlogin (char *);
60 static  void     checknologin (void);
61 static  void     dolastlog (int);
62 static  void     getloginname (int);
63 static  int      rootterm (char *);
64 static  char    *stypeof (char *);
65 static  RETSIGTYPE       timedout (int);
66 static  int      doremotelogin (char *);
67 void    login_fbtab (char *, uid_t, gid_t);
68 #ifdef KERBEROS
69 int     klogin (struct passwd *, char *, char *, char *);
70 #endif
71
72 #define TTYGRPNAME      "tty"           /* name of group to own ttys */
73
74 /*
75  * This bounds the time given to login.  Change it in
76  * `/etc/default/login'.
77  */
78
79 static  u_int   login_timeout;
80
81 #ifdef KERBEROS
82 int     notickets = 1;
83 int     noticketsdontcomplain = 1;
84 char    *instance;
85 char    *krbtkfile_env;
86 int     authok;
87 #endif
88
89 #ifdef HAVE_SHADOW_H
90 static  struct spwd *spwd = NULL;
91 #endif
92
93 static  char    *ttyprompt;
94
95 static  struct  passwd *pwd;
96 static  int     failures;
97 static  char    term[64], *hostname, *username, *tty;
98
99 static  char rusername[100], lusername[100];
100
101 static int
102 change_passwd(struct passwd  *who)
103 {
104     int status;
105     pid_t pid;
106  
107     switch (pid = fork()) {
108     case -1:
109         warn("fork /bin/passwd");
110         sleepexit(1);
111     case 0:
112         execlp("/bin/passwd", "passwd", who->pw_name, (char *) 0);
113         _exit(1);
114     default:
115         waitpid(pid, &status, 0);
116         return (status);
117     }
118 }
119
120 #ifndef NO_MOTD /* message of the day stuff */
121
122 jmp_buf motdinterrupt;
123
124 static RETSIGTYPE
125 sigint(int signo)
126 {
127         longjmp(motdinterrupt, 1);
128 }
129
130 static void
131 motd(void)
132 {
133         int fd, nchars;
134         RETSIGTYPE (*oldint)();
135         char tbuf[8192];
136
137         if ((fd = open(_PATH_MOTDFILE, O_RDONLY, 0)) < 0)
138                 return;
139         oldint = signal(SIGINT, sigint);
140         if (setjmp(motdinterrupt) == 0)
141                 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
142                         write(fileno(stdout), tbuf, nchars);
143         signal(SIGINT, oldint);
144         close(fd);
145 }
146
147 #endif /* !NO_MOTD */
148
149 #define AUTH_NONE 0
150 #define AUTH_OTP  1
151
152 /*
153  * getpwnam and try to detect the worst form of NIS attack.
154  */
155
156 static struct passwd *
157 paranoid_getpwnam (char *user)
158 {
159         struct passwd *p;
160
161         p = k_getpwnam (user);
162         if (p == NULL)
163                 return p;
164         if (p->pw_uid == 0 && strcmp (username, "root") != 0) {
165                 syslog (LOG_ALERT,
166                         "NIS attack, user %s has uid 0", username);
167                 return NULL;
168         }
169         return p;
170 }
171
172 int
173 main(int argc, char **argv)
174 {
175         struct group *gr;
176         int ask, ch, cnt, fflag, hflag, pflag, quietlog, nomailcheck;
177         int rootlogin, rval;
178         int rflag;
179         int changepass = 0;
180         uid_t uid;
181         char *domain, *p, passwd[128], *ttyn;
182         char tbuf[MaxPathLen + 2], tname[sizeof(_PATH_TTY) + 10];
183         char localhost[MaxHostNameLen];
184         char full_hostname[MaxHostNameLen];
185         int auth_level = AUTH_NONE;
186 #ifdef OTP
187         OtpContext otp_ctx;
188 #endif
189         int mask = 022;         /* Default umask (set below) */
190         int maxtrys = 5;        /* Default number of allowed failed logins */
191
192         set_progname(argv[0]);
193
194         openlog("login", LOG_ODELAY, LOG_AUTH);
195
196         /* Read defaults file and set the login timeout period. */
197         sysv_defaults();
198         login_timeout = atoi(default_timeout);
199         maxtrys = atoi(default_maxtrys);
200         if (sscanf(default_umask, "%o", &mask) != 1 || (mask & ~0777))
201                 syslog(LOG_WARNING, "bad umask default: %s", default_umask);
202         else
203                 umask(mask);
204
205         signal(SIGALRM, timedout);
206         alarm(login_timeout);
207         signal(SIGQUIT, SIG_IGN);
208         signal(SIGINT, SIG_IGN);
209         setpriority(PRIO_PROCESS, 0, 0);
210
211         /*
212          * -p is used by getty to tell login not to destroy the environment
213          * -f is used to skip a second login authentication
214          * -h is used by other servers to pass the name of the remote
215          *    host to login so that it may be placed in utmp and wtmp
216          * -r is used by old-style rlogind to execute the autologin protocol
217          */
218
219         *full_hostname = '\0';
220         domain = NULL;
221         if (gethostname(localhost, sizeof(localhost)) < 0)
222                 syslog(LOG_ERR, "couldn't get local hostname: %m");
223         else
224                 domain = strchr(localhost, '.');
225
226         fflag = hflag = pflag = rflag = 0;
227         uid = getuid();
228         while ((ch = getopt(argc, argv, "a:d:fh:pr:")) != -1)
229                 switch (ch) {
230                 case 'a':
231                         if (strcmp (optarg, "none") == 0)
232                                 auth_level = AUTH_NONE;
233 #ifdef OTP
234                         else if (strcmp (optarg, "otp") == 0)
235                                 auth_level = AUTH_OTP;
236 #endif
237                         else
238                                 warnx ("bad value for -a: %s", optarg);
239                         break;
240                 case 'd':
241                         break;
242                 case 'f':
243                         fflag = 1;
244                         break;
245                 case 'h':
246                         if (rflag || hflag) {
247                             printf("Only one of -r and -h allowed\n");
248                             exit(1);
249                         }
250                         if (uid)
251                                 errx(1, "-h option: %s", strerror(EPERM));
252                         hflag = 1;
253                         strlcpy(full_hostname,
254                                         optarg,
255                                         sizeof(full_hostname));
256                         if (domain && (p = strchr(optarg, '.')) &&
257                             strcasecmp(p, domain) == 0)
258                                 *p = 0;
259                         hostname = optarg;
260                         break;
261                 case 'p':
262                         if (getuid()) {
263                                 warnx("-p for super-user only.");
264                                 exit(1);
265                         }
266                         pflag = 1;
267                         break;
268                 case 'r':
269                         if (rflag || hflag) {
270                                 warnx("Only one of -r and -h allowed\n");
271                                 exit(1);
272                         }
273                         if (getuid()) {
274                                 warnx("-r for super-user only.");
275                                 exit(1);
276                         }
277                         rflag = 1;
278                         strlcpy(full_hostname,
279                                         optarg,
280                                         sizeof(full_hostname));
281                         if (domain && (p = strchr(optarg, '.')) &&
282                             strcasecmp(p, domain) == 0)
283                                 *p = 0;
284                         hostname = optarg;
285                         fflag = (doremotelogin(full_hostname) == 0);
286                         break;
287                 case '?':
288                 default:
289                         if (!uid)
290                                 syslog(LOG_ERR, "invalid flag %c", ch);
291                         fprintf(stderr,
292                                 "usage: login [-fp]"
293 #ifdef OTP
294                                 " [-a otp]"
295 #endif
296                                 " [-h hostname | -r hostname] [username]\n");
297                         exit(1);
298                 }
299         argc -= optind;
300         argv += optind;
301
302         if (geteuid() != 0) {
303                 warnx("only root may use login, use su");
304                 /* Or install login setuid root, which is not necessary */
305                 sleep(10);
306                 exit(1);
307         }
308         /*
309          * Figure out if we should ask for the username or not. The name
310          * may be given on the command line or via the environment, and
311          * it may even be in the terminal input queue.
312          */
313         if (rflag) {
314                 username = lusername;
315                 ask = 0;
316               } else
317         if (*argv && strchr(*argv, '=')) {
318                 ask = 1;
319               } else
320         if (*argv && strcmp(*argv, "-") == 0) {
321                 argc--;
322                 argv++;
323                 ask = 1;
324               } else
325         if (*argv) {
326                 username = *argv;
327                 ask = 0;
328                 argc--;
329                 argv++;
330         } else if ((ttyprompt = getenv("TTYPROMPT")) && *ttyprompt) {
331                 getloginname(0);
332                 ask = 0;
333         } else
334                 ask = 1;
335
336         /* Default tty settings. */
337         stty_default();
338
339         for (cnt = getdtablesize(); cnt > 2; cnt--)
340                 close(cnt);
341
342         /*
343          * Determine the tty name. BSD takes the basename, SYSV4 takes
344          * whatever remains after stripping the "/dev/" prefix. The code
345          * below should produce sensible results in either environment.
346          */
347         ttyn = ttyname(STDIN_FILENO);
348         if (ttyn == NULL || *ttyn == '\0') {
349                 snprintf(tname, sizeof(tname), "%s??", _PATH_TTY);
350                 ttyn = tname;
351         }
352         if ((tty = strchr(ttyn + 1, '/')))
353                 ++tty;
354         else
355                 tty = ttyn;
356
357         for (cnt = 0;; ask = 1) {
358                 char prompt[128], ss[256];
359                 if (ask) {
360                         fflag = 0;
361                         getloginname(1);
362                 }
363                 rootlogin = 0;
364                 rval = 1;
365 #ifdef  KERBEROS
366                 if ((instance = strchr(username, '.')) != NULL) {
367                     if (strcmp(instance, ".root") == 0)
368                         rootlogin = 1;
369                     *instance++ = '\0';
370                 } else
371                     instance = "";
372 #endif
373                 if (strlen(username) > UT_NAMESIZE)
374                         username[UT_NAMESIZE] = '\0';
375
376                 /*
377                  * Note if trying multiple user names; log failures for
378                  * previous user name, but don't bother logging one failure
379                  * for nonexistent name (mistyped username).
380                  */
381                 if (failures && strcmp(tbuf, username)) {
382                         if (failures > (pwd ? 0 : 1))
383                                 badlogin(tbuf);
384                         failures = 0;
385                 }
386                 strlcpy(tbuf, username, sizeof(tbuf));
387
388                 pwd = paranoid_getpwnam (username);
389
390                 /*
391                  * if we have a valid account name, and it doesn't have a
392                  * password, or the -f option was specified and the caller
393                  * is root or the caller isn't changing their uid, don't
394                  * authenticate.
395                  */
396                 if (pwd) {
397                         if (pwd->pw_uid == 0)
398                                 rootlogin = 1;
399
400                         if (fflag && (uid == 0 || uid == pwd->pw_uid)) {
401                                 /* already authenticated */
402                                 break;
403                         } else if (pwd->pw_passwd[0] == '\0') {
404                                 /* pretend password okay */
405                                 rval = 0;
406                                 goto ttycheck;
407                         }
408                 }
409
410                 fflag = 0;
411
412                 setpriority(PRIO_PROCESS, 0, -4);
413
414 #ifdef OTP
415                 if (otp_challenge (&otp_ctx, username,
416                                    ss, sizeof(ss)) == 0)
417                         snprintf (prompt, sizeof(prompt), "%s's %s Password: ",
418                                   username, ss);
419                 else
420 #endif
421                 {
422                         if (auth_level == AUTH_NONE)
423                                 snprintf(prompt, sizeof(prompt), "%s's Password: ",
424                                          username);
425                         else {
426                                 char *s;
427
428                                 rval = 1;
429 #ifdef OTP
430                                 s = otp_error(&otp_ctx);
431                                 if(s)
432                                         printf ("OTP: %s\n", s);
433 #endif
434                                 continue;
435                         }
436                 }
437
438                 if (des_read_pw_string (passwd, sizeof(passwd) - 1, prompt, 0))
439                         continue;
440                 passwd[sizeof(passwd) - 1] = '\0';
441
442                 /* Verify it somehow */
443
444 #ifdef OTP
445                 if (otp_verify_user (&otp_ctx, passwd) == 0)
446                         rval = 0;
447                 else
448 #endif
449                 if (pwd == NULL)
450                         ;
451                 else if (auth_level == AUTH_NONE) {
452                         uid_t pwd_uid = pwd->pw_uid;
453
454                         rval = unix_verify_user (username, passwd);
455
456                         if (rval == 0)
457                           {
458                             if (rootlogin && pwd_uid != 0)
459                               rootlogin = 0;
460                           }
461                         else
462                           {
463                             rval = klogin(pwd, instance, localhost, passwd);
464                             if (rval != 0 && rootlogin && pwd_uid != 0)
465                               rootlogin = 0;
466                             if (rval == 0)
467                               authok = 1;
468                           }
469                 } else {
470                         char *s;
471
472                         rval = 1;
473 #ifdef OTP
474                         if ((s = otp_error(&otp_ctx)))
475                                 printf ("OTP: %s\n", s);
476 #endif
477                 }
478
479                 memset (passwd, 0, sizeof(passwd));
480                 setpriority (PRIO_PROCESS, 0, 0);
481
482                 /*
483                  * Santa Claus, give me a portable and reentrant getpwnam.
484                  */
485                 pwd = paranoid_getpwnam (username);
486
487         ttycheck:
488                 /*
489                  * If trying to log in as root without Kerberos,
490                  * but with insecure terminal, refuse the login attempt.
491                  */
492 #ifdef KERBEROS
493                 if (authok == 0)
494 #endif
495                 if (pwd && !rval && rootlogin && !rootterm(tty)
496                     && !rootterm(ttyn)) {
497                         warnx("%s login refused on this terminal.",
498                               pwd->pw_name);
499                         if (hostname)
500                                 syslog(LOG_NOTICE,
501                                        "LOGIN %s REFUSED FROM %s ON TTY %s",
502                                        pwd->pw_name, hostname, tty);
503                         else
504                                 syslog(LOG_NOTICE,
505                                        "LOGIN %s REFUSED ON TTY %s",
506                                        pwd->pw_name, tty);
507                         continue;
508                 }
509
510                 if (rval == 0)
511                         break;
512
513                 printf("Login incorrect\n");
514                 failures++;
515
516                 /* max number of attemps and delays taken from defaults file */
517                 /* we allow maxtrys tries, but after 2 we start backing off */
518                 if (++cnt > 2) {
519                         if (cnt >= maxtrys) {
520                                 badlogin(username);
521                                 sleepexit(1);
522                         }
523                         sleep((u_int)((cnt - 2) * atoi(default_sleep)));
524                 }
525         }
526
527         /* committed to login -- turn off timeout */
528         alarm(0);
529
530         endpwent();
531
532 #if defined(HAVE_GETUDBNAM) && defined(HAVE_SETLIM)
533         {
534             struct udb *udb;
535             long t;
536             const long maxcpu = 46116860184; /* some random constant */
537             
538             if(setjob(pwd->pw_uid, 0) < 0) 
539                 warn("setjob");
540
541             udb = getudbnam(pwd->pw_name);
542             if(udb == UDB_NULL)
543                 errx(1, "Failed to get UDB entry.");
544
545             /* per process cpu limit */
546             t = udb->ue_pcpulim[UDBRC_INTER];
547             if(t == 0 || t > maxcpu)
548                 t = CPUUNLIM;
549             else
550                 t *= CLK_TCK;
551
552             if(limit(C_PROC, 0, L_CPU, t) < 0)
553                 warn("limit process cpu");
554
555             /* per process memory limit */
556             if(limit(C_PROC, 0, L_MEM, udb->ue_pmemlim[UDBRC_INTER]) < 0)
557                 warn("limit process memory");
558
559             /* per job cpu limit */
560             t = udb->ue_jcpulim[UDBRC_INTER];
561             if(t == 0 || t > maxcpu)
562                 t = CPUUNLIM;
563             else
564                 t *= CLK_TCK;
565
566             if(limit(C_JOB, 0, L_CPU, t) < 0)
567                 warn("limit job cpu");
568             
569             /* per job processor limit */
570             if(limit(C_JOB, 0, L_CPROC, udb->ue_jproclim[UDBRC_INTER]) < 0)
571                 warn("limit job processors");
572
573             /* per job memory limit */
574             if(limit(C_JOB, 0, L_MEM, udb->ue_jmemlim[UDBRC_INTER]) < 0)
575                 warn("limit job memory");
576
577             nice(udb->ue_nice[UDBRC_INTER]);
578         }
579 #endif
580         /* if user not super-user, check for disabled logins */
581         if (!rootlogin)
582                 checknologin();
583
584         if (chdir(pwd->pw_dir) < 0) {
585                 printf("No home directory %s!\n", pwd->pw_dir);
586                 if (chdir("/"))
587                         exit(0);
588                 pwd->pw_dir = "/";
589                 printf("Logging in with home = \"/\".\n");
590         }
591
592         quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0;
593         nomailcheck = access(_PATH_NOMAILCHECK, F_OK) == 0;
594
595 #if defined(HAVE_PASSWD_CHANGE) && defined(HAVE_PASSWD_EXPIRE)
596         if (pwd->pw_change || pwd->pw_expire)
597                 gettimeofday(&tp, (struct timezone *)NULL);
598
599         if (pwd->pw_change) {
600                 time_t t;
601
602                 if (tp.tv_sec >= pwd->pw_change) {
603                         printf("Sorry -- your password has expired.\n");
604                         changepass=1;
605                 } else if (pwd->pw_change - tp.tv_sec <
606                            2 * DAYSPERWEEK * SECSPERDAY && !quietlog) {
607                         t = pwd->pw_change;
608                         printf("Warning: your password expires on %s",
609                                ctime(&t));
610                 }
611         if (pwd->pw_expire)
612                 if (tp.tv_sec >= pwd->pw_expire) {
613                         printf("Sorry -- your account has expired.\n");
614                         sleepexit(1);
615                 } else if (pwd->pw_expire - tp.tv_sec <
616                            2 * DAYSPERWEEK * SECSPERDAY && !quietlog) {
617                         t = pwd->pw_expire;
618                         printf("Warning: your account expires on %s",
619                                ctime(&t));
620                 }
621 #endif /* defined(HAVE_PASSWD_CHANGE) && defined(HAVE_PASSWD_EXPIRE) */
622
623         /* Nothing else left to fail -- really log in. */
624
625         /*
626          * Update the utmp files, both BSD and SYSV style.
627          */
628         if (utmpx_login(tty, username, hostname ? hostname : "") != 0
629             && !fflag) {
630                 printf("No utmpx entry.  You must exec \"login\" from the lowest level \"sh\".\n");
631                 sleepexit(0);
632         }
633         utmp_login(ttyn, username, hostname ? hostname : "");
634         dolastlog(quietlog);
635
636         /*
637          * Set device protections, depending on what terminal the
638          * user is logged in. This feature is used on Suns to give
639          * console users better privacy.
640          */
641         login_fbtab(tty, pwd->pw_uid, pwd->pw_gid);
642
643         if (chown(ttyn, pwd->pw_uid,
644             (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid) < 0)
645           err(1, "chown tty failed");
646         if (chmod(ttyn, S_IRUSR | S_IWUSR | S_IWGRP) < 0)
647           err(1, "chmod tty failed");
648         setgid(pwd->pw_gid);
649
650         initgroups(username, pwd->pw_gid);
651
652         if (*pwd->pw_shell == '\0')
653                 pwd->pw_shell = _PATH_BSHELL;
654
655         /*
656          * Set up a new environment. With SYSV, some variables are always
657          * preserved; some varables are never preserved, and some variables
658          * are always clobbered. With BSD, nothing is always preserved, and
659          * some variables are always clobbered. We add code to make sure
660          * that LD_* and IFS are never preserved.
661          */
662         if (term[0] == '\0')
663                 strlcpy(term, stypeof(tty), sizeof(term));
664         /* set up a somewhat censored environment. */
665         sysv_newenv(argc, argv, pwd, term, pflag);
666 #ifdef KERBEROS
667         if (krbtkfile_env)
668             setenv("KRBTKFILE", krbtkfile_env, 1);
669 #endif
670
671         if (tty[sizeof("tty")-1] == 'd')
672                 syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
673
674         /* If fflag is on, assume caller/authenticator has logged root login. */
675         if (rootlogin && fflag == 0) {
676                 if (hostname)
677                         syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s",
678                             username, tty, hostname);
679                 else
680                         syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s", username, tty);
681         }
682
683 #ifdef KERBEROS
684         if (!quietlog && notickets == 1 && !noticketsdontcomplain)
685                 printf("Warning: no Kerberos tickets issued.\n");
686 #endif
687
688 #ifdef LOGALL
689         /*
690          * Syslog each successful login, so we don't have to watch hundreds
691          * of wtmp or lastlogin files.
692          */
693         if (hostname) {
694                 syslog(LOG_INFO, "login from %s as %s", hostname, pwd->pw_name);
695         } else {
696                 syslog(LOG_INFO, "login on %s as %s", tty, pwd->pw_name);
697         }
698 #endif
699
700 #ifndef NO_MOTD
701         /*
702          * Optionally show the message of the day. System V login leaves
703          * motd and mail stuff up to the shell startup file.
704          */
705         if (!quietlog) {
706                 struct stat st;
707 #if 0
708                 printf("%s\n\t%s  %s\n\n",
709             "Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994",
710                     "The Regents of the University of California. ",
711                     "All rights reserved.");
712 #endif
713                 motd();
714                 if(!nomailcheck){
715                     snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_MAILDIR, pwd->pw_name);
716                     if (stat(tbuf, &st) == 0 && st.st_size != 0)
717                         printf("You have %smail.\n",
718                                (st.st_mtime > st.st_atime) ? "new " : "");
719                 }
720         }
721 #endif /* NO_MOTD */
722
723 #ifdef LOGIN_ACCESS
724         if (login_access(pwd, hostname ? full_hostname : tty) == 0) {
725                 printf("Permission denied\n");
726                 if (hostname)
727                         syslog(LOG_NOTICE, "%s LOGIN REFUSED FROM %s",
728                                 pwd->pw_name, hostname);
729                 else
730                         syslog(LOG_NOTICE, "%s LOGIN REFUSED ON %s",
731                                 pwd->pw_name, tty);
732                 sleepexit(1);
733         }
734 #endif
735
736         signal(SIGALRM, SIG_DFL);
737         signal(SIGQUIT, SIG_DFL);
738         signal(SIGINT, SIG_DFL);
739 #ifdef SIGTSTP
740         signal(SIGTSTP, SIG_IGN);
741 #endif
742
743         p = strrchr(pwd->pw_shell, '/');
744         snprintf (tbuf, sizeof(tbuf), "-%s", p ? p + 1 : pwd->pw_shell);
745
746 #ifdef HAVE_SETLOGIN
747         if (setlogin(pwd->pw_name) < 0)
748                 syslog(LOG_ERR, "setlogin() failure: %m");
749 #endif
750
751 #ifdef HAVE_SETPCRED
752         if (setpcred (pwd->pw_name, NULL) == -1)
753                 syslog(LOG_ERR, "setpcred() failure: %m");
754 #endif /* HAVE_SETPCRED */
755
756 #if defined(SYSV_SHADOW) && defined(HAVE_GETSPNAM)
757         spwd = getspnam (username);
758         endspent ();
759 #endif
760         /* perhaps work some magic */
761         if(do_osfc2_magic(pwd->pw_uid))
762             sleepexit(1);
763 #if defined(HAVE_SGI_GETCAPABILITYBYNAME) && defined(HAVE_CAP_SET_PROC)
764         /* XXX SGI capability hack IRIX 6.x (x >= 0?) has something
765            called capabilities, that allow you to give away
766            permissions (such as chown) to specific processes. From 6.5
767            this is default on, and the default capability set seems to
768            not always be the empty set. The problem is that the
769            runtime linker refuses to do just about anything if the
770            process has *any* capabilities set, so we have to remove
771            them here (unless otherwise instructed by /etc/capability).
772            In IRIX < 6.5, these functions was called sgi_cap_setproc,
773            etc, but we ignore this fact (it works anyway). */
774         {
775             struct user_cap *ucap = sgi_getcapabilitybyname(pwd->pw_name);
776             cap_t cap;
777             if(ucap == NULL)
778                 cap = cap_from_text("all=");
779             else
780                 cap = cap_from_text(ucap->ca_default);
781             if(cap == NULL)
782                 err(1, "cap_from_text");
783             if(cap_set_proc(cap) < 0)
784                 err(1, "cap_set_proc");
785             cap_free(cap);
786             free(ucap);
787         }
788 #endif
789         /* Discard permissions last so can't get killed and drop core. */
790         {
791             int uid = rootlogin ? 0 : pwd->pw_uid;
792             if(setuid(uid) != 0){
793                     warn("setuid(%d)", uid);
794                     if(!rootlogin)
795                             exit(1);
796             }
797             if (uid != 0 && setuid(0) != -1) {
798                     syslog(LOG_ALERT | LOG_AUTH,
799                            "Failed to drop privileges for user %d", uid);
800                     errx(1, "Sorry");
801             }
802         }
803                        
804
805         /*
806          * After dropping privileges and after cleaning up the environment,
807          * optionally run, as the user, /bin/passwd.
808          */
809  
810         if (pwd->pw_passwd[0] == 0 &&
811             strcasecmp(default_passreq, "YES") == 0) {
812                 printf("You don't have a password.  Choose one.\n");
813                 if (change_passwd(pwd))
814                         sleepexit(0);
815                 changepass = 0;
816         }
817
818 #ifdef SYSV_SHADOW
819         if (spwd && sysv_expire(spwd)) {
820                 if (change_passwd(pwd))
821                         sleepexit(0);
822                 changepass = 0;
823         }
824 #endif /* SYSV_SHADOW */
825         if (changepass) {
826                 int res;
827                 if ((res=system(_PATH_CHPASS)))
828                         sleepexit(1);
829         }
830
831         if (k_hasafs()) {
832             char cell[64];
833 #ifdef _AIX
834             /* XXX this is a fix for a bug in AFS for AIX 4.3, w/o
835                this hack the kernel crashes on the following
836                pioctl... */
837             char *pw_dir = strdup(pwd->pw_dir);
838 #else
839             char *pw_dir = pwd->pw_dir;
840 #endif
841             k_setpag();
842             if(k_afs_cell_of_file(pw_dir, cell, sizeof(cell)) == 0)
843                 krb_afslog(cell, 0);
844             krb_afslog(0, 0);
845         }
846
847         execlp(pwd->pw_shell, tbuf, 0);
848         if (getuid() == 0) {
849                 warnx("Can't exec %s, trying %s\n", 
850                       pwd->pw_shell, _PATH_BSHELL);
851                 execlp(_PATH_BSHELL, tbuf, 0);
852                 err(1, "%s", _PATH_BSHELL);
853         }
854         err(1, "%s", pwd->pw_shell);
855         return 1;
856 }
857
858 #ifdef  KERBEROS
859 #define NBUFSIZ         (UT_NAMESIZE + 1 + 5)   /* .root suffix */
860 #else
861 #define NBUFSIZ         (UT_NAMESIZE + 1)
862 #endif
863
864 static void
865 getloginname(int prompt)
866 {
867     int ch;
868     char *p;
869     static char nbuf[NBUFSIZ];
870
871     for (;;) {
872         if (prompt) {
873             if (ttyprompt && *ttyprompt)
874                 printf("%s", ttyprompt);
875             else
876                 printf("login: ");
877         }
878         prompt = 1;
879         for (p = nbuf; (ch = getchar()) != '\n'; ) {
880             if (ch == EOF) {
881                 badlogin(username);
882                 exit(0);
883             }
884             if (p < nbuf + (NBUFSIZ - 1))
885                 *p++ = ch;
886         }
887         if (p > nbuf) {
888             if (nbuf[0] == '-')
889                 warnx("login names may not start with '-'.");
890             else {
891                 *p = '\0';
892                 username = nbuf;
893                 break;
894             }
895         }
896     }
897 }
898
899 static int
900 find_in_etc_securetty (char *ttyn)
901 {
902     FILE *f;
903     char buf[128];
904     int ret = 0;
905
906     f = fopen (_PATH_ETC_SECURETTY, "r");
907     if (f == NULL)
908         return 0;
909     while (fgets(buf, sizeof(buf), f) != NULL) {
910         if(buf[strlen(buf) - 1] == '\n')
911             buf[strlen(buf) - 1] = '\0';
912         if (strcmp (buf, ttyn) == 0) {
913             ret = 1;
914             break;
915         }
916     }
917     fclose(f);
918     return ret;
919 }
920
921 static int
922 rootterm(char *ttyn)
923 {
924 #ifdef HAVE_TTYENT_H
925     {
926         struct ttyent *t;
927
928         t = getttynam (ttyn);
929         if (t && t->ty_status & TTY_SECURE)
930             return 1;
931     }
932 #endif
933     if (find_in_etc_securetty(ttyn))
934         return 1;
935     if (default_console == 0 || strcmp(default_console, ttyn) == 0)
936         return 1;
937     return 0;
938 }
939
940 static RETSIGTYPE
941 timedout(int signo)
942 {
943         fprintf(stderr, "Login timed out after %d seconds\n",
944                 login_timeout);
945         exit(0);
946 }
947
948 static void
949 checknologin(void)
950 {
951         int fd, nchars;
952         char tbuf[8192];
953
954         if ((fd = open(_PATH_NOLOGIN, O_RDONLY, 0)) >= 0) {
955                 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
956                         write(fileno(stdout), tbuf, nchars);
957                 sleepexit(0);
958         }
959 }
960
961 static void
962 dolastlog(int quiet)
963 {
964 #if defined(HAVE_LASTLOG_H) || defined(HAVE_LOGIN_H)
965         struct lastlog ll;
966         int fd;
967         time_t t;
968
969         if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) {
970                 lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), SEEK_SET);
971 #ifdef SYSV_SHADOW
972                 if (read(fd, &ll, sizeof(ll)) == sizeof(ll) &&
973                     ll.ll_time != 0) {
974                         if (pwd->pw_uid && spwd && spwd->sp_inact > 0
975                             && ll.ll_time / (24 * 60 * 60)
976                             + spwd->sp_inact < time(0)) {
977                                 printf("Your account has been inactive too long.\n");
978                                 sleepexit(1);
979                         }
980                         if (!quiet) {
981                                 t = ll.ll_time;
982                                 printf("Last login: %.*s ", 24-5, ctime(&t));
983                                 if (*ll.ll_host != '\0') {
984                                         printf("from %.*s\n",
985                                             (int)sizeof(ll.ll_host),
986                                                ll.ll_host);
987                                 } else
988                                         printf("on %.*s\n",
989                                             (int)sizeof(ll.ll_line),
990                                                ll.ll_line);
991                         }
992                 }
993                 lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), SEEK_SET);
994 #else /* SYSV_SHADOW */
995                 if (!quiet) {
996                         if (read(fd, &ll, sizeof(ll)) == sizeof(ll) &&
997                             ll.ll_time != 0) {
998                                 t = ll.ll_time;
999                                 printf("Last login: %.*s ", 24-5, ctime(&t));
1000                                 if (*ll.ll_host != '\0')
1001                                         printf("from %.*s\n",
1002                                             (int)sizeof(ll.ll_host),
1003                                             ll.ll_host);
1004                                 else
1005                                         printf("on %.*s\n",
1006                                             (int)sizeof(ll.ll_line),
1007                                             ll.ll_line);
1008                         }
1009                         lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), SEEK_SET);
1010                 }
1011 #endif /* SYSV_SHADOW */
1012                 memset(&ll, 0, sizeof(ll));
1013                 ll.ll_time = time(NULL);
1014                 strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
1015                 if (hostname)
1016                         strncpy(ll.ll_host, hostname, sizeof(ll.ll_host));
1017                 write(fd, &ll, sizeof(ll));
1018                 close(fd);
1019         }
1020 #endif /* DOLASTLOG */
1021 }
1022
1023 static void
1024 badlogin(char *name)
1025 {
1026
1027         if (failures == 0)
1028                 return;
1029         if (hostname) {
1030                 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s",
1031                     failures, failures > 1 ? "S" : "", hostname);
1032                 syslog(LOG_AUTHPRIV|LOG_NOTICE,
1033                     "%d LOGIN FAILURE%s FROM %s, %s",
1034                     failures, failures > 1 ? "S" : "", hostname, name);
1035         } else {
1036                 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s",
1037                     failures, failures > 1 ? "S" : "", tty);
1038                 syslog(LOG_AUTHPRIV|LOG_NOTICE,
1039                     "%d LOGIN FAILURE%s ON %s, %s",
1040                     failures, failures > 1 ? "S" : "", tty, name);
1041         }
1042 }
1043
1044 #undef  UNKNOWN
1045 #define UNKNOWN "su"
1046
1047 static char *
1048 stypeof(char *ttyid)
1049 {
1050     /* TERM is probably a better guess than anything else. */
1051     char *term = getenv("TERM");
1052
1053     if (term != 0 && term[0] != 0)
1054         return term;
1055
1056     {
1057 #ifndef HAVE_TTYENT_H
1058         return UNKNOWN;
1059 #else
1060         struct ttyent *t;
1061         return (ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN);
1062 #endif
1063     }
1064 }
1065
1066 static void
1067 xgetstr(char *buf, int cnt, char *err)
1068 {
1069         char ch;
1070  
1071         do {
1072                 if (read(0, &ch, sizeof(ch)) != sizeof(ch))
1073                         exit(1);
1074                 if (--cnt < 0) {
1075                         fprintf(stderr, "%s too long\r\n", err);
1076                         sleepexit(1);
1077                 }
1078                 *buf++ = ch;
1079         } while (ch);
1080 }
1081
1082 /*
1083  * Some old rlogind's unknowingly pass remuser, locuser and
1084  * terminal_type/speed so we need to take care of that part of the
1085  * protocol here. Also, we can't make a getpeername(2) on the socket
1086  * so we have to trust that rlogind resolved the name correctly.
1087  */
1088
1089 static int
1090 doremotelogin(char *host)
1091 {
1092         int code;
1093         char *cp;
1094
1095         xgetstr(rusername, sizeof (rusername), "remuser");
1096         xgetstr(lusername, sizeof (lusername), "locuser");
1097         xgetstr(term, sizeof(term), "Terminal type");
1098         cp = strchr(term, '/');
1099         if (cp != 0)
1100                 *cp = 0;        /* For now ignore speed/bg */
1101         pwd = k_getpwnam(lusername);
1102         if (pwd == NULL)
1103                 return(-1);
1104         code = ruserok(host, (pwd->pw_uid == 0), rusername, lusername);
1105         if (code == 0)
1106           syslog(LOG_NOTICE,
1107                  "Warning: An old rlogind accepted login probably from host %s",
1108                  host);
1109         return(code);
1110 }
1111  
1112 void
1113 sleepexit(int eval)
1114 {
1115
1116         sleep(5);
1117         exit(eval);
1118 }