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