pico-login.c revision 146187
184309Sluigi/*- 284309Sluigi * Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994 384309Sluigi * The Regents of the University of California. All rights reserved. 484309Sluigi * 584309Sluigi * Redistribution and use in source and binary forms, with or without 684309Sluigi * modification, are permitted provided that the following conditions 784309Sluigi * are met: 884309Sluigi * 1. Redistributions of source code must retain the above copyright 984309Sluigi * notice, this list of conditions and the following disclaimer. 1084309Sluigi * 2. Redistributions in binary form must reproduce the above copyright 1184309Sluigi * notice, this list of conditions and the following disclaimer in the 1284309Sluigi * documentation and/or other materials provided with the distribution. 1384309Sluigi * 3. All advertising materials mentioning features or use of this software 1484309Sluigi * must display the following acknowledgement: 1584309Sluigi * This product includes software developed by the University of 1684309Sluigi * California, Berkeley and its contributors. 1784309Sluigi * 4. Neither the name of the University nor the names of its contributors 1884309Sluigi * may be used to endorse or promote products derived from this software 1984309Sluigi * without specific prior written permission. 2084309Sluigi * 2184309Sluigi * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2284309Sluigi * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2384309Sluigi * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2484309Sluigi * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2584309Sluigi * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2684309Sluigi * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2784309Sluigi * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2884309Sluigi * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2984309Sluigi * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3084309Sluigi * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3184309Sluigi * SUCH DAMAGE. 3284309Sluigi */ 3384309Sluigi 3484309Sluigi#if 0 3584309Sluigistatic char copyright[] = 3684309Sluigi"@(#) Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994\n\ 3784309Sluigi The Regents of the University of California. All rights reserved.\n"; 3884309Sluigi#endif 3984309Sluigi 4084309Sluigi#ifndef lint 4184309Sluigi#if 0 4284309Sluigistatic char sccsid[] = "@(#)login.c 8.4 (Berkeley) 4/2/94"; 4384309Sluigi#endif 4484309Sluigistatic const char rcsid[] = 4584605Sluigi "$FreeBSD: head/release/picobsd/tinyware/login/pico-login.c 146187 2005-05-13 16:31:11Z ume $"; 4684309Sluigi#endif /* not lint */ 4784309Sluigi 4884309Sluigi/* 4984309Sluigi * login [ name ] 5084309Sluigi * login -h hostname (for telnetd, etc.) 5184309Sluigi * login -f name (for pre-authenticated login: datakit, xterm, etc.) 5284309Sluigi */ 5384309Sluigi 5484309Sluigi#include <sys/copyright.h> 5584309Sluigi#include <sys/param.h> 5684309Sluigi#include <sys/stat.h> 5784309Sluigi#include <sys/socket.h> 5884309Sluigi#include <sys/time.h> 5984309Sluigi#include <sys/resource.h> 6084309Sluigi#include <sys/file.h> 6184309Sluigi#include <netinet/in.h> 6284309Sluigi#include <arpa/inet.h> 6384309Sluigi 6484309Sluigi#include <err.h> 6584309Sluigi#include <errno.h> 6684309Sluigi#include <grp.h> 6784309Sluigi#include <libutil.h> 6884309Sluigi#include <login_cap.h> 6984309Sluigi#include <netdb.h> 7084309Sluigi#include <pwd.h> 7184309Sluigi#include <setjmp.h> 7284309Sluigi#include <signal.h> 7384309Sluigi#include <stdio.h> 7484309Sluigi#include <stdlib.h> 7584309Sluigi#include <string.h> 7684309Sluigi#include <syslog.h> 7784309Sluigi#include <ttyent.h> 7884309Sluigi#include <unistd.h> 7984309Sluigi#include <utmp.h> 8084309Sluigi 8184309Sluigi#ifdef USE_PAM 8284309Sluigi#include <security/pam_appl.h> 8394201Sru#include <security/openpam.h> 8484309Sluigi#include <sys/wait.h> 8584309Sluigi#endif /* USE_PAM */ 8684309Sluigi 8784309Sluigi#include "pathnames.h" 8884309Sluigi 89104744Salfredvoid badlogin(char *); 90104744Salfredvoid checknologin(void); 91104744Salfredvoid dolastlog(int); 92104744Salfredvoid getloginname(void); 93104744Salfredvoid motd(const char *); 94104744Salfredint rootterm(char *); 95104744Salfredvoid sigint(int); 96104744Salfredvoid sleepexit(int); 97104744Salfredvoid refused(char *,char *,int); 98104744Salfredchar *stypeof(char *); 99104744Salfredvoid timedout(int); 100104744Salfredint login_access(char *, char *); 101104744Salfredvoid login_fbtab(char *, uid_t, gid_t); 10284309Sluigi 10384309Sluigi#ifdef USE_PAM 104104744Salfredstatic int auth_pam(void); 105104744Salfredstatic int export_pam_environment(void); 106104744Salfredstatic int ok_to_export(const char *); 10784309Sluigi 10884309Sluigistatic pam_handle_t *pamh = NULL; 10984309Sluigistatic char **environ_pam; 11084309Sluigi 11184309Sluigi#define PAM_END { \ 11284309Sluigi if ((e = pam_setcred(pamh, PAM_DELETE_CRED)) != PAM_SUCCESS) \ 11384309Sluigi syslog(LOG_ERR, "pam_setcred: %s", pam_strerror(pamh, e)); \ 11484309Sluigi if ((e = pam_close_session(pamh,0)) != PAM_SUCCESS) \ 11584309Sluigi syslog(LOG_ERR, "pam_close_session: %s", pam_strerror(pamh, e)); \ 11684309Sluigi if ((e = pam_end(pamh, e)) != PAM_SUCCESS) \ 11784309Sluigi syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e)); \ 11884309Sluigi} 11984309Sluigi#endif 12084309Sluigi 121104744Salfredstatic int auth_traditional(void); 122104744Salfredextern void login(struct utmp *); 123104744Salfredstatic void usage(void); 12484309Sluigi 12584309Sluigi#define TTYGRPNAME "tty" /* name of group to own ttys */ 12684309Sluigi#define DEFAULT_BACKOFF 3 12784309Sluigi#define DEFAULT_RETRIES 10 12884309Sluigi#define DEFAULT_PROMPT "login: " 12984309Sluigi#define DEFAULT_PASSWD_PROMPT "Password:" 13084309Sluigi 13184309Sluigi/* 13284309Sluigi * This bounds the time given to login. Not a define so it can 13384309Sluigi * be patched on machines where it's too small. 13484309Sluigi */ 13584309Sluigiu_int timeout = 300; 13684309Sluigi 13784309Sluigi/* Buffer for signal handling of timeout */ 13884309Sluigijmp_buf timeout_buf; 13984309Sluigi 14084309Sluigistruct passwd *pwd; 14184309Sluigiint failures; 14294203Sruchar *term, *envinit[1], *hostname, *tty, *username; 14394203Sruconst char *passwd_prompt, *prompt; 14484309Sluigichar full_hostname[MAXHOSTNAMELEN]; 14584309Sluigi 14684309Sluigiint 14784309Sluigimain(argc, argv) 14884309Sluigi int argc; 14984309Sluigi char *argv[]; 15084309Sluigi{ 15184309Sluigi extern char **environ; 15284309Sluigi struct group *gr; 15384309Sluigi struct stat st; 15484309Sluigi struct timeval tp; 15584309Sluigi struct utmp utmp; 15684309Sluigi int rootok, retries, backoff; 15784309Sluigi int ask, ch, cnt, fflag, hflag, pflag, quietlog, rootlogin, rval; 15884309Sluigi int changepass; 15984309Sluigi time_t warntime; 16084309Sluigi uid_t uid, euid; 16184309Sluigi gid_t egid; 16284309Sluigi char *p, *ttyn; 16384309Sluigi char tbuf[MAXPATHLEN + 2]; 16484309Sluigi char tname[sizeof(_PATH_TTY) + 10]; 16594203Sru const char *shell = NULL; 16684309Sluigi login_cap_t *lc = NULL; 16784309Sluigi#ifdef USE_PAM 16884309Sluigi pid_t pid; 16984309Sluigi int e; 17084309Sluigi#endif /* USE_PAM */ 17184309Sluigi 17284309Sluigi (void)signal(SIGQUIT, SIG_IGN); 17384309Sluigi (void)signal(SIGINT, SIG_IGN); 17484309Sluigi (void)signal(SIGHUP, SIG_IGN); 17584309Sluigi if (setjmp(timeout_buf)) { 17684309Sluigi if (failures) 17784309Sluigi badlogin(tbuf); 17884309Sluigi (void)fprintf(stderr, "Login timed out after %d seconds\n", 17984309Sluigi timeout); 18084309Sluigi exit(0); 18184309Sluigi } 18284309Sluigi (void)signal(SIGALRM, timedout); 18384309Sluigi (void)alarm(timeout); 18484309Sluigi (void)setpriority(PRIO_PROCESS, 0, 0); 18584309Sluigi 18684309Sluigi openlog("login", LOG_ODELAY, LOG_AUTH); 18784309Sluigi 18884309Sluigi /* 18984309Sluigi * -p is used by getty to tell login not to destroy the environment 19084309Sluigi * -f is used to skip a second login authentication 19184309Sluigi * -h is used by other servers to pass the name of the remote 19284309Sluigi * host to login so that it may be placed in utmp and wtmp 19384309Sluigi */ 19484309Sluigi *full_hostname = '\0'; 19584309Sluigi term = NULL; 19684309Sluigi 19784309Sluigi fflag = hflag = pflag = 0; 19884309Sluigi uid = getuid(); 19984309Sluigi euid = geteuid(); 20084309Sluigi egid = getegid(); 20184309Sluigi while ((ch = getopt(argc, argv, "fh:p")) != -1) 20284309Sluigi switch (ch) { 20384309Sluigi case 'f': 20484309Sluigi fflag = 1; 20584309Sluigi break; 20684309Sluigi case 'h': 20784309Sluigi if (uid) 20884309Sluigi errx(1, "-h option: %s", strerror(EPERM)); 20984309Sluigi hflag = 1; 21084309Sluigi if (strlcpy(full_hostname, optarg, 21184309Sluigi sizeof(full_hostname)) >= sizeof(full_hostname)) 21284309Sluigi errx(1, "-h option: %s: exceeds maximum " 21384309Sluigi "hostname size", optarg); 21484309Sluigi 21584309Sluigi trimdomain(optarg, UT_HOSTSIZE); 21684309Sluigi 21784309Sluigi if (strlen(optarg) > UT_HOSTSIZE) { 21884309Sluigi struct addrinfo hints, *res; 21984309Sluigi int ga_err; 22084309Sluigi 22184309Sluigi memset(&hints, 0, sizeof(hints)); 22284309Sluigi hints.ai_family = AF_UNSPEC; 22384309Sluigi ga_err = getaddrinfo(optarg, NULL, &hints, 22484309Sluigi &res); 22584309Sluigi if (ga_err == 0) { 22684309Sluigi char hostbuf[MAXHOSTNAMELEN]; 22784309Sluigi 22884309Sluigi getnameinfo(res->ai_addr, 22984309Sluigi res->ai_addrlen, 23084309Sluigi hostbuf, 23184309Sluigi sizeof(hostbuf), NULL, 0, 232146187Sume NI_NUMERICHOST); 23384309Sluigi optarg = strdup(hostbuf); 23484309Sluigi if (optarg == NULL) { 23584309Sluigi syslog(LOG_NOTICE, 23684309Sluigi "strdup(): %m"); 23784309Sluigi sleepexit(1); 23884309Sluigi } 23984309Sluigi } else 24084309Sluigi optarg = "invalid hostname"; 24184309Sluigi if (res != NULL) 24284309Sluigi freeaddrinfo(res); 24384309Sluigi } 24484309Sluigi hostname = optarg; 24584309Sluigi break; 24684309Sluigi case 'p': 24784309Sluigi pflag = 1; 24884309Sluigi break; 24984309Sluigi case '?': 25084309Sluigi default: 25184309Sluigi if (!uid) 25284309Sluigi syslog(LOG_ERR, "invalid flag %c", ch); 25384309Sluigi usage(); 25484309Sluigi } 25584309Sluigi argc -= optind; 25684309Sluigi argv += optind; 25784309Sluigi 25884309Sluigi if (*argv) { 25984309Sluigi username = *argv; 26084309Sluigi ask = 0; 26184309Sluigi } else 26284309Sluigi ask = 1; 26384309Sluigi 26484309Sluigi for (cnt = getdtablesize(); cnt > 2; cnt--) 26584309Sluigi (void)close(cnt); 26684309Sluigi 26784309Sluigi ttyn = ttyname(STDIN_FILENO); 26884309Sluigi if (ttyn == NULL || *ttyn == '\0') { 26984309Sluigi (void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY); 27084309Sluigi ttyn = tname; 27184309Sluigi } 27284309Sluigi if ((tty = strrchr(ttyn, '/')) != NULL) 27384309Sluigi ++tty; 27484309Sluigi else 27584309Sluigi tty = ttyn; 27684309Sluigi 27784309Sluigi /* 27884309Sluigi * Get "login-retries" & "login-backoff" from default class 27984309Sluigi */ 28084309Sluigi lc = login_getclass(NULL); 28184309Sluigi prompt = login_getcapstr(lc, "prompt", DEFAULT_PROMPT, DEFAULT_PROMPT); 28284309Sluigi passwd_prompt = login_getcapstr(lc, "passwd_prompt", 28384309Sluigi DEFAULT_PASSWD_PROMPT, DEFAULT_PASSWD_PROMPT); 28484309Sluigi retries = login_getcapnum(lc, "login-retries", DEFAULT_RETRIES, 28584309Sluigi DEFAULT_RETRIES); 28684309Sluigi backoff = login_getcapnum(lc, "login-backoff", DEFAULT_BACKOFF, 28784309Sluigi DEFAULT_BACKOFF); 28884309Sluigi login_close(lc); 28984309Sluigi lc = NULL; 29084309Sluigi 29184309Sluigi for (cnt = 0;; ask = 1) { 29284309Sluigi if (ask) { 29384309Sluigi fflag = 0; 29484309Sluigi getloginname(); 29584309Sluigi } 29684309Sluigi rootlogin = 0; 29784309Sluigi rootok = rootterm(tty); /* Default (auth may change) */ 29884309Sluigi 29984309Sluigi if (strlen(username) > UT_NAMESIZE) 30084309Sluigi username[UT_NAMESIZE] = '\0'; 30184309Sluigi 30284309Sluigi /* 30384309Sluigi * Note if trying multiple user names; log failures for 30484309Sluigi * previous user name, but don't bother logging one failure 30584309Sluigi * for nonexistent name (mistyped username). 30684309Sluigi */ 30784309Sluigi if (failures && strcmp(tbuf, username)) { 30884309Sluigi if (failures > (pwd ? 0 : 1)) 30984309Sluigi badlogin(tbuf); 31084309Sluigi } 31184309Sluigi (void)strlcpy(tbuf, username, sizeof(tbuf)); 31284309Sluigi 31384309Sluigi pwd = getpwnam(username); 31484309Sluigi 31584309Sluigi /* 31684309Sluigi * if we have a valid account name, and it doesn't have a 31784309Sluigi * password, or the -f option was specified and the caller 31884309Sluigi * is root or the caller isn't changing their uid, don't 31984309Sluigi * authenticate. 32084309Sluigi */ 32184309Sluigi if (pwd != NULL) { 32284309Sluigi if (pwd->pw_uid == 0) 32384309Sluigi rootlogin = 1; 32484309Sluigi 32584309Sluigi if (fflag && (uid == (uid_t)0 || 32684309Sluigi uid == (uid_t)pwd->pw_uid)) { 32784309Sluigi /* already authenticated */ 32884309Sluigi break; 32984309Sluigi } else if (pwd->pw_passwd[0] == '\0') { 33084309Sluigi if (!rootlogin || rootok) { 33184309Sluigi /* pretend password okay */ 33284309Sluigi rval = 0; 33384309Sluigi goto ttycheck; 33484309Sluigi } 33584309Sluigi } 33684309Sluigi } 33784309Sluigi 33884309Sluigi fflag = 0; 33984309Sluigi 34084309Sluigi (void)setpriority(PRIO_PROCESS, 0, -4); 34184309Sluigi 34284309Sluigi#ifdef USE_PAM 34384309Sluigi /* 34484309Sluigi * Try to authenticate using PAM. If a PAM system error 34584309Sluigi * occurs, perhaps because of a botched configuration, 34684309Sluigi * then fall back to using traditional Unix authentication. 34784309Sluigi */ 34884309Sluigi if ((rval = auth_pam()) == -1) 34984309Sluigi#endif /* USE_PAM */ 35084309Sluigi rval = auth_traditional(); 35184309Sluigi 35284309Sluigi (void)setpriority(PRIO_PROCESS, 0, 0); 35384309Sluigi 35484309Sluigi#ifdef USE_PAM 35584309Sluigi /* 35684309Sluigi * PAM authentication may have changed "pwd" to the 35784309Sluigi * entry for the template user. Check again to see if 35884309Sluigi * this is a root login after all. 35984309Sluigi */ 36084309Sluigi if (pwd != NULL && pwd->pw_uid == 0) 36184309Sluigi rootlogin = 1; 36284309Sluigi#endif /* USE_PAM */ 36384309Sluigi 36484309Sluigi ttycheck: 36584309Sluigi /* 36684309Sluigi * If trying to log in as root without Kerberos, 36784309Sluigi * but with insecure terminal, refuse the login attempt. 36884309Sluigi */ 36984309Sluigi if (pwd && !rval) { 37084309Sluigi if (rootlogin && !rootok) 37184309Sluigi refused(NULL, "NOROOT", 0); 37284309Sluigi else /* valid password & authenticated */ 37384309Sluigi break; 37484309Sluigi } 37584309Sluigi 37684309Sluigi (void)printf("Login incorrect\n"); 37784309Sluigi failures++; 37884309Sluigi 37984309Sluigi /* 38084309Sluigi * we allow up to 'retry' (10) tries, 38184309Sluigi * but after 'backoff' (3) we start backing off 38284309Sluigi */ 38384309Sluigi if (++cnt > backoff) { 38484309Sluigi if (cnt >= retries) { 38584309Sluigi badlogin(username); 38684309Sluigi sleepexit(1); 38784309Sluigi } 38884309Sluigi sleep((u_int)((cnt - backoff) * 5)); 38984309Sluigi } 39084309Sluigi } 39184309Sluigi 39284309Sluigi /* committed to login -- turn off timeout */ 39384309Sluigi (void)alarm((u_int)0); 39484309Sluigi (void)signal(SIGHUP, SIG_DFL); 39584309Sluigi 39684309Sluigi endpwent(); 39784309Sluigi 39884309Sluigi /* 39984309Sluigi * Establish the login class. 40084309Sluigi */ 40184309Sluigi lc = login_getpwclass(pwd); 40284309Sluigi 40384309Sluigi /* if user not super-user, check for disabled logins */ 40484309Sluigi if (!rootlogin) 40584309Sluigi auth_checknologin(lc); 40684309Sluigi 40784309Sluigi quietlog = login_getcapbool(lc, "hushlogin", 0); 40884309Sluigi /* 40984309Sluigi * Switching needed for NFS with root access disabled. 41084309Sluigi * 41184309Sluigi * XXX: This change fails to modify the additional groups for the 41284309Sluigi * process, and as such, may restrict rights normally granted 41384309Sluigi * through those groups. 41484309Sluigi */ 41584309Sluigi (void)setegid(pwd->pw_gid); 41684309Sluigi (void)seteuid(rootlogin ? 0 : pwd->pw_uid); 41784309Sluigi if (!*pwd->pw_dir || chdir(pwd->pw_dir) < 0) { 41884309Sluigi if (login_getcapbool(lc, "requirehome", 0)) 41984309Sluigi refused("Home directory not available", "HOMEDIR", 1); 42084309Sluigi if (chdir("/") < 0) 42184309Sluigi refused("Cannot find root directory", "ROOTDIR", 1); 42284309Sluigi if (!quietlog || *pwd->pw_dir) 42384309Sluigi printf("No home directory.\nLogging in with home = \"/\".\n"); 42484309Sluigi pwd->pw_dir = "/"; 42584309Sluigi } 42684309Sluigi (void)seteuid(euid); 42784309Sluigi (void)setegid(egid); 42884309Sluigi if (!quietlog) 42984309Sluigi quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0; 43084309Sluigi 43184309Sluigi if (pwd->pw_change || pwd->pw_expire) 43284309Sluigi (void)gettimeofday(&tp, (struct timezone *)NULL); 43384309Sluigi 43484309Sluigi#define DEFAULT_WARN (2L * 7L * 86400L) /* Two weeks */ 43584309Sluigi 43684309Sluigi warntime = login_getcaptime(lc, "warnexpire", DEFAULT_WARN, 43784309Sluigi DEFAULT_WARN); 43884309Sluigi 43984309Sluigi if (pwd->pw_expire) { 44084309Sluigi if (tp.tv_sec >= pwd->pw_expire) { 44184309Sluigi refused("Sorry -- your account has expired", "EXPIRED", 44284309Sluigi 1); 44384309Sluigi } else if (pwd->pw_expire - tp.tv_sec < warntime && !quietlog) 44484309Sluigi (void)printf("Warning: your account expires on %s", 44584309Sluigi ctime(&pwd->pw_expire)); 44684309Sluigi } 44784309Sluigi 44884309Sluigi warntime = login_getcaptime(lc, "warnpassword", DEFAULT_WARN, 44984309Sluigi DEFAULT_WARN); 45084309Sluigi 45184309Sluigi changepass = 0; 45284309Sluigi if (pwd->pw_change) { 45384309Sluigi if (tp.tv_sec >= pwd->pw_change) { 45484309Sluigi (void)printf("Sorry -- your password has expired.\n"); 45584309Sluigi changepass = 1; 45684309Sluigi syslog(LOG_INFO, "%s Password expired - forcing change", 45784309Sluigi pwd->pw_name); 45884309Sluigi } else if (pwd->pw_change - tp.tv_sec < warntime && !quietlog) 45984309Sluigi (void)printf("Warning: your password expires on %s", 46084309Sluigi ctime(&pwd->pw_change)); 46184309Sluigi } 46284309Sluigi 46384309Sluigi if (lc != NULL) { 46484309Sluigi if (hostname) { 46584309Sluigi struct addrinfo hints, *res; 46684309Sluigi int ga_err; 46784309Sluigi 46884309Sluigi memset(&hints, 0, sizeof(hints)); 46984309Sluigi hints.ai_family = AF_UNSPEC; 47084309Sluigi ga_err = getaddrinfo(full_hostname, NULL, &hints, 47184309Sluigi &res); 47284309Sluigi if (ga_err == 0) { 47384309Sluigi char hostbuf[MAXHOSTNAMELEN]; 47484309Sluigi 47584309Sluigi getnameinfo(res->ai_addr, res->ai_addrlen, 47684309Sluigi hostbuf, sizeof(hostbuf), NULL, 0, 477146187Sume NI_NUMERICHOST); 47884309Sluigi if ((optarg = strdup(hostbuf)) == NULL) { 47984309Sluigi syslog(LOG_NOTICE, "strdup(): %m"); 48084309Sluigi sleepexit(1); 48184309Sluigi } 48284309Sluigi } else 48384309Sluigi optarg = NULL; 48484309Sluigi if (res != NULL) 48584309Sluigi freeaddrinfo(res); 48684309Sluigi if (!auth_hostok(lc, full_hostname, optarg)) 48784309Sluigi refused("Permission denied", "HOST", 1); 48884309Sluigi } 48984309Sluigi 49084309Sluigi if (!auth_ttyok(lc, tty)) 49184309Sluigi refused("Permission denied", "TTY", 1); 49284309Sluigi 49384309Sluigi if (!auth_timeok(lc, time(NULL))) 49484309Sluigi refused("Logins not available right now", "TIME", 1); 49584309Sluigi } 49684309Sluigi shell = login_getcapstr(lc, "shell", pwd->pw_shell, pwd->pw_shell); 49784309Sluigi if (*pwd->pw_shell == '\0') 49884309Sluigi pwd->pw_shell = _PATH_BSHELL; 49984309Sluigi if (*shell == '\0') /* Not overridden */ 50084309Sluigi shell = pwd->pw_shell; 50184309Sluigi if ((shell = strdup(shell)) == NULL) { 50284309Sluigi syslog(LOG_NOTICE, "strdup(): %m"); 50384309Sluigi sleepexit(1); 50484309Sluigi } 50584309Sluigi 50684309Sluigi#ifdef LOGIN_ACCESS 50784309Sluigi if (login_access(pwd->pw_name, hostname ? full_hostname : tty) == 0) 50884309Sluigi refused("Permission denied", "ACCESS", 1); 50984309Sluigi#endif /* LOGIN_ACCESS */ 51084309Sluigi 51184309Sluigi /* Nothing else left to fail -- really log in. */ 51284309Sluigi memset((void *)&utmp, 0, sizeof(utmp)); 51384309Sluigi (void)time(&utmp.ut_time); 51484309Sluigi (void)strncpy(utmp.ut_name, username, sizeof(utmp.ut_name)); 51584309Sluigi if (hostname) 51684309Sluigi (void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host)); 51784309Sluigi (void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line)); 51884309Sluigi login(&utmp); 51984309Sluigi 52084309Sluigi dolastlog(quietlog); 52184309Sluigi 52284309Sluigi /* 52384309Sluigi * Set device protections, depending on what terminal the 52484309Sluigi * user is logged in. This feature is used on Suns to give 52584309Sluigi * console users better privacy. 52684309Sluigi */ 52784309Sluigi login_fbtab(tty, pwd->pw_uid, pwd->pw_gid); 52884309Sluigi 52984309Sluigi /* 53084309Sluigi * Clear flags of the tty. None should be set, and when the 53184309Sluigi * user sets them otherwise, this can cause the chown to fail. 53284309Sluigi * Since it isn't clear that flags are useful on character 53384309Sluigi * devices, we just clear them. 53484309Sluigi */ 53584309Sluigi if (chflags(ttyn, 0) && errno != EOPNOTSUPP) 53684309Sluigi syslog(LOG_ERR, "chmod(%s): %m", ttyn); 53784309Sluigi if (chown(ttyn, pwd->pw_uid, 53884309Sluigi (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid)) 53984309Sluigi syslog(LOG_ERR, "chmod(%s): %m", ttyn); 54084309Sluigi 54184309Sluigi 54284309Sluigi /* 54384309Sluigi * Preserve TERM if it happens to be already set. 54484309Sluigi */ 54584309Sluigi if ((term = getenv("TERM")) != NULL) { 54684309Sluigi if ((term = strdup(term)) == NULL) { 54784309Sluigi syslog(LOG_NOTICE, 54884309Sluigi "strdup(): %m"); 54984309Sluigi sleepexit(1); 55084309Sluigi } 55184309Sluigi } 55284309Sluigi 55384309Sluigi /* 55484309Sluigi * Exclude cons/vt/ptys only, assume dialup otherwise 55584309Sluigi * TODO: Make dialup tty determination a library call 55684309Sluigi * for consistency (finger etc.) 55784309Sluigi */ 55884309Sluigi if (hostname==NULL && isdialuptty(tty)) 55984309Sluigi syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name); 56084309Sluigi 56184309Sluigi#ifdef LOGALL 56284309Sluigi /* 56384309Sluigi * Syslog each successful login, so we don't have to watch hundreds 56484309Sluigi * of wtmp or lastlogin files. 56584309Sluigi */ 56684309Sluigi if (hostname) 56784309Sluigi syslog(LOG_INFO, "login from %s on %s as %s", 56884309Sluigi full_hostname, tty, pwd->pw_name); 56984309Sluigi else 57084309Sluigi syslog(LOG_INFO, "login on %s as %s", 57184309Sluigi tty, pwd->pw_name); 57284309Sluigi#endif 57384309Sluigi 57484309Sluigi /* 57584309Sluigi * If fflag is on, assume caller/authenticator has logged root login. 57684309Sluigi */ 57784309Sluigi if (rootlogin && fflag == 0) 57884309Sluigi { 57984309Sluigi if (hostname) 58084309Sluigi syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s", 58184309Sluigi username, tty, full_hostname); 58284309Sluigi else 58384309Sluigi syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s", 58484309Sluigi username, tty); 58584309Sluigi } 58684309Sluigi 58784309Sluigi /* 58884309Sluigi * Destroy environment unless user has requested its preservation. 58984309Sluigi * We need to do this before setusercontext() because that may 59084309Sluigi * set or reset some environment variables. 59184309Sluigi */ 59284309Sluigi if (!pflag) 59384309Sluigi environ = envinit; 59484309Sluigi 59584309Sluigi /* 59684309Sluigi * PAM modules might add supplementary groups during pam_setcred(). 59784309Sluigi */ 59884309Sluigi if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) != 0) { 59984309Sluigi syslog(LOG_ERR, "setusercontext() failed - exiting"); 60084309Sluigi exit(1); 60184309Sluigi } 60284309Sluigi 60384309Sluigi#ifdef USE_PAM 60484309Sluigi if (pamh) { 60584309Sluigi if ((e = pam_open_session(pamh, 0)) != PAM_SUCCESS) { 60684309Sluigi syslog(LOG_ERR, "pam_open_session: %s", 60784309Sluigi pam_strerror(pamh, e)); 60884309Sluigi } else if ((e = pam_setcred(pamh, PAM_ESTABLISH_CRED)) 60984309Sluigi != PAM_SUCCESS) { 61084309Sluigi syslog(LOG_ERR, "pam_setcred: %s", 61184309Sluigi pam_strerror(pamh, e)); 61284309Sluigi } 61384309Sluigi 61484309Sluigi /* 61584309Sluigi * Add any environmental variables that the 61684309Sluigi * PAM modules may have set. 61784309Sluigi * Call *after* opening session! 61884309Sluigi */ 61984309Sluigi if (pamh) { 62084309Sluigi environ_pam = pam_getenvlist(pamh); 62184309Sluigi if (environ_pam) 62284309Sluigi export_pam_environment(); 62384309Sluigi } 62484309Sluigi 62584309Sluigi /* 62684309Sluigi * We must fork() before setuid() because we need to call 62784309Sluigi * pam_close_session() as root. 62884309Sluigi */ 62984309Sluigi pid = fork(); 63084309Sluigi if (pid < 0) { 63184309Sluigi err(1, "fork"); 63284309Sluigi PAM_END; 63384309Sluigi exit(0); 63484309Sluigi } else if (pid) { 63584309Sluigi /* parent - wait for child to finish, then cleanup 63684309Sluigi session */ 63784309Sluigi wait(NULL); 63884309Sluigi PAM_END; 63984309Sluigi exit(0); 64084309Sluigi } else { 64194201Sru if ((e = pam_end(pamh, 0)) != PAM_SUCCESS) 64284309Sluigi syslog(LOG_ERR, "pam_end: %s", 64384309Sluigi pam_strerror(pamh, e)); 64484309Sluigi } 64584309Sluigi } 64684309Sluigi#endif /* USE_PAM */ 64784309Sluigi 64884309Sluigi /* 64984309Sluigi * We don't need to be root anymore, so 65084309Sluigi * set the user and session context 65184309Sluigi */ 65284309Sluigi if (setlogin(username) != 0) { 65384309Sluigi syslog(LOG_ERR, "setlogin(%s): %m - exiting", username); 65484309Sluigi exit(1); 65584309Sluigi } 65684309Sluigi if (setusercontext(lc, pwd, pwd->pw_uid, 65784309Sluigi LOGIN_SETALL & ~(LOGIN_SETLOGIN|LOGIN_SETGROUP)) != 0) { 65884309Sluigi syslog(LOG_ERR, "setusercontext() failed - exiting"); 65984309Sluigi exit(1); 66084309Sluigi } 66184309Sluigi 66284309Sluigi (void)setenv("SHELL", pwd->pw_shell, 1); 66384309Sluigi (void)setenv("HOME", pwd->pw_dir, 1); 66484309Sluigi if (term != NULL && *term != '\0') 66584309Sluigi (void)setenv("TERM", term, 1); /* Preset overrides */ 66684309Sluigi else { 66784309Sluigi (void)setenv("TERM", stypeof(tty), 0); /* Fallback doesn't */ 66884309Sluigi } 66984309Sluigi (void)setenv("LOGNAME", username, 1); 67084309Sluigi (void)setenv("USER", username, 1); 67184309Sluigi (void)setenv("PATH", rootlogin ? _PATH_STDPATH : _PATH_DEFPATH, 0); 67284309Sluigi 67384309Sluigi if (!quietlog) { 67494203Sru const char *cw; 67584309Sluigi 67684309Sluigi cw = login_getcapstr(lc, "copyright", NULL, NULL); 67784309Sluigi if (cw != NULL && access(cw, F_OK) == 0) 67884309Sluigi motd(cw); 67984309Sluigi else 68084309Sluigi (void)printf("%s\n\t%s %s\n", 68184309Sluigi "Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994", 68284309Sluigi "The Regents of the University of California. ", 68384309Sluigi "All rights reserved."); 68484309Sluigi 68584309Sluigi (void)printf("\n"); 68684309Sluigi 68784309Sluigi cw = login_getcapstr(lc, "welcome", NULL, NULL); 68884309Sluigi if (cw == NULL || access(cw, F_OK) != 0) 68984309Sluigi cw = _PATH_MOTDFILE; 69084309Sluigi motd(cw); 69184309Sluigi 69284309Sluigi cw = getenv("MAIL"); /* $MAIL may have been set by class */ 69384309Sluigi if (cw != NULL) 69484309Sluigi strlcpy(tbuf, cw, sizeof(tbuf)); 69584309Sluigi else 69684309Sluigi snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_MAILDIR, 69784309Sluigi pwd->pw_name); 69884309Sluigi if (stat(tbuf, &st) == 0 && st.st_size != 0) 69984309Sluigi (void)printf("You have %smail.\n", 70084309Sluigi (st.st_mtime > st.st_atime) ? "new " : ""); 70184309Sluigi } 70284309Sluigi 70384309Sluigi login_close(lc); 70484309Sluigi 70584309Sluigi (void)signal(SIGALRM, SIG_DFL); 70684309Sluigi (void)signal(SIGQUIT, SIG_DFL); 70784309Sluigi (void)signal(SIGINT, SIG_DFL); 70884309Sluigi (void)signal(SIGTSTP, SIG_IGN); 70984309Sluigi 71084309Sluigi /* 71184309Sluigi * Login shells have a leading '-' in front of argv[0] 71284309Sluigi */ 71384309Sluigi if (snprintf(tbuf, sizeof(tbuf), "-%s", 71484309Sluigi (p = strrchr(pwd->pw_shell, '/')) ? p + 1 : pwd->pw_shell) >= 71584309Sluigi sizeof(tbuf)) { 71684309Sluigi syslog(LOG_ERR, "user: %s: shell exceeds maximum pathname size", 71784309Sluigi username); 71884309Sluigi errx(1, "shell exceeds maximum pathname size"); 71984309Sluigi } 72084309Sluigi 72184309Sluigi execlp(shell, tbuf, (char *)0); 72284309Sluigi err(1, "%s", shell); 72384309Sluigi} 72484309Sluigi 72584309Sluigistatic int 72684309Sluigiauth_traditional() 72784309Sluigi{ 72884309Sluigi int rval; 72984309Sluigi char *p; 73084309Sluigi char *ep; 73184309Sluigi char *salt; 73284309Sluigi 73384309Sluigi rval = 1; 73484309Sluigi salt = pwd != NULL ? pwd->pw_passwd : "xx"; 73584309Sluigi 73684309Sluigi p = getpass(passwd_prompt); 73784309Sluigi ep = crypt(p, salt); 73884309Sluigi 73984309Sluigi if (pwd) { 74084309Sluigi if (!p[0] && pwd->pw_passwd[0]) 74184309Sluigi ep = ":"; 74284309Sluigi if (strcmp(ep, pwd->pw_passwd) == 0) 74384309Sluigi rval = 0; 74484309Sluigi } 74584309Sluigi 74684309Sluigi /* clear entered password */ 74784309Sluigi memset(p, 0, strlen(p)); 74884309Sluigi return rval; 74984309Sluigi} 75084309Sluigi 75184309Sluigi#ifdef USE_PAM 75284309Sluigi/* 75384309Sluigi * Attempt to authenticate the user using PAM. Returns 0 if the user is 75484309Sluigi * authenticated, or 1 if not authenticated. If some sort of PAM system 75584309Sluigi * error occurs (e.g., the "/etc/pam.conf" file is missing) then this 75684309Sluigi * function returns -1. This can be used as an indication that we should 75784309Sluigi * fall back to a different authentication mechanism. 75884309Sluigi */ 75984309Sluigistatic int 76084309Sluigiauth_pam() 76184309Sluigi{ 76284309Sluigi const char *tmpl_user; 76384309Sluigi const void *item; 76484309Sluigi int rval; 76584309Sluigi int e; 76694201Sru static struct pam_conv conv = { openpam_ttyconv, NULL }; 76784309Sluigi 76884309Sluigi if ((e = pam_start("login", username, &conv, &pamh)) != PAM_SUCCESS) { 76984309Sluigi syslog(LOG_ERR, "pam_start: %s", pam_strerror(pamh, e)); 77084309Sluigi return -1; 77184309Sluigi } 77284309Sluigi if ((e = pam_set_item(pamh, PAM_TTY, tty)) != PAM_SUCCESS) { 77384309Sluigi syslog(LOG_ERR, "pam_set_item(PAM_TTY): %s", 77484309Sluigi pam_strerror(pamh, e)); 77584309Sluigi return -1; 77684309Sluigi } 77784309Sluigi if (hostname != NULL && 77884309Sluigi (e = pam_set_item(pamh, PAM_RHOST, full_hostname)) != PAM_SUCCESS) { 77984309Sluigi syslog(LOG_ERR, "pam_set_item(PAM_RHOST): %s", 78084309Sluigi pam_strerror(pamh, e)); 78184309Sluigi return -1; 78284309Sluigi } 78384309Sluigi e = pam_authenticate(pamh, 0); 78484309Sluigi switch (e) { 78584309Sluigi 78684309Sluigi case PAM_SUCCESS: 78784309Sluigi /* 78884309Sluigi * With PAM we support the concept of a "template" 78984309Sluigi * user. The user enters a login name which is 79084309Sluigi * authenticated by PAM, usually via a remote service 79184309Sluigi * such as RADIUS or TACACS+. If authentication 79284309Sluigi * succeeds, a different but related "template" name 79384309Sluigi * is used for setting the credentials, shell, and 79484309Sluigi * home directory. The name the user enters need only 79584309Sluigi * exist on the remote authentication server, but the 79684309Sluigi * template name must be present in the local password 79784309Sluigi * database. 79884309Sluigi * 79984309Sluigi * This is supported by two various mechanisms in the 80084309Sluigi * individual modules. However, from the application's 80184309Sluigi * point of view, the template user is always passed 80284309Sluigi * back as a changed value of the PAM_USER item. 80384309Sluigi */ 80484309Sluigi if ((e = pam_get_item(pamh, PAM_USER, &item)) == 80584309Sluigi PAM_SUCCESS) { 80684309Sluigi tmpl_user = (const char *) item; 80784309Sluigi if (strcmp(username, tmpl_user) != 0) 80884309Sluigi pwd = getpwnam(tmpl_user); 80984309Sluigi } else 81084309Sluigi syslog(LOG_ERR, "Couldn't get PAM_USER: %s", 81184309Sluigi pam_strerror(pamh, e)); 81284309Sluigi rval = 0; 81384309Sluigi break; 81484309Sluigi 81584309Sluigi case PAM_AUTH_ERR: 81684309Sluigi case PAM_USER_UNKNOWN: 81784309Sluigi case PAM_MAXTRIES: 81884309Sluigi rval = 1; 81984309Sluigi break; 82084309Sluigi 82184309Sluigi default: 82284309Sluigi syslog(LOG_ERR, "pam_authenticate: %s", pam_strerror(pamh, e)); 82384309Sluigi rval = -1; 82484309Sluigi break; 82584309Sluigi } 82684309Sluigi 82784309Sluigi if (rval == 0) { 82884309Sluigi e = pam_acct_mgmt(pamh, 0); 82984309Sluigi if (e == PAM_NEW_AUTHTOK_REQD) { 83084309Sluigi e = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK); 83184309Sluigi if (e != PAM_SUCCESS) { 83284309Sluigi syslog(LOG_ERR, "pam_chauthtok: %s", 83384309Sluigi pam_strerror(pamh, e)); 83484309Sluigi rval = 1; 83584309Sluigi } 83684309Sluigi } else if (e != PAM_SUCCESS) { 83784309Sluigi rval = 1; 83884309Sluigi } 83984309Sluigi } 84084309Sluigi 84184309Sluigi if (rval != 0) { 84284309Sluigi if ((e = pam_end(pamh, e)) != PAM_SUCCESS) { 84384309Sluigi syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e)); 84484309Sluigi } 84584309Sluigi pamh = NULL; 84684309Sluigi } 84784309Sluigi return rval; 84884309Sluigi} 84984309Sluigi 85084309Sluigistatic int 85184309Sluigiexport_pam_environment() 85284309Sluigi{ 85384309Sluigi char **pp; 85484309Sluigi 85584309Sluigi for (pp = environ_pam; *pp != NULL; pp++) { 85684309Sluigi if (ok_to_export(*pp)) 85784309Sluigi (void) putenv(*pp); 85884309Sluigi free(*pp); 85984309Sluigi } 86084309Sluigi return PAM_SUCCESS; 86184309Sluigi} 86284309Sluigi 86384309Sluigi/* 86484309Sluigi * Sanity checks on PAM environmental variables: 86584309Sluigi * - Make sure there is an '=' in the string. 86684309Sluigi * - Make sure the string doesn't run on too long. 86784309Sluigi * - Do not export certain variables. This list was taken from the 86884309Sluigi * Solaris pam_putenv(3) man page. 86984309Sluigi */ 87084309Sluigistatic int 87184309Sluigiok_to_export(s) 87284309Sluigi const char *s; 87384309Sluigi{ 87484309Sluigi static const char *noexport[] = { 87584309Sluigi "SHELL", "HOME", "LOGNAME", "MAIL", "CDPATH", 87684309Sluigi "IFS", "PATH", NULL 87784309Sluigi }; 87884309Sluigi const char **pp; 87984309Sluigi size_t n; 88084309Sluigi 88184309Sluigi if (strlen(s) > 1024 || strchr(s, '=') == NULL) 88284309Sluigi return 0; 88384309Sluigi if (strncmp(s, "LD_", 3) == 0) 88484309Sluigi return 0; 88584309Sluigi for (pp = noexport; *pp != NULL; pp++) { 88684309Sluigi n = strlen(*pp); 88784309Sluigi if (s[n] == '=' && strncmp(s, *pp, n) == 0) 88884309Sluigi return 0; 88984309Sluigi } 89084309Sluigi return 1; 89184309Sluigi} 89284309Sluigi#endif /* USE_PAM */ 89384309Sluigi 89484309Sluigistatic void 89584309Sluigiusage() 89684309Sluigi{ 89784309Sluigi 89884309Sluigi (void)fprintf(stderr, "usage: login [-fp] [-h hostname] [username]\n"); 89984309Sluigi exit(1); 90084309Sluigi} 90184309Sluigi 90284309Sluigi/* 90384309Sluigi * Allow for authentication style and/or kerberos instance 90484309Sluigi */ 90584309Sluigi 90684309Sluigi#define NBUFSIZ UT_NAMESIZE + 64 90784309Sluigi 90884309Sluigivoid 90984309Sluigigetloginname() 91084309Sluigi{ 91184309Sluigi int ch; 91284309Sluigi char *p; 91384309Sluigi static char nbuf[NBUFSIZ]; 91484309Sluigi 91584309Sluigi for (;;) { 91684309Sluigi (void)printf("%s", prompt); 91784309Sluigi for (p = nbuf; (ch = getchar()) != '\n'; ) { 91884309Sluigi if (ch == EOF) { 91984309Sluigi badlogin(username); 92084309Sluigi exit(0); 92184309Sluigi } 92284309Sluigi if (p < nbuf + (NBUFSIZ - 1)) 92384309Sluigi *p++ = ch; 92484309Sluigi } 92584309Sluigi if (p > nbuf) { 92684309Sluigi if (nbuf[0] == '-') 92784309Sluigi (void)fprintf(stderr, 92884309Sluigi "login names may not start with '-'.\n"); 92984309Sluigi else { 93084309Sluigi *p = '\0'; 93184309Sluigi username = nbuf; 93284309Sluigi break; 93384309Sluigi } 93484309Sluigi } 93584309Sluigi } 93684309Sluigi} 93784309Sluigi 93884309Sluigiint 93984309Sluigirootterm(ttyn) 94084309Sluigi char *ttyn; 94184309Sluigi{ 94284309Sluigi struct ttyent *t; 94384309Sluigi 94484309Sluigi return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE); 94584309Sluigi} 94684309Sluigi 94784309Sluigivolatile int motdinterrupt; 94884309Sluigi 94984309Sluigivoid 95084309Sluigisigint(signo) 95184309Sluigi int signo __unused; 95284309Sluigi{ 95384309Sluigi motdinterrupt = 1; 95484309Sluigi} 95584309Sluigi 95684309Sluigivoid 95784309Sluigimotd(motdfile) 95894203Sru const char *motdfile; 95984309Sluigi{ 96084309Sluigi int fd, nchars; 96184309Sluigi sig_t oldint; 96284309Sluigi char tbuf[256]; 96384309Sluigi 96484309Sluigi if ((fd = open(motdfile, O_RDONLY, 0)) < 0) 96584309Sluigi return; 96684309Sluigi motdinterrupt = 0; 96784309Sluigi oldint = signal(SIGINT, sigint); 96884309Sluigi while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0 && !motdinterrupt) 96984309Sluigi (void)write(fileno(stdout), tbuf, nchars); 97084309Sluigi (void)signal(SIGINT, oldint); 97184309Sluigi (void)close(fd); 97284309Sluigi} 97384309Sluigi 97484309Sluigi/* ARGSUSED */ 97584309Sluigivoid 97684309Sluigitimedout(signo) 97784309Sluigi int signo; 97884309Sluigi{ 97984309Sluigi 98084309Sluigi longjmp(timeout_buf, signo); 98184309Sluigi} 98284309Sluigi 98384309Sluigi 98484309Sluigivoid 98584309Sluigidolastlog(quiet) 98684309Sluigi int quiet; 98784309Sluigi{ 98884309Sluigi struct lastlog ll; 98984309Sluigi int fd; 99084309Sluigi 99184309Sluigi if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) { 99284309Sluigi (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); 99384309Sluigi if (!quiet) { 99484309Sluigi if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) && 99584309Sluigi ll.ll_time != 0) { 99684309Sluigi (void)printf("Last login: %.*s ", 99784309Sluigi 24-5, (char *)ctime(&ll.ll_time)); 99884309Sluigi if (*ll.ll_host != '\0') 99984309Sluigi (void)printf("from %.*s\n", 100084309Sluigi (int)sizeof(ll.ll_host), 100184309Sluigi ll.ll_host); 100284309Sluigi else 100384309Sluigi (void)printf("on %.*s\n", 100484309Sluigi (int)sizeof(ll.ll_line), 100584309Sluigi ll.ll_line); 100684309Sluigi } 100784309Sluigi (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); 100884309Sluigi } 100984309Sluigi memset((void *)&ll, 0, sizeof(ll)); 101084309Sluigi (void)time(&ll.ll_time); 101184309Sluigi (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); 101284309Sluigi if (hostname) 101384309Sluigi (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host)); 101484309Sluigi (void)write(fd, (char *)&ll, sizeof(ll)); 101584309Sluigi (void)close(fd); 101684309Sluigi } else { 101784309Sluigi syslog(LOG_ERR, "cannot open %s: %m", _PATH_LASTLOG); 101884309Sluigi } 101984309Sluigi} 102084309Sluigi 102184309Sluigivoid 102284309Sluigibadlogin(name) 102384309Sluigi char *name; 102484309Sluigi{ 102584309Sluigi 102684309Sluigi if (failures == 0) 102784309Sluigi return; 102884309Sluigi if (hostname) { 102984309Sluigi syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s", 103084309Sluigi failures, failures > 1 ? "S" : "", full_hostname); 103184309Sluigi syslog(LOG_AUTHPRIV|LOG_NOTICE, 103284309Sluigi "%d LOGIN FAILURE%s FROM %s, %s", 103384309Sluigi failures, failures > 1 ? "S" : "", full_hostname, name); 103484309Sluigi } else { 103584309Sluigi syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s", 103684309Sluigi failures, failures > 1 ? "S" : "", tty); 103784309Sluigi syslog(LOG_AUTHPRIV|LOG_NOTICE, 103884309Sluigi "%d LOGIN FAILURE%s ON %s, %s", 103984309Sluigi failures, failures > 1 ? "S" : "", tty, name); 104084309Sluigi } 104184309Sluigi failures = 0; 104284309Sluigi} 104384309Sluigi 104484309Sluigi#undef UNKNOWN 104584309Sluigi#define UNKNOWN "su" 104684309Sluigi 104784309Sluigichar * 104884309Sluigistypeof(ttyid) 104984309Sluigi char *ttyid; 105084309Sluigi{ 105184309Sluigi struct ttyent *t; 105284309Sluigi 105384309Sluigi if (ttyid != NULL && *ttyid != '\0') { 105484309Sluigi t = getttynam(ttyid); 105584309Sluigi if (t != NULL && t->ty_type != NULL) 105684309Sluigi return (t->ty_type); 105784309Sluigi } 105884309Sluigi return (UNKNOWN); 105984309Sluigi} 106084309Sluigi 106184309Sluigivoid 106284309Sluigirefused(msg, rtype, lout) 106384309Sluigi char *msg; 106484309Sluigi char *rtype; 106584309Sluigi int lout; 106684309Sluigi{ 106784309Sluigi 106884309Sluigi if (msg != NULL) 106984309Sluigi printf("%s.\n", msg); 107084309Sluigi if (hostname) 107184309Sluigi syslog(LOG_NOTICE, "LOGIN %s REFUSED (%s) FROM %s ON TTY %s", 107284309Sluigi pwd->pw_name, rtype, full_hostname, tty); 107384309Sluigi else 107484309Sluigi syslog(LOG_NOTICE, "LOGIN %s REFUSED (%s) ON TTY %s", 107584309Sluigi pwd->pw_name, rtype, tty); 107684309Sluigi if (lout) 107784309Sluigi sleepexit(1); 107884309Sluigi} 107984309Sluigi 108084309Sluigivoid 108184309Sluigisleepexit(eval) 108284309Sluigi int eval; 108384309Sluigi{ 108484309Sluigi 108584309Sluigi (void)sleep(5); 108684309Sluigi exit(eval); 108784309Sluigi} 1088