login.c revision 1.56 1 /* $NetBSD: login.c,v 1.56 2000/03/07 14:11:22 enami Exp $ */
2
3 /*-
4 * Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #include <sys/cdefs.h>
37 #ifndef lint
38 __COPYRIGHT(
39 "@(#) Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994\n\
40 The Regents of the University of California. All rights reserved.\n");
41 #endif /* not lint */
42
43 #ifndef lint
44 #if 0
45 static char sccsid[] = "@(#)login.c 8.4 (Berkeley) 4/2/94";
46 #endif
47 __RCSID("$NetBSD: login.c,v 1.56 2000/03/07 14:11:22 enami Exp $");
48 #endif /* not lint */
49
50 /*
51 * login [ name ]
52 * login -h hostname (for telnetd, etc.)
53 * login -f name (for pre-authenticated login: datakit, xterm, etc.)
54 */
55
56 #include <sys/param.h>
57 #include <sys/stat.h>
58 #include <sys/time.h>
59 #include <sys/resource.h>
60 #include <sys/file.h>
61 #include <sys/wait.h>
62
63 #include <err.h>
64 #include <errno.h>
65 #include <grp.h>
66 #include <pwd.h>
67 #include <setjmp.h>
68 #include <signal.h>
69 #include <stdio.h>
70 #include <stdlib.h>
71 #include <string.h>
72 #include <syslog.h>
73 #include <time.h>
74 #include <ttyent.h>
75 #include <tzfile.h>
76 #include <unistd.h>
77 #include <utmp.h>
78 #include <util.h>
79 #ifdef SKEY
80 #include <skey.h>
81 #endif
82 #ifdef KERBEROS5
83 #include <krb5/krb5.h>
84 #include <com_err.h>
85 #endif
86 #ifdef LOGIN_CAP
87 #include <login_cap.h>
88 #endif
89
90 #include "pathnames.h"
91
92 void badlogin __P((char *));
93 void checknologin __P((char *));
94 void dolastlog __P((int));
95 void getloginname __P((void));
96 int main __P((int, char *[]));
97 void motd __P((char *));
98 int rootterm __P((char *));
99 void sigint __P((int));
100 void sleepexit __P((int));
101 const char *stypeof __P((const char *));
102 void timedout __P((int));
103 #if defined(KERBEROS) || defined(KERBEROS5)
104 int klogin __P((struct passwd *, char *, char *, char *));
105 void kdestroy __P((void));
106 void dofork __P((void));
107 #endif
108 #ifdef KERBEROS5
109 int k5_read_creds __P((char*));
110 int k5_write_creds __P((void));
111 #endif
112
113 #define TTYGRPNAME "tty" /* name of group to own ttys */
114
115 #define DEFAULT_BACKOFF 3
116 #define DEFAULT_RETRIES 10
117
118 /*
119 * This bounds the time given to login. Not a define so it can
120 * be patched on machines where it's too small.
121 */
122 u_int timeout = 300;
123
124 #if defined(KERBEROS) || defined(KERBEROS5)
125 int notickets = 1;
126 char *instance;
127 char *krbtkfile_env;
128 #endif
129 #ifdef KERBEROS5
130 extern krb5_context kcontext;
131 extern int have_forward;
132 extern int use_krb5;
133 #endif
134
135 struct passwd *pwd;
136 int failures;
137 char term[64], *envinit[1], *hostname, *username, *tty;
138
139 static const char copyrightstr[] = "\
140 Copyright (c) 1996, 1997, 1998, 1999, 2000\n\
141 \tThe NetBSD Foundation, Inc. All rights reserved.\n\
142 Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994\n\
143 \tThe Regents of the University of California. All rights reserved.\n\n";
144
145 int
146 main(argc, argv)
147 int argc;
148 char *argv[];
149 {
150 extern char **environ;
151 struct group *gr;
152 struct stat st;
153 struct timeval tp;
154 struct utmp utmp;
155 int ask, ch, cnt, fflag, hflag, pflag, sflag, quietlog, rootlogin, rval;
156 int Fflag;
157 uid_t uid, saved_uid;
158 gid_t saved_gid, saved_gids[NGROUPS_MAX];
159 int nsaved_gids;
160 char *domain, *p, *ttyn, *pwprompt;
161 const char *salt;
162 char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10];
163 char localhost[MAXHOSTNAMELEN + 1];
164 int need_chpass, require_chpass;
165 int login_retries = DEFAULT_RETRIES,
166 login_backoff = DEFAULT_BACKOFF;
167 time_t pw_warntime = _PASSWORD_WARNDAYS * SECSPERDAY;
168 #ifdef KERBEROS5
169 krb5_error_code kerror;
170 #endif
171 #ifdef LOGIN_CAP
172 char *shell = NULL;
173 login_cap_t *lc = NULL;
174 #endif
175
176 tbuf[0] = '\0';
177 rval = 0;
178 pwprompt = NULL;
179 need_chpass = require_chpass = 0;
180
181 (void)signal(SIGALRM, timedout);
182 (void)alarm(timeout);
183 (void)signal(SIGQUIT, SIG_IGN);
184 (void)signal(SIGINT, SIG_IGN);
185 (void)setpriority(PRIO_PROCESS, 0, 0);
186
187 openlog("login", LOG_ODELAY, LOG_AUTH);
188
189 /*
190 * -p is used by getty to tell login not to destroy the environment
191 * -f is used to skip a second login authentication
192 * -h is used by other servers to pass the name of the remote
193 * host to login so that it may be placed in utmp and wtmp
194 * -s is used to force use of S/Key or equivalent.
195 */
196 domain = NULL;
197 if (gethostname(localhost, sizeof(localhost)) < 0)
198 syslog(LOG_ERR, "couldn't get local hostname: %m");
199 else
200 domain = strchr(localhost, '.');
201 localhost[sizeof(localhost) - 1] = '\0';
202
203 Fflag = fflag = hflag = pflag = sflag = 0;
204 #ifdef KERBEROS5
205 have_forward = 0;
206 use_krb5 = 1;
207 #endif
208 uid = getuid();
209 while ((ch = getopt(argc, argv, "Ffh:ps")) != -1)
210 switch (ch) {
211 case 'F':
212 Fflag = 1;
213 /* FALLTHROUGH */
214 case 'f':
215 fflag = 1;
216 break;
217 case 'h':
218 if (uid)
219 errx(1, "-h option: %s", strerror(EPERM));
220 hflag = 1;
221 if (domain && (p = strchr(optarg, '.')) != NULL &&
222 strcasecmp(p, domain) == 0)
223 *p = 0;
224 hostname = optarg;
225 break;
226 case 'p':
227 pflag = 1;
228 break;
229 case 's':
230 sflag = 1;
231 break;
232 default:
233 case '?':
234 (void)fprintf(stderr,
235 "usage: login [-fps] [-h hostname] [username]\n");
236 exit(1);
237 }
238 argc -= optind;
239 argv += optind;
240
241 if (*argv) {
242 username = *argv;
243 ask = 0;
244 } else
245 ask = 1;
246
247 for (cnt = getdtablesize(); cnt > 2; cnt--)
248 (void)close(cnt);
249
250 ttyn = ttyname(STDIN_FILENO);
251 if (ttyn == NULL || *ttyn == '\0') {
252 (void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY);
253 ttyn = tname;
254 }
255 if ((tty = strrchr(ttyn, '/')) != NULL)
256 ++tty;
257 else
258 tty = ttyn;
259
260 #ifdef LOGIN_CAP
261 /* Get "login-retries" and "login-backoff" from default class */
262 if ((lc = login_getclass(NULL)) != NULL) {
263 login_retries = (int)login_getcapnum(lc, "login-retries",
264 DEFAULT_RETRIES, DEFAULT_RETRIES);
265 login_backoff = (int)login_getcapnum(lc, "login-backoff",
266 DEFAULT_BACKOFF, DEFAULT_BACKOFF);
267 login_close(lc);
268 lc = NULL;
269 }
270 #endif
271
272 #ifdef KERBEROS5
273 kerror = krb5_init_context(&kcontext);
274 if (kerror) {
275 syslog(LOG_NOTICE, "%s when initializing Kerberos context",
276 error_message(kerror));
277 use_krb5 = 0;
278 }
279 #endif KERBEROS5
280
281 for (cnt = 0;; ask = 1) {
282 #if defined(KERBEROS) || defined(KERBEROS5)
283 kdestroy();
284 #endif
285 if (ask) {
286 fflag = 0;
287 getloginname();
288 }
289 rootlogin = 0;
290 #ifdef KERBEROS
291 if ((instance = strchr(username, '.')) != NULL)
292 *instance++ = '\0';
293 else
294 instance = "";
295 #endif
296 #ifdef KERBEROS5
297 if ((instance = strchr(username, '/')) != NULL)
298 *instance++ = '\0';
299 else
300 instance = "";
301 #endif
302 if (strlen(username) > MAXLOGNAME)
303 username[MAXLOGNAME] = '\0';
304
305 /*
306 * Note if trying multiple user names; log failures for
307 * previous user name, but don't bother logging one failure
308 * for nonexistent name (mistyped username).
309 */
310 if (failures && strcmp(tbuf, username)) {
311 if (failures > (pwd ? 0 : 1))
312 badlogin(tbuf);
313 failures = 0;
314 }
315 (void)strncpy(tbuf, username, sizeof(tbuf) - 1);
316 tbuf[sizeof(tbuf) - 1] = '\0';
317
318 if ((pwd = getpwnam(username)) != NULL)
319 salt = pwd->pw_passwd;
320 else
321 salt = "xx";
322
323 #ifdef LOGIN_CAP
324 /*
325 * Establish the class now, before we might goto
326 * within the next block. pwd can be NULL since it
327 * falls back to the "default" class if it is.
328 */
329 lc = login_getclass(pwd ? pwd->pw_class : NULL);
330 #endif
331 /*
332 * if we have a valid account name, and it doesn't have a
333 * password, or the -f option was specified and the caller
334 * is root or the caller isn't changing their uid, don't
335 * authenticate.
336 */
337 if (pwd) {
338 if (pwd->pw_uid == 0)
339 rootlogin = 1;
340
341 if (fflag && (uid == 0 || uid == pwd->pw_uid)) {
342 /* already authenticated */
343 #ifdef KERBEROS5
344 if (Fflag)
345 k5_read_creds(username);
346 #endif
347 break;
348 } else if (pwd->pw_passwd[0] == '\0') {
349 /* pretend password okay */
350 rval = 0;
351 goto ttycheck;
352 }
353 }
354
355 fflag = 0;
356
357 (void)setpriority(PRIO_PROCESS, 0, -4);
358
359 #ifdef SKEY
360 if (skey_haskey(username) == 0) {
361 static char skprompt[80];
362 char *skinfo = skey_keyinfo(username);
363
364 (void)snprintf(skprompt, sizeof(skprompt)-1,
365 "Password [%s]:",
366 skinfo ? skinfo : "error getting challenge");
367 pwprompt = skprompt;
368 } else
369 #endif
370 pwprompt = "Password:";
371
372 p = getpass(pwprompt);
373
374 if (pwd == NULL) {
375 rval = 1;
376 goto skip;
377 }
378 #ifdef KERBEROS
379 if (klogin(pwd, instance, localhost, p) == 0) {
380 rval = 0;
381 goto skip;
382 }
383 #endif
384 #ifdef KERBEROS5
385 if (klogin(pwd, instance, localhost, p) == 0) {
386 rval = 0;
387 goto skip;
388 }
389 #endif
390 #ifdef SKEY
391 if (skey_haskey(username) == 0 &&
392 skey_passcheck(username, p) != -1) {
393 rval = 0;
394 goto skip;
395 }
396 #endif
397 if (!sflag && *pwd->pw_passwd != '\0' &&
398 !strcmp(crypt(p, pwd->pw_passwd), pwd->pw_passwd)) {
399 rval = 0;
400 require_chpass = 1;
401 goto skip;
402 }
403 rval = 1;
404
405 skip:
406 memset(p, 0, strlen(p));
407
408 (void)setpriority(PRIO_PROCESS, 0, 0);
409
410 ttycheck:
411 /*
412 * If trying to log in as root without Kerberos,
413 * but with insecure terminal, refuse the login attempt.
414 */
415 if (pwd && !rval && rootlogin && !rootterm(tty)) {
416 (void)fprintf(stderr,
417 "%s login refused on this terminal.\n",
418 pwd->pw_name);
419 if (hostname)
420 syslog(LOG_NOTICE,
421 "LOGIN %s REFUSED FROM %s ON TTY %s",
422 pwd->pw_name, hostname, tty);
423 else
424 syslog(LOG_NOTICE,
425 "LOGIN %s REFUSED ON TTY %s",
426 pwd->pw_name, tty);
427 continue;
428 }
429
430 if (pwd && !rval)
431 break;
432
433 (void)printf("Login incorrect\n");
434 failures++;
435 cnt++;
436 /* we allow 10 tries, but after 3 we start backing off */
437 if (cnt > login_backoff) {
438 if (cnt >= login_retries) {
439 badlogin(username);
440 sleepexit(1);
441 }
442 sleep((u_int)((cnt - 3) * 5));
443 }
444 }
445
446 /* committed to login -- turn off timeout */
447 (void)alarm((u_int)0);
448
449 endpwent();
450
451 /* if user not super-user, check for disabled logins */
452 #ifdef LOGIN_CAP
453 if (!login_getcapbool(lc, "ignorenologin", rootlogin))
454 checknologin(login_getcapstr(lc, "nologin", NULL, NULL));
455 #else
456 if (!rootlogin)
457 checknologin(NULL);
458 #endif
459
460 #ifdef LOGIN_CAP
461 quietlog = login_getcapbool(lc, "hushlogin", 0);
462 #else
463 quietlog = 0;
464 #endif
465 /* Temporarily give up special privileges so we can change */
466 /* into NFS-mounted homes that are exported for non-root */
467 /* access and have mode 7x0 */
468 saved_uid = geteuid();
469 saved_gid = getegid();
470 nsaved_gids = getgroups(NGROUPS_MAX, saved_gids);
471
472 (void)setegid(pwd->pw_gid);
473 initgroups(username, pwd->pw_gid);
474 (void)seteuid(pwd->pw_uid);
475
476 if (chdir(pwd->pw_dir) < 0) {
477 #ifdef LOGIN_CAP
478 if (login_getcapbool(lc, "requirehome", 0)) {
479 (void)printf("Home directory %s required\n",
480 pwd->pw_dir);
481 sleepexit(1);
482 }
483 #endif
484 (void)printf("No home directory %s!\n", pwd->pw_dir);
485 if (chdir("/"))
486 exit(0);
487 pwd->pw_dir = "/";
488 (void)printf("Logging in with home = \"/\".\n");
489 }
490
491 if (!quietlog)
492 quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0;
493
494 /* regain special privileges */
495 (void)seteuid(saved_uid);
496 setgroups(nsaved_gids, saved_gids);
497 (void)setegid(saved_gid);
498
499 #ifdef LOGIN_CAP
500 pw_warntime = login_getcaptime(lc, "password-warn",
501 _PASSWORD_WARNDAYS * SECSPERDAY,
502 _PASSWORD_WARNDAYS * SECSPERDAY);
503 #endif
504
505 if (pwd->pw_change || pwd->pw_expire)
506 (void)gettimeofday(&tp, (struct timezone *)NULL);
507 if (pwd->pw_expire) {
508 if (tp.tv_sec >= pwd->pw_expire) {
509 (void)printf("Sorry -- your account has expired.\n");
510 sleepexit(1);
511 } else if (pwd->pw_expire - tp.tv_sec < pw_warntime &&
512 !quietlog)
513 (void)printf("Warning: your account expires on %s",
514 ctime(&pwd->pw_expire));
515 }
516 if (pwd->pw_change) {
517 if (pwd->pw_change == _PASSWORD_CHGNOW)
518 need_chpass = 1;
519 else if (tp.tv_sec >= pwd->pw_change) {
520 (void)printf("Sorry -- your password has expired.\n");
521 sleepexit(1);
522 } else if (pwd->pw_change - tp.tv_sec < pw_warntime &&
523 !quietlog)
524 (void)printf("Warning: your password expires on %s",
525 ctime(&pwd->pw_change));
526
527 }
528 /* Nothing else left to fail -- really log in. */
529 memset((void *)&utmp, 0, sizeof(utmp));
530 (void)time(&utmp.ut_time);
531 (void)strncpy(utmp.ut_name, username, sizeof(utmp.ut_name));
532 if (hostname)
533 (void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host));
534 (void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line));
535 login(&utmp);
536
537 dolastlog(quietlog);
538
539 (void)chown(ttyn, pwd->pw_uid,
540 (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid);
541
542 if (ttyaction(ttyn, "login", pwd->pw_name))
543 (void)printf("Warning: ttyaction failed.\n");
544
545 #if defined(KERBEROS) || defined(KERBEROS5)
546 /* Fork so that we can call kdestroy */
547 if (krbtkfile_env)
548 dofork();
549 #endif
550
551 /* Destroy environment unless user has requested its preservation. */
552 if (!pflag)
553 environ = envinit;
554
555 #ifdef LOGIN_CAP
556 if (setusercontext(lc, pwd, pwd->pw_uid,
557 LOGIN_SETALL & ~LOGIN_SETPATH) != 0) {
558 syslog(LOG_ERR, "setusercontext failed");
559 exit(1);
560 }
561 #else
562 (void)setgid(pwd->pw_gid);
563
564 initgroups(username, pwd->pw_gid);
565
566 if (setlogin(pwd->pw_name) < 0)
567 syslog(LOG_ERR, "setlogin() failure: %m");
568
569 /* Discard permissions last so can't get killed and drop core. */
570 if (rootlogin)
571 (void)setuid(0);
572 else
573 (void)setuid(pwd->pw_uid);
574 #endif
575
576 if (*pwd->pw_shell == '\0')
577 pwd->pw_shell = _PATH_BSHELL;
578 #ifdef LOGIN_CAP
579 if ((shell = login_getcapstr(lc, "shell", NULL, NULL)) != NULL) {
580 if ((shell = strdup(shell)) == NULL) {
581 syslog(LOG_NOTICE, "Cannot alloc mem");
582 sleepexit(1);
583 }
584 pwd->pw_shell = shell;
585 }
586 #endif
587
588 (void)setenv("HOME", pwd->pw_dir, 1);
589 (void)setenv("SHELL", pwd->pw_shell, 1);
590 if (term[0] == '\0') {
591 char *tt = (char *)stypeof(tty);
592 #ifdef LOGIN_CAP
593 if (tt == NULL)
594 tt = login_getcapstr(lc, "term", NULL, NULL);
595 #endif
596 /* unknown term -> "su" */
597 (void)strncpy(term, tt != NULL ? tt : "su", sizeof(term));
598 }
599 (void)setenv("TERM", term, 0);
600 (void)setenv("LOGNAME", pwd->pw_name, 1);
601 (void)setenv("USER", pwd->pw_name, 1);
602
603 #ifdef LOGIN_CAP
604 setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETPATH);
605 #else
606 (void)setenv("PATH", _PATH_DEFPATH, 0);
607 #endif
608
609 #ifdef KERBEROS
610 if (krbtkfile_env)
611 (void)setenv("KRBTKFILE", krbtkfile_env, 1);
612 #endif
613 #ifdef KERBEROS5
614 if (krbtkfile_env)
615 (void)setenv("KRB5CCNAME", krbtkfile_env, 1);
616 #endif
617
618 if (tty[sizeof("tty")-1] == 'd')
619 syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
620
621 /* If fflag is on, assume caller/authenticator has logged root login. */
622 if (rootlogin && fflag == 0) {
623 if (hostname)
624 syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s",
625 username, tty, hostname);
626 else
627 syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s",
628 username, tty);
629 }
630
631 #if defined(KERBEROS) || defined(KERBEROS5)
632 if (!quietlog && notickets == 1)
633 (void)printf("Warning: no Kerberos tickets issued.\n");
634 #endif
635
636 if (!quietlog) {
637 char *fname;
638 #ifdef LOGIN_CAP
639 fname = login_getcapstr(lc, "copyright", NULL, NULL);
640 if (fname != NULL && access(fname, F_OK) == 0)
641 motd(fname);
642 else
643 #endif
644 (void)printf(copyrightstr);
645
646 #ifdef LOGIN_CAP
647 fname = login_getcapstr(lc, "welcome", NULL, NULL);
648 if (fname == NULL || access(fname, F_OK) != 0)
649 #endif
650 fname = _PATH_MOTDFILE;
651 motd(fname);
652
653 (void)snprintf(tbuf,
654 sizeof(tbuf), "%s/%s", _PATH_MAILDIR, pwd->pw_name);
655 if (stat(tbuf, &st) == 0 && st.st_size != 0)
656 (void)printf("You have %smail.\n",
657 (st.st_mtime > st.st_atime) ? "new " : "");
658 }
659
660 #ifdef LOGIN_CAP
661 login_close(lc);
662 #endif
663
664 (void)signal(SIGALRM, SIG_DFL);
665 (void)signal(SIGQUIT, SIG_DFL);
666 (void)signal(SIGINT, SIG_DFL);
667 (void)signal(SIGTSTP, SIG_IGN);
668
669 tbuf[0] = '-';
670 (void)strncpy(tbuf + 1, (p = strrchr(pwd->pw_shell, '/')) ?
671 p + 1 : pwd->pw_shell, sizeof(tbuf) - 2);
672
673 /* Wait to change password until we're unprivileged */
674 if (need_chpass) {
675 if (!require_chpass)
676 (void)printf(
677 "Warning: your password has expired. Please change it as soon as possible.\n");
678 else {
679 int status;
680
681 (void)printf(
682 "Your password has expired. Please choose a new one.\n");
683 switch (fork()) {
684 case -1:
685 warn("fork");
686 sleepexit(1);
687 case 0:
688 execl(_PATH_BINPASSWD, "passwd", 0);
689 _exit(1);
690 default:
691 if (wait(&status) == -1 ||
692 WEXITSTATUS(status))
693 sleepexit(1);
694 }
695 }
696 }
697
698 #ifdef KERBEROS5
699 k5_write_creds();
700 #endif
701 execlp(pwd->pw_shell, tbuf, 0);
702 err(1, "%s", pwd->pw_shell);
703 }
704
705 #if defined(KERBEROS) || defined(KERBEROS5)
706 #define NBUFSIZ (MAXLOGNAME + 1 + 5) /* .root suffix */
707 #else
708 #define NBUFSIZ (MAXLOGNAME + 1)
709 #endif
710
711 #if defined(KERBEROS) || defined(KERBEROS5)
712 /*
713 * This routine handles cleanup stuff, and the like.
714 * It exists only in the child process.
715 */
716 #include <sys/wait.h>
717 void
718 dofork()
719 {
720 int child;
721
722 if (!(child = fork()))
723 return; /* Child process */
724
725 /*
726 * Setup stuff? This would be things we could do in parallel
727 * with login
728 */
729 (void)chdir("/"); /* Let's not keep the fs busy... */
730
731 /* If we're the parent, watch the child until it dies */
732 while (wait(0) != child)
733 ;
734
735 /* Cleanup stuff */
736 /* Run kdestroy to destroy tickets */
737 kdestroy();
738
739 /* Leave */
740 exit(0);
741 }
742 #endif
743
744 void
745 getloginname()
746 {
747 int ch;
748 char *p;
749 static char nbuf[NBUFSIZ];
750
751 for (;;) {
752 (void)printf("login: ");
753 for (p = nbuf; (ch = getchar()) != '\n'; ) {
754 if (ch == EOF) {
755 badlogin(username);
756 exit(0);
757 }
758 if (p < nbuf + (NBUFSIZ - 1))
759 *p++ = ch;
760 }
761 if (p > nbuf) {
762 if (nbuf[0] == '-')
763 (void)fprintf(stderr,
764 "login names may not start with '-'.\n");
765 else {
766 *p = '\0';
767 username = nbuf;
768 break;
769 }
770 }
771 }
772 }
773
774 int
775 rootterm(ttyn)
776 char *ttyn;
777 {
778 struct ttyent *t;
779
780 return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE);
781 }
782
783 jmp_buf motdinterrupt;
784
785 void
786 motd(fname)
787 char *fname;
788 {
789 int fd, nchars;
790 sig_t oldint;
791 char tbuf[8192];
792
793 if ((fd = open(fname ? fname : _PATH_MOTDFILE, O_RDONLY, 0)) < 0)
794 return;
795 oldint = signal(SIGINT, sigint);
796 if (setjmp(motdinterrupt) == 0)
797 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
798 (void)write(fileno(stdout), tbuf, nchars);
799 (void)signal(SIGINT, oldint);
800 (void)close(fd);
801 }
802
803 /* ARGSUSED */
804 void
805 sigint(signo)
806 int signo;
807 {
808
809 longjmp(motdinterrupt, 1);
810 }
811
812 /* ARGSUSED */
813 void
814 timedout(signo)
815 int signo;
816 {
817
818 (void)fprintf(stderr, "Login timed out after %d seconds\n", timeout);
819 exit(0);
820 }
821
822 void
823 checknologin(fname)
824 char *fname;
825 {
826 int fd, nchars;
827 char tbuf[8192];
828
829 if ((fd = open(fname ? fname : _PATH_NOLOGIN, O_RDONLY, 0)) >= 0) {
830 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
831 (void)write(fileno(stdout), tbuf, nchars);
832 sleepexit(0);
833 }
834 }
835
836 void
837 dolastlog(quiet)
838 int quiet;
839 {
840 struct lastlog ll;
841 int fd;
842
843 if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) {
844 (void)lseek(fd, (off_t)(pwd->pw_uid * sizeof(ll)), SEEK_SET);
845 if (!quiet) {
846 if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) &&
847 ll.ll_time != 0) {
848 (void)printf("Last login: %.*s ",
849 24, (char *)ctime(&ll.ll_time));
850 if (*ll.ll_host != '\0')
851 (void)printf("from %.*s\n",
852 (int)sizeof(ll.ll_host),
853 ll.ll_host);
854 else
855 (void)printf("on %.*s\n",
856 (int)sizeof(ll.ll_line),
857 ll.ll_line);
858 }
859 (void)lseek(fd, (off_t)(pwd->pw_uid * sizeof(ll)),
860 SEEK_SET);
861 }
862 memset((void *)&ll, 0, sizeof(ll));
863 (void)time(&ll.ll_time);
864 (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
865 if (hostname)
866 (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host));
867 (void)write(fd, (char *)&ll, sizeof(ll));
868 (void)close(fd);
869 }
870 }
871
872 void
873 badlogin(name)
874 char *name;
875 {
876
877 if (failures == 0)
878 return;
879 if (hostname) {
880 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s",
881 failures, failures > 1 ? "S" : "", hostname);
882 syslog(LOG_AUTHPRIV|LOG_NOTICE,
883 "%d LOGIN FAILURE%s FROM %s, %s",
884 failures, failures > 1 ? "S" : "", hostname, name);
885 } else {
886 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s",
887 failures, failures > 1 ? "S" : "", tty);
888 syslog(LOG_AUTHPRIV|LOG_NOTICE,
889 "%d LOGIN FAILURE%s ON %s, %s",
890 failures, failures > 1 ? "S" : "", tty, name);
891 }
892 }
893
894 const char *
895 stypeof(ttyid)
896 const char *ttyid;
897 {
898 struct ttyent *t;
899
900 return (ttyid && (t = getttynam(ttyid)) ? t->ty_type : NULL);
901 }
902
903 void
904 sleepexit(eval)
905 int eval;
906 {
907
908 (void)sleep(5);
909 exit(eval);
910 }
911