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