]> git.saurik.com Git - apple/system_cmds.git/blob - login.tproj/login.c
2b0d828ba693a5c06c70bf7395566fa3a3d39816
[apple/system_cmds.git] / login.tproj / login.c
1 /*-
2 * Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
4 * Copyright (c) 2002 Networks Associates Technologies, Inc.
5 * All rights reserved.
6 *
7 * Portions of this software were developed for the FreeBSD Project by
8 * ThinkSec AS and NAI Labs, the Security Research Division of Network
9 * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
10 * ("CBOSS"), as part of the DARPA CHATS research program.
11 * Portions copyright (c) 1999-2007 Apple Inc. All rights reserved.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. All advertising materials mentioning features or use of this software
22 * must display the following acknowledgement:
23 * This product includes software developed by the University of
24 * California, Berkeley and its contributors.
25 * 4. Neither the name of the University nor the names of its contributors
26 * may be used to endorse or promote products derived from this software
27 * without specific prior written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 * SUCH DAMAGE.
40 */
41
42 #if 0
43 #ifndef lint
44 static char sccsid[] = "@(#)login.c 8.4 (Berkeley) 4/2/94";
45 #endif
46 #endif
47
48 #include <sys/cdefs.h>
49 __FBSDID("$FreeBSD: src/usr.bin/login/login.c,v 1.106 2007/07/04 00:00:40 scf Exp $");
50
51 /*
52 * login [ name ]
53 * login -h hostname (for telnetd, etc.)
54 * login -f name (for pre-authenticated login: datakit, xterm, etc.)
55 */
56
57 #ifndef __APPLE__
58 #include <sys/copyright.h>
59 #endif
60 #ifdef __APPLE__
61 #include <TargetConditionals.h>
62 #endif
63 #include <sys/param.h>
64 #include <sys/file.h>
65 #include <sys/stat.h>
66 #include <sys/time.h>
67 #include <sys/resource.h>
68 #include <sys/wait.h>
69
70 #include <err.h>
71 #include <errno.h>
72 #include <grp.h>
73 #ifdef __APPLE__
74 #include <util.h>
75 #else
76 #include <libutil.h>
77 #endif
78 #ifdef LOGIN_CAP
79 #include <login_cap.h>
80 #endif
81 #include <pwd.h>
82 #include <setjmp.h>
83 #include <signal.h>
84 #include <stdio.h>
85 #include <stdlib.h>
86 #include <string.h>
87 #include <syslog.h>
88 #include <ttyent.h>
89 #include <unistd.h>
90 #ifdef __APPLE__
91 #include <utmpx.h>
92 #ifdef USE_PAM
93 #else /* !USE_PAM */
94 #ifndef _UTX_USERSIZE
95 #define _UTX_USERSIZE MAXLOGNAME
96 #endif
97 #endif /* USE_PAM */
98 #endif /* __APPLE__ */
99
100 #include <sys/types.h>
101 #include <sys/socket.h>
102 #include <netinet/in.h>
103 #include <arpa/inet.h>
104 #include <netdb.h>
105
106 #ifdef USE_BSM_AUDIT
107 #include <bsm/libbsm.h>
108 #include <bsm/audit_uevents.h>
109 #endif
110
111 #ifdef __APPLE__
112 #include <mach/mach_types.h>
113 #include <mach/task.h>
114 #include <mach/mach_init.h>
115 #include <servers/bootstrap.h>
116
117 #include <sys/file.h>
118 #include <tzfile.h>
119 #endif /* __APPLE__ */
120
121 #ifdef USE_PAM
122 #include <security/pam_appl.h>
123 #include <security/openpam.h>
124 #endif /* USE_PAM */
125
126 #include "login.h"
127 #include "pathnames.h"
128
129 #ifdef USE_PAM
130 static int auth_pam(void);
131 #endif /* USE_PAM */
132 static void bail(int, int);
133 #ifdef USE_PAM
134 static int export(const char *);
135 static void export_pam_environment(void);
136 #endif /* USE_PAM */
137 static int motd(const char *);
138 static void badlogin(char *);
139 static char *getloginname(void);
140 #ifdef USE_PAM
141 static void pam_syslog(const char *);
142 static void pam_cleanup(void);
143 #endif /* USE_PAM */
144 static void refused(const char *, const char *, int);
145 static const char *stypeof(char *);
146 static void sigint(int);
147 static void timedout(int);
148 static void usage(void);
149
150 #ifdef __APPLE__
151 static void dolastlog(int);
152 static void handle_sighup(int);
153
154 #ifndef USE_PAM
155 static void checknologin(void);
156 static int rootterm(const char *);
157 #endif /* !USE_PAM */
158 #endif /* __APPLE__ */
159
160 #define TTYGRPNAME "tty" /* group to own ttys */
161 #define DEFAULT_BACKOFF 3
162 #define DEFAULT_RETRIES 10
163 #define DEFAULT_PROMPT "login: "
164 #define DEFAULT_PASSWD_PROMPT "Password:"
165 #define TERM_UNKNOWN "su"
166 #define DEFAULT_WARN (2L * 7L * 86400L) /* Two weeks */
167 #define NO_SLEEP_EXIT 0
168 #define SLEEP_EXIT 5
169
170 /*
171 * This bounds the time given to login. Not a define so it can
172 * be patched on machines where it's too small.
173 */
174 static u_int timeout = 300;
175
176 /* Buffer for signal handling of timeout */
177 static jmp_buf timeout_buf;
178
179 struct passwd *pwd;
180 static int failures;
181
182 static char *envinit[1]; /* empty environment list */
183
184 /*
185 * Command line flags and arguments
186 */
187 static int fflag; /* -f: do not perform authentication */
188 #ifdef __APPLE__
189 static int lflag; /* -l: login session to the commmand that follows username */
190 #endif
191 static int hflag; /* -h: login from remote host */
192 static char *hostname; /* hostname from command line */
193 static int pflag; /* -p: preserve environment */
194
195 /*
196 * User name
197 */
198 static char *username; /* user name */
199 static char *olduser; /* previous user name */
200
201 /*
202 * Prompts
203 */
204 static char default_prompt[] = DEFAULT_PROMPT;
205 static const char *prompt;
206 static char default_passwd_prompt[] = DEFAULT_PASSWD_PROMPT;
207 static const char *passwd_prompt;
208
209 static char *tty;
210
211 /*
212 * PAM data
213 */
214 #ifdef USE_PAM
215 static pam_handle_t *pamh = NULL;
216 static struct pam_conv pamc = { openpam_ttyconv, NULL };
217 static int pam_err;
218 static int pam_silent = PAM_SILENT;
219 static int pam_cred_established;
220 static int pam_session_established;
221 #endif /* USE_PAM */
222
223 #ifdef __APPLE__
224 pid_t pid;
225
226 #ifdef USE_PAM
227 static struct lastlogx lastlog;
228 #endif /* USE_PAM */
229
230 #ifdef USE_BSM_AUDIT
231 au_tid_t tid;
232 #endif /* USE_BSM_AUDIT */
233 #endif /* __APPLE__ */
234
235 int
236 main(int argc, char *argv[])
237 {
238 struct group *gr;
239 struct stat st;
240 int retries, backoff;
241 int ask, ch, cnt, quietlog = 0, rootlogin, rval;
242 uid_t uid, euid;
243 gid_t egid;
244 char *term;
245 char *p, *ttyn;
246 char tname[sizeof(_PATH_TTY) + 10];
247 char *arg0;
248 const char *tp;
249 #ifdef __APPLE__
250 int prio;
251 #ifdef USE_PAM
252 const char *name = "login"; /* PAM config */
253 #else
254 struct utmpx utmp;
255 #endif /* USE_PAM */
256 const char *shell = NULL;
257 #endif /* !__APPLE__ */
258 #ifdef LOGIN_CAP
259 login_cap_t *lc = NULL;
260 login_cap_t *lc_user = NULL;
261 #endif /* LOGIN_CAP */
262 #ifndef __APPLE__
263 pid_t pid;
264 #endif
265 #ifdef USE_BSM_AUDIT
266 char auditsuccess = 1;
267 #endif
268
269 (void)signal(SIGQUIT, SIG_IGN);
270 (void)signal(SIGINT, SIG_IGN);
271 (void)signal(SIGHUP, SIG_IGN);
272 if (setjmp(timeout_buf)) {
273 if (failures)
274 badlogin(username);
275 (void)fprintf(stderr, "Login timed out after %d seconds\n",
276 timeout);
277 bail(NO_SLEEP_EXIT, 0);
278 }
279 (void)signal(SIGALRM, timedout);
280 (void)alarm(timeout);
281 #ifdef __APPLE__
282 prio = getpriority(PRIO_PROCESS, 0);
283 #endif
284 (void)setpriority(PRIO_PROCESS, 0, 0);
285
286 openlog("login", LOG_ODELAY, LOG_AUTH);
287
288 uid = getuid();
289 euid = geteuid();
290 egid = getegid();
291
292 #ifdef __APPLE__
293 while ((ch = getopt(argc, argv, "1fh:lpq")) != -1)
294 #else
295 while ((ch = getopt(argc, argv, "fh:p")) != -1)
296 #endif
297 switch (ch) {
298 case 'f':
299 fflag = 1;
300 break;
301 case 'h':
302 if (uid != 0)
303 errx(1, "-h option: %s", strerror(EPERM));
304 if (strlen(optarg) >= MAXHOSTNAMELEN)
305 errx(1, "-h option: %s: exceeds maximum "
306 "hostname size", optarg);
307 hflag = 1;
308 hostname = optarg;
309 break;
310 case 'p':
311 pflag = 1;
312 break;
313 #ifdef __APPLE__
314 case '1':
315 break;
316 case 'l':
317 lflag = 1;
318 break;
319 case 'q':
320 quietlog = 1;
321 break;
322 #endif
323 case '?':
324 default:
325 if (uid == 0)
326 syslog(LOG_ERR, "invalid flag %c", ch);
327 usage();
328 }
329 argc -= optind;
330 argv += optind;
331
332 if (argc > 0) {
333 username = strdup(*argv);
334 if (username == NULL)
335 err(1, "strdup()");
336 ask = 0;
337 #ifdef __APPLE__
338 argv++;
339 #endif /* __APPLE__ */
340 } else {
341 ask = 1;
342 }
343
344 #ifndef __APPLE__
345 setproctitle("-%s", getprogname());
346 #endif /* !__APPLE__ */
347
348 for (cnt = getdtablesize(); cnt > 2; cnt--)
349 (void)close(cnt);
350
351 /*
352 * Get current TTY
353 */
354 ttyn = ttyname(STDIN_FILENO);
355 if (ttyn == NULL || *ttyn == '\0') {
356 (void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY);
357 ttyn = tname;
358 }
359 if ((tty = strrchr(ttyn, '/')) != NULL)
360 ++tty;
361 else
362 tty = ttyn;
363
364 #ifdef LOGIN_CAP
365 /*
366 * Get "login-retries" & "login-backoff" from default class
367 */
368 lc = login_getclass(NULL);
369 prompt = login_getcapstr(lc, "login_prompt",
370 default_prompt, default_prompt);
371 passwd_prompt = login_getcapstr(lc, "passwd_prompt",
372 default_passwd_prompt, default_passwd_prompt);
373 retries = login_getcapnum(lc, "login-retries",
374 DEFAULT_RETRIES, DEFAULT_RETRIES);
375 backoff = login_getcapnum(lc, "login-backoff",
376 DEFAULT_BACKOFF, DEFAULT_BACKOFF);
377 login_close(lc);
378 lc = NULL;
379 #else /* !LOGIN_CAP */
380 prompt = default_prompt;
381 passwd_prompt = default_passwd_prompt;
382 retries = DEFAULT_RETRIES;
383 backoff = DEFAULT_BACKOFF;
384 #endif /* !LOGIN_CAP */
385
386 #ifdef __APPLE__
387 #ifdef USE_BSM_AUDIT
388 /* Set the terminal id */
389 audit_set_terminal_id(&tid);
390 if (fstat(STDIN_FILENO, &st) < 0) {
391 fprintf(stderr, "login: Unable to stat terminal\n");
392 au_login_fail("Unable to stat terminal", 1);
393 exit(-1);
394 }
395 if (S_ISCHR(st.st_mode)) {
396 tid.port = st.st_rdev;
397 } else {
398 tid.port = 0;
399 }
400 #endif /* USE_BSM_AUDIT */
401 #endif /* __APPLE__ */
402
403 /*
404 * Try to authenticate the user until we succeed or time out.
405 */
406 for (cnt = 0;; ask = 1) {
407 if (ask) {
408 fflag = 0;
409 if (olduser != NULL)
410 free(olduser);
411 olduser = username;
412 username = getloginname();
413 }
414 rootlogin = 0;
415
416 #ifdef __APPLE__
417 if (strlen(username) > _UTX_USERSIZE)
418 username[_UTX_USERSIZE] = '\0';
419 #endif /* __APPLE__ */
420
421 /*
422 * Note if trying multiple user names; log failures for
423 * previous user name, but don't bother logging one failure
424 * for nonexistent name (mistyped username).
425 */
426 if (failures && strcmp(olduser, username) != 0) {
427 if (failures > (pwd ? 0 : 1))
428 badlogin(olduser);
429 }
430
431 #ifdef __APPLE__
432 #ifdef USE_PAM
433 /* get lastlog info before PAM make a new entry */
434 if (!quietlog)
435 getlastlogxbyname(username, &lastlog);
436 #endif /* USE_PAM */
437 #endif /* __APPLE__ */
438
439 pwd = getpwnam(username);
440
441 #ifdef USE_PAM
442 /*
443 * Load the PAM policy and set some variables
444 */
445 #ifdef __APPLE__
446 if (fflag && (pwd != NULL) && (pwd->pw_uid == uid)) {
447 name = "login.term";
448 }
449 #endif
450 pam_err = pam_start(name, username, &pamc, &pamh);
451 if (pam_err != PAM_SUCCESS) {
452 pam_syslog("pam_start()");
453 #ifdef USE_BSM_AUDIT
454 au_login_fail("PAM Error", 1);
455 #endif
456 bail(NO_SLEEP_EXIT, 1);
457 }
458 pam_err = pam_set_item(pamh, PAM_TTY, tty);
459 if (pam_err != PAM_SUCCESS) {
460 pam_syslog("pam_set_item(PAM_TTY)");
461 #ifdef USE_BSM_AUDIT
462 au_login_fail("PAM Error", 1);
463 #endif
464 bail(NO_SLEEP_EXIT, 1);
465 }
466 pam_err = pam_set_item(pamh, PAM_RHOST, hostname);
467 if (pam_err != PAM_SUCCESS) {
468 pam_syslog("pam_set_item(PAM_RHOST)");
469 #ifdef USE_BSM_AUDIT
470 au_login_fail("PAM Error", 1);
471 #endif
472 bail(NO_SLEEP_EXIT, 1);
473 }
474 #endif /* USE_PAM */
475
476 if (pwd != NULL && pwd->pw_uid == 0)
477 rootlogin = 1;
478
479 /*
480 * If the -f option was specified and the caller is
481 * root or the caller isn't changing their uid, don't
482 * authenticate.
483 */
484 if (pwd != NULL && fflag &&
485 (uid == (uid_t)0 || uid == (uid_t)pwd->pw_uid)) {
486 /* already authenticated */
487 rval = 0;
488 #ifdef USE_BSM_AUDIT
489 auditsuccess = 0; /* opened a terminal window only */
490 #endif
491
492 #ifdef __APPLE__
493 #ifndef USE_PAM
494 /* If the account doesn't have a password, authenticate. */
495 } else if (pwd != NULL && pwd->pw_passwd[0] == '\0') {
496 rval = 0;
497 #endif /* !USE_PAM */
498 #endif /* __APPLE__ */
499 } else if( pwd ) {
500 fflag = 0;
501 (void)setpriority(PRIO_PROCESS, 0, -4);
502 #ifdef USE_PAM
503 rval = auth_pam();
504 #else
505 {
506 char* salt = pwd->pw_passwd;
507 char* p = getpass(passwd_prompt);
508 rval = strcmp(crypt(p, salt), salt);
509 memset(p, 0, strlen(p));
510 }
511 #endif
512 (void)setpriority(PRIO_PROCESS, 0, 0);
513 } else {
514 rval = -1;
515 }
516
517 #ifdef __APPLE__
518 #ifndef USE_PAM
519 /*
520 * If trying to log in as root but with insecure terminal,
521 * refuse the login attempt.
522 */
523 if (pwd && rootlogin && !rootterm(tty)) {
524 refused("root login refused on this terminal", "ROOTTERM", 0);
525 #ifdef USE_BSM_AUDIT
526 au_login_fail("Login refused on terminal", 0);
527 #endif
528 continue;
529 }
530 #endif /* !USE_PAM */
531 #endif /* __APPLE__ */
532
533 if (pwd && rval == 0)
534 break;
535
536 #ifdef USE_PAM
537 pam_cleanup();
538 #endif /* USE_PAM */
539
540 /*
541 * We are not exiting here, but this corresponds to a failed
542 * login event, so set exitstatus to 1.
543 */
544 #ifdef USE_BSM_AUDIT
545 au_login_fail("Login incorrect", 1);
546 #endif
547
548 (void)printf("Login incorrect\n");
549 failures++;
550
551 pwd = NULL;
552
553 /*
554 * Allow up to 'retry' (10) attempts, but start
555 * backing off after 'backoff' (3) attempts.
556 */
557 if (++cnt > backoff) {
558 if (cnt >= retries) {
559 badlogin(username);
560 bail(SLEEP_EXIT, 1);
561 }
562 sleep((u_int)((cnt - backoff) * 5));
563 }
564 }
565
566 /* committed to login -- turn off timeout */
567 (void)alarm((u_int)0);
568 (void)signal(SIGHUP, SIG_DFL);
569
570 endpwent();
571
572 #ifdef __APPLE__
573 if (!pwd) {
574 fprintf(stderr, "login: Unable to find user: %s\n", username);
575 exit(1);
576 }
577
578 #ifndef USE_PAM
579 /* if user not super-user, check for disabled logins */
580 if (!rootlogin)
581 checknologin();
582 #endif /* !USE_PAM */
583 #endif /* APPLE */
584
585 #ifdef USE_BSM_AUDIT
586 /* Audit successful login. */
587 if (auditsuccess)
588 au_login_success();
589 #endif
590
591 #ifdef LOGIN_CAP
592 /*
593 * Establish the login class.
594 */
595 lc = login_getpwclass(pwd);
596 lc_user = login_getuserclass(pwd);
597
598 if (!(quietlog = login_getcapbool(lc_user, "hushlogin", 0)))
599 quietlog = login_getcapbool(lc, "hushlogin", 0);
600 #endif /* LOGIN_CAP */
601
602 #ifndef __APPLE__
603 /*
604 * Switching needed for NFS with root access disabled.
605 *
606 * XXX: This change fails to modify the additional groups for the
607 * process, and as such, may restrict rights normally granted
608 * through those groups.
609 */
610 (void)setegid(pwd->pw_gid);
611 (void)seteuid(rootlogin ? 0 : pwd->pw_uid);
612
613 if (!*pwd->pw_dir || chdir(pwd->pw_dir) < 0) {
614 #ifdef LOGIN_CAP
615 if (login_getcapbool(lc, "requirehome", 0))
616 refused("Home directory not available", "HOMEDIR", 1);
617 #endif /* LOGIN_CAP */
618 if (chdir("/") < 0)
619 refused("Cannot find root directory", "ROOTDIR", 1);
620 if (!quietlog || *pwd->pw_dir)
621 printf("No home directory.\nLogging in with home = \"/\".\n");
622 pwd->pw_dir = strdup("/");
623 if (pwd->pw_dir == NULL) {
624 syslog(LOG_NOTICE, "strdup(): %m");
625 bail(SLEEP_EXIT, 1);
626 }
627 }
628
629 (void)seteuid(euid);
630 (void)setegid(egid);
631 #endif /* !__APPLE__ */
632 if (!quietlog) {
633 quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0;
634 #ifdef USE_PAM
635 if (!quietlog)
636 pam_silent = 0;
637 #endif /* USE_PAM */
638 }
639
640 #ifdef __APPLE__
641 /* Nothing else left to fail -- really log in. */
642 #ifndef USE_PAM
643 memset((void *)&utmp, 0, sizeof(utmp));
644 (void)gettimeofday(&utmp.ut_tv, NULL);
645 (void)strncpy(utmp.ut_user, username, sizeof(utmp.ut_user));
646 if (hostname)
647 (void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host));
648 (void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line));
649 utmp.ut_type = USER_PROCESS | UTMPX_AUTOFILL_MASK;
650 utmp.ut_pid = getpid();
651 pututxline(&utmp);
652 #endif /* USE_PAM */
653
654 shell = "";
655 #endif /* !__APPLE__ */
656 #ifdef LOGIN_CAP
657 shell = login_getcapstr(lc, "shell", pwd->pw_shell, pwd->pw_shell);
658 #endif /* !LOGIN_CAP */
659 if (*pwd->pw_shell == '\0')
660 pwd->pw_shell = strdup(_PATH_BSHELL);
661 if (pwd->pw_shell == NULL) {
662 syslog(LOG_NOTICE, "strdup(): %m");
663 bail(SLEEP_EXIT, 1);
664 }
665
666 #if defined(__APPLE__) && TARGET_OS_EMBEDDED
667 /* on embedded, allow a shell to live in /var/debug_mount/bin/sh */
668 #define _PATH_DEBUGSHELL "/var/debug_mount/bin/sh"
669 if (stat(pwd->pw_shell, &st) != 0) {
670 if (stat(_PATH_DEBUGSHELL, &st) == 0) {
671 pwd->pw_shell = strdup(_PATH_DEBUGSHELL);
672 }
673 }
674 #endif
675
676 if (*shell == '\0') /* Not overridden */
677 shell = pwd->pw_shell;
678 if ((shell = strdup(shell)) == NULL) {
679 syslog(LOG_NOTICE, "strdup(): %m");
680 bail(SLEEP_EXIT, 1);
681 }
682
683 #ifdef __APPLE__
684 dolastlog(quietlog);
685 #endif
686
687 #ifndef __APPLE__
688 /*
689 * Set device protections, depending on what terminal the
690 * user is logged in. This feature is used on Suns to give
691 * console users better privacy.
692 */
693 login_fbtab(tty, pwd->pw_uid, pwd->pw_gid);
694 #endif /* !__APPLE__ */
695
696 /*
697 * Clear flags of the tty. None should be set, and when the
698 * user sets them otherwise, this can cause the chown to fail.
699 * Since it isn't clear that flags are useful on character
700 * devices, we just clear them.
701 *
702 * We don't log in the case of EOPNOTSUPP because dev might be
703 * on NFS, which doesn't support chflags.
704 *
705 * We don't log in the EROFS because that means that /dev is on
706 * a read only file system and we assume that the permissions there
707 * are sane.
708 */
709 if (ttyn != tname && chflags(ttyn, 0))
710 #ifdef __APPLE__
711 if (errno != EOPNOTSUPP && errno != ENOTSUP && errno != EROFS)
712 #else
713 if (errno != EOPNOTSUPP && errno != EROFS)
714 #endif
715 syslog(LOG_ERR, "chflags(%s): %m", ttyn);
716 if (ttyn != tname && chown(ttyn, pwd->pw_uid,
717 (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid))
718 if (errno != EROFS)
719 syslog(LOG_ERR, "chown(%s): %m", ttyn);
720
721 #ifdef __APPLE__
722 (void)chmod(ttyn, 0620);
723 #endif /* __APPLE__ */
724
725 #ifndef __APPLE__
726 /*
727 * Exclude cons/vt/ptys only, assume dialup otherwise
728 * TODO: Make dialup tty determination a library call
729 * for consistency (finger etc.)
730 */
731 if (hflag && isdialuptty(tty))
732 syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
733 #endif /* !__APPLE__ */
734
735 #ifdef LOGALL
736 /*
737 * Syslog each successful login, so we don't have to watch
738 * hundreds of wtmp or lastlogin files.
739 */
740 if (hflag)
741 syslog(LOG_INFO, "login from %s on %s as %s",
742 hostname, tty, pwd->pw_name);
743 else
744 syslog(LOG_INFO, "login on %s as %s",
745 tty, pwd->pw_name);
746 #endif
747
748 /*
749 * If fflag is on, assume caller/authenticator has logged root
750 * login.
751 */
752 if (rootlogin && fflag == 0) {
753 if (hflag)
754 syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s",
755 username, tty, hostname);
756 else
757 syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s",
758 username, tty);
759 }
760
761 /*
762 * Destroy environment unless user has requested its
763 * preservation - but preserve TERM in all cases
764 */
765 term = getenv("TERM");
766 if (!pflag)
767 environ = envinit;
768 if (term != NULL)
769 setenv("TERM", term, 0);
770
771 #ifndef __APPLE__
772 /*
773 * PAM modules might add supplementary groups during pam_setcred().
774 */
775 if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) != 0) {
776 syslog(LOG_ERR, "setusercontext() failed - exiting");
777 bail(NO_SLEEP_EXIT, 1);
778 }
779 #endif /* !__APPLE__ */
780 #ifdef USE_PAM
781 pam_err = pam_setcred(pamh, pam_silent|PAM_ESTABLISH_CRED);
782 if (pam_err != PAM_SUCCESS) {
783 pam_syslog("pam_setcred()");
784 bail(NO_SLEEP_EXIT, 1);
785 }
786 pam_cred_established = 1;
787
788 pam_err = pam_open_session(pamh, pam_silent);
789 if (pam_err != PAM_SUCCESS) {
790 pam_syslog("pam_open_session()");
791 bail(NO_SLEEP_EXIT, 1);
792 }
793 pam_session_established = 1;
794 #endif /* USE_PAM */
795
796 #ifdef __APPLE__
797 /* <rdar://problem/5377791>
798 Install a signal handler that will forward SIGHUP to the
799 child and process group. The parent should not exit on
800 SIGHUP so that the tty ownership can be reset. */
801 (void)signal(SIGHUP, handle_sighup);
802 #endif /* __APPLE__ */
803
804 /*
805 * We must fork() before setuid() because we need to call
806 * pam_close_session() as root.
807 */
808 pid = fork();
809 if (pid < 0) {
810 err(1, "fork");
811 } else if (pid != 0) {
812 /*
813 * Parent: wait for child to finish, then clean up
814 * session.
815 */
816 int status;
817 #ifndef __APPLE__
818 setproctitle("-%s [pam]", getprogname());
819 #endif /* !__APPLE__ */
820 #ifdef __APPLE__
821 /* Our SIGHUP handler may interrupt the wait */
822 int res;
823 do {
824 res = waitpid(pid, &status, 0);
825 } while (res == -1 && errno == EINTR);
826 #else
827 waitpid(pid, &status, 0);
828 #endif
829 #ifdef __APPLE__
830 chown(ttyn, 0, 0);
831 chmod(ttyn, 0666);
832 #endif /* __APPLE__ */
833 bail(NO_SLEEP_EXIT, 0);
834 }
835
836 /*
837 * NOTICE: We are now in the child process!
838 */
839
840 #ifdef __APPLE__
841 /* Restore the default SIGHUP handler for the child. */
842 (void)signal(SIGHUP, SIG_DFL);
843 #endif /* __APPLE__ */
844
845 #ifdef USE_PAM
846 /*
847 * Add any environment variables the PAM modules may have set.
848 */
849 export_pam_environment();
850
851 /*
852 * We're done with PAM now; our parent will deal with the rest.
853 */
854 pam_end(pamh, 0);
855 pamh = NULL;
856 #endif /* USE_PAM */
857
858 /*
859 * We don't need to be root anymore, so set the login name and
860 * the UID.
861 */
862 if (setlogin(username) != 0) {
863 syslog(LOG_ERR, "setlogin(%s): %m - exiting", username);
864 bail(NO_SLEEP_EXIT, 1);
865 }
866 #ifdef __APPLE__
867 /* <rdar://problem/6041650> restore process priority if not changing uids */
868 if (uid == (uid_t)pwd->pw_uid) {
869 (void)setpriority(PRIO_PROCESS, 0, prio);
870 }
871
872 (void)setgid(pwd->pw_gid);
873 if (initgroups(username, pwd->pw_gid) == -1)
874 syslog(LOG_ERR, "login: initgroups() failed");
875 pwd = getpwnam(username); // 7258548
876 (void) setuid(rootlogin ? 0 : pwd->pw_uid);
877 #else /* !__APPLE__ */
878 if (setusercontext(lc, pwd, pwd->pw_uid,
879 LOGIN_SETALL & ~(LOGIN_SETLOGIN|LOGIN_SETGROUP)) != 0) {
880 syslog(LOG_ERR, "setusercontext() failed - exiting");
881 exit(1);
882 }
883 #endif /* !__APPLE__ */
884
885 #ifdef __APPLE__
886 /* We test for the home directory after pam_open_session(3)
887 * as the home directory may have been mounted by a session
888 * module, and after changing uid as the home directory may
889 * be NFS with root access disabled. */
890 if (!lflag) {
891 /* First do a stat in case the homedir is automounted */
892 stat(pwd->pw_dir,&st);
893 if (!*pwd->pw_dir || chdir(pwd->pw_dir) < 0) {
894 printf("No home directory: %s\n", pwd->pw_dir);
895 if (chdir("/") < 0) {
896 refused("Cannot find root directory", "ROOTDIR", 0);
897 exit(1);
898 }
899 pwd->pw_dir = strdup("/");
900 if (pwd->pw_dir == NULL) {
901 syslog(LOG_NOTICE, "strdup(): %m");
902 exit(1);
903 }
904 }
905 }
906 #endif /* __APPLE__ */
907 if (pwd->pw_shell) {
908 (void)setenv("SHELL", pwd->pw_shell, 1);
909 } else {
910 syslog(LOG_ERR, "pwd->pw_shell not set - exiting", username);
911 bail(NO_SLEEP_EXIT, 1);
912 }
913 if (pwd->pw_dir) {
914 (void)setenv("HOME", pwd->pw_dir, 1);
915 } else {
916 (void)setenv("HOME", "/", 1);
917 }
918 /* Overwrite "term" from login.conf(5) for any known TERM */
919 if (term == NULL && (tp = stypeof(tty)) != NULL)
920 (void)setenv("TERM", tp, 1);
921 else
922 (void)setenv("TERM", TERM_UNKNOWN, 0);
923 (void)setenv("LOGNAME", username, 1);
924 (void)setenv("USER", username, 1);
925 (void)setenv("PATH", rootlogin ? _PATH_STDPATH : _PATH_DEFPATH, 0);
926
927 #ifdef __APPLE__
928 /* Re-enable crash reporter */
929 do {
930 kern_return_t kr;
931 mach_port_t bp, ep, mts;
932 thread_state_flavor_t flavor = 0;
933
934 #if defined(__ppc__)
935 flavor = PPC_THREAD_STATE64;
936 #elif defined(__i386__) || defined(__x86_64__)
937 flavor = x86_THREAD_STATE;
938 #elif defined(__arm__)
939 flavor = ARM_THREAD_STATE;
940 #else
941 #error unsupported architecture
942 #endif
943
944 mts = mach_task_self();
945
946 kr = task_get_bootstrap_port(mts, &bp);
947 if (kr != KERN_SUCCESS) {
948 syslog(LOG_ERR, "task_get_bootstrap_port() failure: %s (%d)",
949 bootstrap_strerror(kr), kr);
950 break;
951 }
952
953 const char* bs = "com.apple.ReportCrash";
954 kr = bootstrap_look_up(bp, (char*)bs, &ep);
955 if (kr != KERN_SUCCESS) {
956 syslog(LOG_ERR, "bootstrap_look_up(%s) failure: %s (%d)",
957 bs, bootstrap_strerror(kr), kr);
958 break;
959 }
960
961 kr = task_set_exception_ports(mts, EXC_MASK_CRASH, ep, EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES, flavor);
962 if (kr != KERN_SUCCESS) {
963 syslog(LOG_ERR, "task_set_exception_ports() failure: %d", kr);
964 break;
965 }
966 } while (0);
967 #endif __APPLE__
968
969 if (!quietlog) {
970 #ifdef LOGIN_CAP
971 const char *cw;
972
973 cw = login_getcapstr(lc, "copyright", NULL, NULL);
974 if (cw == NULL || motd(cw) == -1)
975 (void)printf("%s", copyright);
976
977 (void)printf("\n");
978
979 cw = login_getcapstr(lc, "welcome", NULL, NULL);
980 if (cw != NULL && access(cw, F_OK) == 0)
981 motd(cw);
982 else
983 motd(_PATH_MOTDFILE);
984
985 if (login_getcapbool(lc_user, "nocheckmail", 0) == 0 &&
986 login_getcapbool(lc, "nocheckmail", 0) == 0) {
987 #else /* !LOGIN_CAP */
988 motd(_PATH_MOTDFILE);
989 {
990 #endif /* !LOGIN_CAP */
991 char *cx;
992
993 /* $MAIL may have been set by class. */
994 cx = getenv("MAIL");
995 if (cx == NULL) {
996 asprintf(&cx, "%s/%s",
997 _PATH_MAILDIR, pwd->pw_name);
998 }
999 if (cx && stat(cx, &st) == 0 && st.st_size != 0)
1000 (void)printf("You have %smail.\n",
1001 (st.st_mtime > st.st_atime) ? "new " : "");
1002 if (getenv("MAIL") == NULL)
1003 free(cx);
1004 }
1005 }
1006
1007 #ifdef LOGIN_CAP
1008 login_close(lc_user);
1009 login_close(lc);
1010 #endif /* LOGIN_CAP */
1011
1012 (void)signal(SIGALRM, SIG_DFL);
1013 (void)signal(SIGQUIT, SIG_DFL);
1014 (void)signal(SIGINT, SIG_DFL);
1015 (void)signal(SIGTSTP, SIG_IGN);
1016
1017 #ifdef __APPLE__
1018 if (fflag && *argv) pwd->pw_shell = *argv;
1019 #endif /* __APPLE__ */
1020
1021 /*
1022 * Login shells have a leading '-' in front of argv[0]
1023 */
1024 p = strrchr(pwd->pw_shell, '/');
1025 #ifdef __APPLE__
1026 if (asprintf(&arg0, "%s%s", lflag ? "" : "-", p ? p + 1 : pwd->pw_shell) >= MAXPATHLEN) {
1027 #else /* __APPLE__ */
1028 if (asprintf(&arg0, "-%s", p ? p + 1 : pwd->pw_shell) >= MAXPATHLEN) {
1029 #endif /* __APPLE__ */
1030 syslog(LOG_ERR, "user: %s: shell exceeds maximum pathname size",
1031 username);
1032 errx(1, "shell exceeds maximum pathname size");
1033 } else if (arg0 == NULL) {
1034 err(1, "asprintf()");
1035 }
1036
1037 #ifdef __APPLE__
1038 if (fflag && *argv) {
1039 *argv = arg0;
1040 execvp(pwd->pw_shell, argv);
1041 err(1, "%s", arg0);
1042 }
1043 #endif /* __APPLE__ */
1044 execlp(shell, arg0, (char *)0);
1045 err(1, "%s", shell);
1046
1047 /*
1048 * That's it, folks!
1049 */
1050 }
1051
1052 #ifdef USE_PAM
1053 /*
1054 * Attempt to authenticate the user using PAM. Returns 0 if the user is
1055 * authenticated, or 1 if not authenticated. If some sort of PAM system
1056 * error occurs (e.g., the "/etc/pam.conf" file is missing) then this
1057 * function returns -1. This can be used as an indication that we should
1058 * fall back to a different authentication mechanism.
1059 */
1060 static int
1061 auth_pam(void)
1062 {
1063 const char *tmpl_user;
1064 const void *item;
1065 int rval;
1066
1067 pam_err = pam_authenticate(pamh, pam_silent);
1068 switch (pam_err) {
1069
1070 case PAM_SUCCESS:
1071 /*
1072 * With PAM we support the concept of a "template"
1073 * user. The user enters a login name which is
1074 * authenticated by PAM, usually via a remote service
1075 * such as RADIUS or TACACS+. If authentication
1076 * succeeds, a different but related "template" name
1077 * is used for setting the credentials, shell, and
1078 * home directory. The name the user enters need only
1079 * exist on the remote authentication server, but the
1080 * template name must be present in the local password
1081 * database.
1082 *
1083 * This is supported by two various mechanisms in the
1084 * individual modules. However, from the application's
1085 * point of view, the template user is always passed
1086 * back as a changed value of the PAM_USER item.
1087 */
1088 pam_err = pam_get_item(pamh, PAM_USER, &item);
1089 if (pam_err == PAM_SUCCESS) {
1090 tmpl_user = (const char *)item;
1091 if (strcmp(username, tmpl_user) != 0)
1092 pwd = getpwnam(tmpl_user);
1093 } else {
1094 pam_syslog("pam_get_item(PAM_USER)");
1095 }
1096 rval = 0;
1097 break;
1098
1099 case PAM_AUTH_ERR:
1100 case PAM_USER_UNKNOWN:
1101 case PAM_MAXTRIES:
1102 rval = 1;
1103 break;
1104
1105 default:
1106 pam_syslog("pam_authenticate()");
1107 rval = -1;
1108 break;
1109 }
1110
1111 if (rval == 0) {
1112 pam_err = pam_acct_mgmt(pamh, pam_silent);
1113 switch (pam_err) {
1114 case PAM_SUCCESS:
1115 break;
1116 case PAM_NEW_AUTHTOK_REQD:
1117 pam_err = pam_chauthtok(pamh,
1118 pam_silent|PAM_CHANGE_EXPIRED_AUTHTOK);
1119 if (pam_err != PAM_SUCCESS) {
1120 pam_syslog("pam_chauthtok()");
1121 rval = 1;
1122 }
1123 break;
1124 default:
1125 pam_syslog("pam_acct_mgmt()");
1126 rval = 1;
1127 break;
1128 }
1129 }
1130
1131 if (rval != 0) {
1132 pam_end(pamh, pam_err);
1133 pamh = NULL;
1134 }
1135 return (rval);
1136 }
1137
1138 /*
1139 * Export any environment variables PAM modules may have set
1140 */
1141 static void
1142 export_pam_environment()
1143 {
1144 char **pam_env;
1145 char **pp;
1146
1147 pam_env = pam_getenvlist(pamh);
1148 if (pam_env != NULL) {
1149 for (pp = pam_env; *pp != NULL; pp++) {
1150 (void)export(*pp);
1151 free(*pp);
1152 }
1153 }
1154 }
1155
1156 /*
1157 * Perform sanity checks on an environment variable:
1158 * - Make sure there is an '=' in the string.
1159 * - Make sure the string doesn't run on too long.
1160 * - Do not export certain variables. This list was taken from the
1161 * Solaris pam_putenv(3) man page.
1162 * Then export it.
1163 */
1164 static int
1165 export(const char *s)
1166 {
1167 static const char *noexport[] = {
1168 "SHELL", "HOME", "LOGNAME", "MAIL", "CDPATH",
1169 "IFS", "PATH", NULL
1170 };
1171 char *p;
1172 const char **pp;
1173 size_t n;
1174
1175 if (strlen(s) > 1024 || (p = strchr(s, '=')) == NULL)
1176 return (0);
1177 if (strncmp(s, "LD_", 3) == 0)
1178 return (0);
1179 for (pp = noexport; *pp != NULL; pp++) {
1180 n = strlen(*pp);
1181 if (s[n] == '=' && strncmp(s, *pp, n) == 0)
1182 return (0);
1183 }
1184 *p = '\0';
1185 (void)setenv(s, p + 1, 1);
1186 *p = '=';
1187 return (1);
1188 }
1189 #endif /* USE_PAM */
1190
1191 static void
1192 usage()
1193 {
1194 #ifdef __APPLE__
1195 (void)fprintf(stderr, "usage: login [-pq] [-h hostname] [username]\n");
1196 (void)fprintf(stderr, " login -f [-lpq] [-h hostname] [username [prog [arg ...]]]\n");
1197 #else
1198 (void)fprintf(stderr, "usage: login [-fp] [-h hostname] [username]\n");
1199 #endif
1200 exit(1);
1201 }
1202
1203 /*
1204 * Prompt user and read login name from stdin.
1205 */
1206 static char *
1207 getloginname()
1208 {
1209 char *nbuf, *p;
1210 int ch;
1211
1212 nbuf = malloc(MAXLOGNAME);
1213 if (nbuf == NULL)
1214 err(1, "malloc()");
1215 do {
1216 (void)printf("%s", prompt);
1217 for (p = nbuf; (ch = getchar()) != '\n'; ) {
1218 if (ch == EOF) {
1219 badlogin(username);
1220 bail(NO_SLEEP_EXIT, 0);
1221 }
1222 if (p < nbuf + MAXLOGNAME - 1)
1223 *p++ = ch;
1224 }
1225 } while (p == nbuf);
1226
1227 *p = '\0';
1228 if (nbuf[0] == '-') {
1229 #ifdef USE_PAM
1230 pam_silent = 0;
1231 #endif /* USE_PAM */
1232 memmove(nbuf, nbuf + 1, strlen(nbuf));
1233 } else {
1234 #ifdef USE_PAM
1235 pam_silent = PAM_SILENT;
1236 #endif /* USE_PAM */
1237 }
1238 return nbuf;
1239 }
1240
1241 #ifdef __APPLE__
1242 #ifndef USE_PAM
1243 static int
1244 rootterm(const char* ttyn)
1245 {
1246 struct ttyent *t;
1247 return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE);
1248 }
1249 #endif /* !USE_PAM */
1250 #endif /* __APPLE__ */
1251
1252 /*
1253 * SIGINT handler for motd().
1254 */
1255 static volatile int motdinterrupt;
1256 static void
1257 sigint(int signo __unused)
1258 {
1259 motdinterrupt = 1;
1260 }
1261
1262 /*
1263 * Display the contents of a file (such as /etc/motd).
1264 */
1265 static int
1266 motd(const char *motdfile)
1267 {
1268 sig_t oldint;
1269 FILE *f;
1270 int ch;
1271
1272 if ((f = fopen(motdfile, "r")) == NULL)
1273 return (-1);
1274 motdinterrupt = 0;
1275 oldint = signal(SIGINT, sigint);
1276 while ((ch = fgetc(f)) != EOF && !motdinterrupt)
1277 putchar(ch);
1278 signal(SIGINT, oldint);
1279 if (ch != EOF || ferror(f)) {
1280 fclose(f);
1281 return (-1);
1282 }
1283 fclose(f);
1284 return (0);
1285 }
1286
1287 /*
1288 * SIGHUP handler
1289 * Forwards the SIGHUP to the child process and current process group.
1290 */
1291 static void
1292 handle_sighup(int signo)
1293 {
1294 if (pid > 0) {
1295 /* close the controlling terminal */
1296 close(STDIN_FILENO);
1297 close(STDOUT_FILENO);
1298 close(STDERR_FILENO);
1299 /* Ignore SIGHUP to avoid tail-recursion on signaling
1300 the current process group (of which we are a member). */
1301 (void)signal(SIGHUP, SIG_IGN);
1302 /* Forward the signal to the current process group. */
1303 (void)kill(0, signo);
1304 /* Forward the signal to the child if not a member of the current
1305 * process group <rdar://problem/6244808>. */
1306 if (getpgid(pid) != getpgrp()) {
1307 (void)kill(pid, signo);
1308 }
1309 }
1310 }
1311
1312 /*
1313 * SIGALRM handler, to enforce login prompt timeout.
1314 *
1315 * XXX This can potentially confuse the hell out of PAM. We should
1316 * XXX instead implement a conversation function that returns
1317 * XXX PAM_CONV_ERR when interrupted by a signal, and have the signal
1318 * XXX handler just set a flag.
1319 */
1320 static void
1321 timedout(int signo __unused)
1322 {
1323
1324 longjmp(timeout_buf, signo);
1325 }
1326
1327 #ifdef __APPLE__
1328 #ifndef USE_PAM
1329 void
1330 checknologin()
1331 {
1332 int fd, nchars;
1333 char tbuf[8192];
1334
1335 if ((fd = open(_PATH_NOLOGIN, O_RDONLY, 0)) >= 0) {
1336 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
1337 (void)write(fileno(stdout), tbuf, nchars);
1338 #ifdef USE_BSM_AUDIT
1339 au_login_fail("No login", 0);
1340 #endif
1341 sleep(5);
1342 exit(0);
1343 }
1344 }
1345 #endif /* !USE_PAM */
1346
1347 void
1348 dolastlog(quiet)
1349 int quiet;
1350 {
1351 #ifdef USE_PAM
1352 if (quiet)
1353 return;
1354 if (*lastlog.ll_line) {
1355 (void)printf("Last login: %.*s ",
1356 24-5, (char *)ctime(&lastlog.ll_tv.tv_sec));
1357 if (*lastlog.ll_host != '\0')
1358 (void)printf("from %.*s\n",
1359 (int)sizeof(lastlog.ll_host),
1360 lastlog.ll_host);
1361 else
1362 (void)printf("on %.*s\n",
1363 (int)sizeof(lastlog.ll_line),
1364 lastlog.ll_line);
1365 }
1366 #else /* !USE_PAM */
1367 struct lastlogx ll;
1368
1369 if(!quiet && getlastlogx(pwd->pw_uid, &ll) != NULL) {
1370 (void)printf("Last login: %.*s ",
1371 24-5, (char *)ctime(&ll.ll_tv.tv_sec));
1372 if (*ll.ll_host != '\0')
1373 (void)printf("from %.*s\n",
1374 (int)sizeof(ll.ll_host),
1375 ll.ll_host);
1376 else
1377 (void)printf("on %.*s\n",
1378 (int)sizeof(ll.ll_line),
1379 ll.ll_line);
1380 }
1381 #endif /* USE_PAM */
1382 }
1383 #endif /* __APPLE__ */
1384
1385 static void
1386 badlogin(char *name)
1387 {
1388
1389 if (failures == 0)
1390 return;
1391 if (hflag) {
1392 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s",
1393 failures, failures > 1 ? "S" : "", hostname);
1394 syslog(LOG_AUTHPRIV|LOG_NOTICE,
1395 "%d LOGIN FAILURE%s FROM %s, %s",
1396 failures, failures > 1 ? "S" : "", hostname, name);
1397 } else {
1398 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s",
1399 failures, failures > 1 ? "S" : "", tty);
1400 syslog(LOG_AUTHPRIV|LOG_NOTICE,
1401 "%d LOGIN FAILURE%s ON %s, %s",
1402 failures, failures > 1 ? "S" : "", tty, name);
1403 }
1404 failures = 0;
1405 }
1406
1407 const char *
1408 stypeof(char *ttyid)
1409 {
1410 struct ttyent *t;
1411
1412 if (ttyid != NULL && *ttyid != '\0') {
1413 t = getttynam(ttyid);
1414 if (t != NULL && t->ty_type != NULL)
1415 return (t->ty_type);
1416 }
1417 return (NULL);
1418 }
1419
1420 static void
1421 refused(const char *msg, const char *rtype, int lout)
1422 {
1423
1424 if (msg != NULL)
1425 printf("%s.\n", msg);
1426 if (hflag)
1427 syslog(LOG_NOTICE, "LOGIN %s REFUSED (%s) FROM %s ON TTY %s",
1428 pwd->pw_name, rtype, hostname, tty);
1429 else
1430 syslog(LOG_NOTICE, "LOGIN %s REFUSED (%s) ON TTY %s",
1431 pwd->pw_name, rtype, tty);
1432 if (lout)
1433 bail(SLEEP_EXIT, 1);
1434 }
1435
1436 #ifdef USE_PAM
1437 /*
1438 * Log a PAM error
1439 */
1440 static void
1441 pam_syslog(const char *msg)
1442 {
1443 syslog(LOG_ERR, "%s: %s", msg, pam_strerror(pamh, pam_err));
1444 }
1445
1446 /*
1447 * Shut down PAM
1448 */
1449 static void
1450 pam_cleanup()
1451 {
1452
1453 if (pamh != NULL) {
1454 if (pam_session_established) {
1455 pam_err = pam_close_session(pamh, 0);
1456 if (pam_err != PAM_SUCCESS)
1457 pam_syslog("pam_close_session()");
1458 }
1459 pam_session_established = 0;
1460 if (pam_cred_established) {
1461 pam_err = pam_setcred(pamh, pam_silent|PAM_DELETE_CRED);
1462 if (pam_err != PAM_SUCCESS)
1463 pam_syslog("pam_setcred()");
1464 }
1465 pam_cred_established = 0;
1466 pam_end(pamh, pam_err);
1467 pamh = NULL;
1468 }
1469 }
1470 #endif /* USE_PAM */
1471
1472 /*
1473 * Exit, optionally after sleeping a few seconds
1474 */
1475 void
1476 bail(int sec, int eval)
1477 {
1478
1479 #ifdef USE_PAM
1480 pam_cleanup();
1481 #endif /* USE_PAM */
1482 #ifdef USE_BSM_AUDIT
1483 if (pwd != NULL)
1484 audit_logout();
1485 #endif
1486 (void)sleep(sec);
1487 exit(eval);
1488 }