login.c revision 1.71 1 /* $NetBSD: login.c,v 1.71 2002/11/16 04:38:45 itojun 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.71 2002/11/16 04:38:45 itojun 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 #include <sys/socket.h>
63
64 #include <err.h>
65 #include <errno.h>
66 #include <grp.h>
67 #include <pwd.h>
68 #include <setjmp.h>
69 #include <signal.h>
70 #include <stdio.h>
71 #include <stdlib.h>
72 #include <string.h>
73 #include <syslog.h>
74 #include <time.h>
75 #include <ttyent.h>
76 #include <tzfile.h>
77 #include <unistd.h>
78 #ifdef SUPPORT_UTMP
79 #include <utmp.h>
80 #endif
81 #ifdef SUPPORT_UTMPX
82 #include <utmpx.h>
83 #endif
84 #include <util.h>
85 #ifdef SKEY
86 #include <skey.h>
87 #endif
88 #ifdef KERBEROS5
89 #include <krb5/krb5.h>
90 #include <com_err.h>
91 #endif
92 #ifdef LOGIN_CAP
93 #include <login_cap.h>
94 #endif
95
96 #include "pathnames.h"
97
98 #ifdef KERBEROS5
99 int login_krb5_get_tickets = 1;
100 int login_krb4_get_tickets = 0;
101 int login_krb5_forwardable_tgt = 0;
102 int login_krb5_retain_ccache = 0;
103 #endif
104
105 void badlogin __P((char *));
106 void checknologin __P((char *));
107 #ifdef SUPPORT_UTMP
108 static void doutmp __P((void));
109 static void dolastlog __P((int));
110 #endif
111 #ifdef SUPPORT_UTMPX
112 static void doutmpx __P((void));
113 static void dolastlogx __P((int));
114 #endif
115 static void update_db __P((int));
116 void getloginname __P((void));
117 int main __P((int, char *[]));
118 void motd __P((char *));
119 int rootterm __P((char *));
120 void sigint __P((int));
121 void sleepexit __P((int));
122 const char *stypeof __P((const char *));
123 void timedout __P((int));
124 #if defined(KERBEROS)
125 int klogin __P((struct passwd *, char *, char *, char *));
126 void kdestroy __P((void));
127 #endif
128 #ifdef KERBEROS5
129 int k5login __P((struct passwd *, char *, char *, char *));
130 void k5destroy __P((void));
131 int k5_read_creds __P((char*));
132 int k5_write_creds __P((void));
133 #endif
134 #if defined(KERBEROS) || defined(KERBEROS5)
135 void dofork __P((void));
136 #endif
137
138 #define TTYGRPNAME "tty" /* name of group to own ttys */
139
140 #define DEFAULT_BACKOFF 3
141 #define DEFAULT_RETRIES 10
142
143 /*
144 * This bounds the time given to login. Not a define so it can
145 * be patched on machines where it's too small.
146 */
147 u_int timeout = 300;
148
149 #if defined(KERBEROS) || defined(KERBEROS5)
150 int notickets = 1;
151 char *instance;
152 int has_ccache = 0;
153 #endif
154 #ifdef KERBEROS
155 extern char *krbtkfile_env;
156 extern int krb_configured;
157 #endif
158 #ifdef KERBEROS5
159 extern krb5_context kcontext;
160 extern int have_forward;
161 extern char *krb5tkfile_env;
162 extern int krb5_configured;
163 #endif
164
165 #if defined(KERBEROS) && defined(KERBEROS5)
166 #define KERBEROS_CONFIGURED (krb_configured || krb5_configured)
167 #elif defined(KERBEROS)
168 #define KERBEROS_CONFIGURED krb_configured
169 #elif defined(KERBEROS5)
170 #define KERBEROS_CONFIGURED krb5_configured
171 #endif
172
173 struct passwd *pwd;
174 int failures;
175 char term[64], *envinit[1], *hostname, *username, *tty, *nested;
176 struct timeval now;
177 struct sockaddr_storage ss;
178
179 static const char copyrightstr[] = "\
180 Copyright (c) 1996, 1997, 1998, 1999, 2000, 2001, 2002\n\
181 \tThe NetBSD Foundation, Inc. All rights reserved.\n\
182 Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994\n\
183 \tThe Regents of the University of California. All rights reserved.\n\n";
184
185 int
186 main(argc, argv)
187 int argc;
188 char *argv[];
189 {
190 extern char **environ;
191 struct group *gr;
192 struct stat st;
193 int ask, ch, cnt, fflag, hflag, pflag, sflag, quietlog, rootlogin, rval;
194 int Fflag;
195 uid_t uid, saved_uid;
196 gid_t saved_gid, saved_gids[NGROUPS_MAX];
197 int nsaved_gids;
198 char *domain, *p, *ttyn, *pwprompt;
199 const char *salt;
200 char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10];
201 char localhost[MAXHOSTNAMELEN + 1];
202 int need_chpass, require_chpass;
203 int login_retries = DEFAULT_RETRIES,
204 login_backoff = DEFAULT_BACKOFF;
205 time_t pw_warntime = _PASSWORD_WARNDAYS * SECSPERDAY;
206 #ifdef KERBEROS5
207 krb5_error_code kerror;
208 #endif
209 #if defined(KERBEROS) || defined(KERBEROS5)
210 int got_tickets = 0;
211 #endif
212 #ifdef LOGIN_CAP
213 char *shell = NULL;
214 login_cap_t *lc = NULL;
215 #endif
216
217 tbuf[0] = '\0';
218 rval = 0;
219 pwprompt = NULL;
220 nested = NULL;
221 need_chpass = require_chpass = 0;
222
223 (void)signal(SIGALRM, timedout);
224 (void)alarm(timeout);
225 (void)signal(SIGQUIT, SIG_IGN);
226 (void)signal(SIGINT, SIG_IGN);
227 (void)setpriority(PRIO_PROCESS, 0, 0);
228
229 openlog("login", 0, LOG_AUTH);
230
231 /*
232 * -p is used by getty to tell login not to destroy the environment
233 * -f is used to skip a second login authentication
234 * -h is used by other servers to pass the name of the remote host to
235 * login so that it may be placed in utmp/utmpx and wtmp/wtmpx
236 * -s is used to force use of S/Key or equivalent.
237 */
238 domain = NULL;
239 if (gethostname(localhost, sizeof(localhost)) < 0)
240 syslog(LOG_ERR, "couldn't get local hostname: %m");
241 else
242 domain = strchr(localhost, '.');
243 localhost[sizeof(localhost) - 1] = '\0';
244
245 Fflag = fflag = hflag = pflag = sflag = 0;
246 #ifdef KERBEROS5
247 have_forward = 0;
248 #endif
249 uid = getuid();
250 while ((ch = getopt(argc, argv, "Ffh:ps")) != -1)
251 switch (ch) {
252 case 'F':
253 Fflag = 1;
254 /* FALLTHROUGH */
255 case 'f':
256 fflag = 1;
257 break;
258 case 'h':
259 if (uid)
260 errx(1, "-h option: %s", strerror(EPERM));
261 hflag = 1;
262 if (domain && (p = strchr(optarg, '.')) != NULL &&
263 strcasecmp(p, domain) == 0)
264 *p = 0;
265 hostname = optarg;
266 break;
267 case 'p':
268 pflag = 1;
269 break;
270 case 's':
271 sflag = 1;
272 break;
273 default:
274 case '?':
275 (void)fprintf(stderr,
276 "usage: login [-fps] [-h hostname] [username]\n");
277 exit(1);
278 }
279 argc -= optind;
280 argv += optind;
281
282 if (*argv) {
283 username = *argv;
284 ask = 0;
285 } else
286 ask = 1;
287
288 for (cnt = getdtablesize(); cnt > 2; cnt--)
289 (void)close(cnt);
290
291 ttyn = ttyname(STDIN_FILENO);
292 if (ttyn == NULL || *ttyn == '\0') {
293 (void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY);
294 ttyn = tname;
295 }
296 if ((tty = strrchr(ttyn, '/')) != NULL)
297 ++tty;
298 else
299 tty = ttyn;
300
301 if (issetugid()) {
302 nested = strdup(user_from_uid(getuid(), 0));
303 if (nested == NULL) {
304 syslog(LOG_ERR, "strdup: %m");
305 sleepexit(1);
306 }
307 }
308
309 #ifdef LOGIN_CAP
310 /* Get "login-retries" and "login-backoff" from default class */
311 if ((lc = login_getclass(NULL)) != NULL) {
312 login_retries = (int)login_getcapnum(lc, "login-retries",
313 DEFAULT_RETRIES, DEFAULT_RETRIES);
314 login_backoff = (int)login_getcapnum(lc, "login-backoff",
315 DEFAULT_BACKOFF, DEFAULT_BACKOFF);
316 login_close(lc);
317 lc = NULL;
318 }
319 #endif
320
321 #ifdef KERBEROS5
322 kerror = krb5_init_context(&kcontext);
323 if (kerror) {
324 /*
325 * If Kerberos is not configured, that is, we are
326 * not using Kerberos, do not log the error message.
327 * However, if Kerberos is configured, and the
328 * context init fails for some other reason, we need
329 * to issue a no tickets warning to the user when the
330 * login succeeds.
331 */
332 if (kerror != ENXIO) { /* XXX NetBSD-local Heimdal hack */
333 syslog(LOG_NOTICE,
334 "%s when initializing Kerberos context",
335 error_message(kerror));
336 krb5_configured = 1;
337 }
338 login_krb5_get_tickets = 0;
339 }
340 #endif /* KERBEROS5 */
341
342 for (cnt = 0;; ask = 1) {
343 #if defined(KERBEROS)
344 kdestroy();
345 #endif
346 #if defined(KERBEROS5)
347 if (login_krb5_get_tickets)
348 k5destroy();
349 #endif
350 if (ask) {
351 fflag = 0;
352 getloginname();
353 }
354 rootlogin = 0;
355 #ifdef KERBEROS
356 if ((instance = strchr(username, '.')) != NULL)
357 *instance++ = '\0';
358 else
359 instance = "";
360 #endif
361 #ifdef KERBEROS5
362 if ((instance = strchr(username, '/')) != NULL)
363 *instance++ = '\0';
364 else
365 instance = "";
366 #endif
367 if (strlen(username) > MAXLOGNAME)
368 username[MAXLOGNAME] = '\0';
369
370 /*
371 * Note if trying multiple user names; log failures for
372 * previous user name, but don't bother logging one failure
373 * for nonexistent name (mistyped username).
374 */
375 if (failures && strcmp(tbuf, username)) {
376 if (failures > (pwd ? 0 : 1))
377 badlogin(tbuf);
378 failures = 0;
379 }
380 (void)strlcpy(tbuf, username, sizeof(tbuf));
381
382 if ((pwd = getpwnam(username)) != NULL)
383 salt = pwd->pw_passwd;
384 else
385 salt = "xx";
386
387 #ifdef LOGIN_CAP
388 /*
389 * Establish the class now, before we might goto
390 * within the next block. pwd can be NULL since it
391 * falls back to the "default" class if it is.
392 */
393 lc = login_getclass(pwd ? pwd->pw_class : NULL);
394 #endif
395 /*
396 * if we have a valid account name, and it doesn't have a
397 * password, or the -f option was specified and the caller
398 * is root or the caller isn't changing their uid, don't
399 * authenticate.
400 */
401 if (pwd) {
402 if (pwd->pw_uid == 0)
403 rootlogin = 1;
404
405 if (fflag && (uid == 0 || uid == pwd->pw_uid)) {
406 /* already authenticated */
407 #ifdef KERBEROS5
408 if (login_krb5_get_tickets && Fflag)
409 k5_read_creds(username);
410 #endif
411 break;
412 } else if (pwd->pw_passwd[0] == '\0') {
413 /* pretend password okay */
414 rval = 0;
415 goto ttycheck;
416 }
417 }
418
419 fflag = 0;
420
421 (void)setpriority(PRIO_PROCESS, 0, -4);
422
423 #ifdef SKEY
424 if (skey_haskey(username) == 0) {
425 static char skprompt[80];
426 const char *skinfo = skey_keyinfo(username);
427
428 (void)snprintf(skprompt, sizeof(skprompt)-1,
429 "Password [%s]:",
430 skinfo ? skinfo : "error getting challenge");
431 pwprompt = skprompt;
432 } else
433 #endif
434 pwprompt = "Password:";
435
436 p = getpass(pwprompt);
437
438 if (pwd == NULL) {
439 rval = 1;
440 goto skip;
441 }
442 #ifdef KERBEROS
443 if (
444 #ifdef KERBEROS5
445 /* allow a user to get both krb4 and krb5 tickets, if
446 * desired. If krb5 is compiled in, the default action
447 * is to ignore krb4 and get krb5 tickets, but the user
448 * can override this in the krb5.conf. */
449 login_krb4_get_tickets &&
450 #endif
451 klogin(pwd, instance, localhost, p) == 0) {
452 rval = 0;
453 got_tickets = 1;
454 }
455 #endif
456 #ifdef KERBEROS5
457 if (login_krb5_get_tickets &&
458 k5login(pwd, instance, localhost, p) == 0) {
459 rval = 0;
460 got_tickets = 1;
461 }
462 #endif
463 #if defined(KERBEROS) || defined(KERBEROS5)
464 if (got_tickets)
465 goto skip;
466 #endif
467 #ifdef SKEY
468 if (skey_haskey(username) == 0 &&
469 skey_passcheck(username, p) != -1) {
470 rval = 0;
471 goto skip;
472 }
473 #endif
474 if (!sflag && *pwd->pw_passwd != '\0' &&
475 !strcmp(crypt(p, pwd->pw_passwd), pwd->pw_passwd)) {
476 rval = 0;
477 require_chpass = 1;
478 goto skip;
479 }
480 rval = 1;
481
482 skip:
483 memset(p, 0, strlen(p));
484
485 (void)setpriority(PRIO_PROCESS, 0, 0);
486
487 ttycheck:
488 /*
489 * If trying to log in as root without Kerberos,
490 * but with insecure terminal, refuse the login attempt.
491 */
492 if (pwd && !rval && rootlogin && !rootterm(tty)) {
493 (void)fprintf(stderr,
494 "%s login refused on this terminal.\n",
495 pwd->pw_name);
496 if (hostname)
497 syslog(LOG_NOTICE,
498 "LOGIN %s REFUSED FROM %s ON TTY %s",
499 pwd->pw_name, hostname, tty);
500 else
501 syslog(LOG_NOTICE,
502 "LOGIN %s REFUSED ON TTY %s",
503 pwd->pw_name, tty);
504 continue;
505 }
506
507 if (pwd && !rval)
508 break;
509
510 (void)printf("Login incorrect\n");
511 failures++;
512 cnt++;
513 /* we allow 10 tries, but after 3 we start backing off */
514 if (cnt > login_backoff) {
515 if (cnt >= login_retries) {
516 badlogin(username);
517 sleepexit(1);
518 }
519 sleep((u_int)((cnt - 3) * 5));
520 }
521 }
522
523 /* committed to login -- turn off timeout */
524 (void)alarm((u_int)0);
525
526 endpwent();
527
528 /* if user not super-user, check for disabled logins */
529 #ifdef LOGIN_CAP
530 if (!login_getcapbool(lc, "ignorenologin", rootlogin))
531 checknologin(login_getcapstr(lc, "nologin", NULL, NULL));
532 #else
533 if (!rootlogin)
534 checknologin(NULL);
535 #endif
536
537 #ifdef LOGIN_CAP
538 quietlog = login_getcapbool(lc, "hushlogin", 0);
539 #else
540 quietlog = 0;
541 #endif
542 /* Temporarily give up special privileges so we can change */
543 /* into NFS-mounted homes that are exported for non-root */
544 /* access and have mode 7x0 */
545 saved_uid = geteuid();
546 saved_gid = getegid();
547 nsaved_gids = getgroups(NGROUPS_MAX, saved_gids);
548
549 (void)setegid(pwd->pw_gid);
550 initgroups(username, pwd->pw_gid);
551 (void)seteuid(pwd->pw_uid);
552
553 if (chdir(pwd->pw_dir) < 0) {
554 #ifdef LOGIN_CAP
555 if (login_getcapbool(lc, "requirehome", 0)) {
556 (void)printf("Home directory %s required\n",
557 pwd->pw_dir);
558 sleepexit(1);
559 }
560 #endif
561 (void)printf("No home directory %s!\n", pwd->pw_dir);
562 if (chdir("/"))
563 exit(0);
564 pwd->pw_dir = "/";
565 (void)printf("Logging in with home = \"/\".\n");
566 }
567
568 if (!quietlog)
569 quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0;
570
571 /* regain special privileges */
572 (void)seteuid(saved_uid);
573 setgroups(nsaved_gids, saved_gids);
574 (void)setegid(saved_gid);
575
576 #ifdef LOGIN_CAP
577 pw_warntime = login_getcaptime(lc, "password-warn",
578 _PASSWORD_WARNDAYS * SECSPERDAY,
579 _PASSWORD_WARNDAYS * SECSPERDAY);
580 #endif
581
582 (void)gettimeofday(&now, (struct timezone *)NULL);
583 if (pwd->pw_expire) {
584 if (now.tv_sec >= pwd->pw_expire) {
585 (void)printf("Sorry -- your account has expired.\n");
586 sleepexit(1);
587 } else if (pwd->pw_expire - now.tv_sec < pw_warntime &&
588 !quietlog)
589 (void)printf("Warning: your account expires on %s",
590 ctime(&pwd->pw_expire));
591 }
592 if (pwd->pw_change) {
593 if (pwd->pw_change == _PASSWORD_CHGNOW)
594 need_chpass = 1;
595 else if (now.tv_sec >= pwd->pw_change) {
596 (void)printf("Sorry -- your password has expired.\n");
597 sleepexit(1);
598 } else if (pwd->pw_change - now.tv_sec < pw_warntime &&
599 !quietlog)
600 (void)printf("Warning: your password expires on %s",
601 ctime(&pwd->pw_change));
602
603 }
604 /* Nothing else left to fail -- really log in. */
605 update_db(quietlog);
606
607 (void)chown(ttyn, pwd->pw_uid,
608 (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid);
609
610 if (ttyaction(ttyn, "login", pwd->pw_name))
611 (void)printf("Warning: ttyaction failed.\n");
612
613 #if defined(KERBEROS) || defined(KERBEROS5)
614 /* Fork so that we can call kdestroy */
615 if (
616 #ifdef KERBEROS5
617 ! login_krb5_retain_ccache &&
618 #endif
619 has_ccache)
620 dofork();
621 #endif
622
623 /* Destroy environment unless user has requested its preservation. */
624 if (!pflag)
625 environ = envinit;
626
627 #ifdef LOGIN_CAP
628 if (nested == NULL && setusercontext(lc, pwd, pwd->pw_uid,
629 LOGIN_SETLOGIN) != 0) {
630 syslog(LOG_ERR, "setusercontext failed");
631 exit(1);
632 }
633 if (setusercontext(lc, pwd, pwd->pw_uid,
634 (LOGIN_SETALL & ~(LOGIN_SETPATH|LOGIN_SETLOGIN))) != 0) {
635 syslog(LOG_ERR, "setusercontext failed");
636 exit(1);
637 }
638 #else
639 (void)setgid(pwd->pw_gid);
640
641 initgroups(username, pwd->pw_gid);
642
643 if (nested == NULL && setlogin(pwd->pw_name) < 0)
644 syslog(LOG_ERR, "setlogin() failure: %m");
645
646 /* Discard permissions last so can't get killed and drop core. */
647 if (rootlogin)
648 (void)setuid(0);
649 else
650 (void)setuid(pwd->pw_uid);
651 #endif
652
653 if (*pwd->pw_shell == '\0')
654 pwd->pw_shell = _PATH_BSHELL;
655 #ifdef LOGIN_CAP
656 if ((shell = login_getcapstr(lc, "shell", NULL, NULL)) != NULL) {
657 if ((shell = strdup(shell)) == NULL) {
658 syslog(LOG_ERR, "Cannot alloc mem");
659 sleepexit(1);
660 }
661 pwd->pw_shell = shell;
662 }
663 #endif
664
665 (void)setenv("HOME", pwd->pw_dir, 1);
666 (void)setenv("SHELL", pwd->pw_shell, 1);
667 if (term[0] == '\0') {
668 char *tt = (char *)stypeof(tty);
669 #ifdef LOGIN_CAP
670 if (tt == NULL)
671 tt = login_getcapstr(lc, "term", NULL, NULL);
672 #endif
673 /* unknown term -> "su" */
674 (void)strlcpy(term, tt != NULL ? tt : "su", sizeof(term));
675 }
676 (void)setenv("TERM", term, 0);
677 (void)setenv("LOGNAME", pwd->pw_name, 1);
678 (void)setenv("USER", pwd->pw_name, 1);
679
680 #ifdef LOGIN_CAP
681 setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETPATH);
682 #else
683 (void)setenv("PATH", _PATH_DEFPATH, 0);
684 #endif
685
686 #ifdef KERBEROS
687 if (krbtkfile_env)
688 (void)setenv("KRBTKFILE", krbtkfile_env, 1);
689 #endif
690 #ifdef KERBEROS5
691 if (krb5tkfile_env)
692 (void)setenv("KRB5CCNAME", krb5tkfile_env, 1);
693 #endif
694
695 if (tty[sizeof("tty")-1] == 'd')
696 syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
697
698 /* If fflag is on, assume caller/authenticator has logged root login. */
699 if (rootlogin && fflag == 0) {
700 if (hostname)
701 syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s",
702 username, tty, hostname);
703 else
704 syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s",
705 username, tty);
706 }
707
708 #if defined(KERBEROS) || defined(KERBEROS5)
709 if (KERBEROS_CONFIGURED && !quietlog && notickets == 1)
710 (void)printf("Warning: no Kerberos tickets issued.\n");
711 #endif
712
713 if (!quietlog) {
714 char *fname;
715 #ifdef LOGIN_CAP
716 fname = login_getcapstr(lc, "copyright", NULL, NULL);
717 if (fname != NULL && access(fname, F_OK) == 0)
718 motd(fname);
719 else
720 #endif
721 (void)printf("%s", copyrightstr);
722
723 #ifdef LOGIN_CAP
724 fname = login_getcapstr(lc, "welcome", NULL, NULL);
725 if (fname == NULL || access(fname, F_OK) != 0)
726 #endif
727 fname = _PATH_MOTDFILE;
728 motd(fname);
729
730 (void)snprintf(tbuf,
731 sizeof(tbuf), "%s/%s", _PATH_MAILDIR, pwd->pw_name);
732 if (stat(tbuf, &st) == 0 && st.st_size != 0)
733 (void)printf("You have %smail.\n",
734 (st.st_mtime > st.st_atime) ? "new " : "");
735 }
736
737 #ifdef LOGIN_CAP
738 login_close(lc);
739 #endif
740
741 (void)signal(SIGALRM, SIG_DFL);
742 (void)signal(SIGQUIT, SIG_DFL);
743 (void)signal(SIGINT, SIG_DFL);
744 (void)signal(SIGTSTP, SIG_IGN);
745
746 tbuf[0] = '-';
747 (void)strlcpy(tbuf + 1, (p = strrchr(pwd->pw_shell, '/')) ?
748 p + 1 : pwd->pw_shell, sizeof(tbuf) - 1);
749
750 /* Wait to change password until we're unprivileged */
751 if (need_chpass) {
752 if (!require_chpass)
753 (void)printf(
754 "Warning: your password has expired. Please change it as soon as possible.\n");
755 else {
756 int status;
757
758 (void)printf(
759 "Your password has expired. Please choose a new one.\n");
760 switch (fork()) {
761 case -1:
762 warn("fork");
763 sleepexit(1);
764 case 0:
765 execl(_PATH_BINPASSWD, "passwd", 0);
766 _exit(1);
767 default:
768 if (wait(&status) == -1 ||
769 WEXITSTATUS(status))
770 sleepexit(1);
771 }
772 }
773 }
774
775 #ifdef KERBEROS5
776 if (login_krb5_get_tickets)
777 k5_write_creds();
778 #endif
779 execlp(pwd->pw_shell, tbuf, 0);
780 err(1, "%s", pwd->pw_shell);
781 }
782
783 #if defined(KERBEROS) || defined(KERBEROS5)
784 #define NBUFSIZ (MAXLOGNAME + 1 + 5) /* .root suffix */
785 #else
786 #define NBUFSIZ (MAXLOGNAME + 1)
787 #endif
788
789 #if defined(KERBEROS) || defined(KERBEROS5)
790 /*
791 * This routine handles cleanup stuff, and the like.
792 * It exists only in the child process.
793 */
794 #include <sys/wait.h>
795 void
796 dofork()
797 {
798 int child;
799
800 if (!(child = fork()))
801 return; /* Child process */
802
803 /*
804 * Setup stuff? This would be things we could do in parallel
805 * with login
806 */
807 (void)chdir("/"); /* Let's not keep the fs busy... */
808
809 /* If we're the parent, watch the child until it dies */
810 while (wait(0) != child)
811 ;
812
813 /* Cleanup stuff */
814 /* Run kdestroy to destroy tickets */
815 #ifdef KERBEROS
816 kdestroy();
817 #endif
818 #ifdef KERBEROS5
819 if (login_krb5_get_tickets)
820 k5destroy();
821 #endif
822
823 /* Leave */
824 exit(0);
825 }
826 #endif
827
828 void
829 getloginname()
830 {
831 int ch;
832 char *p;
833 static char nbuf[NBUFSIZ];
834
835 for (;;) {
836 (void)printf("login: ");
837 for (p = nbuf; (ch = getchar()) != '\n'; ) {
838 if (ch == EOF) {
839 badlogin(username);
840 exit(0);
841 }
842 if (p < nbuf + (NBUFSIZ - 1))
843 *p++ = ch;
844 }
845 if (p > nbuf) {
846 if (nbuf[0] == '-')
847 (void)fprintf(stderr,
848 "login names may not start with '-'.\n");
849 else {
850 *p = '\0';
851 username = nbuf;
852 break;
853 }
854 }
855 }
856 }
857
858 int
859 rootterm(ttyn)
860 char *ttyn;
861 {
862 struct ttyent *t;
863
864 return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE);
865 }
866
867 jmp_buf motdinterrupt;
868
869 void
870 motd(fname)
871 char *fname;
872 {
873 int fd, nchars;
874 sig_t oldint;
875 char tbuf[8192];
876
877 if ((fd = open(fname ? fname : _PATH_MOTDFILE, O_RDONLY, 0)) < 0)
878 return;
879 oldint = signal(SIGINT, sigint);
880 if (setjmp(motdinterrupt) == 0)
881 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
882 (void)write(fileno(stdout), tbuf, nchars);
883 (void)signal(SIGINT, oldint);
884 (void)close(fd);
885 }
886
887 /* ARGSUSED */
888 void
889 sigint(signo)
890 int signo;
891 {
892
893 longjmp(motdinterrupt, 1);
894 }
895
896 /* ARGSUSED */
897 void
898 timedout(signo)
899 int signo;
900 {
901
902 (void)fprintf(stderr, "Login timed out after %d seconds\n", timeout);
903 exit(0);
904 }
905
906 void
907 checknologin(fname)
908 char *fname;
909 {
910 int fd, nchars;
911 char tbuf[8192];
912
913 if ((fd = open(fname ? fname : _PATH_NOLOGIN, O_RDONLY, 0)) >= 0) {
914 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
915 (void)write(fileno(stdout), tbuf, nchars);
916 sleepexit(0);
917 }
918 }
919
920 static void
921 update_db(int quietlog)
922 {
923 if (nested != NULL) {
924 if (hostname != NULL)
925 syslog(LOG_NOTICE, "%s to %s on tty %s from %s",
926 nested, pwd->pw_name, tty, hostname);
927 else
928 syslog(LOG_NOTICE, "%s to %s on tty %s", nested,
929 pwd->pw_name, tty);
930
931 return;
932 }
933 if (hostname != NULL) {
934 socklen_t len = sizeof(ss);
935 (void)getpeername(STDIN_FILENO, (struct sockaddr *)&ss, &len);
936 }
937 (void)gettimeofday(&now, NULL);
938 #ifdef SUPPORT_UTMPX
939 doutmpx();
940 dolastlogx(quietlog);
941 quietlog = 1;
942 #endif
943 #ifdef SUPPORT_UTMP
944 doutmp();
945 dolastlog(quietlog);
946 #endif
947 }
948
949 #ifdef SUPPORT_UTMPX
950 static void
951 doutmpx()
952 {
953 struct utmpx utmpx;
954 char *t;
955
956 memset((void *)&utmpx, 0, sizeof(utmpx));
957 utmpx.ut_tv = now;
958 (void)strncpy(utmpx.ut_name, username, sizeof(utmpx.ut_name));
959 if (hostname) {
960 (void)strncpy(utmpx.ut_host, hostname, sizeof(utmpx.ut_host));
961 utmpx.ut_ss = ss;
962 }
963 (void)strncpy(utmpx.ut_line, tty, sizeof(utmpx.ut_line));
964 utmpx.ut_type = USER_PROCESS;
965 utmpx.ut_pid = getpid();
966 t = tty + strlen(tty);
967 if (t - tty >= sizeof(utmpx.ut_id)) {
968 (void)strncpy(utmpx.ut_id, t - sizeof(utmpx.ut_id),
969 sizeof(utmpx.ut_id));
970 } else {
971 (void)strncpy(utmpx.ut_id, tty, sizeof(utmpx.ut_id));
972 }
973 if (pututxline(&utmpx) == NULL)
974 syslog(LOG_NOTICE, "Cannot update utmpx %m");
975 endutxent();
976 if (updwtmpx(_PATH_WTMPX, &utmpx) != 0)
977 syslog(LOG_NOTICE, "Cannot update wtmpx %m");
978 }
979
980 static void
981 dolastlogx(quiet)
982 int quiet;
983 {
984 struct lastlogx ll;
985 if (getlastlogx(pwd->pw_uid, &ll) != NULL) {
986 time_t t = (time_t)ll.ll_tv.tv_sec;
987 (void)printf("Last login: %.24s ", ctime(&t));
988 if (*ll.ll_host != '\0')
989 (void)printf("from %.*s ",
990 (int)sizeof(ll.ll_host),
991 ll.ll_host);
992 (void)printf("on %.*s\n",
993 (int)sizeof(ll.ll_line),
994 ll.ll_line);
995 }
996 ll.ll_tv = now;
997 (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
998 if (hostname) {
999 (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host));
1000 ll.ll_ss = ss;
1001 }
1002 if (updlastlogx(_PATH_LASTLOGX, pwd->pw_uid, &ll) != 0)
1003 syslog(LOG_NOTICE, "Cannot update lastlogx %m");
1004 }
1005 #endif
1006
1007 #ifdef SUPPORT_UTMP
1008 static void
1009 doutmp()
1010 {
1011 struct utmp utmp;
1012
1013 (void)memset((void *)&utmp, 0, sizeof(utmp));
1014 utmp.ut_time = now.tv_sec;
1015 (void)strncpy(utmp.ut_name, username, sizeof(utmp.ut_name));
1016 if (hostname)
1017 (void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host));
1018 (void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line));
1019 login(&utmp);
1020 }
1021
1022 static void
1023 dolastlog(quiet)
1024 int quiet;
1025 {
1026 struct lastlog ll;
1027 int fd;
1028
1029 if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) {
1030 (void)lseek(fd, (off_t)(pwd->pw_uid * sizeof(ll)), SEEK_SET);
1031 if (!quiet) {
1032 if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) &&
1033 ll.ll_time != 0) {
1034 (void)printf("Last login: %.24s ",
1035 ctime(&ll.ll_time));
1036 if (*ll.ll_host != '\0')
1037 (void)printf("from %.*s ",
1038 (int)sizeof(ll.ll_host),
1039 ll.ll_host);
1040 (void)printf("on %.*s\n",
1041 (int)sizeof(ll.ll_line), ll.ll_line);
1042 }
1043 (void)lseek(fd, (off_t)(pwd->pw_uid * sizeof(ll)),
1044 SEEK_SET);
1045 }
1046 memset((void *)&ll, 0, sizeof(ll));
1047 ll.ll_time = now.tv_sec;
1048 (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
1049 if (hostname)
1050 (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host));
1051 (void)write(fd, (char *)&ll, sizeof(ll));
1052 (void)close(fd);
1053 }
1054 }
1055 #endif
1056
1057 void
1058 badlogin(name)
1059 char *name;
1060 {
1061
1062 if (failures == 0)
1063 return;
1064 if (hostname) {
1065 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s",
1066 failures, failures > 1 ? "S" : "", hostname);
1067 syslog(LOG_AUTHPRIV|LOG_NOTICE,
1068 "%d LOGIN FAILURE%s FROM %s, %s",
1069 failures, failures > 1 ? "S" : "", hostname, name);
1070 } else {
1071 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s",
1072 failures, failures > 1 ? "S" : "", tty);
1073 syslog(LOG_AUTHPRIV|LOG_NOTICE,
1074 "%d LOGIN FAILURE%s ON %s, %s",
1075 failures, failures > 1 ? "S" : "", tty, name);
1076 }
1077 }
1078
1079 const char *
1080 stypeof(ttyid)
1081 const char *ttyid;
1082 {
1083 struct ttyent *t;
1084
1085 return (ttyid && (t = getttynam(ttyid)) ? t->ty_type : NULL);
1086 }
1087
1088 void
1089 sleepexit(eval)
1090 int eval;
1091 {
1092
1093 (void)sleep(5);
1094 exit(eval);
1095 }
1096