2 * Copyright (c) 1999, 2004, 2006 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 * Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994
25 * The Regents of the University of California. All rights reserved.
27 * Redistribution and use in source and binary forms, with or without
28 * modification, are permitted provided that the following conditions
30 * 1. Redistributions of source code must retain the above copyright
31 * notice, this list of conditions and the following disclaimer.
32 * 2. Redistributions in binary form must reproduce the above copyright
33 * notice, this list of conditions and the following disclaimer in the
34 * documentation and/or other materials provided with the distribution.
35 * 3. All advertising materials mentioning features or use of this software
36 * must display the following acknowledgement:
37 * This product includes software developed by the University of
38 * California, Berkeley and its contributors.
39 * 4. Neither the name of the University nor the names of its contributors
40 * may be used to endorse or promote products derived from this software
41 * without specific prior written permission.
43 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
44 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
45 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
47 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
49 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
50 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
51 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57 static char copyright
[] =
58 "@(#) Copyright (c) Apple Computer, Inc. 1997\n\n";
63 * login -h hostname (for telnetd, etc.)
64 * login -f name (for pre-authenticated login: datakit, xterm, etc.)
67 #include <sys/param.h>
70 #include <sys/resource.h>
93 #include <sys/types.h>
94 #include <sys/socket.h>
95 #include <netinet/in.h>
96 #include <arpa/inet.h>
99 #include <TargetConditionals.h>
102 #include <bsm/libbsm.h>
103 #include <bsm/audit_uevents.h>
107 #include <pam/pam_appl.h>
108 #include <pam/pam_misc.h>
111 #include <mach/mach_types.h>
113 #include <servers/bootstrap.h>
115 #include "pathnames.h"
117 void badlogin
__P((char *));
118 void checknologin
__P((void));
119 void dolastlog
__P((int));
120 void getloginname
__P((void));
121 void motd
__P((void));
122 int rootterm
__P((char *));
123 void sigint
__P((int));
124 void sleepexit
__P((int));
125 char *stypeof
__P((char *));
126 void timedout
__P((int));
128 int klogin
__P((struct passwd
*, char *, char *, char *));
131 void au_fail(char *, int);
135 extern void login
__P((struct utmp
*));
136 #endif /* !USE_PAM */
137 static void bail(int, int);
138 static void refused(const char *, const char *, int);
140 #define TTYGRPNAME "tty" /* name of group to own ttys */
141 #define NO_SLEEP_EXIT 0
145 * This bounds the time given to login. Not a define so it can
146 * be patched on machines where it's too small.
159 char term
[64], *hostname
, *username
= NULL
, *tty
;
161 static pam_handle_t
*pamh
= NULL
;
162 static struct pam_conv conv
= { misc_conv
, NULL
};
164 static int pam_silent
= PAM_SILENT
;
165 static int pam_cred_established
;
166 static int pam_session_established
;
167 static struct lastlogx lastlog
;
172 #define NA_EVENT_STR_SIZE 25
181 extern char **environ
;
187 int ask
, ch
, cnt
, oflag
= 0, fflag
, lflag
, pflag
;
188 int quietlog
= 0, rootlogin
= 0;
192 char *domain
, *p
, *ttyn
;
193 char tbuf
[MAXPATHLEN
+ 2], tname
[sizeof(_PATH_TTY
) + 10];
194 char localhost
[MAXHOSTNAMELEN
];
203 char auditsuccess
= 1;
205 (void)signal(SIGALRM
, timedout
);
206 (void)alarm(timeout
);
207 (void)signal(SIGQUIT
, SIG_IGN
);
208 (void)signal(SIGINT
, SIG_IGN
);
209 (void)setpriority(PRIO_PROCESS
, 0, 0);
211 openlog("login", LOG_ODELAY
, LOG_AUTH
);
214 * -p is used by getty to tell login not to destroy the environment
215 * -f is used to skip a second login authentication
216 * -l is used to indicate a login session to the command that
218 * -h is used by other servers to pass the name of the remote
219 * host to login so that it may be placed in utmp and wtmp
220 * -q is used to force hushlogin
223 if (gethostname(localhost
, sizeof(localhost
)) < 0)
224 syslog(LOG_ERR
, "couldn't get local hostname: %m");
226 domain
= strchr(localhost
, '.');
231 fflag
= hflag
= lflag
= pflag
= 0;
233 while ((ch
= getopt(argc
, argv
, "1fh:lpq")) != EOF
)
243 errx(1, "-h option: %s", strerror(EPERM
));
245 if (domain
&& (p
= strchr(optarg
, '.')) &&
246 strcasecmp(p
, domain
) == 0)
262 syslog(LOG_ERR
, "invalid flag %c", ch
);
263 (void)fprintf(stderr
,
264 "usage: login [-pq] [-h hostname] [username]\n");
265 (void)fprintf(stderr
,
266 " login -f [-lpq] [-h hostname] [username [prog [arg ...]]]\n");
278 for (cnt
= getdtablesize(); cnt
> 2; cnt
--)
281 ttyn
= ttyname(STDIN_FILENO
);
282 if (ttyn
== NULL
|| *ttyn
== '\0') {
283 (void)snprintf(tname
, sizeof(tname
), "%s??", _PATH_TTY
);
286 if (tty
= strrchr(ttyn
, '/'))
292 /* Set the terminal id */
293 audit_set_terminal_id(&tid
);
294 if (fstat(STDIN_FILENO
, &st
) < 0) {
295 fprintf(stderr
, "login: Unable to stat terminal\n");
296 au_fail("Unable to stat terminal", 1);
299 if (S_ISCHR(st
.st_mode
)) {
300 tid
.port
= st
.st_rdev
;
307 pam_err
= pam_start("login", username
, &conv
, &pamh
);
308 if( pam_err
!= PAM_SUCCESS
) {
309 fprintf(stderr
, "login: PAM Error (line %d): %s\n", __LINE__
, pam_strerror(pamh
, pam_err
));
310 au_fail("PAM Error", 1);
313 pam_err
= pam_set_item(pamh
, PAM_TTY
, tty
);
314 if( pam_err
!= PAM_SUCCESS
) {
315 fprintf(stderr
, "login: PAM Error (line %d): %s\n", __LINE__
, pam_strerror(pamh
, pam_err
));
316 au_fail("PAM Error", 1);
320 pam_err
= pam_set_item(pamh
, PAM_RHOST
, hostname
);
321 if( pam_err
!= PAM_SUCCESS
) {
322 fprintf(stderr
, "login: PAM Error (line %d): %s\n", __LINE__
, pam_strerror(pamh
, pam_err
));
323 au_fail("PAM Error", 1);
327 pam_err
= pam_set_item(pamh
, PAM_USER_PROMPT
, "login: ");
328 if( pam_err
!= PAM_SUCCESS
) {
329 fprintf(stderr
, "login: PAM Error (line %d): %s\n", __LINE__
, pam_strerror(pamh
, pam_err
));
330 au_fail("PAM Error", 1);
336 pam_set_item(pamh
, PAM_USER
, username
);
337 pwd
= getpwnam(username
);
338 if( (pwd
!= NULL
) && (pwd
->pw_uid
== 0) )
341 if( (pwd
!= NULL
) && fflag
&& ((uid
== 0) || (uid
== pwd
->pw_uid
)) ){
343 auditsuccess
= 0; /* we've simply opened a terminal window */
346 pam_err
= pam_authenticate(pamh
, 0);
347 while( (!oflag
) && (cnt
++ < 10) && ((pam_err
== PAM_AUTH_ERR
) ||
348 (pam_err
== PAM_USER_UNKNOWN
) ||
349 (pam_err
== PAM_CRED_INSUFFICIENT
) ||
350 (pam_err
== PAM_AUTHINFO_UNAVAIL
))) {
352 * we are not exiting here, but this corresponds to
353 * a failed login event, so set exitstatus to 1
355 au_fail("Login incorrect", 1);
357 printf("Login incorrect\n");
360 pwd
= getpwnam(username
);
361 if( (pwd
!= NULL
) && (pwd
->pw_uid
== 0) )
363 pam_set_item(pamh
, PAM_USER
, username
);
364 pam_err
= pam_authenticate(pamh
, 0);
367 if( pam_err
!= PAM_SUCCESS
) {
368 pam_get_item(pamh
, PAM_USER
, (void *)&username
);
370 printf("Login incorrect\n");
371 au_fail("Login incorrect", 1);
375 pam_err
= pam_acct_mgmt(pamh
, 0);
376 if( pam_err
== PAM_NEW_AUTHTOK_REQD
) {
377 pam_err
= pam_chauthtok(pamh
, PAM_CHANGE_EXPIRED_AUTHTOK
);
379 if( pam_err
!= PAM_SUCCESS
) {
380 fprintf(stderr
, "login: PAM Error (line %d): %s\n", __LINE__
, pam_strerror(pamh
, pam_err
));
381 au_fail("PAM error", 1);
386 pam_err
= pam_get_item(pamh
, PAM_USER
, (void *)&username
);
387 if( (pam_err
== PAM_SUCCESS
) && username
&& *username
)
388 pwd
= getpwnam(username
);
390 /* get lastlog info before PAM make a new entry */
392 getlastlogxbyname(username
, &lastlog
);
394 pam_err
= pam_open_session(pamh
, 0);
395 if( pam_err
!= PAM_SUCCESS
) {
396 fprintf(stderr
, "login: PAM Error (line %d): %s\n", __LINE__
, pam_strerror(pamh
, pam_err
));
397 au_fail("PAM error", 1);
401 pam_err
= pam_setcred(pamh
, PAM_ESTABLISH_CRED
);
402 if( pam_err
!= PAM_SUCCESS
) {
403 fprintf(stderr
, "login: PAM Error (line %d): %s\n", __LINE__
, pam_strerror(pamh
, pam_err
));
404 au_fail("PAM error", 1);
409 for (cnt
= 0;; ask
= 1) {
416 if ((instance
= strchr(username
, '.')) != NULL
) {
417 if (strncmp(instance
, ".root", 5) == 0)
423 if (strlen(username
) > UT_NAMESIZE
)
424 username
[UT_NAMESIZE
] = '\0';
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).
431 if (failures
&& strcmp(tbuf
, username
)) {
432 if (failures
> (pwd
? 0 : 1)) {
437 (void)strcpy(tbuf
, username
);
439 if (pwd
= getpwnam(username
))
440 salt
= pwd
->pw_passwd
;
445 * if we have a valid account name, and it doesn't have a
446 * password, or the -f option was specified and the caller
447 * is root or the caller isn't changing their uid, don't
450 if (pwd
&& (*pwd
->pw_passwd
== '\0' ||
451 fflag
&& (uid
== 0 || uid
== pwd
->pw_uid
)))
454 if (pwd
&& pwd
->pw_uid
== 0)
457 (void)setpriority(PRIO_PROCESS
, 0, -4);
459 p
= getpass("Password:");
463 rval
= klogin(pwd
, instance
, localhost
, p
);
464 if (rval
!= 0 && rootlogin
&& pwd
->pw_uid
!= 0)
469 rval
= strcmp(crypt(p
, salt
), pwd
->pw_passwd
);
471 rval
= strcmp(crypt(p
, salt
), pwd
->pw_passwd
);
474 memset(p
, 0, strlen(p
));
476 (void)setpriority(PRIO_PROCESS
, 0, 0);
479 * If trying to log in as root without Kerberos,
480 * but with insecure terminal, refuse the login attempt.
485 if (pwd
&& rootlogin
&& !rootterm(tty
)) {
486 (void)fprintf(stderr
,
487 "%s login refused on this terminal.\n",
491 "LOGIN %s REFUSED FROM %s ON TTY %s",
492 pwd
->pw_name
, hostname
, tty
);
495 "LOGIN %s REFUSED ON TTY %s",
497 au_fail("Login refused on terminal", 0);
504 (void)printf("Login incorrect\n");
506 /* we allow 10 tries, but after 3 we start backing off */
510 au_fail("Login incorrect", 1);
513 au_fail("Login incorrect", 1);
514 sleep((u_int
)((cnt
- 3) * 5));
519 /* committed to login -- turn off timeout */
520 (void)alarm((u_int
)0);
525 fprintf(stderr
, "login: Unable to find user: %s\n", username
);
529 /* if user not super-user, check for disabled logins */
533 /* Audit successful login */
537 setegid(pwd
->pw_gid
);
538 seteuid(rootlogin
? 0 : pwd
->pw_uid
);
541 /* First do a stat in case the homedir is automounted */
542 stat(pwd
->pw_dir
,&st
);
544 if (!*pwd
->pw_dir
|| chdir(pwd
->pw_dir
) < 0) {
545 printf("No home directory %s!\n", pwd
->pw_dir
);
547 refused("Cannot find root directory", "HOMEDIR", 1);
548 pwd
->pw_dir
= strdup("/");
549 if (pwd
->pw_dir
== NULL
) {
550 syslog(LOG_NOTICE
, "strdup(): %m");
553 printf("Logging in with home = \"/\".\n");
560 quietlog
= access(_PATH_HUSHLOGIN
, F_OK
) == 0;
562 /* Nothing else left to fail -- really log in. */
564 memset((void *)&utmp
, 0, sizeof(utmp
));
565 (void)time(&utmp
.ut_time
);
566 (void)strncpy(utmp
.ut_name
, username
, sizeof(utmp
.ut_name
));
568 (void)strncpy(utmp
.ut_host
, hostname
, sizeof(utmp
.ut_host
));
569 (void)strncpy(utmp
.ut_line
, tty
, sizeof(utmp
.ut_line
));
575 (void)chown(ttyn
, pwd
->pw_uid
,
576 (gr
= getgrnam(TTYGRPNAME
)) ? gr
->gr_gid
: pwd
->pw_gid
);
577 (void)chmod(ttyn
, 0620);
578 (void)setgid(pwd
->pw_gid
);
580 if (initgroups(username
, pwd
->pw_gid
) == -1)
581 syslog(LOG_ERR
, "login: initgroups() failed");
583 if (*pwd
->pw_shell
== '\0')
584 pwd
->pw_shell
= strdup(_PATH_BSHELL
);
585 if (pwd
->pw_shell
== NULL
) {
586 syslog(LOG_NOTICE
, "strdup(): %m");
590 #if TARGET_OS_EMBEDDED
591 /* on embedded, allow a shell to live in /var/debug_mount/bin/sh */
592 #define _PATH_DEBUGSHELL "/var/debug_mount/bin/sh"
593 if (stat(pwd
->pw_shell
, &st
) != 0) {
594 if (stat(_PATH_DEBUGSHELL
, &st
) == 0) {
595 pwd
->pw_shell
= strdup(_PATH_DEBUGSHELL
);
600 /* Destroy environment unless user has requested its preservation. */
602 environ
= malloc(sizeof(char *));
605 (void)setenv("HOME", pwd
->pw_dir
, 1);
606 (void)setenv("SHELL", pwd
->pw_shell
, 1);
608 (void)strncpy(term
, stypeof(tty
), sizeof(term
));
609 (void)setenv("TERM", term
, 0);
610 (void)setenv("LOGNAME", pwd
->pw_name
, 1);
611 (void)setenv("USER", pwd
->pw_name
, 1);
612 (void)setenv("PATH", _PATH_DEFPATH
, 0);
615 (void)setenv("KRBTKFILE", krbtkfile_env
, 1);
619 pmenv
= pam_getenvlist(pamh
);
620 for( cnt
= 0; pmenv
&& pmenv
[cnt
]; cnt
++ )
623 /* Ignore SIGHUP so that the parent's call to waitpid will
624 succeed and the tty ownership can be reset. */
625 (void)signal(SIGHUP
, SIG_IGN
);
630 } else if( pid
!= 0 ) {
631 waitpid(pid
, NULL
, 0);
632 pam_setcred(pamh
, PAM_DELETE_CRED
);
633 pam_err
= pam_close_session(pamh
, 0);
634 pam_end(pamh
,pam_err
);
640 /* Restore the default SIGHUP handler for the child. */
641 (void)signal(SIGHUP
, SIG_DFL
);
645 if (tty
[sizeof("tty")-1] == 'd')
646 syslog(LOG_INFO
, "DIALUP %s, %s", tty
, pwd
->pw_name
);
648 /* If fflag is on, assume caller/authenticator has logged root login. */
649 if (rootlogin
&& fflag
== 0)
651 syslog(LOG_NOTICE
, "ROOT LOGIN (%s) ON %s FROM %s",
652 username
, tty
, hostname
);
654 syslog(LOG_NOTICE
, "ROOT LOGIN (%s) ON %s", username
, tty
);
657 if (!quietlog
&& notickets
== 1)
658 (void)printf("Warning: no Kerberos tickets issued.\n");
664 sizeof(tbuf
), "%s/%s", _PATH_MAILDIR
, pwd
->pw_name
);
665 if (stat(tbuf
, &st
) == 0 && st
.st_size
!= 0)
666 (void)printf("You have %smail.\n",
667 (st
.st_mtime
> st
.st_atime
) ? "new " : "");
670 (void)signal(SIGALRM
, SIG_DFL
);
671 (void)signal(SIGQUIT
, SIG_DFL
);
672 (void)signal(SIGINT
, SIG_DFL
);
673 (void)signal(SIGTSTP
, SIG_IGN
);
675 if (setlogin(pwd
->pw_name
) < 0)
676 syslog(LOG_ERR
, "setlogin() failure: %m");
678 /* Discard permissions last so can't get killed and drop core. */
682 (void) setuid(pwd
->pw_uid
);
684 /* Re-enable crash reporter */
687 mach_port_t bp
, ep
, mts
;
688 thread_state_flavor_t flavor
= 0;
691 flavor
= PPC_THREAD_STATE64
;
692 #elif defined(__i386__)
693 flavor
= x86_THREAD_STATE
;
696 mts
= mach_task_self();
698 kr
= task_get_bootstrap_port(mts
, &bp
);
699 if (kr
!= KERN_SUCCESS
) {
700 syslog(LOG_ERR
, "task_get_bootstrap_port() failure: %s (%d)",
701 bootstrap_strerror(kr
), kr
);
705 const char* bs
= "com.apple.ReportCrash";
706 kr
= bootstrap_look_up(bp
, (char*)bs
, &ep
);
707 if (kr
!= KERN_SUCCESS
) {
708 syslog(LOG_ERR
, "bootstrap_look_up(%s) failure: %s (%d)",
709 bs
, bootstrap_strerror(kr
), kr
);
713 kr
= task_set_exception_ports(mts
, EXC_MASK_CRASH
, ep
, EXCEPTION_STATE_IDENTITY
| MACH_EXCEPTION_CODES
, flavor
);
714 if (kr
!= KERN_SUCCESS
) {
715 syslog(LOG_ERR
, "task_set_exception_ports() failure: %d", kr
);
720 if (fflag
&& *argv
) {
723 (void)strlcpy(tbuf
, (p
= strrchr(*argv
, '/')) ?
724 p
+ 1 : *argv
, sizeof(tbuf
));
727 (void)strlcpy(tbuf
+ 1, (p
= strrchr(*argv
, '/')) ?
728 p
+ 1 : *argv
, sizeof(tbuf
) - 1);
735 (void)strlcpy(tbuf
, (p
= strrchr(pwd
->pw_shell
, '/')) ?
736 p
+ 1 : pwd
->pw_shell
, sizeof(tbuf
));
739 (void)strlcpy(tbuf
+ 1, (p
= strrchr(pwd
->pw_shell
, '/')) ?
740 p
+ 1 : pwd
->pw_shell
, sizeof(tbuf
) - 1);
742 execlp(pwd
->pw_shell
, tbuf
, (char *)NULL
);
743 err(1, "%s", pwd
->pw_shell
);
748 #define NBUFSIZ (MAXLOGNAME + 1 + 5) /* .root suffix */
750 #define NBUFSIZ (MAXLOGNAME + 1)
754 * The following tokens are included in the audit record for successful login attempts
766 uid_t uid
= pwd
->pw_uid
;
767 gid_t gid
= pwd
->pw_gid
;
768 pid_t pid
= getpid();
771 /* If we are not auditing, don't cut an audit record; just return */
772 if (auditon(A_GETCOND
, &au_cond
, sizeof(long)) < 0) {
773 fprintf(stderr
, "login: Could not determine audit condition\n");
776 if (au_cond
== AUC_NOAUDIT
)
779 /* Compute and Set the user's preselection mask */
780 if(au_user_mask(pwd
->pw_name
, &aumask
) == -1) {
781 fprintf(stderr
, "login: Could not set audit mask\n");
785 /* Set the audit info for the user */
786 auinfo
.ai_auid
= uid
;
787 auinfo
.ai_asid
= pid
;
788 bcopy(&tid
, &auinfo
.ai_termid
, sizeof(auinfo
.ai_termid
));
789 bcopy(&aumask
, &auinfo
.ai_mask
, sizeof(auinfo
.ai_mask
));
790 if(setaudit(&auinfo
) != 0) {
791 fprintf(stderr
, "login: setaudit failed: %s\n", strerror(errno
));
795 if((aufd
= au_open()) == -1) {
796 fprintf(stderr
, "login: Audit Error: au_open() failed\n");
800 /* The subject that is created (euid, egid of the current process) */
801 if((tok
= au_to_subject32(uid
, geteuid(), getegid(),
802 uid
, gid
, pid
, pid
, &tid
)) == NULL
) {
803 fprintf(stderr
, "login: Audit Error: au_to_subject32() failed\n");
808 if((tok
= au_to_return32(0, 0)) == NULL
) {
809 fprintf(stderr
, "login: Audit Error: au_to_return32() failed\n");
814 if(au_close(aufd
, 1, AUE_login
) == -1) {
815 fprintf(stderr
, "login: Audit Record was not committed.\n");
822 * The following tokens are included in the audit record for successful login attempts
828 void au_fail(char *errmsg
, int na
)
836 pid_t pid
= getpid();
838 /* If we are not auditing, don't cut an audit record; just return */
839 if (auditon(A_GETCOND
, &au_cond
, sizeof(long)) < 0) {
840 fprintf(stderr
, "login: Could not determine audit condition\n");
843 if (au_cond
== AUC_NOAUDIT
)
846 if((aufd
= au_open()) == -1) {
847 fprintf(stderr
, "login: Audit Error: au_open() failed\n");
852 /* Non attributable event */
853 /* Assuming that login is not called within a users' session => auid,asid == -1 */
854 if((tok
= au_to_subject32(-1, geteuid(), getegid(), -1, -1,
855 pid
, -1, &tid
)) == NULL
) {
857 fprintf(stderr
, "login: Audit Error: au_to_subject32() failed\n");
862 /* we know the subject -- so use its value instead */
865 if((tok
= au_to_subject32(uid
, geteuid(), getegid(),
866 uid
, gid
, pid
, pid
, &tid
)) == NULL
) {
867 fprintf(stderr
, "login: Audit Error: au_to_subject32() failed\n");
873 /* Include the error message */
874 if((tok
= au_to_text(errmsg
)) == NULL
) {
875 fprintf(stderr
, "login: Audit Error: au_to_text() failed\n");
880 if((tok
= au_to_return32(1, errno
)) == NULL
) {
881 fprintf(stderr
, "login: Audit Error: au_to_return32() failed\n");
886 if(au_close(aufd
, 1, AUE_login
) == -1) {
887 fprintf(stderr
, "login: Audit Error: au_close() was not committed\n");
898 static char nbuf
[NBUFSIZ
];
901 (void)printf("login: ");
902 for (p
= nbuf
; (ch
= getchar()) != '\n'; ) {
907 if (p
< nbuf
+ (NBUFSIZ
- 1))
912 (void)fprintf(stderr
,
913 "login names may not start with '-'.\n");
929 return ((t
= getttynam(ttyn
)) && t
->ty_status
& TTY_SECURE
);
932 jmp_buf motdinterrupt
;
941 if ((fd
= open(_PATH_MOTDFILE
, O_RDONLY
, 0)) < 0)
943 oldint
= signal(SIGINT
, sigint
);
944 if (setjmp(motdinterrupt
) == 0)
945 while ((nchars
= read(fd
, tbuf
, sizeof(tbuf
))) > 0)
946 (void)write(fileno(stdout
), tbuf
, nchars
);
947 (void)signal(SIGINT
, oldint
);
957 longjmp(motdinterrupt
, 1);
966 (void)fprintf(stderr
, "Login timed out after %d seconds\n", timeout
);
976 if ((fd
= open(_PATH_NOLOGIN
, O_RDONLY
, 0)) >= 0) {
977 while ((nchars
= read(fd
, tbuf
, sizeof(tbuf
))) > 0)
978 (void)write(fileno(stdout
), tbuf
, nchars
);
979 au_fail("No login", 0);
991 if (*lastlog
.ll_line
) {
992 (void)printf("Last login: %.*s ",
993 24-5, (char *)ctime(&lastlog
.ll_tv
.tv_sec
));
994 if (*lastlog
.ll_host
!= '\0')
995 (void)printf("from %.*s\n",
996 (int)sizeof(lastlog
.ll_host
),
999 (void)printf("on %.*s\n",
1000 (int)sizeof(lastlog
.ll_line
),
1003 #else /* !USE_PAM */
1007 /* HACK HACK HACK: This is because HFS doesn't support sparse files
1008 * and seeking into the file too far is too slow. The "solution"
1009 * is to just bail if the seek time for a large uid would be too
1012 if(pwd
->pw_uid
> 100000) {
1013 syslog(LOG_NOTICE
, "User login %s (%d) not logged in lastlog. UID too large.", pwd
->pw_name
, pwd
->pw_uid
);
1017 if ((fd
= open(_PATH_LASTLOG
, O_RDWR
, 0)) >= 0) {
1018 (void)lseek(fd
, (off_t
)pwd
->pw_uid
* sizeof(ll
), L_SET
);
1020 if (read(fd
, (char *)&ll
, sizeof(ll
)) == sizeof(ll
) &&
1022 (void)printf("Last login: %.*s ",
1023 24-5, (char *)ctime(&ll
.ll_time
));
1024 if (*ll
.ll_host
!= '\0')
1025 (void)printf("from %.*s\n",
1026 (int)sizeof(ll
.ll_host
),
1029 (void)printf("on %.*s\n",
1030 (int)sizeof(ll
.ll_line
),
1033 (void)lseek(fd
, (off_t
)pwd
->pw_uid
* sizeof(ll
), L_SET
);
1035 memset((void *)&ll
, 0, sizeof(ll
));
1036 (void)time(&ll
.ll_time
);
1037 (void)strncpy(ll
.ll_line
, tty
, sizeof(ll
.ll_line
));
1039 (void)strncpy(ll
.ll_host
, hostname
, sizeof(ll
.ll_host
));
1040 (void)write(fd
, (char *)&ll
, sizeof(ll
));
1043 #endif /* USE_PAM */
1054 syslog(LOG_NOTICE
, "%d LOGIN FAILURE%s FROM %s",
1055 failures
, failures
> 1 ? "S" : "", hostname
);
1056 syslog(LOG_AUTHPRIV
|LOG_NOTICE
,
1057 "%d LOGIN FAILURE%s FROM %s, %s",
1058 failures
, failures
> 1 ? "S" : "", hostname
, name
);
1060 syslog(LOG_NOTICE
, "%d LOGIN FAILURE%s ON %s",
1061 failures
, failures
> 1 ? "S" : "", tty
);
1062 syslog(LOG_AUTHPRIV
|LOG_NOTICE
,
1063 "%d LOGIN FAILURE%s ON %s, %s",
1064 failures
, failures
> 1 ? "S" : "", tty
, name
);
1069 #define UNKNOWN "su"
1077 return (ttyid
&& (t
= getttynam(ttyid
)) ? t
->ty_type
: UNKNOWN
);
1090 refused(const char *msg
, const char *rtype
, int lout
)
1094 printf("%s.\n", msg
);
1096 syslog(LOG_NOTICE
, "LOGIN %s REFUSED (%s) FROM %s ON TTY %s",
1097 pwd
->pw_name
, rtype
, hostname
, tty
);
1099 syslog(LOG_NOTICE
, "LOGIN %s REFUSED (%s) ON TTY %s",
1100 pwd
->pw_name
, rtype
, tty
);
1102 bail(SLEEP_EXIT
, 1);
1110 pam_syslog(const char *msg
)
1112 syslog(LOG_ERR
, "%s: %s", msg
, pam_strerror(pamh
, pam_err
));
1123 if (pam_session_established
) {
1124 pam_err
= pam_close_session(pamh
, 0);
1125 if (pam_err
!= PAM_SUCCESS
)
1126 pam_syslog("pam_close_session()");
1128 pam_session_established
= 0;
1129 if (pam_cred_established
) {
1130 pam_err
= pam_setcred(pamh
, pam_silent
|PAM_DELETE_CRED
);
1131 if (pam_err
!= PAM_SUCCESS
)
1132 pam_syslog("pam_setcred()");
1134 pam_cred_established
= 0;
1135 pam_end(pamh
, pam_err
);
1139 #endif /* USE_PAM */
1141 * Exit, optionally after sleeping a few seconds
1144 bail(int sec
, int eval
)