login.c revision 1.54 1 /* $NetBSD: login.c,v 1.54 2000/02/14 03:21:02 aidan 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.54 2000/02/14 03:21:02 aidan 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
141 \tThe NetBSD Foundation, Inc. All rights reserved.
142 Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994
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)))
263 {
264 login_retries = (int) login_getcapnum(lc, "login-retries",
265 DEFAULT_RETRIES, DEFAULT_RETRIES);
266 login_backoff = (int) login_getcapnum(lc, "login-backoff",
267 DEFAULT_BACKOFF, DEFAULT_BACKOFF);
268 login_close(lc);
269 lc = NULL;
270 }
271 #endif
272
273 #ifdef KERBEROS5
274 kerror = krb5_init_context(&kcontext);
275 if (kerror) {
276 syslog(LOG_NOTICE, "%s when initializing Kerberos context",
277 error_message(kerror));
278 use_krb5 = 0;
279 }
280 #endif KERBEROS5
281
282 for (cnt = 0;; ask = 1) {
283 #if defined(KERBEROS) || defined(KERBEROS5)
284 kdestroy();
285 #endif
286 if (ask) {
287 fflag = 0;
288 getloginname();
289 }
290 rootlogin = 0;
291 #ifdef KERBEROS
292 if ((instance = strchr(username, '.')) != NULL)
293 *instance++ = '\0';
294 else
295 instance = "";
296 #endif
297 #ifdef KERBEROS5
298 if ((instance = strchr(username, '/')) != NULL)
299 *instance++ = '\0';
300 else
301 instance = "";
302 #endif
303 if (strlen(username) > MAXLOGNAME)
304 username[MAXLOGNAME] = '\0';
305
306 /*
307 * Note if trying multiple user names; log failures for
308 * previous user name, but don't bother logging one failure
309 * for nonexistent name (mistyped username).
310 */
311 if (failures && strcmp(tbuf, username)) {
312 if (failures > (pwd ? 0 : 1))
313 badlogin(tbuf);
314 failures = 0;
315 }
316 (void)strncpy(tbuf, username, sizeof(tbuf) - 1);
317 tbuf[sizeof(tbuf) - 1] = '\0';
318
319 if ((pwd = getpwnam(username)) != NULL)
320 salt = pwd->pw_passwd;
321 else
322 salt = "xx";
323
324 #ifdef LOGIN_CAP
325 /*
326 * Establish the class now, before we might goto
327 * within the next block. pwd can be NULL since it
328 * falls back to the "default" class if it is.
329 */
330 lc = login_getclass(pwd ? pwd->pw_class : NULL);
331 #endif
332 /*
333 * if we have a valid account name, and it doesn't have a
334 * password, or the -f option was specified and the caller
335 * is root or the caller isn't changing their uid, don't
336 * authenticate.
337 */
338 if (pwd) {
339 if (pwd->pw_uid == 0)
340 rootlogin = 1;
341
342 if (fflag && (uid == 0 || uid == pwd->pw_uid)) {
343 /* already authenticated */
344 #ifdef KERBEROS5
345 if (Fflag)
346 k5_read_creds(username);
347 #endif
348 break;
349 } else if (pwd->pw_passwd[0] == '\0') {
350 /* pretend password okay */
351 rval = 0;
352 goto ttycheck;
353 }
354 }
355
356 fflag = 0;
357
358 (void)setpriority(PRIO_PROCESS, 0, -4);
359
360 #ifdef SKEY
361 if (skey_haskey(username) == 0) {
362 static char skprompt[80];
363 char *skinfo = skey_keyinfo(username);
364
365 (void)snprintf(skprompt, sizeof(skprompt)-1,
366 "Password [%s]:",
367 skinfo ? skinfo : "error getting challenge");
368 pwprompt = skprompt;
369 } else
370 #endif
371 pwprompt = "Password:";
372
373 p = getpass(pwprompt);
374
375 if (pwd == NULL) {
376 rval = 1;
377 goto skip;
378 }
379 #ifdef KERBEROS
380 if (klogin(pwd, instance, localhost, p) == 0) {
381 rval = 0;
382 goto skip;
383 }
384 #endif
385 #ifdef KERBEROS5
386 if (klogin(pwd, instance, localhost, p) == 0) {
387 rval = 0;
388 goto skip;
389 }
390 #endif
391 #ifdef SKEY
392 if (skey_haskey(username) == 0 &&
393 skey_passcheck(username, p) != -1) {
394 rval = 0;
395 goto skip;
396 }
397 #endif
398 if (!sflag && *pwd->pw_passwd != '\0' &&
399 !strcmp(crypt(p, pwd->pw_passwd), pwd->pw_passwd)) {
400 rval = 0;
401 require_chpass = 1;
402 goto skip;
403 }
404 rval = 1;
405
406 skip:
407 memset(p, 0, strlen(p));
408
409 (void)setpriority(PRIO_PROCESS, 0, 0);
410
411 ttycheck:
412 /*
413 * If trying to log in as root without Kerberos,
414 * but with insecure terminal, refuse the login attempt.
415 */
416 if (pwd && !rval && rootlogin && !rootterm(tty)) {
417 (void)fprintf(stderr,
418 "%s login refused on this terminal.\n",
419 pwd->pw_name);
420 if (hostname)
421 syslog(LOG_NOTICE,
422 "LOGIN %s REFUSED FROM %s ON TTY %s",
423 pwd->pw_name, hostname, tty);
424 else
425 syslog(LOG_NOTICE,
426 "LOGIN %s REFUSED ON TTY %s",
427 pwd->pw_name, tty);
428 continue;
429 }
430
431 if (pwd && !rval)
432 break;
433
434 (void)printf("Login incorrect\n");
435 failures++;
436 cnt++;
437 /* we allow 10 tries, but after 3 we start backing off */
438 if (cnt > login_backoff) {
439 if (cnt >= login_retries) {
440 badlogin(username);
441 sleepexit(1);
442 }
443 sleep((u_int)((cnt - 3) * 5));
444 }
445 }
446
447 /* committed to login -- turn off timeout */
448 (void)alarm((u_int)0);
449
450 endpwent();
451
452 /* if user not super-user, check for disabled logins */
453 #ifdef LOGIN_CAP
454 if (!rootlogin || login_getcapbool(lc, "ignorenologin", 0))
455 checknologin(login_getcapstr(lc, "nologin", NULL, NULL));
456 #else
457 if (!rootlogin)
458 checknologin(NULL);
459 #endif
460
461 #ifdef LOGIN_CAP
462 quietlog = login_getcapbool(lc, "hushlogin", 0);
463 #else
464 quietlog = 0;
465 #endif
466 /* Temporarily give up special privileges so we can change */
467 /* into NFS-mounted homes that are exported for non-root */
468 /* access and have mode 7x0 */
469 saved_uid = geteuid();
470 saved_gid = getegid();
471 nsaved_gids = getgroups(NGROUPS_MAX, saved_gids);
472
473 (void)setegid(pwd->pw_gid);
474 initgroups(username, pwd->pw_gid);
475 (void)seteuid(pwd->pw_uid);
476
477 if (chdir(pwd->pw_dir) < 0) {
478 #ifdef LOGIN_CAP
479 if (login_getcapbool(lc, "requirehome", 0)) {
480 (void) printf("Home directory %s required\n", 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))) {
580 if(!(shell = strdup(shell))) {
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)
594 tt = login_getcapstr(lc, "term", NULL, NULL);
595 #endif
596 /* unknown term -> "su" */
597 (void)strncpy(term, tt ? 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,
628 "ROOT LOGIN (%s) ON %s", 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 && access(fname, F_OK) == 0)
641 motd(fname);
642 else
643 (void)printf(copyrightstr);
644 #else
645 (void)printf(copyrightstr);
646 #endif
647
648 #ifdef LOGIN_CAP
649 fname = login_getcapstr(lc, "welcome", NULL, NULL);
650 if (fname == NULL || access(fname, F_OK) != 0)
651 #endif
652 fname = _PATH_MOTDFILE;
653 motd(fname);
654
655 (void)snprintf(tbuf,
656 sizeof(tbuf), "%s/%s", _PATH_MAILDIR, pwd->pw_name);
657 if (stat(tbuf, &st) == 0 && st.st_size != 0)
658 (void)printf("You have %smail.\n",
659 (st.st_mtime > st.st_atime) ? "new " : "");
660 }
661
662 #ifdef LOGIN_CAP
663 login_close(lc);
664 #endif
665
666 (void)signal(SIGALRM, SIG_DFL);
667 (void)signal(SIGQUIT, SIG_DFL);
668 (void)signal(SIGINT, SIG_DFL);
669 (void)signal(SIGTSTP, SIG_IGN);
670
671 tbuf[0] = '-';
672 (void)strncpy(tbuf + 1, (p = strrchr(pwd->pw_shell, '/')) ?
673 p + 1 : pwd->pw_shell, sizeof(tbuf) - 2);
674
675 /* Wait to change password until we're unprivileged */
676 if (need_chpass) {
677 if (!require_chpass)
678 (void)printf(
679 "Warning: your password has expired. Please change it as soon as possible.\n");
680 else {
681 int status;
682
683 (void)printf(
684 "Your password has expired. Please choose a new one.\n");
685 switch (fork()) {
686 case -1:
687 warn("fork");
688 sleepexit(1);
689 case 0:
690 execl(_PATH_BINPASSWD, "passwd", 0);
691 _exit(1);
692 default:
693 if (wait(&status) == -1 ||
694 WEXITSTATUS(status))
695 sleepexit(1);
696 }
697 }
698 }
699
700 #ifdef KERBEROS5
701 k5_write_creds();
702 #endif
703 execlp(pwd->pw_shell, tbuf, 0);
704 err(1, "%s", pwd->pw_shell);
705 }
706
707 #if defined(KERBEROS) || defined(KERBEROS5)
708 #define NBUFSIZ (MAXLOGNAME + 1 + 5) /* .root suffix */
709 #else
710 #define NBUFSIZ (MAXLOGNAME + 1)
711 #endif
712
713 #if defined(KERBEROS) || defined(KERBEROS5)
714 /*
715 * This routine handles cleanup stuff, and the like.
716 * It exists only in the child process.
717 */
718 #include <sys/wait.h>
719 void
720 dofork()
721 {
722 int child;
723
724 if (!(child = fork()))
725 return; /* Child process */
726
727 /* Setup stuff? This would be things we could do in parallel with login */
728 (void) chdir("/"); /* Let's not keep the fs busy... */
729
730 /* If we're the parent, watch the child until it dies */
731 while (wait(0) != child)
732 ;
733
734 /* Cleanup stuff */
735 /* Run kdestroy to destroy tickets */
736 kdestroy();
737
738 /* Leave */
739 exit(0);
740 }
741 #endif
742
743 void
744 getloginname()
745 {
746 int ch;
747 char *p;
748 static char nbuf[NBUFSIZ];
749
750 for (;;) {
751 (void)printf("login: ");
752 for (p = nbuf; (ch = getchar()) != '\n'; ) {
753 if (ch == EOF) {
754 badlogin(username);
755 exit(0);
756 }
757 if (p < nbuf + (NBUFSIZ - 1))
758 *p++ = ch;
759 }
760 if (p > nbuf) {
761 if (nbuf[0] == '-')
762 (void)fprintf(stderr,
763 "login names may not start with '-'.\n");
764 else {
765 *p = '\0';
766 username = nbuf;
767 break;
768 }
769 }
770 }
771 }
772
773 int
774 rootterm(ttyn)
775 char *ttyn;
776 {
777 struct ttyent *t;
778
779 return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE);
780 }
781
782 jmp_buf motdinterrupt;
783
784 void
785 motd(fname)
786 char *fname;
787 {
788 int fd, nchars;
789 sig_t oldint;
790 char tbuf[8192];
791
792 if ((fd = open(fname ? fname : _PATH_MOTDFILE, O_RDONLY, 0)) < 0)
793 return;
794 oldint = signal(SIGINT, sigint);
795 if (setjmp(motdinterrupt) == 0)
796 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
797 (void)write(fileno(stdout), tbuf, nchars);
798 (void)signal(SIGINT, oldint);
799 (void)close(fd);
800 }
801
802 /* ARGSUSED */
803 void
804 sigint(signo)
805 int signo;
806 {
807
808 longjmp(motdinterrupt, 1);
809 }
810
811 /* ARGSUSED */
812 void
813 timedout(signo)
814 int signo;
815 {
816
817 (void)fprintf(stderr, "Login timed out after %d seconds\n", timeout);
818 exit(0);
819 }
820
821 void
822 checknologin(fname)
823 char *fname;
824 {
825 int fd, nchars;
826 char tbuf[8192];
827
828 if ((fd = open(fname ? fname : _PATH_NOLOGIN, O_RDONLY, 0)) >= 0) {
829 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
830 (void)write(fileno(stdout), tbuf, nchars);
831 sleepexit(0);
832 }
833 }
834
835 void
836 dolastlog(quiet)
837 int quiet;
838 {
839 struct lastlog ll;
840 int fd;
841
842 if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) {
843 (void)lseek(fd, (off_t)(pwd->pw_uid * sizeof(ll)), SEEK_SET);
844 if (!quiet) {
845 if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) &&
846 ll.ll_time != 0) {
847 (void)printf("Last login: %.*s ",
848 24, (char *)ctime(&ll.ll_time));
849 if (*ll.ll_host != '\0')
850 (void)printf("from %.*s\n",
851 (int)sizeof(ll.ll_host),
852 ll.ll_host);
853 else
854 (void)printf("on %.*s\n",
855 (int)sizeof(ll.ll_line),
856 ll.ll_line);
857 }
858 (void)lseek(fd, (off_t)(pwd->pw_uid * sizeof(ll)),
859 SEEK_SET);
860 }
861 memset((void *)&ll, 0, sizeof(ll));
862 (void)time(&ll.ll_time);
863 (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
864 if (hostname)
865 (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host));
866 (void)write(fd, (char *)&ll, sizeof(ll));
867 (void)close(fd);
868 }
869 }
870
871 void
872 badlogin(name)
873 char *name;
874 {
875 if (failures == 0)
876 return;
877 if (hostname) {
878 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s",
879 failures, failures > 1 ? "S" : "", hostname);
880 syslog(LOG_AUTHPRIV|LOG_NOTICE,
881 "%d LOGIN FAILURE%s FROM %s, %s",
882 failures, failures > 1 ? "S" : "", hostname, name);
883 } else {
884 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s",
885 failures, failures > 1 ? "S" : "", tty);
886 syslog(LOG_AUTHPRIV|LOG_NOTICE,
887 "%d LOGIN FAILURE%s ON %s, %s",
888 failures, failures > 1 ? "S" : "", tty, name);
889 }
890 }
891
892 const char *
893 stypeof(ttyid)
894 const char *ttyid;
895 {
896 struct ttyent *t;
897
898 return (ttyid && (t = getttynam(ttyid)) ? t->ty_type : NULL);
899 }
900
901 void
902 sleepexit(eval)
903 int eval;
904 {
905
906 (void)sleep(5);
907 exit(eval);
908 }
909