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