]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - crypto/kerberosIV/appl/bsd/login.c
This commit was generated by cvs2svn to compensate for changes in r56067,
[FreeBSD/FreeBSD.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 1999/11/30 19:24:01 bg 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                 if (tp.tv_sec >= pwd->pw_change) {
601                         printf("Sorry -- your password has expired.\n");
602                         changepass=1;
603                 } else if (pwd->pw_change - tp.tv_sec <
604                     2 * DAYSPERWEEK * SECSPERDAY && !quietlog)
605                         printf("Warning: your password expires on %s",
606                             ctime(&pwd->pw_change));
607         if (pwd->pw_expire)
608                 if (tp.tv_sec >= pwd->pw_expire) {
609                         printf("Sorry -- your account has expired.\n");
610                         sleepexit(1);
611                 } else if (pwd->pw_expire - tp.tv_sec <
612                     2 * DAYSPERWEEK * SECSPERDAY && !quietlog)
613                         printf("Warning: your account expires on %s",
614                             ctime(&pwd->pw_expire));
615 #endif /* defined(HAVE_PASSWD_CHANGE) && defined(HAVE_PASSWD_EXPIRE) */
616
617         /* Nothing else left to fail -- really log in. */
618
619         /*
620          * Update the utmp files, both BSD and SYSV style.
621          */
622         if (utmpx_login(tty, username, hostname ? hostname : "") != 0
623             && !fflag) {
624                 printf("No utmpx entry.  You must exec \"login\" from the lowest level \"sh\".\n");
625                 sleepexit(0);
626         }
627         utmp_login(ttyn, username, hostname ? hostname : "");
628         dolastlog(quietlog);
629
630         /*
631          * Set device protections, depending on what terminal the
632          * user is logged in. This feature is used on Suns to give
633          * console users better privacy.
634          */
635         login_fbtab(tty, pwd->pw_uid, pwd->pw_gid);
636
637         if (chown(ttyn, pwd->pw_uid,
638             (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid) < 0)
639           err(1, "chown tty failed");
640         if (chmod(ttyn, S_IRUSR | S_IWUSR | S_IWGRP) < 0)
641           err(1, "chmod tty failed");
642         setgid(pwd->pw_gid);
643
644         initgroups(username, pwd->pw_gid);
645
646         if (*pwd->pw_shell == '\0')
647                 pwd->pw_shell = _PATH_BSHELL;
648
649         /*
650          * Set up a new environment. With SYSV, some variables are always
651          * preserved; some varables are never preserved, and some variables
652          * are always clobbered. With BSD, nothing is always preserved, and
653          * some variables are always clobbered. We add code to make sure
654          * that LD_* and IFS are never preserved.
655          */
656         if (term[0] == '\0')
657                 strlcpy(term, stypeof(tty), sizeof(term));
658         /* set up a somewhat censored environment. */
659         sysv_newenv(argc, argv, pwd, term, pflag);
660 #ifdef KERBEROS
661         if (krbtkfile_env)
662             setenv("KRBTKFILE", krbtkfile_env, 1);
663 #endif
664
665         if (tty[sizeof("tty")-1] == 'd')
666                 syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
667
668         /* If fflag is on, assume caller/authenticator has logged root login. */
669         if (rootlogin && fflag == 0) {
670                 if (hostname)
671                         syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s",
672                             username, tty, hostname);
673                 else
674                         syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s", username, tty);
675         }
676
677 #ifdef KERBEROS
678         if (!quietlog && notickets == 1 && !noticketsdontcomplain)
679                 printf("Warning: no Kerberos tickets issued.\n");
680 #endif
681
682 #ifdef LOGALL
683         /*
684          * Syslog each successful login, so we don't have to watch hundreds
685          * of wtmp or lastlogin files.
686          */
687         if (hostname) {
688                 syslog(LOG_INFO, "login from %s as %s", hostname, pwd->pw_name);
689         } else {
690                 syslog(LOG_INFO, "login on %s as %s", tty, pwd->pw_name);
691         }
692 #endif
693
694 #ifndef NO_MOTD
695         /*
696          * Optionally show the message of the day. System V login leaves
697          * motd and mail stuff up to the shell startup file.
698          */
699         if (!quietlog) {
700                 struct stat st;
701 #if 0
702                 printf("%s\n\t%s  %s\n\n",
703             "Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994",
704                     "The Regents of the University of California. ",
705                     "All rights reserved.");
706 #endif
707                 motd();
708                 if(!nomailcheck){
709                     snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_MAILDIR, pwd->pw_name);
710                     if (stat(tbuf, &st) == 0 && st.st_size != 0)
711                         printf("You have %smail.\n",
712                                (st.st_mtime > st.st_atime) ? "new " : "");
713                 }
714         }
715 #endif /* NO_MOTD */
716
717 #ifdef LOGIN_ACCESS
718         if (login_access(pwd, hostname ? full_hostname : tty) == 0) {
719                 printf("Permission denied\n");
720                 if (hostname)
721                         syslog(LOG_NOTICE, "%s LOGIN REFUSED FROM %s",
722                                 pwd->pw_name, hostname);
723                 else
724                         syslog(LOG_NOTICE, "%s LOGIN REFUSED ON %s",
725                                 pwd->pw_name, tty);
726                 sleepexit(1);
727         }
728 #endif
729
730         signal(SIGALRM, SIG_DFL);
731         signal(SIGQUIT, SIG_DFL);
732         signal(SIGINT, SIG_DFL);
733 #ifdef SIGTSTP
734         signal(SIGTSTP, SIG_IGN);
735 #endif
736
737         p = strrchr(pwd->pw_shell, '/');
738         snprintf (tbuf, sizeof(tbuf), "-%s", p ? p + 1 : pwd->pw_shell);
739
740 #ifdef HAVE_SETLOGIN
741         if (setlogin(pwd->pw_name) < 0)
742                 syslog(LOG_ERR, "setlogin() failure: %m");
743 #endif
744
745 #ifdef HAVE_SETPCRED
746         if (setpcred (pwd->pw_name, NULL) == -1)
747                 syslog(LOG_ERR, "setpcred() failure: %m");
748 #endif /* HAVE_SETPCRED */
749
750 #if defined(SYSV_SHADOW) && defined(HAVE_GETSPNAM)
751         spwd = getspnam (username);
752         endspent ();
753 #endif
754         /* perhaps work some magic */
755         if(do_osfc2_magic(pwd->pw_uid))
756             sleepexit(1);
757 #if defined(HAVE_SGI_GETCAPABILITYBYNAME) && defined(HAVE_CAP_SET_PROC)
758         /* XXX SGI capability hack IRIX 6.x (x >= 0?) has something
759            called capabilities, that allow you to give away
760            permissions (such as chown) to specific processes. From 6.5
761            this is default on, and the default capability set seems to
762            not always be the empty set. The problem is that the
763            runtime linker refuses to do just about anything if the
764            process has *any* capabilities set, so we have to remove
765            them here (unless otherwise instructed by /etc/capability).
766            In IRIX < 6.5, these functions was called sgi_cap_setproc,
767            etc, but we ignore this fact (it works anyway). */
768         {
769             struct user_cap *ucap = sgi_getcapabilitybyname(pwd->pw_name);
770             cap_t cap;
771             if(ucap == NULL)
772                 cap = cap_from_text("all=");
773             else
774                 cap = cap_from_text(ucap->ca_default);
775             if(cap == NULL)
776                 err(1, "cap_from_text");
777             if(cap_set_proc(cap) < 0)
778                 err(1, "cap_set_proc");
779             cap_free(cap);
780             free(ucap);
781         }
782 #endif
783         /* Discard permissions last so can't get killed and drop core. */
784         {
785             int uid = rootlogin ? 0 : pwd->pw_uid;
786             if(setuid(uid) != 0){
787                     warn("setuid(%d)", uid);
788                     if(!rootlogin)
789                             exit(1);
790             }
791         }
792                        
793
794         /*
795          * After dropping privileges and after cleaning up the environment,
796          * optionally run, as the user, /bin/passwd.
797          */
798  
799         if (pwd->pw_passwd[0] == 0 &&
800             strcasecmp(default_passreq, "YES") == 0) {
801                 printf("You don't have a password.  Choose one.\n");
802                 if (change_passwd(pwd))
803                         sleepexit(0);
804                 changepass = 0;
805         }
806
807 #ifdef SYSV_SHADOW
808         if (spwd && sysv_expire(spwd)) {
809                 if (change_passwd(pwd))
810                         sleepexit(0);
811                 changepass = 0;
812         }
813 #endif /* SYSV_SHADOW */
814         if (changepass) {
815                 int res;
816                 if ((res=system(_PATH_CHPASS)))
817                         sleepexit(1);
818         }
819
820         if (k_hasafs()) {
821             char cell[64];
822 #ifdef _AIX
823             /* XXX this is a fix for a bug in AFS for AIX 4.3, w/o
824                this hack the kernel crashes on the following
825                pioctl... */
826             char *pw_dir = strdup(pwd->pw_dir);
827 #else
828             char *pw_dir = pwd->pw_dir;
829 #endif
830             k_setpag();
831             if(k_afs_cell_of_file(pw_dir, cell, sizeof(cell)) == 0)
832                 krb_afslog(cell, 0);
833             krb_afslog(0, 0);
834         }
835
836         execlp(pwd->pw_shell, tbuf, 0);
837         if (getuid() == 0) {
838                 warnx("Can't exec %s, trying %s\n", 
839                       pwd->pw_shell, _PATH_BSHELL);
840                 execlp(_PATH_BSHELL, tbuf, 0);
841                 err(1, "%s", _PATH_BSHELL);
842         }
843         err(1, "%s", pwd->pw_shell);
844         return 1;
845 }
846
847 #ifdef  KERBEROS
848 #define NBUFSIZ         (UT_NAMESIZE + 1 + 5)   /* .root suffix */
849 #else
850 #define NBUFSIZ         (UT_NAMESIZE + 1)
851 #endif
852
853 static void
854 getloginname(int prompt)
855 {
856     int ch;
857     char *p;
858     static char nbuf[NBUFSIZ];
859
860     for (;;) {
861         if (prompt) {
862             if (ttyprompt && *ttyprompt)
863                 printf("%s", ttyprompt);
864             else
865                 printf("login: ");
866         }
867         prompt = 1;
868         for (p = nbuf; (ch = getchar()) != '\n'; ) {
869             if (ch == EOF) {
870                 badlogin(username);
871                 exit(0);
872             }
873             if (p < nbuf + (NBUFSIZ - 1))
874                 *p++ = ch;
875         }
876         if (p > nbuf) {
877             if (nbuf[0] == '-')
878                 warnx("login names may not start with '-'.");
879             else {
880                 *p = '\0';
881                 username = nbuf;
882                 break;
883             }
884         }
885     }
886 }
887
888 static int
889 find_in_etc_securetty (char *ttyn)
890 {
891     FILE *f;
892     char buf[128];
893     int ret = 0;
894
895     f = fopen (_PATH_ETC_SECURETTY, "r");
896     if (f == NULL)
897         return 0;
898     while (fgets(buf, sizeof(buf), f) != NULL) {
899         if(buf[strlen(buf) - 1] == '\n')
900             buf[strlen(buf) - 1] = '\0';
901         if (strcmp (buf, ttyn) == 0) {
902             ret = 1;
903             break;
904         }
905     }
906     fclose(f);
907     return ret;
908 }
909
910 static int
911 rootterm(char *ttyn)
912 {
913 #ifdef HAVE_TTYENT_H
914     {
915         struct ttyent *t;
916
917         t = getttynam (ttyn);
918         if (t && t->ty_status & TTY_SECURE)
919             return 1;
920     }
921 #endif
922     if (find_in_etc_securetty(ttyn))
923         return 1;
924     if (default_console == 0 || strcmp(default_console, ttyn) == 0)
925         return 1;
926     return 0;
927 }
928
929 static RETSIGTYPE
930 timedout(int signo)
931 {
932         fprintf(stderr, "Login timed out after %d seconds\n",
933                 login_timeout);
934         exit(0);
935 }
936
937 static void
938 checknologin(void)
939 {
940         int fd, nchars;
941         char tbuf[8192];
942
943         if ((fd = open(_PATH_NOLOGIN, O_RDONLY, 0)) >= 0) {
944                 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
945                         write(fileno(stdout), tbuf, nchars);
946                 sleepexit(0);
947         }
948 }
949
950 static void
951 dolastlog(int quiet)
952 {
953 #if defined(HAVE_LASTLOG_H) || defined(HAVE_LOGIN_H)
954         struct lastlog ll;
955         int fd;
956
957         if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) {
958                 lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), SEEK_SET);
959 #ifdef SYSV_SHADOW
960                 if (read(fd, &ll, sizeof(ll)) == sizeof(ll) &&
961                     ll.ll_time != 0) {
962                         if (pwd->pw_uid && spwd && spwd->sp_inact > 0
963                             && ll.ll_time / (24 * 60 * 60)
964                             + spwd->sp_inact < time(0)) {
965                                 printf("Your account has been inactive too long.\n");
966                                 sleepexit(1);
967                         }
968                         if (!quiet) {
969                                 printf("Last login: %.*s ",
970                                     24-5, ctime(&ll.ll_time));
971                                 if (*ll.ll_host != '\0') {
972                                         printf("from %.*s\n",
973                                             (int)sizeof(ll.ll_host),
974                                                ll.ll_host);
975                                 } else
976                                         printf("on %.*s\n",
977                                             (int)sizeof(ll.ll_line),
978                                                ll.ll_line);
979                         }
980                 }
981                 lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), SEEK_SET);
982 #else /* SYSV_SHADOW */
983                 if (!quiet) {
984                         if (read(fd, &ll, sizeof(ll)) == sizeof(ll) &&
985                             ll.ll_time != 0) {
986                                 printf("Last login: %.*s ",
987                                     24-5, ctime(&ll.ll_time));
988                                 if (*ll.ll_host != '\0')
989                                         printf("from %.*s\n",
990                                             (int)sizeof(ll.ll_host),
991                                             ll.ll_host);
992                                 else
993                                         printf("on %.*s\n",
994                                             (int)sizeof(ll.ll_line),
995                                             ll.ll_line);
996                         }
997                         lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), SEEK_SET);
998                 }
999 #endif /* SYSV_SHADOW */
1000                 memset(&ll, 0, sizeof(ll));
1001                 time(&ll.ll_time);
1002                 strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
1003                 if (hostname)
1004                         strncpy(ll.ll_host, hostname, sizeof(ll.ll_host));
1005                 write(fd, &ll, sizeof(ll));
1006                 close(fd);
1007         }
1008 #endif /* DOLASTLOG */
1009 }
1010
1011 static void
1012 badlogin(char *name)
1013 {
1014
1015         if (failures == 0)
1016                 return;
1017         if (hostname) {
1018                 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s",
1019                     failures, failures > 1 ? "S" : "", hostname);
1020                 syslog(LOG_AUTHPRIV|LOG_NOTICE,
1021                     "%d LOGIN FAILURE%s FROM %s, %s",
1022                     failures, failures > 1 ? "S" : "", hostname, name);
1023         } else {
1024                 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s",
1025                     failures, failures > 1 ? "S" : "", tty);
1026                 syslog(LOG_AUTHPRIV|LOG_NOTICE,
1027                     "%d LOGIN FAILURE%s ON %s, %s",
1028                     failures, failures > 1 ? "S" : "", tty, name);
1029         }
1030 }
1031
1032 #undef  UNKNOWN
1033 #define UNKNOWN "su"
1034
1035 static char *
1036 stypeof(char *ttyid)
1037 {
1038     /* TERM is probably a better guess than anything else. */
1039     char *term = getenv("TERM");
1040
1041     if (term != 0 && term[0] != 0)
1042         return term;
1043
1044     {
1045 #ifndef HAVE_TTYENT_H
1046         return UNKNOWN;
1047 #else
1048         struct ttyent *t;
1049         return (ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN);
1050 #endif
1051     }
1052 }
1053
1054 static void
1055 xgetstr(char *buf, int cnt, char *err)
1056 {
1057         char ch;
1058  
1059         do {
1060                 if (read(0, &ch, sizeof(ch)) != sizeof(ch))
1061                         exit(1);
1062                 if (--cnt < 0) {
1063                         fprintf(stderr, "%s too long\r\n", err);
1064                         sleepexit(1);
1065                 }
1066                 *buf++ = ch;
1067         } while (ch);
1068 }
1069
1070 /*
1071  * Some old rlogind's unknowingly pass remuser, locuser and
1072  * terminal_type/speed so we need to take care of that part of the
1073  * protocol here. Also, we can't make a getpeername(2) on the socket
1074  * so we have to trust that rlogind resolved the name correctly.
1075  */
1076
1077 static int
1078 doremotelogin(char *host)
1079 {
1080         int code;
1081         char *cp;
1082
1083         xgetstr(rusername, sizeof (rusername), "remuser");
1084         xgetstr(lusername, sizeof (lusername), "locuser");
1085         xgetstr(term, sizeof(term), "Terminal type");
1086         cp = strchr(term, '/');
1087         if (cp != 0)
1088                 *cp = 0;        /* For now ignore speed/bg */
1089         pwd = k_getpwnam(lusername);
1090         if (pwd == NULL)
1091                 return(-1);
1092         code = ruserok(host, (pwd->pw_uid == 0), rusername, lusername);
1093         if (code == 0)
1094           syslog(LOG_NOTICE,
1095                  "Warning: An old rlogind accepted login probably from host %s",
1096                  host);
1097         return(code);
1098 }
1099  
1100 void
1101 sleepexit(int eval)
1102 {
1103
1104         sleep(5);
1105         exit(eval);
1106 }