login.c revision 1.52 1 /* $NetBSD: login.c,v 1.52 2000/01/22 09:48:52 mjl 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.52 2000/01/22 09:48:52 mjl 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 <kerberosIV/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 #ifdef LOGIN_CAP
551 if (setusercontext(lc, pwd, pwd->pw_uid,
552 LOGIN_SETALL & ~LOGIN_SETPATH) != 0) {
553 syslog(LOG_ERR, "setusercontext failed");
554 exit(1);
555 }
556 #else
557 (void)setgid(pwd->pw_gid);
558
559 initgroups(username, pwd->pw_gid);
560
561 if (setlogin(pwd->pw_name) < 0)
562 syslog(LOG_ERR, "setlogin() failure: %m");
563
564 /* Discard permissions last so can't get killed and drop core. */
565 if (rootlogin)
566 (void)setuid(0);
567 else
568 (void)setuid(pwd->pw_uid);
569 #endif
570
571 if (*pwd->pw_shell == '\0')
572 pwd->pw_shell = _PATH_BSHELL;
573 #ifdef LOGIN_CAP
574 if((shell = login_getcapstr(lc, "shell", NULL, NULL))) {
575 if(!(shell = strdup(shell))) {
576 syslog(LOG_NOTICE, "Cannot alloc mem");
577 sleepexit(1);
578 }
579 pwd->pw_shell = shell;
580 }
581 #endif
582
583 /* Destroy environment unless user has requested its preservation. */
584 if (!pflag)
585 environ = envinit;
586 (void)setenv("HOME", pwd->pw_dir, 1);
587 (void)setenv("SHELL", pwd->pw_shell, 1);
588 if (term[0] == '\0') {
589 char *tt = (char *) stypeof(tty);
590 #ifdef LOGIN_CAP
591 if(!tt)
592 tt = login_getcapstr(lc, "term", NULL, NULL);
593 #endif
594 /* unknown term -> "su" */
595 (void)strncpy(term, tt ? tt : "su", sizeof(term));
596 }
597 (void)setenv("TERM", term, 0);
598 (void)setenv("LOGNAME", pwd->pw_name, 1);
599 (void)setenv("USER", pwd->pw_name, 1);
600
601 #ifdef LOGIN_CAP
602 setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETPATH);
603 #else
604 (void)setenv("PATH", _PATH_DEFPATH, 0);
605 #endif
606
607 #ifdef KERBEROS
608 if (krbtkfile_env)
609 (void)setenv("KRBTKFILE", krbtkfile_env, 1);
610 #endif
611 #ifdef KERBEROS5
612 if (krbtkfile_env)
613 (void)setenv("KRB5CCNAME", krbtkfile_env, 1);
614 #endif
615
616 if (tty[sizeof("tty")-1] == 'd')
617 syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
618
619 /* If fflag is on, assume caller/authenticator has logged root login. */
620 if (rootlogin && fflag == 0) {
621 if (hostname)
622 syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s",
623 username, tty, hostname);
624 else
625 syslog(LOG_NOTICE,
626 "ROOT LOGIN (%s) ON %s", username, tty);
627 }
628
629 #if defined(KERBEROS) || defined(KERBEROS5)
630 if (!quietlog && notickets == 1)
631 (void)printf("Warning: no Kerberos tickets issued.\n");
632 #endif
633
634 if (!quietlog) {
635 char *fname;
636 #ifdef LOGIN_CAP
637 fname = login_getcapstr(lc, "copyright", NULL, NULL);
638 if (fname && access(fname, F_OK) == 0)
639 motd(fname);
640 else
641 (void)printf(copyrightstr);
642 #else
643 (void)printf(copyrightstr);
644 #endif
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 /* Setup stuff? This would be things we could do in parallel with login */
726 (void) chdir("/"); /* Let's not keep the fs busy... */
727
728 /* If we're the parent, watch the child until it dies */
729 while (wait(0) != child)
730 ;
731
732 /* Cleanup stuff */
733 /* Run kdestroy to destroy tickets */
734 kdestroy();
735
736 /* Leave */
737 exit(0);
738 }
739 #endif
740
741 void
742 getloginname()
743 {
744 int ch;
745 char *p;
746 static char nbuf[NBUFSIZ];
747
748 for (;;) {
749 (void)printf("login: ");
750 for (p = nbuf; (ch = getchar()) != '\n'; ) {
751 if (ch == EOF) {
752 badlogin(username);
753 exit(0);
754 }
755 if (p < nbuf + (NBUFSIZ - 1))
756 *p++ = ch;
757 }
758 if (p > nbuf) {
759 if (nbuf[0] == '-')
760 (void)fprintf(stderr,
761 "login names may not start with '-'.\n");
762 else {
763 *p = '\0';
764 username = nbuf;
765 break;
766 }
767 }
768 }
769 }
770
771 int
772 rootterm(ttyn)
773 char *ttyn;
774 {
775 struct ttyent *t;
776
777 return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE);
778 }
779
780 jmp_buf motdinterrupt;
781
782 void
783 motd(fname)
784 char *fname;
785 {
786 int fd, nchars;
787 sig_t oldint;
788 char tbuf[8192];
789
790 if ((fd = open(fname ? fname : _PATH_MOTDFILE, O_RDONLY, 0)) < 0)
791 return;
792 oldint = signal(SIGINT, sigint);
793 if (setjmp(motdinterrupt) == 0)
794 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
795 (void)write(fileno(stdout), tbuf, nchars);
796 (void)signal(SIGINT, oldint);
797 (void)close(fd);
798 }
799
800 /* ARGSUSED */
801 void
802 sigint(signo)
803 int signo;
804 {
805
806 longjmp(motdinterrupt, 1);
807 }
808
809 /* ARGSUSED */
810 void
811 timedout(signo)
812 int signo;
813 {
814
815 (void)fprintf(stderr, "Login timed out after %d seconds\n", timeout);
816 exit(0);
817 }
818
819 void
820 checknologin(fname)
821 char *fname;
822 {
823 int fd, nchars;
824 char tbuf[8192];
825
826 if ((fd = open(fname ? fname : _PATH_NOLOGIN, O_RDONLY, 0)) >= 0) {
827 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
828 (void)write(fileno(stdout), tbuf, nchars);
829 sleepexit(0);
830 }
831 }
832
833 void
834 dolastlog(quiet)
835 int quiet;
836 {
837 struct lastlog ll;
838 int fd;
839
840 if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) {
841 (void)lseek(fd, (off_t)(pwd->pw_uid * sizeof(ll)), SEEK_SET);
842 if (!quiet) {
843 if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) &&
844 ll.ll_time != 0) {
845 (void)printf("Last login: %.*s ",
846 24, (char *)ctime(&ll.ll_time));
847 if (*ll.ll_host != '\0')
848 (void)printf("from %.*s\n",
849 (int)sizeof(ll.ll_host),
850 ll.ll_host);
851 else
852 (void)printf("on %.*s\n",
853 (int)sizeof(ll.ll_line),
854 ll.ll_line);
855 }
856 (void)lseek(fd, (off_t)(pwd->pw_uid * sizeof(ll)),
857 SEEK_SET);
858 }
859 memset((void *)&ll, 0, sizeof(ll));
860 (void)time(&ll.ll_time);
861 (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
862 if (hostname)
863 (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host));
864 (void)write(fd, (char *)&ll, sizeof(ll));
865 (void)close(fd);
866 }
867 }
868
869 void
870 badlogin(name)
871 char *name;
872 {
873 if (failures == 0)
874 return;
875 if (hostname) {
876 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s",
877 failures, failures > 1 ? "S" : "", hostname);
878 syslog(LOG_AUTHPRIV|LOG_NOTICE,
879 "%d LOGIN FAILURE%s FROM %s, %s",
880 failures, failures > 1 ? "S" : "", hostname, name);
881 } else {
882 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s",
883 failures, failures > 1 ? "S" : "", tty);
884 syslog(LOG_AUTHPRIV|LOG_NOTICE,
885 "%d LOGIN FAILURE%s ON %s, %s",
886 failures, failures > 1 ? "S" : "", tty, name);
887 }
888 }
889
890 const char *
891 stypeof(ttyid)
892 const char *ttyid;
893 {
894 struct ttyent *t;
895
896 return (ttyid && (t = getttynam(ttyid)) ? t->ty_type : NULL);
897 }
898
899 void
900 sleepexit(eval)
901 int eval;
902 {
903
904 (void)sleep(5);
905 exit(eval);
906 }
907