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$"; 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> 79203876Sluigi#include <utmpx.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); 122104744Salfredstatic void usage(void); 12384309Sluigi 12484309Sluigi#define TTYGRPNAME "tty" /* name of group to own ttys */ 12584309Sluigi#define DEFAULT_BACKOFF 3 12684309Sluigi#define DEFAULT_RETRIES 10 12784309Sluigi#define DEFAULT_PROMPT "login: " 12884309Sluigi#define DEFAULT_PASSWD_PROMPT "Password:" 12984309Sluigi 13084309Sluigi/* 13184309Sluigi * This bounds the time given to login. Not a define so it can 13284309Sluigi * be patched on machines where it's too small. 13384309Sluigi */ 13484309Sluigiu_int timeout = 300; 13584309Sluigi 13684309Sluigi/* Buffer for signal handling of timeout */ 13784309Sluigijmp_buf timeout_buf; 13884309Sluigi 13984309Sluigistruct passwd *pwd; 14084309Sluigiint failures; 14194203Sruchar *term, *envinit[1], *hostname, *tty, *username; 14294203Sruconst char *passwd_prompt, *prompt; 14384309Sluigichar full_hostname[MAXHOSTNAMELEN]; 14484309Sluigi 14584309Sluigiint 14684309Sluigimain(argc, argv) 14784309Sluigi int argc; 14884309Sluigi char *argv[]; 14984309Sluigi{ 15084309Sluigi extern char **environ; 15184309Sluigi struct group *gr; 15284309Sluigi struct stat st; 153203876Sluigi struct utmpx utmp; 15484309Sluigi int rootok, retries, backoff; 15584309Sluigi int ask, ch, cnt, fflag, hflag, pflag, quietlog, rootlogin, rval; 15684309Sluigi int changepass; 157239991Sed time_t now, warntime; 15884309Sluigi uid_t uid, euid; 15984309Sluigi gid_t egid; 16084309Sluigi char *p, *ttyn; 16184309Sluigi char tbuf[MAXPATHLEN + 2]; 16284309Sluigi char tname[sizeof(_PATH_TTY) + 10]; 16394203Sru const char *shell = NULL; 16484309Sluigi login_cap_t *lc = NULL; 165203876Sluigi int UT_HOSTSIZE = sizeof(utmp.ut_host); 166203876Sluigi int UT_NAMESIZE = sizeof(utmp.ut_user); 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); 281211079Sgavin prompt = login_getcapstr(lc, "login_prompt", 282211079Sgavin DEFAULT_PROMPT, DEFAULT_PROMPT); 28384309Sluigi passwd_prompt = login_getcapstr(lc, "passwd_prompt", 28484309Sluigi DEFAULT_PASSWD_PROMPT, DEFAULT_PASSWD_PROMPT); 28584309Sluigi retries = login_getcapnum(lc, "login-retries", DEFAULT_RETRIES, 28684309Sluigi DEFAULT_RETRIES); 28784309Sluigi backoff = login_getcapnum(lc, "login-backoff", DEFAULT_BACKOFF, 28884309Sluigi DEFAULT_BACKOFF); 28984309Sluigi login_close(lc); 29084309Sluigi lc = NULL; 29184309Sluigi 29284309Sluigi for (cnt = 0;; ask = 1) { 29384309Sluigi if (ask) { 29484309Sluigi fflag = 0; 29584309Sluigi getloginname(); 29684309Sluigi } 29784309Sluigi rootlogin = 0; 29884309Sluigi rootok = rootterm(tty); /* Default (auth may change) */ 29984309Sluigi 30084309Sluigi if (strlen(username) > UT_NAMESIZE) 30184309Sluigi username[UT_NAMESIZE] = '\0'; 30284309Sluigi 30384309Sluigi /* 30484309Sluigi * Note if trying multiple user names; log failures for 30584309Sluigi * previous user name, but don't bother logging one failure 30684309Sluigi * for nonexistent name (mistyped username). 30784309Sluigi */ 30884309Sluigi if (failures && strcmp(tbuf, username)) { 30984309Sluigi if (failures > (pwd ? 0 : 1)) 31084309Sluigi badlogin(tbuf); 31184309Sluigi } 31284309Sluigi (void)strlcpy(tbuf, username, sizeof(tbuf)); 31384309Sluigi 31484309Sluigi pwd = getpwnam(username); 31584309Sluigi 31684309Sluigi /* 31784309Sluigi * if we have a valid account name, and it doesn't have a 31884309Sluigi * password, or the -f option was specified and the caller 31984309Sluigi * is root or the caller isn't changing their uid, don't 32084309Sluigi * authenticate. 32184309Sluigi */ 32284309Sluigi if (pwd != NULL) { 32384309Sluigi if (pwd->pw_uid == 0) 32484309Sluigi rootlogin = 1; 32584309Sluigi 32684309Sluigi if (fflag && (uid == (uid_t)0 || 32784309Sluigi uid == (uid_t)pwd->pw_uid)) { 32884309Sluigi /* already authenticated */ 32984309Sluigi break; 33084309Sluigi } else if (pwd->pw_passwd[0] == '\0') { 33184309Sluigi if (!rootlogin || rootok) { 33284309Sluigi /* pretend password okay */ 33384309Sluigi rval = 0; 33484309Sluigi goto ttycheck; 33584309Sluigi } 33684309Sluigi } 33784309Sluigi } 33884309Sluigi 33984309Sluigi fflag = 0; 34084309Sluigi 34184309Sluigi (void)setpriority(PRIO_PROCESS, 0, -4); 34284309Sluigi 34384309Sluigi#ifdef USE_PAM 34484309Sluigi /* 34584309Sluigi * Try to authenticate using PAM. If a PAM system error 34684309Sluigi * occurs, perhaps because of a botched configuration, 34784309Sluigi * then fall back to using traditional Unix authentication. 34884309Sluigi */ 34984309Sluigi if ((rval = auth_pam()) == -1) 35084309Sluigi#endif /* USE_PAM */ 35184309Sluigi rval = auth_traditional(); 35284309Sluigi 35384309Sluigi (void)setpriority(PRIO_PROCESS, 0, 0); 35484309Sluigi 35584309Sluigi#ifdef USE_PAM 35684309Sluigi /* 35784309Sluigi * PAM authentication may have changed "pwd" to the 35884309Sluigi * entry for the template user. Check again to see if 35984309Sluigi * this is a root login after all. 36084309Sluigi */ 36184309Sluigi if (pwd != NULL && pwd->pw_uid == 0) 36284309Sluigi rootlogin = 1; 36384309Sluigi#endif /* USE_PAM */ 36484309Sluigi 36584309Sluigi ttycheck: 36684309Sluigi /* 36784309Sluigi * If trying to log in as root without Kerberos, 36884309Sluigi * but with insecure terminal, refuse the login attempt. 36984309Sluigi */ 37084309Sluigi if (pwd && !rval) { 37184309Sluigi if (rootlogin && !rootok) 37284309Sluigi refused(NULL, "NOROOT", 0); 37384309Sluigi else /* valid password & authenticated */ 37484309Sluigi break; 37584309Sluigi } 37684309Sluigi 37784309Sluigi (void)printf("Login incorrect\n"); 37884309Sluigi failures++; 37984309Sluigi 38084309Sluigi /* 38184309Sluigi * we allow up to 'retry' (10) tries, 38284309Sluigi * but after 'backoff' (3) we start backing off 38384309Sluigi */ 38484309Sluigi if (++cnt > backoff) { 38584309Sluigi if (cnt >= retries) { 38684309Sluigi badlogin(username); 38784309Sluigi sleepexit(1); 38884309Sluigi } 38984309Sluigi sleep((u_int)((cnt - backoff) * 5)); 39084309Sluigi } 39184309Sluigi } 39284309Sluigi 39384309Sluigi /* committed to login -- turn off timeout */ 39484309Sluigi (void)alarm((u_int)0); 39584309Sluigi (void)signal(SIGHUP, SIG_DFL); 39684309Sluigi 39784309Sluigi endpwent(); 39884309Sluigi 39984309Sluigi /* 40084309Sluigi * Establish the login class. 40184309Sluigi */ 40284309Sluigi lc = login_getpwclass(pwd); 40384309Sluigi 40484309Sluigi /* if user not super-user, check for disabled logins */ 40584309Sluigi if (!rootlogin) 40684309Sluigi auth_checknologin(lc); 40784309Sluigi 40884309Sluigi quietlog = login_getcapbool(lc, "hushlogin", 0); 40984309Sluigi /* 41084309Sluigi * Switching needed for NFS with root access disabled. 41184309Sluigi * 41284309Sluigi * XXX: This change fails to modify the additional groups for the 41384309Sluigi * process, and as such, may restrict rights normally granted 41484309Sluigi * through those groups. 41584309Sluigi */ 41684309Sluigi (void)setegid(pwd->pw_gid); 41784309Sluigi (void)seteuid(rootlogin ? 0 : pwd->pw_uid); 41884309Sluigi if (!*pwd->pw_dir || chdir(pwd->pw_dir) < 0) { 41984309Sluigi if (login_getcapbool(lc, "requirehome", 0)) 42084309Sluigi refused("Home directory not available", "HOMEDIR", 1); 42184309Sluigi if (chdir("/") < 0) 42284309Sluigi refused("Cannot find root directory", "ROOTDIR", 1); 42384309Sluigi if (!quietlog || *pwd->pw_dir) 42484309Sluigi printf("No home directory.\nLogging in with home = \"/\".\n"); 42584309Sluigi pwd->pw_dir = "/"; 42684309Sluigi } 42784309Sluigi (void)seteuid(euid); 42884309Sluigi (void)setegid(egid); 42984309Sluigi if (!quietlog) 43084309Sluigi quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0; 43184309Sluigi 432239991Sed now = time(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) { 440239991Sed if (now >= pwd->pw_expire) { 44184309Sluigi refused("Sorry -- your account has expired", "EXPIRED", 44284309Sluigi 1); 443239991Sed } else if (pwd->pw_expire - now < 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) { 453239991Sed if (now >= 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); 458239991Sed } else if (pwd->pw_change - now < 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 511203876Sluigi#if 1 512203876Sluigi ulog_login(tty, username, hostname); 513203876Sluigi#else 51484309Sluigi /* Nothing else left to fail -- really log in. */ 51584309Sluigi memset((void *)&utmp, 0, sizeof(utmp)); 516203876Sluigi (void)gettimeofday(&utmp.ut_tv, NULL); 517203876Sluigi (void)strncpy(utmp.ut_user, username, sizeof(utmp.ut_user)); 51884309Sluigi if (hostname) 51984309Sluigi (void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host)); 52084309Sluigi (void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line)); 52184309Sluigi login(&utmp); 522203876Sluigi#endif 52384309Sluigi 52484309Sluigi dolastlog(quietlog); 52584309Sluigi 52684309Sluigi /* 52784309Sluigi * Set device protections, depending on what terminal the 52884309Sluigi * user is logged in. This feature is used on Suns to give 52984309Sluigi * console users better privacy. 53084309Sluigi */ 53184309Sluigi login_fbtab(tty, pwd->pw_uid, pwd->pw_gid); 53284309Sluigi 53384309Sluigi /* 53484309Sluigi * Clear flags of the tty. None should be set, and when the 53584309Sluigi * user sets them otherwise, this can cause the chown to fail. 53684309Sluigi * Since it isn't clear that flags are useful on character 53784309Sluigi * devices, we just clear them. 53884309Sluigi */ 53984309Sluigi if (chflags(ttyn, 0) && errno != EOPNOTSUPP) 540211077Sgavin syslog(LOG_ERR, "chflags(%s): %m", ttyn); 54184309Sluigi if (chown(ttyn, pwd->pw_uid, 54284309Sluigi (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid)) 543211077Sgavin syslog(LOG_ERR, "chown(%s): %m", ttyn); 54484309Sluigi 54584309Sluigi 54684309Sluigi /* 54784309Sluigi * Preserve TERM if it happens to be already set. 54884309Sluigi */ 54984309Sluigi if ((term = getenv("TERM")) != NULL) { 55084309Sluigi if ((term = strdup(term)) == NULL) { 55184309Sluigi syslog(LOG_NOTICE, 55284309Sluigi "strdup(): %m"); 55384309Sluigi sleepexit(1); 55484309Sluigi } 55584309Sluigi } 55684309Sluigi 55784309Sluigi /* 55884309Sluigi * Exclude cons/vt/ptys only, assume dialup otherwise 55984309Sluigi * TODO: Make dialup tty determination a library call 56084309Sluigi * for consistency (finger etc.) 56184309Sluigi */ 56284309Sluigi if (hostname==NULL && isdialuptty(tty)) 56384309Sluigi syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name); 56484309Sluigi 56584309Sluigi#ifdef LOGALL 56684309Sluigi /* 56784309Sluigi * Syslog each successful login, so we don't have to watch hundreds 56884309Sluigi * of wtmp or lastlogin files. 56984309Sluigi */ 57084309Sluigi if (hostname) 57184309Sluigi syslog(LOG_INFO, "login from %s on %s as %s", 57284309Sluigi full_hostname, tty, pwd->pw_name); 57384309Sluigi else 57484309Sluigi syslog(LOG_INFO, "login on %s as %s", 57584309Sluigi tty, pwd->pw_name); 57684309Sluigi#endif 57784309Sluigi 57884309Sluigi /* 57984309Sluigi * If fflag is on, assume caller/authenticator has logged root login. 58084309Sluigi */ 58184309Sluigi if (rootlogin && fflag == 0) 58284309Sluigi { 58384309Sluigi if (hostname) 58484309Sluigi syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s", 58584309Sluigi username, tty, full_hostname); 58684309Sluigi else 58784309Sluigi syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s", 58884309Sluigi username, tty); 58984309Sluigi } 59084309Sluigi 59184309Sluigi /* 59284309Sluigi * Destroy environment unless user has requested its preservation. 59384309Sluigi * We need to do this before setusercontext() because that may 59484309Sluigi * set or reset some environment variables. 59584309Sluigi */ 59684309Sluigi if (!pflag) 59784309Sluigi environ = envinit; 59884309Sluigi 59984309Sluigi /* 60084309Sluigi * PAM modules might add supplementary groups during pam_setcred(). 60184309Sluigi */ 60284309Sluigi if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) != 0) { 60384309Sluigi syslog(LOG_ERR, "setusercontext() failed - exiting"); 60484309Sluigi exit(1); 60584309Sluigi } 60684309Sluigi 60784309Sluigi#ifdef USE_PAM 60884309Sluigi if (pamh) { 60984309Sluigi if ((e = pam_open_session(pamh, 0)) != PAM_SUCCESS) { 61084309Sluigi syslog(LOG_ERR, "pam_open_session: %s", 61184309Sluigi pam_strerror(pamh, e)); 61284309Sluigi } else if ((e = pam_setcred(pamh, PAM_ESTABLISH_CRED)) 61384309Sluigi != PAM_SUCCESS) { 61484309Sluigi syslog(LOG_ERR, "pam_setcred: %s", 61584309Sluigi pam_strerror(pamh, e)); 61684309Sluigi } 61784309Sluigi 61884309Sluigi /* 61984309Sluigi * Add any environmental variables that the 62084309Sluigi * PAM modules may have set. 62184309Sluigi * Call *after* opening session! 62284309Sluigi */ 62384309Sluigi if (pamh) { 62484309Sluigi environ_pam = pam_getenvlist(pamh); 62584309Sluigi if (environ_pam) 62684309Sluigi export_pam_environment(); 62784309Sluigi } 62884309Sluigi 62984309Sluigi /* 63084309Sluigi * We must fork() before setuid() because we need to call 63184309Sluigi * pam_close_session() as root. 63284309Sluigi */ 63384309Sluigi pid = fork(); 63484309Sluigi if (pid < 0) { 63584309Sluigi err(1, "fork"); 63684309Sluigi PAM_END; 63784309Sluigi exit(0); 63884309Sluigi } else if (pid) { 63984309Sluigi /* parent - wait for child to finish, then cleanup 64084309Sluigi session */ 64184309Sluigi wait(NULL); 64284309Sluigi PAM_END; 64384309Sluigi exit(0); 64484309Sluigi } else { 64594201Sru if ((e = pam_end(pamh, 0)) != PAM_SUCCESS) 64684309Sluigi syslog(LOG_ERR, "pam_end: %s", 64784309Sluigi pam_strerror(pamh, e)); 64884309Sluigi } 64984309Sluigi } 65084309Sluigi#endif /* USE_PAM */ 65184309Sluigi 65284309Sluigi /* 65384309Sluigi * We don't need to be root anymore, so 65484309Sluigi * set the user and session context 65584309Sluigi */ 65684309Sluigi if (setlogin(username) != 0) { 65784309Sluigi syslog(LOG_ERR, "setlogin(%s): %m - exiting", username); 65884309Sluigi exit(1); 65984309Sluigi } 66084309Sluigi if (setusercontext(lc, pwd, pwd->pw_uid, 66184309Sluigi LOGIN_SETALL & ~(LOGIN_SETLOGIN|LOGIN_SETGROUP)) != 0) { 66284309Sluigi syslog(LOG_ERR, "setusercontext() failed - exiting"); 66384309Sluigi exit(1); 66484309Sluigi } 66584309Sluigi 66684309Sluigi (void)setenv("SHELL", pwd->pw_shell, 1); 66784309Sluigi (void)setenv("HOME", pwd->pw_dir, 1); 66884309Sluigi if (term != NULL && *term != '\0') 66984309Sluigi (void)setenv("TERM", term, 1); /* Preset overrides */ 67084309Sluigi else { 67184309Sluigi (void)setenv("TERM", stypeof(tty), 0); /* Fallback doesn't */ 67284309Sluigi } 67384309Sluigi (void)setenv("LOGNAME", username, 1); 67484309Sluigi (void)setenv("USER", username, 1); 67584309Sluigi (void)setenv("PATH", rootlogin ? _PATH_STDPATH : _PATH_DEFPATH, 0); 67684309Sluigi 67784309Sluigi if (!quietlog) { 67894203Sru const char *cw; 67984309Sluigi 68084309Sluigi cw = login_getcapstr(lc, "copyright", NULL, NULL); 68184309Sluigi if (cw != NULL && access(cw, F_OK) == 0) 68284309Sluigi motd(cw); 68384309Sluigi else 68484309Sluigi (void)printf("%s\n\t%s %s\n", 68584309Sluigi "Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994", 68684309Sluigi "The Regents of the University of California. ", 68784309Sluigi "All rights reserved."); 68884309Sluigi 68984309Sluigi (void)printf("\n"); 69084309Sluigi 69184309Sluigi cw = login_getcapstr(lc, "welcome", NULL, NULL); 69284309Sluigi if (cw == NULL || access(cw, F_OK) != 0) 69384309Sluigi cw = _PATH_MOTDFILE; 69484309Sluigi motd(cw); 69584309Sluigi 69684309Sluigi cw = getenv("MAIL"); /* $MAIL may have been set by class */ 69784309Sluigi if (cw != NULL) 69884309Sluigi strlcpy(tbuf, cw, sizeof(tbuf)); 69984309Sluigi else 70084309Sluigi snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_MAILDIR, 70184309Sluigi pwd->pw_name); 70284309Sluigi if (stat(tbuf, &st) == 0 && st.st_size != 0) 70384309Sluigi (void)printf("You have %smail.\n", 70484309Sluigi (st.st_mtime > st.st_atime) ? "new " : ""); 70584309Sluigi } 70684309Sluigi 70784309Sluigi login_close(lc); 70884309Sluigi 70984309Sluigi (void)signal(SIGALRM, SIG_DFL); 71084309Sluigi (void)signal(SIGQUIT, SIG_DFL); 71184309Sluigi (void)signal(SIGINT, SIG_DFL); 71284309Sluigi (void)signal(SIGTSTP, SIG_IGN); 71384309Sluigi 71484309Sluigi /* 71584309Sluigi * Login shells have a leading '-' in front of argv[0] 71684309Sluigi */ 71784309Sluigi if (snprintf(tbuf, sizeof(tbuf), "-%s", 71884309Sluigi (p = strrchr(pwd->pw_shell, '/')) ? p + 1 : pwd->pw_shell) >= 71984309Sluigi sizeof(tbuf)) { 72084309Sluigi syslog(LOG_ERR, "user: %s: shell exceeds maximum pathname size", 72184309Sluigi username); 72284309Sluigi errx(1, "shell exceeds maximum pathname size"); 72384309Sluigi } 72484309Sluigi 72584309Sluigi execlp(shell, tbuf, (char *)0); 72684309Sluigi err(1, "%s", shell); 72784309Sluigi} 72884309Sluigi 72984309Sluigistatic int 73084309Sluigiauth_traditional() 73184309Sluigi{ 73284309Sluigi int rval; 73384309Sluigi char *p; 73484309Sluigi char *ep; 73584309Sluigi char *salt; 73684309Sluigi 73784309Sluigi rval = 1; 73884309Sluigi salt = pwd != NULL ? pwd->pw_passwd : "xx"; 73984309Sluigi 74084309Sluigi p = getpass(passwd_prompt); 74184309Sluigi ep = crypt(p, salt); 74284309Sluigi 74384309Sluigi if (pwd) { 74484309Sluigi if (!p[0] && pwd->pw_passwd[0]) 74584309Sluigi ep = ":"; 74684309Sluigi if (strcmp(ep, pwd->pw_passwd) == 0) 74784309Sluigi rval = 0; 74884309Sluigi } 74984309Sluigi 75084309Sluigi /* clear entered password */ 75184309Sluigi memset(p, 0, strlen(p)); 75284309Sluigi return rval; 75384309Sluigi} 75484309Sluigi 75584309Sluigi#ifdef USE_PAM 75684309Sluigi/* 75784309Sluigi * Attempt to authenticate the user using PAM. Returns 0 if the user is 75884309Sluigi * authenticated, or 1 if not authenticated. If some sort of PAM system 75984309Sluigi * error occurs (e.g., the "/etc/pam.conf" file is missing) then this 76084309Sluigi * function returns -1. This can be used as an indication that we should 76184309Sluigi * fall back to a different authentication mechanism. 76284309Sluigi */ 76384309Sluigistatic int 76484309Sluigiauth_pam() 76584309Sluigi{ 76684309Sluigi const char *tmpl_user; 76784309Sluigi const void *item; 76884309Sluigi int rval; 76984309Sluigi int e; 77094201Sru static struct pam_conv conv = { openpam_ttyconv, NULL }; 77184309Sluigi 77284309Sluigi if ((e = pam_start("login", username, &conv, &pamh)) != PAM_SUCCESS) { 77384309Sluigi syslog(LOG_ERR, "pam_start: %s", pam_strerror(pamh, e)); 77484309Sluigi return -1; 77584309Sluigi } 77684309Sluigi if ((e = pam_set_item(pamh, PAM_TTY, tty)) != PAM_SUCCESS) { 77784309Sluigi syslog(LOG_ERR, "pam_set_item(PAM_TTY): %s", 77884309Sluigi pam_strerror(pamh, e)); 77984309Sluigi return -1; 78084309Sluigi } 78184309Sluigi if (hostname != NULL && 78284309Sluigi (e = pam_set_item(pamh, PAM_RHOST, full_hostname)) != PAM_SUCCESS) { 78384309Sluigi syslog(LOG_ERR, "pam_set_item(PAM_RHOST): %s", 78484309Sluigi pam_strerror(pamh, e)); 78584309Sluigi return -1; 78684309Sluigi } 78784309Sluigi e = pam_authenticate(pamh, 0); 78884309Sluigi switch (e) { 78984309Sluigi 79084309Sluigi case PAM_SUCCESS: 79184309Sluigi /* 79284309Sluigi * With PAM we support the concept of a "template" 79384309Sluigi * user. The user enters a login name which is 79484309Sluigi * authenticated by PAM, usually via a remote service 79584309Sluigi * such as RADIUS or TACACS+. If authentication 79684309Sluigi * succeeds, a different but related "template" name 79784309Sluigi * is used for setting the credentials, shell, and 79884309Sluigi * home directory. The name the user enters need only 79984309Sluigi * exist on the remote authentication server, but the 80084309Sluigi * template name must be present in the local password 80184309Sluigi * database. 80284309Sluigi * 80384309Sluigi * This is supported by two various mechanisms in the 80484309Sluigi * individual modules. However, from the application's 80584309Sluigi * point of view, the template user is always passed 80684309Sluigi * back as a changed value of the PAM_USER item. 80784309Sluigi */ 80884309Sluigi if ((e = pam_get_item(pamh, PAM_USER, &item)) == 80984309Sluigi PAM_SUCCESS) { 81084309Sluigi tmpl_user = (const char *) item; 81184309Sluigi if (strcmp(username, tmpl_user) != 0) 81284309Sluigi pwd = getpwnam(tmpl_user); 81384309Sluigi } else 81484309Sluigi syslog(LOG_ERR, "Couldn't get PAM_USER: %s", 81584309Sluigi pam_strerror(pamh, e)); 81684309Sluigi rval = 0; 81784309Sluigi break; 81884309Sluigi 81984309Sluigi case PAM_AUTH_ERR: 82084309Sluigi case PAM_USER_UNKNOWN: 82184309Sluigi case PAM_MAXTRIES: 82284309Sluigi rval = 1; 82384309Sluigi break; 82484309Sluigi 82584309Sluigi default: 82684309Sluigi syslog(LOG_ERR, "pam_authenticate: %s", pam_strerror(pamh, e)); 82784309Sluigi rval = -1; 82884309Sluigi break; 82984309Sluigi } 83084309Sluigi 83184309Sluigi if (rval == 0) { 83284309Sluigi e = pam_acct_mgmt(pamh, 0); 83384309Sluigi if (e == PAM_NEW_AUTHTOK_REQD) { 83484309Sluigi e = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK); 83584309Sluigi if (e != PAM_SUCCESS) { 83684309Sluigi syslog(LOG_ERR, "pam_chauthtok: %s", 83784309Sluigi pam_strerror(pamh, e)); 83884309Sluigi rval = 1; 83984309Sluigi } 84084309Sluigi } else if (e != PAM_SUCCESS) { 84184309Sluigi rval = 1; 84284309Sluigi } 84384309Sluigi } 84484309Sluigi 84584309Sluigi if (rval != 0) { 84684309Sluigi if ((e = pam_end(pamh, e)) != PAM_SUCCESS) { 84784309Sluigi syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e)); 84884309Sluigi } 84984309Sluigi pamh = NULL; 85084309Sluigi } 85184309Sluigi return rval; 85284309Sluigi} 85384309Sluigi 85484309Sluigistatic int 85584309Sluigiexport_pam_environment() 85684309Sluigi{ 85784309Sluigi char **pp; 85884309Sluigi 85984309Sluigi for (pp = environ_pam; *pp != NULL; pp++) { 86084309Sluigi if (ok_to_export(*pp)) 86184309Sluigi (void) putenv(*pp); 86284309Sluigi free(*pp); 86384309Sluigi } 86484309Sluigi return PAM_SUCCESS; 86584309Sluigi} 86684309Sluigi 86784309Sluigi/* 86884309Sluigi * Sanity checks on PAM environmental variables: 86984309Sluigi * - Make sure there is an '=' in the string. 87084309Sluigi * - Make sure the string doesn't run on too long. 87184309Sluigi * - Do not export certain variables. This list was taken from the 87284309Sluigi * Solaris pam_putenv(3) man page. 87384309Sluigi */ 87484309Sluigistatic int 87584309Sluigiok_to_export(s) 87684309Sluigi const char *s; 87784309Sluigi{ 87884309Sluigi static const char *noexport[] = { 87984309Sluigi "SHELL", "HOME", "LOGNAME", "MAIL", "CDPATH", 88084309Sluigi "IFS", "PATH", NULL 88184309Sluigi }; 88284309Sluigi const char **pp; 88384309Sluigi size_t n; 88484309Sluigi 88584309Sluigi if (strlen(s) > 1024 || strchr(s, '=') == NULL) 88684309Sluigi return 0; 88784309Sluigi if (strncmp(s, "LD_", 3) == 0) 88884309Sluigi return 0; 88984309Sluigi for (pp = noexport; *pp != NULL; pp++) { 89084309Sluigi n = strlen(*pp); 89184309Sluigi if (s[n] == '=' && strncmp(s, *pp, n) == 0) 89284309Sluigi return 0; 89384309Sluigi } 89484309Sluigi return 1; 89584309Sluigi} 89684309Sluigi#endif /* USE_PAM */ 89784309Sluigi 89884309Sluigistatic void 89984309Sluigiusage() 90084309Sluigi{ 90184309Sluigi 90284309Sluigi (void)fprintf(stderr, "usage: login [-fp] [-h hostname] [username]\n"); 90384309Sluigi exit(1); 90484309Sluigi} 90584309Sluigi 90684309Sluigi/* 90784309Sluigi * Allow for authentication style and/or kerberos instance 90884309Sluigi */ 90984309Sluigi 910203876Sluigi#define NBUFSIZ 128 // XXX was UT_NAMESIZE + 64 91184309Sluigi 91284309Sluigivoid 91384309Sluigigetloginname() 91484309Sluigi{ 91584309Sluigi int ch; 91684309Sluigi char *p; 91784309Sluigi static char nbuf[NBUFSIZ]; 91884309Sluigi 91984309Sluigi for (;;) { 92084309Sluigi (void)printf("%s", prompt); 92184309Sluigi for (p = nbuf; (ch = getchar()) != '\n'; ) { 92284309Sluigi if (ch == EOF) { 92384309Sluigi badlogin(username); 92484309Sluigi exit(0); 92584309Sluigi } 92684309Sluigi if (p < nbuf + (NBUFSIZ - 1)) 92784309Sluigi *p++ = ch; 92884309Sluigi } 92984309Sluigi if (p > nbuf) { 93084309Sluigi if (nbuf[0] == '-') 93184309Sluigi (void)fprintf(stderr, 93284309Sluigi "login names may not start with '-'.\n"); 93384309Sluigi else { 93484309Sluigi *p = '\0'; 93584309Sluigi username = nbuf; 93684309Sluigi break; 93784309Sluigi } 93884309Sluigi } 93984309Sluigi } 94084309Sluigi} 94184309Sluigi 94284309Sluigiint 94384309Sluigirootterm(ttyn) 94484309Sluigi char *ttyn; 94584309Sluigi{ 94684309Sluigi struct ttyent *t; 94784309Sluigi 94884309Sluigi return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE); 94984309Sluigi} 95084309Sluigi 95184309Sluigivolatile int motdinterrupt; 95284309Sluigi 95384309Sluigivoid 95484309Sluigisigint(signo) 95584309Sluigi int signo __unused; 95684309Sluigi{ 95784309Sluigi motdinterrupt = 1; 95884309Sluigi} 95984309Sluigi 96084309Sluigivoid 96184309Sluigimotd(motdfile) 96294203Sru const char *motdfile; 96384309Sluigi{ 96484309Sluigi int fd, nchars; 96584309Sluigi sig_t oldint; 96684309Sluigi char tbuf[256]; 96784309Sluigi 96884309Sluigi if ((fd = open(motdfile, O_RDONLY, 0)) < 0) 96984309Sluigi return; 97084309Sluigi motdinterrupt = 0; 97184309Sluigi oldint = signal(SIGINT, sigint); 97284309Sluigi while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0 && !motdinterrupt) 97384309Sluigi (void)write(fileno(stdout), tbuf, nchars); 97484309Sluigi (void)signal(SIGINT, oldint); 97584309Sluigi (void)close(fd); 97684309Sluigi} 97784309Sluigi 97884309Sluigi/* ARGSUSED */ 97984309Sluigivoid 98084309Sluigitimedout(signo) 98184309Sluigi int signo; 98284309Sluigi{ 98384309Sluigi 98484309Sluigi longjmp(timeout_buf, signo); 98584309Sluigi} 98684309Sluigi 98784309Sluigi 98884309Sluigivoid 98984309Sluigidolastlog(quiet) 99084309Sluigi int quiet; 99184309Sluigi{ 992203876Sluigi#if 0 /* XXX not implemented after utmp->utmpx change */ 99384309Sluigi struct lastlog ll; 99484309Sluigi int fd; 99584309Sluigi 99684309Sluigi if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) { 99784309Sluigi (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); 99884309Sluigi if (!quiet) { 99984309Sluigi if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) && 100084309Sluigi ll.ll_time != 0) { 100184309Sluigi (void)printf("Last login: %.*s ", 100284309Sluigi 24-5, (char *)ctime(&ll.ll_time)); 100384309Sluigi if (*ll.ll_host != '\0') 100484309Sluigi (void)printf("from %.*s\n", 100584309Sluigi (int)sizeof(ll.ll_host), 100684309Sluigi ll.ll_host); 100784309Sluigi else 100884309Sluigi (void)printf("on %.*s\n", 100984309Sluigi (int)sizeof(ll.ll_line), 101084309Sluigi ll.ll_line); 101184309Sluigi } 101284309Sluigi (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); 101384309Sluigi } 101484309Sluigi memset((void *)&ll, 0, sizeof(ll)); 101584309Sluigi (void)time(&ll.ll_time); 101684309Sluigi (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); 101784309Sluigi if (hostname) 101884309Sluigi (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host)); 101984309Sluigi (void)write(fd, (char *)&ll, sizeof(ll)); 102084309Sluigi (void)close(fd); 102184309Sluigi } else { 102284309Sluigi syslog(LOG_ERR, "cannot open %s: %m", _PATH_LASTLOG); 102384309Sluigi } 1024203876Sluigi#endif 102584309Sluigi} 102684309Sluigi 102784309Sluigivoid 102884309Sluigibadlogin(name) 102984309Sluigi char *name; 103084309Sluigi{ 103184309Sluigi 103284309Sluigi if (failures == 0) 103384309Sluigi return; 103484309Sluigi if (hostname) { 103584309Sluigi syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s", 103684309Sluigi failures, failures > 1 ? "S" : "", full_hostname); 103784309Sluigi syslog(LOG_AUTHPRIV|LOG_NOTICE, 103884309Sluigi "%d LOGIN FAILURE%s FROM %s, %s", 103984309Sluigi failures, failures > 1 ? "S" : "", full_hostname, name); 104084309Sluigi } else { 104184309Sluigi syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s", 104284309Sluigi failures, failures > 1 ? "S" : "", tty); 104384309Sluigi syslog(LOG_AUTHPRIV|LOG_NOTICE, 104484309Sluigi "%d LOGIN FAILURE%s ON %s, %s", 104584309Sluigi failures, failures > 1 ? "S" : "", tty, name); 104684309Sluigi } 104784309Sluigi failures = 0; 104884309Sluigi} 104984309Sluigi 105084309Sluigi#undef UNKNOWN 105184309Sluigi#define UNKNOWN "su" 105284309Sluigi 105384309Sluigichar * 105484309Sluigistypeof(ttyid) 105584309Sluigi char *ttyid; 105684309Sluigi{ 105784309Sluigi struct ttyent *t; 105884309Sluigi 105984309Sluigi if (ttyid != NULL && *ttyid != '\0') { 106084309Sluigi t = getttynam(ttyid); 106184309Sluigi if (t != NULL && t->ty_type != NULL) 106284309Sluigi return (t->ty_type); 106384309Sluigi } 106484309Sluigi return (UNKNOWN); 106584309Sluigi} 106684309Sluigi 106784309Sluigivoid 106884309Sluigirefused(msg, rtype, lout) 106984309Sluigi char *msg; 107084309Sluigi char *rtype; 107184309Sluigi int lout; 107284309Sluigi{ 107384309Sluigi 107484309Sluigi if (msg != NULL) 107584309Sluigi printf("%s.\n", msg); 107684309Sluigi if (hostname) 107784309Sluigi syslog(LOG_NOTICE, "LOGIN %s REFUSED (%s) FROM %s ON TTY %s", 107884309Sluigi pwd->pw_name, rtype, full_hostname, tty); 107984309Sluigi else 108084309Sluigi syslog(LOG_NOTICE, "LOGIN %s REFUSED (%s) ON TTY %s", 108184309Sluigi pwd->pw_name, rtype, tty); 108284309Sluigi if (lout) 108384309Sluigi sleepexit(1); 108484309Sluigi} 108584309Sluigi 108684309Sluigivoid 108784309Sluigisleepexit(eval) 108884309Sluigi int eval; 108984309Sluigi{ 109084309Sluigi 109184309Sluigi (void)sleep(5); 109284309Sluigi exit(eval); 109384309Sluigi} 1094