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