login.c revision 1.48 1 /* $NetBSD: login.c,v 1.48 2000/01/13 06:17:56 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.48 2000/01/13 06:17:56 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 10
116 #define DEFAULT_RETRIES 3
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 char *shell = NULL;
169 #ifdef KERBEROS5
170 krb5_error_code kerror;
171 #endif
172 #ifdef LOGIN_CAP
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 if (pwd != NULL)
331 lc = login_getclass(pwd->pw_class);
332 #endif
333
334 /*
335 * if we have a valid account name, and it doesn't have a
336 * password, or the -f option was specified and the caller
337 * is root or the caller isn't changing their uid, don't
338 * authenticate.
339 */
340 if (pwd) {
341 if (pwd->pw_uid == 0)
342 rootlogin = 1;
343
344 if (fflag && (uid == 0 || uid == pwd->pw_uid)) {
345 /* already authenticated */
346 #ifdef KERBEROS5
347 if (Fflag)
348 k5_read_creds(username);
349 #endif
350 break;
351 } else if (pwd->pw_passwd[0] == '\0') {
352 /* pretend password okay */
353 rval = 0;
354 goto ttycheck;
355 }
356 }
357
358 fflag = 0;
359
360 (void)setpriority(PRIO_PROCESS, 0, -4);
361
362 #ifdef SKEY
363 if (skey_haskey(username) == 0) {
364 static char skprompt[80];
365 char *skinfo = skey_keyinfo(username);
366
367 (void)snprintf(skprompt, sizeof(skprompt)-1,
368 "Password [%s]:",
369 skinfo ? skinfo : "error getting challenge");
370 pwprompt = skprompt;
371 } else
372 #endif
373 pwprompt = "Password:";
374
375 p = getpass(pwprompt);
376
377 if (pwd == NULL) {
378 rval = 1;
379 goto skip;
380 }
381 #ifdef KERBEROS
382 if (klogin(pwd, instance, localhost, p) == 0) {
383 rval = 0;
384 goto skip;
385 }
386 #endif
387 #ifdef KERBEROS5
388 if (klogin(pwd, instance, localhost, p) == 0) {
389 rval = 0;
390 goto skip;
391 }
392 #endif
393 #ifdef SKEY
394 if (skey_haskey(username) == 0 &&
395 skey_passcheck(username, p) != -1) {
396 rval = 0;
397 goto skip;
398 }
399 #endif
400 if (!sflag && *pwd->pw_passwd != '\0' &&
401 !strcmp(crypt(p, pwd->pw_passwd), pwd->pw_passwd)) {
402 rval = 0;
403 require_chpass = 1;
404 goto skip;
405 }
406 rval = 1;
407
408 skip:
409 memset(p, 0, strlen(p));
410
411 (void)setpriority(PRIO_PROCESS, 0, 0);
412
413 ttycheck:
414 /*
415 * If trying to log in as root without Kerberos,
416 * but with insecure terminal, refuse the login attempt.
417 */
418 if (pwd && !rval && rootlogin && !rootterm(tty)) {
419 (void)fprintf(stderr,
420 "%s login refused on this terminal.\n",
421 pwd->pw_name);
422 if (hostname)
423 syslog(LOG_NOTICE,
424 "LOGIN %s REFUSED FROM %s ON TTY %s",
425 pwd->pw_name, hostname, tty);
426 else
427 syslog(LOG_NOTICE,
428 "LOGIN %s REFUSED ON TTY %s",
429 pwd->pw_name, tty);
430 continue;
431 }
432
433 if (pwd && !rval)
434 break;
435
436 (void)printf("Login incorrect\n");
437 failures++;
438 cnt++;
439 /* we allow 10 tries, but after 3 we start backing off */
440 if (cnt > login_backoff || cnt >= login_retries) {
441 if (cnt >= login_retries) {
442 badlogin(username);
443 sleepexit(1);
444 }
445 sleep((u_int)((cnt - 3) * 5));
446 }
447 }
448
449 /* committed to login -- turn off timeout */
450 (void)alarm((u_int)0);
451
452 endpwent();
453
454 /* if user not super-user, check for disabled logins */
455 #ifdef LOGIN_CAP
456 if (!rootlogin || login_getcapbool(lc, "ignorenologin", 0)) {
457 char *fname;
458
459 fname = login_getcapstr(lc, "nologin", NULL, NULL);
460 checknologin(fname);
461 }
462 #else
463 if (!rootlogin)
464 checknologin(NULL);
465 #endif
466
467 #ifdef LOGIN_CAP
468 quietlog = login_getcapbool(lc, "hushlogin", 0);
469 #else
470 quietlog = 0;
471 #endif
472 /* Temporarily give up special privileges so we can change */
473 /* into NFS-mounted homes that are exported for non-root */
474 /* access and have mode 7x0 */
475 saved_uid = geteuid();
476 saved_gid = getegid();
477 nsaved_gids = getgroups(NGROUPS_MAX, saved_gids);
478
479 (void)setegid(pwd->pw_gid);
480 initgroups(username, pwd->pw_gid);
481 (void)seteuid(pwd->pw_uid);
482
483 if (chdir(pwd->pw_dir) < 0) {
484 #ifdef LOGIN_CAP
485 if (login_getcapbool(lc, "requirehome", 0)) {
486 (void) printf("Home directory %s required\n", pwd->pw_dir);
487 sleepexit(1);
488 }
489 #endif
490 (void)printf("No home directory %s!\n", pwd->pw_dir);
491 if (chdir("/"))
492 exit(0);
493 pwd->pw_dir = "/";
494 (void)printf("Logging in with home = \"/\".\n");
495 }
496
497 if(!quietlog)
498 quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0;
499
500 /* regain special privileges */
501 (void)seteuid(saved_uid);
502 setgroups(nsaved_gids, saved_gids);
503 (void)setegid(saved_gid);
504
505 #ifdef LOGIN_CAP
506 pw_warntime = login_getcaptime(lc, "password-warn",
507 _PASSWORD_WARNDAYS * SECSPERDAY,
508 _PASSWORD_WARNDAYS * SECSPERDAY);
509 #endif
510
511 if (pwd->pw_change || pwd->pw_expire)
512 (void)gettimeofday(&tp, (struct timezone *)NULL);
513 if (pwd->pw_expire) {
514 if (tp.tv_sec >= pwd->pw_expire) {
515 (void)printf("Sorry -- your account has expired.\n");
516 sleepexit(1);
517 } else if (pwd->pw_expire - tp.tv_sec < pw_warntime &&
518 !quietlog)
519 (void)printf("Warning: your account expires on %s",
520 ctime(&pwd->pw_expire));
521 }
522 if (pwd->pw_change) {
523 if (pwd->pw_change == _PASSWORD_CHGNOW)
524 need_chpass = 1;
525 else if (tp.tv_sec >= pwd->pw_change) {
526 (void)printf("Sorry -- your password has expired.\n");
527 sleepexit(1);
528 } else if (pwd->pw_change - tp.tv_sec < pw_warntime &&
529 !quietlog)
530 (void)printf("Warning: your password expires on %s",
531 ctime(&pwd->pw_change));
532
533 }
534 /* Nothing else left to fail -- really log in. */
535 memset((void *)&utmp, 0, sizeof(utmp));
536 (void)time(&utmp.ut_time);
537 (void)strncpy(utmp.ut_name, username, sizeof(utmp.ut_name));
538 if (hostname)
539 (void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host));
540 (void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line));
541 login(&utmp);
542
543 dolastlog(quietlog);
544
545 (void)chown(ttyn, pwd->pw_uid,
546 (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid);
547
548 if (ttyaction(ttyn, "login", pwd->pw_name))
549 (void)printf("Warning: ttyaction failed.\n");
550
551 #if defined(KERBEROS) || defined(KERBEROS5)
552 /* Fork so that we can call kdestroy */
553 if (krbtkfile_env)
554 dofork();
555 #endif
556 #ifdef LOGIN_CAP
557 if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETALL & ~LOGIN_SETPATH)
558 != 0) {
559 syslog(LOG_ERR, "setusercontext failed");
560 exit(1);
561 }
562 #else
563 (void)setgid(pwd->pw_gid);
564
565 initgroups(username, pwd->pw_gid);
566
567 if (setlogin(pwd->pw_name) < 0)
568 syslog(LOG_ERR, "setlogin() failure: %m");
569
570 /* Discard permissions last so can't get killed and drop core. */
571 if (rootlogin)
572 (void)setuid(0);
573 else
574 (void)setuid(pwd->pw_uid);
575
576 #endif
577
578 if (*pwd->pw_shell == '\0')
579 pwd->pw_shell = _PATH_BSHELL;
580 #ifdef LOGIN_CAP
581 if((shell = login_getcapstr(lc, "shell", NULL, NULL))) {
582 if(!(shell = strdup(shell))) {
583 syslog(LOG_NOTICE, "Cannot alloc mem");
584 sleepexit(1);
585 }
586 pwd->pw_shell = shell;
587 }
588 #endif
589
590 /* Destroy environment unless user has requested its preservation. */
591 if (!pflag)
592 environ = envinit;
593 (void)setenv("HOME", pwd->pw_dir, 1);
594 (void)setenv("SHELL", pwd->pw_shell, 1);
595 if (term[0] == '\0') {
596 char *tt = (char *) stypeof(tty);
597 #ifdef LOGIN_CAP
598 if(!tt)
599 tt = login_getcapstr(lc, "term", NULL, NULL);
600 #endif
601 /* unknown term -> "su" */
602 (void)strncpy(term, tt ? tt : "su", sizeof(term));
603 }
604 (void)setenv("TERM", term, 0);
605 (void)setenv("LOGNAME", pwd->pw_name, 1);
606 (void)setenv("USER", pwd->pw_name, 1);
607 #ifdef LOGIN_CAP
608 setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETPATH);
609 #else
610 (void)setenv("PATH", _PATH_DEFPATH, 0);
611 #endif
612 #ifdef KERBEROS
613 if (krbtkfile_env)
614 (void)setenv("KRBTKFILE", krbtkfile_env, 1);
615 #endif
616 #ifdef KERBEROS5
617 if (krbtkfile_env)
618 (void)setenv("KRB5CCNAME", krbtkfile_env, 1);
619 #endif
620
621 if (tty[sizeof("tty")-1] == 'd')
622 syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
623
624 /* If fflag is on, assume caller/authenticator has logged root login. */
625 if (rootlogin && fflag == 0) {
626 if (hostname)
627 syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s",
628 username, tty, hostname);
629 else
630 syslog(LOG_NOTICE,
631 "ROOT LOGIN (%s) ON %s", username, tty);
632 }
633
634 #if defined(KERBEROS) || defined(KERBEROS5)
635 if (!quietlog && notickets == 1)
636 (void)printf("Warning: no Kerberos tickets issued.\n");
637 #endif
638
639 if (!quietlog) {
640 char *fname;
641 #ifdef LOGIN_CAP
642
643 fname = login_getcapstr(lc, "copyright", NULL, NULL);
644 if (fname && access(fname, F_OK) == 0)
645 motd(fname);
646 else
647 #endif
648 (void)printf(copyrightstr);
649
650 #ifdef LOGIN_CAP
651 fname = login_getcapstr(lc, "welcome", NULL, NULL);
652 if (fname == NULL || access(fname, F_OK) != 0)
653 #endif
654 fname = _PATH_MOTDFILE;
655 motd(fname);
656
657 (void)snprintf(tbuf,
658 sizeof(tbuf), "%s/%s", _PATH_MAILDIR, pwd->pw_name);
659 if (stat(tbuf, &st) == 0 && st.st_size != 0)
660 (void)printf("You have %smail.\n",
661 (st.st_mtime > st.st_atime) ? "new " : "");
662 }
663
664 #ifdef LOGIN_CAP
665 login_close(lc);
666 #endif
667
668 (void)signal(SIGALRM, SIG_DFL);
669 (void)signal(SIGQUIT, SIG_DFL);
670 (void)signal(SIGINT, SIG_DFL);
671 (void)signal(SIGTSTP, SIG_IGN);
672
673 tbuf[0] = '-';
674 (void)strncpy(tbuf + 1, (p = strrchr(pwd->pw_shell, '/')) ?
675 p + 1 : pwd->pw_shell, sizeof(tbuf) - 2);
676
677 /* Wait to change password until we're unprivileged */
678 if (need_chpass) {
679 if (!require_chpass)
680 (void)printf(
681 "Warning: your password has expired. Please change it as soon as possible.\n");
682 else {
683 int status;
684
685 (void)printf(
686 "Your password has expired. Please choose a new one.\n");
687 switch (fork()) {
688 case -1:
689 warn("fork");
690 sleepexit(1);
691 case 0:
692 execl(_PATH_BINPASSWD, "passwd", 0);
693 _exit(1);
694 default:
695 if (wait(&status) == -1 ||
696 WEXITSTATUS(status))
697 sleepexit(1);
698 }
699 }
700 }
701
702 #ifdef KERBEROS5
703 k5_write_creds();
704 #endif
705 execlp(pwd->pw_shell, tbuf, 0);
706 err(1, "%s", pwd->pw_shell);
707 }
708
709 #if defined(KERBEROS) || defined(KERBEROS5)
710 #define NBUFSIZ (MAXLOGNAME + 1 + 5) /* .root suffix */
711 #else
712 #define NBUFSIZ (MAXLOGNAME + 1)
713 #endif
714
715 #if defined(KERBEROS) || defined(KERBEROS5)
716 /*
717 * This routine handles cleanup stuff, and the like.
718 * It exists only in the child process.
719 */
720 #include <sys/wait.h>
721 void
722 dofork()
723 {
724 int child;
725
726 if (!(child = fork()))
727 return; /* Child process */
728
729 /* Setup stuff? This would be things we could do in parallel with login */
730 (void) chdir("/"); /* Let's not keep the fs busy... */
731
732 /* If we're the parent, watch the child until it dies */
733 while (wait(0) != child)
734 ;
735
736 /* Cleanup stuff */
737 /* Run kdestroy to destroy tickets */
738 kdestroy();
739
740 /* Leave */
741 exit(0);
742 }
743 #endif
744
745 void
746 getloginname()
747 {
748 int ch;
749 char *p;
750 static char nbuf[NBUFSIZ];
751
752 for (;;) {
753 (void)printf("login: ");
754 for (p = nbuf; (ch = getchar()) != '\n'; ) {
755 if (ch == EOF) {
756 badlogin(username);
757 exit(0);
758 }
759 if (p < nbuf + (NBUFSIZ - 1))
760 *p++ = ch;
761 }
762 if (p > nbuf) {
763 if (nbuf[0] == '-')
764 (void)fprintf(stderr,
765 "login names may not start with '-'.\n");
766 else {
767 *p = '\0';
768 username = nbuf;
769 break;
770 }
771 }
772 }
773 }
774
775 int
776 rootterm(ttyn)
777 char *ttyn;
778 {
779 struct ttyent *t;
780
781 return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE);
782 }
783
784 jmp_buf motdinterrupt;
785
786 void
787 motd(fname)
788 char *fname;
789 {
790 int fd, nchars;
791 sig_t oldint;
792 char tbuf[8192];
793
794 if ((fd = open(fname ? fname : _PATH_MOTDFILE, O_RDONLY, 0)) < 0)
795 return;
796 oldint = signal(SIGINT, sigint);
797 if (setjmp(motdinterrupt) == 0)
798 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
799 (void)write(fileno(stdout), tbuf, nchars);
800 (void)signal(SIGINT, oldint);
801 (void)close(fd);
802 }
803
804 /* ARGSUSED */
805 void
806 sigint(signo)
807 int signo;
808 {
809
810 longjmp(motdinterrupt, 1);
811 }
812
813 /* ARGSUSED */
814 void
815 timedout(signo)
816 int signo;
817 {
818
819 (void)fprintf(stderr, "Login timed out after %d seconds\n", timeout);
820 exit(0);
821 }
822
823 void
824 checknologin(fname)
825 char *fname;
826 {
827 int fd, nchars;
828 char tbuf[8192];
829
830 if ((fd = open(fname ? fname : _PATH_NOLOGIN, O_RDONLY, 0)) >= 0) {
831 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
832 (void)write(fileno(stdout), tbuf, nchars);
833 sleepexit(0);
834 }
835 }
836
837 void
838 dolastlog(quiet)
839 int quiet;
840 {
841 struct lastlog ll;
842 int fd;
843
844 if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) {
845 (void)lseek(fd, (off_t)(pwd->pw_uid * sizeof(ll)), SEEK_SET);
846 if (!quiet) {
847 if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) &&
848 ll.ll_time != 0) {
849 (void)printf("Last login: %.*s ",
850 24, (char *)ctime(&ll.ll_time));
851 if (*ll.ll_host != '\0')
852 (void)printf("from %.*s\n",
853 (int)sizeof(ll.ll_host),
854 ll.ll_host);
855 else
856 (void)printf("on %.*s\n",
857 (int)sizeof(ll.ll_line),
858 ll.ll_line);
859 }
860 (void)lseek(fd, (off_t)(pwd->pw_uid * sizeof(ll)),
861 SEEK_SET);
862 }
863 memset((void *)&ll, 0, sizeof(ll));
864 (void)time(&ll.ll_time);
865 (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
866 if (hostname)
867 (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host));
868 (void)write(fd, (char *)&ll, sizeof(ll));
869 (void)close(fd);
870 }
871 }
872
873 void
874 badlogin(name)
875 char *name;
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