login.c revision 1.70 1 /* $NetBSD: login.c,v 1.70 2002/09/25 03:45:32 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.70 2002/09/25 03:45:32 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)strncpy(tbuf, username, sizeof(tbuf) - 1);
381 tbuf[sizeof(tbuf) - 1] = '\0';
382
383 if ((pwd = getpwnam(username)) != NULL)
384 salt = pwd->pw_passwd;
385 else
386 salt = "xx";
387
388 #ifdef LOGIN_CAP
389 /*
390 * Establish the class now, before we might goto
391 * within the next block. pwd can be NULL since it
392 * falls back to the "default" class if it is.
393 */
394 lc = login_getclass(pwd ? pwd->pw_class : NULL);
395 #endif
396 /*
397 * if we have a valid account name, and it doesn't have a
398 * password, or the -f option was specified and the caller
399 * is root or the caller isn't changing their uid, don't
400 * authenticate.
401 */
402 if (pwd) {
403 if (pwd->pw_uid == 0)
404 rootlogin = 1;
405
406 if (fflag && (uid == 0 || uid == pwd->pw_uid)) {
407 /* already authenticated */
408 #ifdef KERBEROS5
409 if (login_krb5_get_tickets && Fflag)
410 k5_read_creds(username);
411 #endif
412 break;
413 } else if (pwd->pw_passwd[0] == '\0') {
414 /* pretend password okay */
415 rval = 0;
416 goto ttycheck;
417 }
418 }
419
420 fflag = 0;
421
422 (void)setpriority(PRIO_PROCESS, 0, -4);
423
424 #ifdef SKEY
425 if (skey_haskey(username) == 0) {
426 static char skprompt[80];
427 const char *skinfo = skey_keyinfo(username);
428
429 (void)snprintf(skprompt, sizeof(skprompt)-1,
430 "Password [%s]:",
431 skinfo ? skinfo : "error getting challenge");
432 pwprompt = skprompt;
433 } else
434 #endif
435 pwprompt = "Password:";
436
437 p = getpass(pwprompt);
438
439 if (pwd == NULL) {
440 rval = 1;
441 goto skip;
442 }
443 #ifdef KERBEROS
444 if (
445 #ifdef KERBEROS5
446 /* allow a user to get both krb4 and krb5 tickets, if
447 * desired. If krb5 is compiled in, the default action
448 * is to ignore krb4 and get krb5 tickets, but the user
449 * can override this in the krb5.conf. */
450 login_krb4_get_tickets &&
451 #endif
452 klogin(pwd, instance, localhost, p) == 0) {
453 rval = 0;
454 got_tickets = 1;
455 }
456 #endif
457 #ifdef KERBEROS5
458 if (login_krb5_get_tickets &&
459 k5login(pwd, instance, localhost, p) == 0) {
460 rval = 0;
461 got_tickets = 1;
462 }
463 #endif
464 #if defined(KERBEROS) || defined(KERBEROS5)
465 if (got_tickets)
466 goto skip;
467 #endif
468 #ifdef SKEY
469 if (skey_haskey(username) == 0 &&
470 skey_passcheck(username, p) != -1) {
471 rval = 0;
472 goto skip;
473 }
474 #endif
475 if (!sflag && *pwd->pw_passwd != '\0' &&
476 !strcmp(crypt(p, pwd->pw_passwd), pwd->pw_passwd)) {
477 rval = 0;
478 require_chpass = 1;
479 goto skip;
480 }
481 rval = 1;
482
483 skip:
484 memset(p, 0, strlen(p));
485
486 (void)setpriority(PRIO_PROCESS, 0, 0);
487
488 ttycheck:
489 /*
490 * If trying to log in as root without Kerberos,
491 * but with insecure terminal, refuse the login attempt.
492 */
493 if (pwd && !rval && rootlogin && !rootterm(tty)) {
494 (void)fprintf(stderr,
495 "%s login refused on this terminal.\n",
496 pwd->pw_name);
497 if (hostname)
498 syslog(LOG_NOTICE,
499 "LOGIN %s REFUSED FROM %s ON TTY %s",
500 pwd->pw_name, hostname, tty);
501 else
502 syslog(LOG_NOTICE,
503 "LOGIN %s REFUSED ON TTY %s",
504 pwd->pw_name, tty);
505 continue;
506 }
507
508 if (pwd && !rval)
509 break;
510
511 (void)printf("Login incorrect\n");
512 failures++;
513 cnt++;
514 /* we allow 10 tries, but after 3 we start backing off */
515 if (cnt > login_backoff) {
516 if (cnt >= login_retries) {
517 badlogin(username);
518 sleepexit(1);
519 }
520 sleep((u_int)((cnt - 3) * 5));
521 }
522 }
523
524 /* committed to login -- turn off timeout */
525 (void)alarm((u_int)0);
526
527 endpwent();
528
529 /* if user not super-user, check for disabled logins */
530 #ifdef LOGIN_CAP
531 if (!login_getcapbool(lc, "ignorenologin", rootlogin))
532 checknologin(login_getcapstr(lc, "nologin", NULL, NULL));
533 #else
534 if (!rootlogin)
535 checknologin(NULL);
536 #endif
537
538 #ifdef LOGIN_CAP
539 quietlog = login_getcapbool(lc, "hushlogin", 0);
540 #else
541 quietlog = 0;
542 #endif
543 /* Temporarily give up special privileges so we can change */
544 /* into NFS-mounted homes that are exported for non-root */
545 /* access and have mode 7x0 */
546 saved_uid = geteuid();
547 saved_gid = getegid();
548 nsaved_gids = getgroups(NGROUPS_MAX, saved_gids);
549
550 (void)setegid(pwd->pw_gid);
551 initgroups(username, pwd->pw_gid);
552 (void)seteuid(pwd->pw_uid);
553
554 if (chdir(pwd->pw_dir) < 0) {
555 #ifdef LOGIN_CAP
556 if (login_getcapbool(lc, "requirehome", 0)) {
557 (void)printf("Home directory %s required\n",
558 pwd->pw_dir);
559 sleepexit(1);
560 }
561 #endif
562 (void)printf("No home directory %s!\n", pwd->pw_dir);
563 if (chdir("/"))
564 exit(0);
565 pwd->pw_dir = "/";
566 (void)printf("Logging in with home = \"/\".\n");
567 }
568
569 if (!quietlog)
570 quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0;
571
572 /* regain special privileges */
573 (void)seteuid(saved_uid);
574 setgroups(nsaved_gids, saved_gids);
575 (void)setegid(saved_gid);
576
577 #ifdef LOGIN_CAP
578 pw_warntime = login_getcaptime(lc, "password-warn",
579 _PASSWORD_WARNDAYS * SECSPERDAY,
580 _PASSWORD_WARNDAYS * SECSPERDAY);
581 #endif
582
583 (void)gettimeofday(&now, (struct timezone *)NULL);
584 if (pwd->pw_expire) {
585 if (now.tv_sec >= pwd->pw_expire) {
586 (void)printf("Sorry -- your account has expired.\n");
587 sleepexit(1);
588 } else if (pwd->pw_expire - now.tv_sec < pw_warntime &&
589 !quietlog)
590 (void)printf("Warning: your account expires on %s",
591 ctime(&pwd->pw_expire));
592 }
593 if (pwd->pw_change) {
594 if (pwd->pw_change == _PASSWORD_CHGNOW)
595 need_chpass = 1;
596 else if (now.tv_sec >= pwd->pw_change) {
597 (void)printf("Sorry -- your password has expired.\n");
598 sleepexit(1);
599 } else if (pwd->pw_change - now.tv_sec < pw_warntime &&
600 !quietlog)
601 (void)printf("Warning: your password expires on %s",
602 ctime(&pwd->pw_change));
603
604 }
605 /* Nothing else left to fail -- really log in. */
606 update_db(quietlog);
607
608 (void)chown(ttyn, pwd->pw_uid,
609 (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid);
610
611 if (ttyaction(ttyn, "login", pwd->pw_name))
612 (void)printf("Warning: ttyaction failed.\n");
613
614 #if defined(KERBEROS) || defined(KERBEROS5)
615 /* Fork so that we can call kdestroy */
616 if (
617 #ifdef KERBEROS5
618 ! login_krb5_retain_ccache &&
619 #endif
620 has_ccache)
621 dofork();
622 #endif
623
624 /* Destroy environment unless user has requested its preservation. */
625 if (!pflag)
626 environ = envinit;
627
628 #ifdef LOGIN_CAP
629 if (nested == NULL && setusercontext(lc, pwd, pwd->pw_uid,
630 LOGIN_SETLOGIN) != 0) {
631 syslog(LOG_ERR, "setusercontext failed");
632 exit(1);
633 }
634 if (setusercontext(lc, pwd, pwd->pw_uid,
635 (LOGIN_SETALL & ~(LOGIN_SETPATH|LOGIN_SETLOGIN))) != 0) {
636 syslog(LOG_ERR, "setusercontext failed");
637 exit(1);
638 }
639 #else
640 (void)setgid(pwd->pw_gid);
641
642 initgroups(username, pwd->pw_gid);
643
644 if (nested == NULL && setlogin(pwd->pw_name) < 0)
645 syslog(LOG_ERR, "setlogin() failure: %m");
646
647 /* Discard permissions last so can't get killed and drop core. */
648 if (rootlogin)
649 (void)setuid(0);
650 else
651 (void)setuid(pwd->pw_uid);
652 #endif
653
654 if (*pwd->pw_shell == '\0')
655 pwd->pw_shell = _PATH_BSHELL;
656 #ifdef LOGIN_CAP
657 if ((shell = login_getcapstr(lc, "shell", NULL, NULL)) != NULL) {
658 if ((shell = strdup(shell)) == NULL) {
659 syslog(LOG_ERR, "Cannot alloc mem");
660 sleepexit(1);
661 }
662 pwd->pw_shell = shell;
663 }
664 #endif
665
666 (void)setenv("HOME", pwd->pw_dir, 1);
667 (void)setenv("SHELL", pwd->pw_shell, 1);
668 if (term[0] == '\0') {
669 char *tt = (char *)stypeof(tty);
670 #ifdef LOGIN_CAP
671 if (tt == NULL)
672 tt = login_getcapstr(lc, "term", NULL, NULL);
673 #endif
674 /* unknown term -> "su" */
675 (void)strncpy(term, tt != NULL ? tt : "su", sizeof(term));
676 }
677 (void)setenv("TERM", term, 0);
678 (void)setenv("LOGNAME", pwd->pw_name, 1);
679 (void)setenv("USER", pwd->pw_name, 1);
680
681 #ifdef LOGIN_CAP
682 setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETPATH);
683 #else
684 (void)setenv("PATH", _PATH_DEFPATH, 0);
685 #endif
686
687 #ifdef KERBEROS
688 if (krbtkfile_env)
689 (void)setenv("KRBTKFILE", krbtkfile_env, 1);
690 #endif
691 #ifdef KERBEROS5
692 if (krb5tkfile_env)
693 (void)setenv("KRB5CCNAME", krb5tkfile_env, 1);
694 #endif
695
696 if (tty[sizeof("tty")-1] == 'd')
697 syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
698
699 /* If fflag is on, assume caller/authenticator has logged root login. */
700 if (rootlogin && fflag == 0) {
701 if (hostname)
702 syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s",
703 username, tty, hostname);
704 else
705 syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s",
706 username, tty);
707 }
708
709 #if defined(KERBEROS) || defined(KERBEROS5)
710 if (KERBEROS_CONFIGURED && !quietlog && notickets == 1)
711 (void)printf("Warning: no Kerberos tickets issued.\n");
712 #endif
713
714 if (!quietlog) {
715 char *fname;
716 #ifdef LOGIN_CAP
717 fname = login_getcapstr(lc, "copyright", NULL, NULL);
718 if (fname != NULL && access(fname, F_OK) == 0)
719 motd(fname);
720 else
721 #endif
722 (void)printf("%s", copyrightstr);
723
724 #ifdef LOGIN_CAP
725 fname = login_getcapstr(lc, "welcome", NULL, NULL);
726 if (fname == NULL || access(fname, F_OK) != 0)
727 #endif
728 fname = _PATH_MOTDFILE;
729 motd(fname);
730
731 (void)snprintf(tbuf,
732 sizeof(tbuf), "%s/%s", _PATH_MAILDIR, pwd->pw_name);
733 if (stat(tbuf, &st) == 0 && st.st_size != 0)
734 (void)printf("You have %smail.\n",
735 (st.st_mtime > st.st_atime) ? "new " : "");
736 }
737
738 #ifdef LOGIN_CAP
739 login_close(lc);
740 #endif
741
742 (void)signal(SIGALRM, SIG_DFL);
743 (void)signal(SIGQUIT, SIG_DFL);
744 (void)signal(SIGINT, SIG_DFL);
745 (void)signal(SIGTSTP, SIG_IGN);
746
747 tbuf[0] = '-';
748 (void)strncpy(tbuf + 1, (p = strrchr(pwd->pw_shell, '/')) ?
749 p + 1 : pwd->pw_shell, sizeof(tbuf) - 2);
750
751 /* Wait to change password until we're unprivileged */
752 if (need_chpass) {
753 if (!require_chpass)
754 (void)printf(
755 "Warning: your password has expired. Please change it as soon as possible.\n");
756 else {
757 int status;
758
759 (void)printf(
760 "Your password has expired. Please choose a new one.\n");
761 switch (fork()) {
762 case -1:
763 warn("fork");
764 sleepexit(1);
765 case 0:
766 execl(_PATH_BINPASSWD, "passwd", 0);
767 _exit(1);
768 default:
769 if (wait(&status) == -1 ||
770 WEXITSTATUS(status))
771 sleepexit(1);
772 }
773 }
774 }
775
776 #ifdef KERBEROS5
777 if (login_krb5_get_tickets)
778 k5_write_creds();
779 #endif
780 execlp(pwd->pw_shell, tbuf, 0);
781 err(1, "%s", pwd->pw_shell);
782 }
783
784 #if defined(KERBEROS) || defined(KERBEROS5)
785 #define NBUFSIZ (MAXLOGNAME + 1 + 5) /* .root suffix */
786 #else
787 #define NBUFSIZ (MAXLOGNAME + 1)
788 #endif
789
790 #if defined(KERBEROS) || defined(KERBEROS5)
791 /*
792 * This routine handles cleanup stuff, and the like.
793 * It exists only in the child process.
794 */
795 #include <sys/wait.h>
796 void
797 dofork()
798 {
799 int child;
800
801 if (!(child = fork()))
802 return; /* Child process */
803
804 /*
805 * Setup stuff? This would be things we could do in parallel
806 * with login
807 */
808 (void)chdir("/"); /* Let's not keep the fs busy... */
809
810 /* If we're the parent, watch the child until it dies */
811 while (wait(0) != child)
812 ;
813
814 /* Cleanup stuff */
815 /* Run kdestroy to destroy tickets */
816 #ifdef KERBEROS
817 kdestroy();
818 #endif
819 #ifdef KERBEROS5
820 if (login_krb5_get_tickets)
821 k5destroy();
822 #endif
823
824 /* Leave */
825 exit(0);
826 }
827 #endif
828
829 void
830 getloginname()
831 {
832 int ch;
833 char *p;
834 static char nbuf[NBUFSIZ];
835
836 for (;;) {
837 (void)printf("login: ");
838 for (p = nbuf; (ch = getchar()) != '\n'; ) {
839 if (ch == EOF) {
840 badlogin(username);
841 exit(0);
842 }
843 if (p < nbuf + (NBUFSIZ - 1))
844 *p++ = ch;
845 }
846 if (p > nbuf) {
847 if (nbuf[0] == '-')
848 (void)fprintf(stderr,
849 "login names may not start with '-'.\n");
850 else {
851 *p = '\0';
852 username = nbuf;
853 break;
854 }
855 }
856 }
857 }
858
859 int
860 rootterm(ttyn)
861 char *ttyn;
862 {
863 struct ttyent *t;
864
865 return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE);
866 }
867
868 jmp_buf motdinterrupt;
869
870 void
871 motd(fname)
872 char *fname;
873 {
874 int fd, nchars;
875 sig_t oldint;
876 char tbuf[8192];
877
878 if ((fd = open(fname ? fname : _PATH_MOTDFILE, O_RDONLY, 0)) < 0)
879 return;
880 oldint = signal(SIGINT, sigint);
881 if (setjmp(motdinterrupt) == 0)
882 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
883 (void)write(fileno(stdout), tbuf, nchars);
884 (void)signal(SIGINT, oldint);
885 (void)close(fd);
886 }
887
888 /* ARGSUSED */
889 void
890 sigint(signo)
891 int signo;
892 {
893
894 longjmp(motdinterrupt, 1);
895 }
896
897 /* ARGSUSED */
898 void
899 timedout(signo)
900 int signo;
901 {
902
903 (void)fprintf(stderr, "Login timed out after %d seconds\n", timeout);
904 exit(0);
905 }
906
907 void
908 checknologin(fname)
909 char *fname;
910 {
911 int fd, nchars;
912 char tbuf[8192];
913
914 if ((fd = open(fname ? fname : _PATH_NOLOGIN, O_RDONLY, 0)) >= 0) {
915 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
916 (void)write(fileno(stdout), tbuf, nchars);
917 sleepexit(0);
918 }
919 }
920
921 static void
922 update_db(int quietlog)
923 {
924 if (nested != NULL) {
925 if (hostname != NULL)
926 syslog(LOG_NOTICE, "%s to %s on tty %s from %s",
927 nested, pwd->pw_name, tty, hostname);
928 else
929 syslog(LOG_NOTICE, "%s to %s on tty %s", nested,
930 pwd->pw_name, tty);
931
932 return;
933 }
934 if (hostname != NULL) {
935 socklen_t len = sizeof(ss);
936 (void)getpeername(STDIN_FILENO, (struct sockaddr *)&ss, &len);
937 }
938 (void)gettimeofday(&now, NULL);
939 #ifdef SUPPORT_UTMPX
940 doutmpx();
941 dolastlogx(quietlog);
942 quietlog = 1;
943 #endif
944 #ifdef SUPPORT_UTMP
945 doutmp();
946 dolastlog(quietlog);
947 #endif
948 }
949
950 #ifdef SUPPORT_UTMPX
951 static void
952 doutmpx()
953 {
954 struct utmpx utmpx;
955 char *t;
956
957 memset((void *)&utmpx, 0, sizeof(utmpx));
958 utmpx.ut_tv = now;
959 (void)strncpy(utmpx.ut_name, username, sizeof(utmpx.ut_name));
960 if (hostname) {
961 (void)strncpy(utmpx.ut_host, hostname, sizeof(utmpx.ut_host));
962 utmpx.ut_ss = ss;
963 }
964 (void)strncpy(utmpx.ut_line, tty, sizeof(utmpx.ut_line));
965 utmpx.ut_type = USER_PROCESS;
966 utmpx.ut_pid = getpid();
967 t = tty + strlen(tty);
968 if (t - tty >= sizeof(utmpx.ut_id)) {
969 (void)strncpy(utmpx.ut_id, t - sizeof(utmpx.ut_id),
970 sizeof(utmpx.ut_id));
971 } else {
972 (void)strncpy(utmpx.ut_id, tty, sizeof(utmpx.ut_id));
973 }
974 if (pututxline(&utmpx) == NULL)
975 syslog(LOG_NOTICE, "Cannot update utmpx %m");
976 endutxent();
977 if (updwtmpx(_PATH_WTMPX, &utmpx) != 0)
978 syslog(LOG_NOTICE, "Cannot update wtmpx %m");
979 }
980
981 static void
982 dolastlogx(quiet)
983 int quiet;
984 {
985 struct lastlogx ll;
986 if (getlastlogx(pwd->pw_uid, &ll) != NULL) {
987 time_t t = (time_t)ll.ll_tv.tv_sec;
988 (void)printf("Last login: %.24s ", ctime(&t));
989 if (*ll.ll_host != '\0')
990 (void)printf("from %.*s ",
991 (int)sizeof(ll.ll_host),
992 ll.ll_host);
993 (void)printf("on %.*s\n",
994 (int)sizeof(ll.ll_line),
995 ll.ll_line);
996 }
997 ll.ll_tv = now;
998 (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
999 if (hostname) {
1000 (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host));
1001 ll.ll_ss = ss;
1002 }
1003 if (updlastlogx(_PATH_LASTLOGX, pwd->pw_uid, &ll) != 0)
1004 syslog(LOG_NOTICE, "Cannot update lastlogx %m");
1005 }
1006 #endif
1007
1008 #ifdef SUPPORT_UTMP
1009 static void
1010 doutmp()
1011 {
1012 struct utmp utmp;
1013
1014 (void)memset((void *)&utmp, 0, sizeof(utmp));
1015 utmp.ut_time = now.tv_sec;
1016 (void)strncpy(utmp.ut_name, username, sizeof(utmp.ut_name));
1017 if (hostname)
1018 (void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host));
1019 (void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line));
1020 login(&utmp);
1021 }
1022
1023 static void
1024 dolastlog(quiet)
1025 int quiet;
1026 {
1027 struct lastlog ll;
1028 int fd;
1029
1030 if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) {
1031 (void)lseek(fd, (off_t)(pwd->pw_uid * sizeof(ll)), SEEK_SET);
1032 if (!quiet) {
1033 if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) &&
1034 ll.ll_time != 0) {
1035 (void)printf("Last login: %.24s ",
1036 ctime(&ll.ll_time));
1037 if (*ll.ll_host != '\0')
1038 (void)printf("from %.*s ",
1039 (int)sizeof(ll.ll_host),
1040 ll.ll_host);
1041 (void)printf("on %.*s\n",
1042 (int)sizeof(ll.ll_line), ll.ll_line);
1043 }
1044 (void)lseek(fd, (off_t)(pwd->pw_uid * sizeof(ll)),
1045 SEEK_SET);
1046 }
1047 memset((void *)&ll, 0, sizeof(ll));
1048 ll.ll_time = now.tv_sec;
1049 (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
1050 if (hostname)
1051 (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host));
1052 (void)write(fd, (char *)&ll, sizeof(ll));
1053 (void)close(fd);
1054 }
1055 }
1056 #endif
1057
1058 void
1059 badlogin(name)
1060 char *name;
1061 {
1062
1063 if (failures == 0)
1064 return;
1065 if (hostname) {
1066 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s",
1067 failures, failures > 1 ? "S" : "", hostname);
1068 syslog(LOG_AUTHPRIV|LOG_NOTICE,
1069 "%d LOGIN FAILURE%s FROM %s, %s",
1070 failures, failures > 1 ? "S" : "", hostname, name);
1071 } else {
1072 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s",
1073 failures, failures > 1 ? "S" : "", tty);
1074 syslog(LOG_AUTHPRIV|LOG_NOTICE,
1075 "%d LOGIN FAILURE%s ON %s, %s",
1076 failures, failures > 1 ? "S" : "", tty, name);
1077 }
1078 }
1079
1080 const char *
1081 stypeof(ttyid)
1082 const char *ttyid;
1083 {
1084 struct ttyent *t;
1085
1086 return (ttyid && (t = getttynam(ttyid)) ? t->ty_type : NULL);
1087 }
1088
1089 void
1090 sleepexit(eval)
1091 int eval;
1092 {
1093
1094 (void)sleep(5);
1095 exit(eval);
1096 }
1097