X-Git-Url: https://git.saurik.com/apple/system_cmds.git/blobdiff_plain/1c51fdde6f257ffe2a1b92d1a783dab947211e95..e34d6a2fe844b92ea51e672fcbb6bfe0e930712f:/login.tproj/login.c diff --git a/login.tproj/login.c b/login.tproj/login.c index cbfd719..76fbc6f 100644 --- a/login.tproj/login.c +++ b/login.tproj/login.c @@ -1,23 +1,22 @@ /* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. + * Copyright (c) 1999, 2004, 2006 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * - * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.0 (the 'License'). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License." + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ @@ -54,10 +53,10 @@ * SUCH DAMAGE. */ -#ifndef lint +#if 0 static char copyright[] = "@(#) Copyright (c) Apple Computer, Inc. 1997\n\n"; -#endif /* not lint */ +#endif /* * login [ name ] @@ -70,6 +69,7 @@ static char copyright[] = #include #include #include +#include #include #include @@ -84,7 +84,33 @@ static char copyright[] = #include #include #include +#ifdef USE_PAM +#include +#else /* !USE_PAM */ #include +#endif /* USE_PAM */ + +#include +#include +#include +#include +#include + +#include + +#ifdef USE_BSM +#include +#include +#endif + +#ifdef USE_PAM +#include +#include +#endif + +#include + +#include #include "pathnames.h" @@ -101,10 +127,19 @@ void timedout __P((int)); #ifdef KERBEROS int klogin __P((struct passwd *, char *, char *, char *)); #endif +void au_success(); +void au_fail(char *, int); + +#ifndef USE_PAM extern void login __P((struct utmp *)); +#endif /* !USE_PAM */ +static void bail(int, int); +static void refused(const char *, const char *, int); #define TTYGRPNAME "tty" /* name of group to own ttys */ +#define NO_SLEEP_EXIT 0 +#define SLEEP_EXIT 5 /* * This bounds the time given to login. Not a define so it can @@ -121,7 +156,22 @@ int authok; struct passwd *pwd; int failures; -char term[64], *envinit[1], *hostname, *username, *tty; +char term[64], *hostname, *username = NULL, *tty; +#ifdef USE_PAM +static pam_handle_t *pamh = NULL; +static struct pam_conv conv = { misc_conv, NULL }; +static int pam_err; +static int pam_silent = PAM_SILENT; +static int pam_cred_established; +static int pam_session_established; +static struct lastlogx lastlog; +#endif /* USE_PAM */ +int hflag; + +#ifdef USE_BSM +#define NA_EVENT_STR_SIZE 25 +au_tid_t tid; +#endif int main(argc, argv) @@ -131,13 +181,26 @@ main(argc, argv) extern char **environ; struct group *gr; struct stat st; - struct timeval tp; +#ifndef USE_PAM struct utmp utmp; - int ask, ch, cnt, fflag, hflag, pflag, quietlog, rootlogin, rval; +#endif /* USE_PAM */ + int ask, ch, cnt, oflag = 0, fflag, lflag, pflag; + int quietlog = 0, rootlogin = 0; uid_t uid; - char *domain, *p, *salt, *ttyn; + uid_t euid; + gid_t egid; + char *domain, *p, *ttyn; char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10]; char localhost[MAXHOSTNAMELEN]; +#ifdef USE_PAM + char **pmenv; + pid_t pid; +#else + int rval; + char *salt; +#endif + + char auditsuccess = 1; (void)signal(SIGALRM, timedout); (void)alarm(timeout); @@ -150,19 +213,28 @@ main(argc, argv) /* * -p is used by getty to tell login not to destroy the environment * -f is used to skip a second login authentication + * -l is used to indicate a login session to the command that + * follows username * -h is used by other servers to pass the name of the remote * host to login so that it may be placed in utmp and wtmp + * -q is used to force hushlogin */ domain = NULL; if (gethostname(localhost, sizeof(localhost)) < 0) syslog(LOG_ERR, "couldn't get local hostname: %m"); else domain = strchr(localhost, '.'); + + euid = geteuid(); + egid = getegid(); - fflag = hflag = pflag = 0; + fflag = hflag = lflag = pflag = 0; uid = getuid(); - while ((ch = getopt(argc, argv, "fh:p")) != EOF) + while ((ch = getopt(argc, argv, "1fh:lpq")) != EOF) switch (ch) { + case '1': + oflag = 1; + break; case 'f': fflag = 1; break; @@ -175,22 +247,30 @@ main(argc, argv) *p = 0; hostname = optarg; break; + case 'l': + lflag = 1; + break; case 'p': pflag = 1; break; + case 'q': + quietlog = 1; + break; case '?': default: if (!uid) syslog(LOG_ERR, "invalid flag %c", ch); (void)fprintf(stderr, - "usage: login [-fp] [-h hostname] [username]\n"); + "usage: login [-pq] [-h hostname] [username]\n"); + (void)fprintf(stderr, + " login -f [-lpq] [-h hostname] [username [prog [arg ...]]]\n"); exit(1); } argc -= optind; argv += optind; if (*argv) { - username = *argv; + username = *argv++; ask = 0; } else ask = 1; @@ -208,6 +288,124 @@ main(argc, argv) else tty = ttyn; +#ifdef USE_BSM + /* Set the terminal id */ + audit_set_terminal_id(&tid); + if (fstat(STDIN_FILENO, &st) < 0) { + fprintf(stderr, "login: Unable to stat terminal\n"); + au_fail("Unable to stat terminal", 1); + exit(-1); + } + if (S_ISCHR(st.st_mode)) { + tid.port = st.st_rdev; + } else { + tid.port = 0; + } +#endif + +#ifdef USE_PAM + pam_err = pam_start("login", username, &conv, &pamh); + if( pam_err != PAM_SUCCESS ) { + fprintf(stderr, "login: PAM Error (line %d): %s\n", __LINE__, pam_strerror(pamh, pam_err)); + au_fail("PAM Error", 1); + exit(1); + } + pam_err = pam_set_item(pamh, PAM_TTY, tty); + if( pam_err != PAM_SUCCESS ) { + fprintf(stderr, "login: PAM Error (line %d): %s\n", __LINE__, pam_strerror(pamh, pam_err)); + au_fail("PAM Error", 1); + exit(1); + } + + pam_err = pam_set_item(pamh, PAM_RHOST, hostname); + if( pam_err != PAM_SUCCESS ) { + fprintf(stderr, "login: PAM Error (line %d): %s\n", __LINE__, pam_strerror(pamh, pam_err)); + au_fail("PAM Error", 1); + exit(1); + } + + pam_err = pam_set_item(pamh, PAM_USER_PROMPT, "login: "); + if( pam_err != PAM_SUCCESS ) { + fprintf(stderr, "login: PAM Error (line %d): %s\n", __LINE__, pam_strerror(pamh, pam_err)); + au_fail("PAM Error", 1); + exit(1); + } + + if( !username ) + getloginname(); + pam_set_item(pamh, PAM_USER, username); + pwd = getpwnam(username); + if( (pwd != NULL) && (pwd->pw_uid == 0) ) + rootlogin = 1; + + if( (pwd != NULL) && fflag && ((uid == 0) || (uid == pwd->pw_uid)) ){ + pam_err = 0; + auditsuccess = 0; /* we've simply opened a terminal window */ + } else { + + pam_err = pam_authenticate(pamh, 0); + while( (!oflag) && (cnt++ < 10) && ((pam_err == PAM_AUTH_ERR) || + (pam_err == PAM_USER_UNKNOWN) || + (pam_err == PAM_CRED_INSUFFICIENT) || + (pam_err == PAM_AUTHINFO_UNAVAIL))) { + /* + * we are not exiting here, but this corresponds to + * a failed login event, so set exitstatus to 1 + */ + au_fail("Login incorrect", 1); + badlogin(username); + printf("Login incorrect\n"); + rootlogin = 0; + getloginname(); + pwd = getpwnam(username); + if( (pwd != NULL) && (pwd->pw_uid == 0) ) + rootlogin = 1; + pam_set_item(pamh, PAM_USER, username); + pam_err = pam_authenticate(pamh, 0); + } + + if( pam_err != PAM_SUCCESS ) { + pam_get_item(pamh, PAM_USER, (void *)&username); + badlogin(username); + printf("Login incorrect\n"); + au_fail("Login incorrect", 1); + exit(1); + } + + pam_err = pam_acct_mgmt(pamh, 0); + if( pam_err == PAM_NEW_AUTHTOK_REQD ) { + pam_err = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK); + } + if( pam_err != PAM_SUCCESS ) { + fprintf(stderr, "login: PAM Error (line %d): %s\n", __LINE__, pam_strerror(pamh, pam_err)); + au_fail("PAM error", 1); + exit(1); + } + } + + pam_err = pam_get_item(pamh, PAM_USER, (void *)&username); + if( (pam_err == PAM_SUCCESS) && username && *username) + pwd = getpwnam(username); + + /* get lastlog info before PAM make a new entry */ + if (!quietlog) + getlastlogxbyname(username, &lastlog); + + pam_err = pam_open_session(pamh, 0); + if( pam_err != PAM_SUCCESS ) { + fprintf(stderr, "login: PAM Error (line %d): %s\n", __LINE__, pam_strerror(pamh, pam_err)); + au_fail("PAM error", 1); + exit(1); + } + + pam_err = pam_setcred(pamh, PAM_ESTABLISH_CRED); + if( pam_err != PAM_SUCCESS ) { + fprintf(stderr, "login: PAM Error (line %d): %s\n", __LINE__, pam_strerror(pamh, pam_err)); + au_fail("PAM error", 1); + exit(1); + } + +#else /* USE_PAM */ for (cnt = 0;; ask = 1) { if (ask) { fflag = 0; @@ -231,8 +429,9 @@ main(argc, argv) * for nonexistent name (mistyped username). */ if (failures && strcmp(tbuf, username)) { - if (failures > (pwd ? 0 : 1)) + if (failures > (pwd ? 0 : 1)) { badlogin(tbuf); + } failures = 0; } (void)strcpy(tbuf, username); @@ -295,6 +494,7 @@ main(argc, argv) syslog(LOG_NOTICE, "LOGIN %s REFUSED ON TTY %s", pwd->pw_name, tty); + au_fail("Login refused on terminal", 0); continue; } @@ -307,51 +507,60 @@ main(argc, argv) if (++cnt > 3) { if (cnt >= 10) { badlogin(username); + au_fail("Login incorrect", 1); sleepexit(1); } + au_fail("Login incorrect", 1); sleep((u_int)((cnt - 3) * 5)); } } +#endif /* committed to login -- turn off timeout */ (void)alarm((u_int)0); endpwent(); + if (!pwd) { + fprintf(stderr, "login: Unable to find user: %s\n", username); + exit(1); + } + /* if user not super-user, check for disabled logins */ if (!rootlogin) checknologin(); - if (chdir(pwd->pw_dir) < 0) { - (void)printf("No home directory %s!\n", pwd->pw_dir); - if (chdir("/")) - exit(0); - pwd->pw_dir = "/"; - (void)printf("Logging in with home = \"/\".\n"); - } - - quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0; - - if (pwd->pw_change || pwd->pw_expire) - (void)gettimeofday(&tp, (struct timezone *)NULL); - if (pwd->pw_change) - if (tp.tv_sec >= pwd->pw_change) { - (void)printf("Sorry -- your password has expired.\n"); - sleepexit(1); - } else if (pwd->pw_change - tp.tv_sec < - 2 * DAYSPERWEEK * SECSPERDAY && !quietlog) - (void)printf("Warning: your password expires on %s", - ctime(&pwd->pw_change)); - if (pwd->pw_expire) - if (tp.tv_sec >= pwd->pw_expire) { - (void)printf("Sorry -- your account has expired.\n"); - sleepexit(1); - } else if (pwd->pw_expire - tp.tv_sec < - 2 * DAYSPERWEEK * SECSPERDAY && !quietlog) - (void)printf("Warning: your account expires on %s", - ctime(&pwd->pw_expire)); + /* Audit successful login */ + if (auditsuccess) + au_success(); + + setegid(pwd->pw_gid); + seteuid(rootlogin ? 0 : pwd->pw_uid); + + if (!lflag) { + /* First do a stat in case the homedir is automounted */ + stat(pwd->pw_dir,&st); + + if (!*pwd->pw_dir || chdir(pwd->pw_dir) < 0) { + printf("No home directory %s!\n", pwd->pw_dir); + if (chdir("/")) + refused("Cannot find root directory", "HOMEDIR", 1); + pwd->pw_dir = strdup("/"); + if (pwd->pw_dir == NULL) { + syslog(LOG_NOTICE, "strdup(): %m"); + bail(SLEEP_EXIT, 1); + } + printf("Logging in with home = \"/\".\n"); + } + } + seteuid(euid); + setegid(egid); + + if (!quietlog) + quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0; /* Nothing else left to fail -- really log in. */ +#ifndef USE_PAM memset((void *)&utmp, 0, sizeof(utmp)); (void)time(&utmp.ut_time); (void)strncpy(utmp.ut_name, username, sizeof(utmp.ut_name)); @@ -359,6 +568,7 @@ main(argc, argv) (void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host)); (void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line)); login(&utmp); +#endif /* USE_PAM */ dolastlog(quietlog); @@ -367,14 +577,31 @@ main(argc, argv) (void)chmod(ttyn, 0620); (void)setgid(pwd->pw_gid); - initgroups(username, pwd->pw_gid); + if (initgroups(username, pwd->pw_gid) == -1) + syslog(LOG_ERR, "login: initgroups() failed"); if (*pwd->pw_shell == '\0') - pwd->pw_shell = _PATH_BSHELL; + pwd->pw_shell = strdup(_PATH_BSHELL); + if (pwd->pw_shell == NULL) { + syslog(LOG_NOTICE, "strdup(): %m"); + bail(SLEEP_EXIT, 1); + } + +#if TARGET_OS_EMBEDDED + /* on embedded, allow a shell to live in /var/debug_mount/bin/sh */ +#define _PATH_DEBUGSHELL "/var/debug_mount/bin/sh" + if (stat(pwd->pw_shell, &st) != 0) { + if (stat(_PATH_DEBUGSHELL, &st) == 0) { + pwd->pw_shell = strdup(_PATH_DEBUGSHELL); + } + } +#endif /* Destroy environment unless user has requested its preservation. */ - if (!pflag) - environ = envinit; + if (!pflag) { + environ = malloc(sizeof(char *)); + *environ = NULL; + } (void)setenv("HOME", pwd->pw_dir, 1); (void)setenv("SHELL", pwd->pw_shell, 1); if (term[0] == '\0') @@ -388,6 +615,33 @@ main(argc, argv) (void)setenv("KRBTKFILE", krbtkfile_env, 1); #endif +#ifdef USE_PAM + pmenv = pam_getenvlist(pamh); + for( cnt = 0; pmenv && pmenv[cnt]; cnt++ ) + putenv(pmenv[cnt]); + + /* Ignore SIGHUP so that the parent's call to waitpid will + succeed and the tty ownership can be reset. */ + (void)signal(SIGHUP, SIG_IGN); + + pid = fork(); + if ( pid < 0 ) { + err(1, "fork"); + } else if( pid != 0 ) { + waitpid(pid, NULL, 0); + pam_setcred(pamh, PAM_DELETE_CRED); + pam_err = pam_close_session(pamh, 0); + pam_end(pamh,pam_err); + chown(ttyn, 0, 0); + chmod(ttyn, 0666); + exit(0); + } + + /* Restore the default SIGHUP handler for the child. */ + (void)signal(SIGHUP, SIG_DFL); + +#endif + if (tty[sizeof("tty")-1] == 'd') syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name); @@ -418,10 +672,6 @@ main(argc, argv) (void)signal(SIGINT, SIG_DFL); (void)signal(SIGTSTP, SIG_IGN); - tbuf[0] = '-'; - (void)strcpy(tbuf + 1, (p = strrchr(pwd->pw_shell, '/')) ? - p + 1 : pwd->pw_shell); - if (setlogin(pwd->pw_name) < 0) syslog(LOG_ERR, "setlogin() failure: %m"); @@ -431,15 +681,214 @@ main(argc, argv) else (void) setuid(pwd->pw_uid); - execlp(pwd->pw_shell, tbuf, 0); - err(1, "%s", pwd->pw_shell); + /* Re-enable crash reporter */ + do { + kern_return_t kr; + mach_port_t bp, ep, mts; + thread_state_flavor_t flavor = 0; + +#if defined(__ppc__) + flavor = PPC_THREAD_STATE64; +#elif defined(__i386__) + flavor = x86_THREAD_STATE; +#endif + + mts = mach_task_self(); + + kr = task_get_bootstrap_port(mts, &bp); + if (kr != KERN_SUCCESS) { + syslog(LOG_ERR, "task_get_bootstrap_port() failure: %s (%d)", + bootstrap_strerror(kr), kr); + break; + } + + const char* bs = "com.apple.ReportCrash"; + kr = bootstrap_look_up(bp, (char*)bs, &ep); + if (kr != KERN_SUCCESS) { + syslog(LOG_ERR, "bootstrap_look_up(%s) failure: %s (%d)", + bs, bootstrap_strerror(kr), kr); + break; + } + + kr = task_set_exception_ports(mts, EXC_MASK_CRASH, ep, EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES, flavor); + if (kr != KERN_SUCCESS) { + syslog(LOG_ERR, "task_set_exception_ports() failure: %d", kr); + break; + } + } while (0); + + if (fflag && *argv) { + char *arg0 = *argv; + if (lflag) + (void)strlcpy(tbuf, (p = strrchr(*argv, '/')) ? + p + 1 : *argv, sizeof(tbuf)); + else { + tbuf[0] = '-'; + (void)strlcpy(tbuf + 1, (p = strrchr(*argv, '/')) ? + p + 1 : *argv, sizeof(tbuf) - 1); + } + *argv = tbuf; + execvp(arg0, argv); + err(1, "%s", arg0); + } else { + if (lflag) + (void)strlcpy(tbuf, (p = strrchr(pwd->pw_shell, '/')) ? + p + 1 : pwd->pw_shell, sizeof(tbuf)); + else { + tbuf[0] = '-'; + (void)strlcpy(tbuf + 1, (p = strrchr(pwd->pw_shell, '/')) ? + p + 1 : pwd->pw_shell, sizeof(tbuf) - 1); + } + execlp(pwd->pw_shell, tbuf, (char *)NULL); + err(1, "%s", pwd->pw_shell); + } } #ifdef KERBEROS -#define NBUFSIZ (UT_NAMESIZE + 1 + 5) /* .root suffix */ +#define NBUFSIZ (MAXLOGNAME + 1 + 5) /* .root suffix */ #else -#define NBUFSIZ (UT_NAMESIZE + 1) +#define NBUFSIZ (MAXLOGNAME + 1) +#endif + +/* + * The following tokens are included in the audit record for successful login attempts + * header + * subject + * return + */ +void au_success() +{ +#ifdef USE_BSM + token_t *tok; + int aufd; + au_mask_t aumask; + auditinfo_t auinfo; + uid_t uid = pwd->pw_uid; + gid_t gid = pwd->pw_gid; + pid_t pid = getpid(); + long au_cond; + + /* If we are not auditing, don't cut an audit record; just return */ + if (auditon(A_GETCOND, &au_cond, sizeof(long)) < 0) { + fprintf(stderr, "login: Could not determine audit condition\n"); + exit(1); + } + if (au_cond == AUC_NOAUDIT) + return; + + /* Compute and Set the user's preselection mask */ + if(au_user_mask(pwd->pw_name, &aumask) == -1) { + fprintf(stderr, "login: Could not set audit mask\n"); + exit(1); + } + + /* Set the audit info for the user */ + auinfo.ai_auid = uid; + auinfo.ai_asid = pid; + bcopy(&tid, &auinfo.ai_termid, sizeof(auinfo.ai_termid)); + bcopy(&aumask, &auinfo.ai_mask, sizeof(auinfo.ai_mask)); + if(setaudit(&auinfo) != 0) { + fprintf(stderr, "login: setaudit failed: %s\n", strerror(errno)); + exit(1); + } + + if((aufd = au_open()) == -1) { + fprintf(stderr, "login: Audit Error: au_open() failed\n"); + exit(1); + } + + /* The subject that is created (euid, egid of the current process) */ + if((tok = au_to_subject32(uid, geteuid(), getegid(), + uid, gid, pid, pid, &tid)) == NULL) { + fprintf(stderr, "login: Audit Error: au_to_subject32() failed\n"); + exit(1); + } + au_write(aufd, tok); + + if((tok = au_to_return32(0, 0)) == NULL) { + fprintf(stderr, "login: Audit Error: au_to_return32() failed\n"); + exit(1); + } + au_write(aufd, tok); + + if(au_close(aufd, 1, AUE_login) == -1) { + fprintf(stderr, "login: Audit Record was not committed.\n"); + exit(1); + } +#endif +} + +/* + * The following tokens are included in the audit record for successful login attempts + * header + * subject + * text + * return + */ +void au_fail(char *errmsg, int na) +{ +#ifdef USE_BSM + token_t *tok; + int aufd; + long au_cond; + uid_t uid; + gid_t gid; + pid_t pid = getpid(); + + /* If we are not auditing, don't cut an audit record; just return */ + if (auditon(A_GETCOND, &au_cond, sizeof(long)) < 0) { + fprintf(stderr, "login: Could not determine audit condition\n"); + exit(1); + } + if (au_cond == AUC_NOAUDIT) + return; + + if((aufd = au_open()) == -1) { + fprintf(stderr, "login: Audit Error: au_open() failed\n"); + exit(1); + } + + if(na) { + /* Non attributable event */ + /* Assuming that login is not called within a users' session => auid,asid == -1 */ + if((tok = au_to_subject32(-1, geteuid(), getegid(), -1, -1, + pid, -1, &tid)) == NULL) { + + fprintf(stderr, "login: Audit Error: au_to_subject32() failed\n"); + exit(1); + } + } + else { + /* we know the subject -- so use its value instead */ + uid = pwd->pw_uid; + gid = pwd->pw_gid; + if((tok = au_to_subject32(uid, geteuid(), getegid(), + uid, gid, pid, pid, &tid)) == NULL) { + fprintf(stderr, "login: Audit Error: au_to_subject32() failed\n"); + exit(1); + } + } + au_write(aufd, tok); + + /* Include the error message */ + if((tok = au_to_text(errmsg)) == NULL) { + fprintf(stderr, "login: Audit Error: au_to_text() failed\n"); + exit(1); + } + au_write(aufd, tok); + + if((tok = au_to_return32(1, errno)) == NULL) { + fprintf(stderr, "login: Audit Error: au_to_return32() failed\n"); + exit(1); + } + au_write(aufd, tok); + + if(au_close(aufd, 1, AUE_login) == -1) { + fprintf(stderr, "login: Audit Error: au_close() was not committed\n"); + exit(1); + } #endif +} void getloginname() @@ -458,7 +907,7 @@ getloginname() if (p < nbuf + (NBUFSIZ - 1)) *p++ = ch; } - if (p > nbuf) + if (p > nbuf) { if (nbuf[0] == '-') (void)fprintf(stderr, "login names may not start with '-'.\n"); @@ -467,6 +916,7 @@ getloginname() username = nbuf; break; } + } } } @@ -526,6 +976,7 @@ checknologin() if ((fd = open(_PATH_NOLOGIN, O_RDONLY, 0)) >= 0) { while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) (void)write(fileno(stdout), tbuf, nchars); + au_fail("No login", 0); sleepexit(0); } } @@ -534,9 +985,35 @@ void dolastlog(quiet) int quiet; { +#ifdef USE_PAM + if (quiet) + return; + if (*lastlog.ll_line) { + (void)printf("Last login: %.*s ", + 24-5, (char *)ctime(&lastlog.ll_tv.tv_sec)); + if (*lastlog.ll_host != '\0') + (void)printf("from %.*s\n", + (int)sizeof(lastlog.ll_host), + lastlog.ll_host); + else + (void)printf("on %.*s\n", + (int)sizeof(lastlog.ll_line), + lastlog.ll_line); + } +#else /* !USE_PAM */ struct lastlog ll; int fd; + /* HACK HACK HACK: This is because HFS doesn't support sparse files + * and seeking into the file too far is too slow. The "solution" + * is to just bail if the seek time for a large uid would be too + * slow. + */ + if(pwd->pw_uid > 100000) { + syslog(LOG_NOTICE, "User login %s (%d) not logged in lastlog. UID too large.", pwd->pw_name, pwd->pw_uid); + return; + } + if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) { (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); if (!quiet) { @@ -563,6 +1040,7 @@ dolastlog(quiet) (void)write(fd, (char *)&ll, sizeof(ll)); (void)close(fd); } +#endif /* USE_PAM */ } void @@ -607,3 +1085,67 @@ sleepexit(eval) (void)sleep(5); exit(eval); } + +static void +refused(const char *msg, const char *rtype, int lout) +{ + + if (msg != NULL) + printf("%s.\n", msg); + if (hflag) + syslog(LOG_NOTICE, "LOGIN %s REFUSED (%s) FROM %s ON TTY %s", + pwd->pw_name, rtype, hostname, tty); + else + syslog(LOG_NOTICE, "LOGIN %s REFUSED (%s) ON TTY %s", + pwd->pw_name, rtype, tty); + if (lout) + bail(SLEEP_EXIT, 1); +} + +#ifdef USE_PAM +/* + * Log a PAM error + */ +static void +pam_syslog(const char *msg) +{ + syslog(LOG_ERR, "%s: %s", msg, pam_strerror(pamh, pam_err)); +} + +/* + * Shut down PAM + */ +static void +pam_cleanup() +{ + + if (pamh != NULL) { + if (pam_session_established) { + pam_err = pam_close_session(pamh, 0); + if (pam_err != PAM_SUCCESS) + pam_syslog("pam_close_session()"); + } + pam_session_established = 0; + if (pam_cred_established) { + pam_err = pam_setcred(pamh, pam_silent|PAM_DELETE_CRED); + if (pam_err != PAM_SUCCESS) + pam_syslog("pam_setcred()"); + } + pam_cred_established = 0; + pam_end(pamh, pam_err); + pamh = NULL; + } +} +#endif /* USE_PAM */ +/* + * Exit, optionally after sleeping a few seconds + */ +void +bail(int sec, int eval) +{ +#ifdef USE_PAM + pam_cleanup(); +#endif + (void)sleep(sec); + exit(eval); +}