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