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