login.c revision 76786
11590Srgrimes/*- 21590Srgrimes * Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * 51590Srgrimes * Redistribution and use in source and binary forms, with or without 61590Srgrimes * modification, are permitted provided that the following conditions 71590Srgrimes * are met: 81590Srgrimes * 1. Redistributions of source code must retain the above copyright 91590Srgrimes * notice, this list of conditions and the following disclaimer. 101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111590Srgrimes * notice, this list of conditions and the following disclaimer in the 121590Srgrimes * documentation and/or other materials provided with the distribution. 131590Srgrimes * 3. All advertising materials mentioning features or use of this software 141590Srgrimes * must display the following acknowledgement: 151590Srgrimes * This product includes software developed by the University of 161590Srgrimes * California, Berkeley and its contributors. 171590Srgrimes * 4. Neither the name of the University nor the names of its contributors 181590Srgrimes * may be used to endorse or promote products derived from this software 191590Srgrimes * without specific prior written permission. 201590Srgrimes * 211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311590Srgrimes * SUCH DAMAGE. 321590Srgrimes */ 331590Srgrimes 3423246Swosch#if 0 351590Srgrimesstatic char copyright[] = 361590Srgrimes"@(#) Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994\n\ 371590Srgrimes The Regents of the University of California. All rights reserved.\n"; 3823246Swosch#endif 391590Srgrimes 401590Srgrimes#ifndef lint 4127605Scharnier#if 0 421590Srgrimesstatic char sccsid[] = "@(#)login.c 8.4 (Berkeley) 4/2/94"; 4327605Scharnier#endif 4427605Scharnierstatic const char rcsid[] = 4550477Speter "$FreeBSD: head/usr.bin/login/login.c 76786 2001-05-18 04:55:16Z obrien $"; 461590Srgrimes#endif /* not lint */ 471590Srgrimes 481590Srgrimes/* 491590Srgrimes * login [ name ] 501590Srgrimes * login -h hostname (for telnetd, etc.) 511590Srgrimes * login -f name (for pre-authenticated login: datakit, xterm, etc.) 521590Srgrimes */ 531590Srgrimes 5423246Swosch#include <sys/copyright.h> 551590Srgrimes#include <sys/param.h> 561590Srgrimes#include <sys/stat.h> 5757339Sshin#include <sys/socket.h> 581590Srgrimes#include <sys/time.h> 591590Srgrimes#include <sys/resource.h> 601590Srgrimes#include <sys/file.h> 6116423Sache#include <netinet/in.h> 6216423Sache#include <arpa/inet.h> 631590Srgrimes 641590Srgrimes#include <err.h> 651590Srgrimes#include <errno.h> 661590Srgrimes#include <grp.h> 6740102Smarkm#include <libutil.h> 6841079Sjdp#include <login_cap.h> 6916423Sache#include <netdb.h> 701590Srgrimes#include <pwd.h> 711590Srgrimes#include <setjmp.h> 721590Srgrimes#include <signal.h> 731590Srgrimes#include <stdio.h> 741590Srgrimes#include <stdlib.h> 751590Srgrimes#include <string.h> 761590Srgrimes#include <syslog.h> 771590Srgrimes#include <ttyent.h> 781590Srgrimes#include <unistd.h> 791590Srgrimes#include <utmp.h> 801590Srgrimes 8174874Smarkm#ifdef USE_PAM 8241279Sjdp#include <security/pam_appl.h> 8341279Sjdp#include <security/pam_misc.h> 8474874Smarkm#include <sys/wait.h> 8574874Smarkm#endif /* USE_PAM */ 863702Spst 871590Srgrimes#include "pathnames.h" 881590Srgrimes 8957339Sshin/* wrapper for KAME-special getnameinfo() */ 9057339Sshin#ifndef NI_WITHSCOPEID 9157339Sshin#define NI_WITHSCOPEID 0 9257339Sshin#endif 9357339Sshin 941590Srgrimesvoid badlogin __P((char *)); 951590Srgrimesvoid checknologin __P((void)); 961590Srgrimesvoid dolastlog __P((int)); 971590Srgrimesvoid getloginname __P((void)); 9821528Sdavidnvoid motd __P((char *)); 991590Srgrimesint rootterm __P((char *)); 1001590Srgrimesvoid sigint __P((int)); 1011590Srgrimesvoid sleepexit __P((int)); 10223985Sdavidnvoid refused __P((char *,char *,int)); 1031590Srgrimeschar *stypeof __P((char *)); 1041590Srgrimesvoid timedout __P((int)); 10529922Smarkmint login_access __P((char *, char *)); 1062224Sguidovoid login_fbtab __P((char *, uid_t, gid_t)); 1071590Srgrimes 10874874Smarkm#ifdef USE_PAM 10941279Sjdpstatic int auth_pam __P((void)); 11072215Snectarstatic int export_pam_environment __P((void)); 11172215Snectarstatic int ok_to_export __P((const char *)); 11274874Smarkm 11374874Smarkmstatic pam_handle_t *pamh = NULL; 11474874Smarkmstatic char **environ_pam; 11574874Smarkm 11674874Smarkm#define PAM_END { \ 11774874Smarkm if ((e = pam_setcred(pamh, PAM_DELETE_CRED)) != PAM_SUCCESS) \ 11874874Smarkm syslog(LOG_ERR, "pam_setcred: %s", pam_strerror(pamh, e)); \ 11974874Smarkm if ((e = pam_close_session(pamh,0)) != PAM_SUCCESS) \ 12074874Smarkm syslog(LOG_ERR, "pam_close_session: %s", pam_strerror(pamh, e)); \ 12174874Smarkm if ((e = pam_end(pamh, e)) != PAM_SUCCESS) \ 12274874Smarkm syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e)); \ 12374874Smarkm} 12474874Smarkm#endif /* USE_PAM */ 12541279Sjdpstatic int auth_traditional __P((void)); 1261590Srgrimesextern void login __P((struct utmp *)); 12727605Scharnierstatic void usage __P((void)); 1281590Srgrimes 1291590Srgrimes#define TTYGRPNAME "tty" /* name of group to own ttys */ 13023985Sdavidn#define DEFAULT_BACKOFF 3 13123985Sdavidn#define DEFAULT_RETRIES 10 13276786Sobrien#define DEFAULT_PROMPT "login: " 13376786Sobrien#define DEFAULT_PASSWD_PROMPT "Password:" 1341590Srgrimes 1351590Srgrimes/* 1361590Srgrimes * This bounds the time given to login. Not a define so it can 1371590Srgrimes * be patched on machines where it's too small. 1381590Srgrimes */ 1391590Srgrimesu_int timeout = 300; 1401590Srgrimes 14142272Seivind/* Buffer for signal handling of timeout */ 14242272Seivindjmp_buf timeout_buf; 14342272Seivind 1441590Srgrimesstruct passwd *pwd; 1451590Srgrimesint failures; 14676786Sobrienchar *term, *envinit[1], *hostname, *passwd_prompt, *prompt, *tty, *username; 14716423Sachechar full_hostname[MAXHOSTNAMELEN]; 1481590Srgrimes 1491590Srgrimesint 1501590Srgrimesmain(argc, argv) 1511590Srgrimes int argc; 1521590Srgrimes char *argv[]; 1531590Srgrimes{ 1541590Srgrimes extern char **environ; 1551590Srgrimes struct group *gr; 1561590Srgrimes struct stat st; 1571590Srgrimes struct timeval tp; 1581590Srgrimes struct utmp utmp; 15923985Sdavidn int rootok, retries, backoff; 1601590Srgrimes int ask, ch, cnt, fflag, hflag, pflag, quietlog, rootlogin, rval; 1614878Sugen int changepass; 16223985Sdavidn time_t warntime; 16335559Speter uid_t uid, euid; 16446007Sache gid_t egid; 16545431Sbrian char *p, *ttyn; 16642272Seivind char tbuf[MAXPATHLEN + 2]; 16742272Seivind char tname[sizeof(_PATH_TTY) + 10]; 16823985Sdavidn char *shell = NULL; 16921528Sdavidn login_cap_t *lc = NULL; 17074874Smarkm#ifdef USE_PAM 17174874Smarkm pid_t pid; 17274874Smarkm int e; 17374874Smarkm#endif /* USE_PAM */ 1741590Srgrimes 17542272Seivind (void)signal(SIGQUIT, SIG_IGN); 17642272Seivind (void)signal(SIGINT, SIG_IGN); 17742272Seivind if (setjmp(timeout_buf)) { 17842272Seivind if (failures) 17942272Seivind badlogin(tbuf); 18042272Seivind (void)fprintf(stderr, 18142272Seivind "Login timed out after %d seconds\n", timeout); 18242272Seivind exit(0); 18342272Seivind } 1841590Srgrimes (void)signal(SIGALRM, timedout); 1851590Srgrimes (void)alarm(timeout); 1861590Srgrimes (void)setpriority(PRIO_PROCESS, 0, 0); 1871590Srgrimes 1881590Srgrimes openlog("login", LOG_ODELAY, LOG_AUTH); 1891590Srgrimes 1901590Srgrimes /* 1911590Srgrimes * -p is used by getty to tell login not to destroy the environment 1921590Srgrimes * -f is used to skip a second login authentication 1931590Srgrimes * -h is used by other servers to pass the name of the remote 1941590Srgrimes * host to login so that it may be placed in utmp and wtmp 1951590Srgrimes */ 1963205Spst *full_hostname = '\0'; 19723985Sdavidn term = NULL; 1981590Srgrimes 1991590Srgrimes fflag = hflag = pflag = 0; 2001590Srgrimes uid = getuid(); 20135557Speter euid = geteuid(); 20246007Sache egid = getegid(); 20324360Simp while ((ch = getopt(argc, argv, "fh:p")) != -1) 2041590Srgrimes switch (ch) { 2051590Srgrimes case 'f': 2061590Srgrimes fflag = 1; 2071590Srgrimes break; 2081590Srgrimes case 'h': 2091590Srgrimes if (uid) 2101590Srgrimes errx(1, "-h option: %s", strerror(EPERM)); 2111590Srgrimes hflag = 1; 2123205Spst strncpy(full_hostname, optarg, sizeof(full_hostname)-1); 21336559Samurai 21445431Sbrian trimdomain(optarg, UT_HOSTSIZE); 21536559Samurai 21616423Sache if (strlen(optarg) > UT_HOSTSIZE) { 21757339Sshin struct addrinfo hints, *res; 21857339Sshin int ga_err; 21957339Sshin 22057339Sshin memset(&hints, 0, sizeof(hints)); 22157339Sshin hints.ai_family = AF_UNSPEC; 22257339Sshin ga_err = getaddrinfo(optarg, NULL, &hints, 22357339Sshin &res); 22457339Sshin if (ga_err == 0) { 22557339Sshin char hostbuf[MAXHOSTNAMELEN]; 22616423Sache 22757339Sshin getnameinfo(res->ai_addr, 22857339Sshin res->ai_addrlen, 22957339Sshin hostbuf, 23057339Sshin sizeof(hostbuf), NULL, 0, 23157339Sshin NI_NUMERICHOST| 23257339Sshin NI_WITHSCOPEID); 23357339Sshin optarg = strdup(hostbuf); 23416423Sache } else 23516423Sache optarg = "invalid hostname"; 23657339Sshin if (res != NULL) 23757339Sshin freeaddrinfo(res); 23816423Sache } 2391590Srgrimes hostname = optarg; 2401590Srgrimes break; 2411590Srgrimes case 'p': 2421590Srgrimes pflag = 1; 2431590Srgrimes break; 2441590Srgrimes case '?': 2451590Srgrimes default: 2461590Srgrimes if (!uid) 2471590Srgrimes syslog(LOG_ERR, "invalid flag %c", ch); 24827605Scharnier usage(); 2491590Srgrimes } 2501590Srgrimes argc -= optind; 2511590Srgrimes argv += optind; 2521590Srgrimes 2531590Srgrimes if (*argv) { 2541590Srgrimes username = *argv; 2551590Srgrimes ask = 0; 2561590Srgrimes } else 2571590Srgrimes ask = 1; 2581590Srgrimes 2591590Srgrimes for (cnt = getdtablesize(); cnt > 2; cnt--) 2601590Srgrimes (void)close(cnt); 2611590Srgrimes 2621590Srgrimes ttyn = ttyname(STDIN_FILENO); 2631590Srgrimes if (ttyn == NULL || *ttyn == '\0') { 2641590Srgrimes (void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY); 2651590Srgrimes ttyn = tname; 2661590Srgrimes } 26723985Sdavidn if ((tty = strrchr(ttyn, '/')) != NULL) 2681590Srgrimes ++tty; 2691590Srgrimes else 2701590Srgrimes tty = ttyn; 2711590Srgrimes 27223985Sdavidn /* 27323985Sdavidn * Get "login-retries" & "login-backoff" from default class 27423985Sdavidn */ 27523985Sdavidn lc = login_getclass(NULL); 27676786Sobrien prompt = login_getcapstr(lc, "prompt", DEFAULT_PROMPT, DEFAULT_PROMPT); 27776786Sobrien passwd_prompt = login_getcapstr(lc, "passwd_prompt", 27876786Sobrien DEFAULT_PASSWD_PROMPT, DEFAULT_PASSWD_PROMPT); 27923985Sdavidn retries = login_getcapnum(lc, "login-retries", DEFAULT_RETRIES, DEFAULT_RETRIES); 28023985Sdavidn backoff = login_getcapnum(lc, "login-backoff", DEFAULT_BACKOFF, DEFAULT_BACKOFF); 28123985Sdavidn login_close(lc); 28223985Sdavidn lc = NULL; 28321528Sdavidn 2841590Srgrimes for (cnt = 0;; ask = 1) { 2851590Srgrimes if (ask) { 2861590Srgrimes fflag = 0; 2871590Srgrimes getloginname(); 2881590Srgrimes } 2891590Srgrimes rootlogin = 0; 29021528Sdavidn rootok = rootterm(tty); /* Default (auth may change) */ 29121528Sdavidn 2921590Srgrimes if (strlen(username) > UT_NAMESIZE) 2931590Srgrimes username[UT_NAMESIZE] = '\0'; 2941590Srgrimes 2951590Srgrimes /* 2961590Srgrimes * Note if trying multiple user names; log failures for 2971590Srgrimes * previous user name, but don't bother logging one failure 2981590Srgrimes * for nonexistent name (mistyped username). 2991590Srgrimes */ 3001590Srgrimes if (failures && strcmp(tbuf, username)) { 3011590Srgrimes if (failures > (pwd ? 0 : 1)) 3021590Srgrimes badlogin(tbuf); 3031590Srgrimes } 30427605Scharnier (void)strncpy(tbuf, username, sizeof tbuf-1); 30527605Scharnier tbuf[sizeof tbuf-1] = '\0'; 3061590Srgrimes 30741279Sjdp pwd = getpwnam(username); 30823985Sdavidn 30923985Sdavidn /* 3101590Srgrimes * if we have a valid account name, and it doesn't have a 3111590Srgrimes * password, or the -f option was specified and the caller 3121590Srgrimes * is root or the caller isn't changing their uid, don't 3131590Srgrimes * authenticate. 3141590Srgrimes */ 31521528Sdavidn if (pwd != NULL) { 3163205Spst if (pwd->pw_uid == 0) 3173205Spst rootlogin = 1; 3183205Spst 31923985Sdavidn if (fflag && (uid == (uid_t)0 || 32023985Sdavidn uid == (uid_t)pwd->pw_uid)) { 3213205Spst /* already authenticated */ 3223205Spst break; 3233205Spst } else if (pwd->pw_passwd[0] == '\0') { 32424321Sdavidn if (!rootlogin || rootok) { 32524251Sdavidn /* pretend password okay */ 32624251Sdavidn rval = 0; 32724251Sdavidn goto ttycheck; 32824251Sdavidn } 3293205Spst } 3303205Spst } 3313205Spst 3321590Srgrimes fflag = 0; 3331590Srgrimes 3341590Srgrimes (void)setpriority(PRIO_PROCESS, 0, -4); 3351590Srgrimes 33674874Smarkm#ifdef USE_PAM 33741279Sjdp /* 33841279Sjdp * Try to authenticate using PAM. If a PAM system error 33941279Sjdp * occurs, perhaps because of a botched configuration, 34041279Sjdp * then fall back to using traditional Unix authentication. 34141279Sjdp */ 34241279Sjdp if ((rval = auth_pam()) == -1) 34374874Smarkm#endif /* USE_PAM */ 34441279Sjdp rval = auth_traditional(); 34523985Sdavidn 34641279Sjdp (void)setpriority(PRIO_PROCESS, 0, 0); 34723985Sdavidn 34874874Smarkm#ifdef USE_PAM 34941279Sjdp /* 35041279Sjdp * PAM authentication may have changed "pwd" to the 35141279Sjdp * entry for the template user. Check again to see if 35241279Sjdp * this is a root login after all. 35341279Sjdp */ 35441279Sjdp if (pwd != NULL && pwd->pw_uid == 0) 35541279Sjdp rootlogin = 1; 35674874Smarkm#endif /* USE_PAM */ 3571590Srgrimes 3583205Spst ttycheck: 3591590Srgrimes /* 3601590Srgrimes * If trying to log in as root without Kerberos, 3611590Srgrimes * but with insecure terminal, refuse the login attempt. 3621590Srgrimes */ 36324222Sdavidn if (pwd && !rval) { 36424222Sdavidn if (rootlogin && !rootok) 36524222Sdavidn refused(NULL, "NOROOT", 0); 36624222Sdavidn else /* valid password & authenticated */ 36724222Sdavidn break; 3681590Srgrimes } 3691590Srgrimes 3701590Srgrimes (void)printf("Login incorrect\n"); 3711590Srgrimes failures++; 37223985Sdavidn 37323985Sdavidn /* 37423985Sdavidn * we allow up to 'retry' (10) tries, 37523985Sdavidn * but after 'backoff' (3) we start backing off 37623985Sdavidn */ 37723985Sdavidn if (++cnt > backoff) { 37823985Sdavidn if (cnt >= retries) { 3791590Srgrimes badlogin(username); 3801590Srgrimes sleepexit(1); 3811590Srgrimes } 38238374Sjkoshy sleep((u_int)((cnt - backoff) * 5)); 3831590Srgrimes } 3841590Srgrimes } 3851590Srgrimes 3861590Srgrimes /* committed to login -- turn off timeout */ 3871590Srgrimes (void)alarm((u_int)0); 3881590Srgrimes 3891590Srgrimes endpwent(); 3901590Srgrimes 39141279Sjdp /* 39241279Sjdp * Establish the login class. 39341279Sjdp */ 39441279Sjdp lc = login_getpwclass(pwd); 39541279Sjdp 3961590Srgrimes /* if user not super-user, check for disabled logins */ 3971590Srgrimes if (!rootlogin) 39821528Sdavidn auth_checknologin(lc); 3991590Srgrimes 40021528Sdavidn quietlog = login_getcapbool(lc, "hushlogin", 0); 40146007Sache /* Switching needed for NFS with root access disabled */ 40246007Sache (void)setegid(pwd->pw_gid); 40335557Speter (void)seteuid(rootlogin ? 0 : pwd->pw_uid); 40421528Sdavidn if (!*pwd->pw_dir || chdir(pwd->pw_dir) < 0) { 40526021Spst if (login_getcapbool(lc, "requirehome", 0)) 40623985Sdavidn refused("Home directory not available", "HOMEDIR", 1); 40724485Sdavidn if (chdir("/") < 0) 40823985Sdavidn refused("Cannot find root directory", "ROOTDIR", 1); 40923985Sdavidn if (!quietlog || *pwd->pw_dir) 41023985Sdavidn printf("No home directory.\nLogging in with home = \"/\".\n"); 41157546Sache pwd->pw_dir = "/"; 4121590Srgrimes } 41335557Speter (void)seteuid(euid); 41446007Sache (void)setegid(egid); 41521528Sdavidn if (!quietlog) 41621528Sdavidn quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0; 4171590Srgrimes 4181590Srgrimes if (pwd->pw_change || pwd->pw_expire) 4191590Srgrimes (void)gettimeofday(&tp, (struct timezone *)NULL); 4202532Sjkh 42130564Sjoerg#define DEFAULT_WARN (2L * 7L * 86400L) /* Two weeks */ 42221528Sdavidn 42376710Seric 42476710Seric warntime = login_getcaptime(lc, "warnexpire", 42576710Seric DEFAULT_WARN, DEFAULT_WARN); 42676710Seric 42776710Seric if (pwd->pw_expire) { 42876710Seric if (tp.tv_sec >= pwd->pw_expire) { 42976710Seric refused("Sorry -- your account has expired", 43076710Seric "EXPIRED", 1); 43176710Seric } else if (pwd->pw_expire - tp.tv_sec < warntime && !quietlog) 43276710Seric (void)printf("Warning: your account expires on %s", 43376710Seric ctime(&pwd->pw_expire)); 43476710Seric } 43576710Seric 43623985Sdavidn warntime = login_getcaptime(lc, "warnpassword", 43723985Sdavidn DEFAULT_WARN, DEFAULT_WARN); 43823985Sdavidn 4394878Sugen changepass=0; 44021528Sdavidn if (pwd->pw_change) { 4411590Srgrimes if (tp.tv_sec >= pwd->pw_change) { 4421590Srgrimes (void)printf("Sorry -- your password has expired.\n"); 4434878Sugen changepass=1; 44423985Sdavidn syslog(LOG_INFO, 44523985Sdavidn "%s Password expired - forcing change", 44623985Sdavidn pwd->pw_name); 44723985Sdavidn } else if (pwd->pw_change - tp.tv_sec < warntime && !quietlog) 44823985Sdavidn (void)printf("Warning: your password expires on %s", 44923985Sdavidn ctime(&pwd->pw_change)); 45023985Sdavidn } 45123985Sdavidn 45221528Sdavidn if (lc != NULL) { 45321528Sdavidn if (hostname) { 45457339Sshin struct addrinfo hints, *res; 45557339Sshin int ga_err; 45621528Sdavidn 45757339Sshin memset(&hints, 0, sizeof(hints)); 45857339Sshin hints.ai_family = AF_UNSPEC; 45957339Sshin ga_err = getaddrinfo(full_hostname, NULL, &hints, 46057339Sshin &res); 46157339Sshin if (ga_err == 0) { 46257339Sshin char hostbuf[MAXHOSTNAMELEN]; 46357339Sshin 46457339Sshin getnameinfo(res->ai_addr, res->ai_addrlen, 46557339Sshin hostbuf, sizeof(hostbuf), NULL, 0, 46657339Sshin NI_NUMERICHOST|NI_WITHSCOPEID); 46757339Sshin optarg = strdup(hostbuf); 46857339Sshin } else 46921528Sdavidn optarg = NULL; 47057339Sshin if (res != NULL) 47157339Sshin freeaddrinfo(res); 47223985Sdavidn if (!auth_hostok(lc, full_hostname, optarg)) 47323985Sdavidn refused("Permission denied", "HOST", 1); 47421528Sdavidn } 47521528Sdavidn 47623985Sdavidn if (!auth_ttyok(lc, tty)) 47723985Sdavidn refused("Permission denied", "TTY", 1); 47821528Sdavidn 47923985Sdavidn if (!auth_timeok(lc, time(NULL))) 48023985Sdavidn refused("Logins not available right now", "TIME", 1); 48121528Sdavidn } 48223985Sdavidn shell=login_getcapstr(lc, "shell", pwd->pw_shell, pwd->pw_shell); 48323985Sdavidn if (*pwd->pw_shell == '\0') 48423985Sdavidn pwd->pw_shell = _PATH_BSHELL; 48523985Sdavidn if (*shell == '\0') /* Not overridden */ 48623985Sdavidn shell = pwd->pw_shell; 48723985Sdavidn if ((shell = strdup(shell)) == NULL) { 48823985Sdavidn syslog(LOG_NOTICE, "memory allocation error"); 48923985Sdavidn sleepexit(1); 49023985Sdavidn } 49121528Sdavidn 49221528Sdavidn#ifdef LOGIN_ACCESS 49323985Sdavidn if (login_access(pwd->pw_name, hostname ? full_hostname : tty) == 0) 49423985Sdavidn refused("Permission denied", "ACCESS", 1); 49521528Sdavidn#endif /* LOGIN_ACCESS */ 49621528Sdavidn 4971590Srgrimes /* Nothing else left to fail -- really log in. */ 4981590Srgrimes memset((void *)&utmp, 0, sizeof(utmp)); 4991590Srgrimes (void)time(&utmp.ut_time); 5001590Srgrimes (void)strncpy(utmp.ut_name, username, sizeof(utmp.ut_name)); 5011590Srgrimes if (hostname) 5021590Srgrimes (void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host)); 5031590Srgrimes (void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line)); 5041590Srgrimes login(&utmp); 5051590Srgrimes 5061590Srgrimes dolastlog(quietlog); 5071590Srgrimes 5082224Sguido /* 5092224Sguido * Set device protections, depending on what terminal the 5102224Sguido * user is logged in. This feature is used on Suns to give 5112224Sguido * console users better privacy. 5122224Sguido */ 5132224Sguido login_fbtab(tty, pwd->pw_uid, pwd->pw_gid); 5142224Sguido 51550124Simp /* 51650124Simp * Clear flags of the tty. None should be set, and when the 51750124Simp * user sets them otherwise, this can cause the chown to fail. 51850124Simp * Since it isn't clear that flags are useful on character 51950124Simp * devices, we just clear them. 52050124Simp */ 52159621Ssheldonh if (chflags(ttyn, 0) && errno != EOPNOTSUPP) 52250124Simp syslog(LOG_ERR, "chmod(%s): %m", ttyn); 52350124Simp if (chown(ttyn, pwd->pw_uid, 52450124Simp (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid)) 52550124Simp syslog(LOG_ERR, "chmod(%s): %m", ttyn); 5261590Srgrimes 52750124Simp 52823985Sdavidn /* 52923985Sdavidn * Preserve TERM if it happens to be already set. 53023985Sdavidn */ 53124222Sdavidn if ((term = getenv("TERM")) != NULL) 53224222Sdavidn term = strdup(term); 5331590Srgrimes 53423985Sdavidn /* 53523985Sdavidn * Exclude cons/vt/ptys only, assume dialup otherwise 53623985Sdavidn * TODO: Make dialup tty determination a library call 53723985Sdavidn * for consistency (finger etc.) 53823985Sdavidn */ 53924894Sdavidn if (hostname==NULL && isdialuptty(tty)) 5401590Srgrimes syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name); 5411590Srgrimes 5423205Spst#ifdef LOGALL 5433205Spst /* 5443205Spst * Syslog each successful login, so we don't have to watch hundreds 5453205Spst * of wtmp or lastlogin files. 5463205Spst */ 54723985Sdavidn if (hostname) 54823985Sdavidn syslog(LOG_INFO, "login from %s on %s as %s", 54923985Sdavidn full_hostname, tty, pwd->pw_name); 55023985Sdavidn else 55123985Sdavidn syslog(LOG_INFO, "login on %s as %s", 55223985Sdavidn tty, pwd->pw_name); 55321528Sdavidn#endif 55421528Sdavidn 55523985Sdavidn /* 55623985Sdavidn * If fflag is on, assume caller/authenticator has logged root login. 55723985Sdavidn */ 55823985Sdavidn if (rootlogin && fflag == 0) 55923985Sdavidn { 56023985Sdavidn if (hostname) 56123985Sdavidn syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s", 56223985Sdavidn username, tty, full_hostname); 56323985Sdavidn else 56423985Sdavidn syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s", 56523985Sdavidn username, tty); 56623985Sdavidn } 56723985Sdavidn 56823985Sdavidn /* 56923985Sdavidn * Destroy environment unless user has requested its preservation. 57023985Sdavidn * We need to do this before setusercontext() because that may 57123985Sdavidn * set or reset some environment variables. 57223985Sdavidn */ 57321528Sdavidn if (!pflag) 57421528Sdavidn environ = envinit; 57521528Sdavidn 57674874Smarkm#ifdef USE_PAM 57723985Sdavidn /* 57872215Snectar * Add any environmental variables that the 57972215Snectar * PAM modules may have set. 58072215Snectar */ 58174874Smarkm if (pamh) { 58274874Smarkm environ_pam = pam_getenvlist(pamh); 58374874Smarkm if (environ_pam) 58474874Smarkm export_pam_environment(); 58574874Smarkm } 58674874Smarkm#endif /* USE_PAM */ 58772215Snectar 58872215Snectar /* 58974874Smarkm * PAM modules might add supplementary groups during pam_setcred(). 59074874Smarkm */ 59174874Smarkm if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) != 0) { 59274874Smarkm syslog(LOG_ERR, "setusercontext() failed - exiting"); 59374874Smarkm exit(1); 59474874Smarkm } 59574874Smarkm 59674874Smarkm#ifdef USE_PAM 59774874Smarkm if (pamh) { 59874874Smarkm if ((e = pam_open_session(pamh, 0)) != PAM_SUCCESS) { 59974874Smarkm syslog(LOG_ERR, "pam_open_session: %s", pam_strerror(pamh, e)); 60074874Smarkm } else if ((e = pam_setcred(pamh, PAM_ESTABLISH_CRED)) != PAM_SUCCESS) { 60174874Smarkm syslog(LOG_ERR, "pam_setcred: %s", pam_strerror(pamh, e)); 60274874Smarkm } 60374874Smarkm 60474874Smarkm /* 60574874Smarkm * We must fork() before setuid() because we need to call 60674874Smarkm * pam_close_session() as root. 60774874Smarkm */ 60874874Smarkm pid = fork(); 60974874Smarkm if (pid < 0) { 61074874Smarkm err(1, "fork"); 61174874Smarkm PAM_END; 61274874Smarkm exit(0); 61374874Smarkm } else if (pid) { 61474874Smarkm /* parent - wait for child to finish, then cleanup session */ 61574874Smarkm wait(NULL); 61674874Smarkm PAM_END; 61774874Smarkm exit(0); 61874874Smarkm } else { 61974874Smarkm if ((e = pam_end(pamh, PAM_DATA_SILENT)) != PAM_SUCCESS) 62074874Smarkm syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e)); 62174874Smarkm } 62274874Smarkm } 62374874Smarkm#endif /* USE_PAM */ 62474874Smarkm 62574874Smarkm /* 62623985Sdavidn * We don't need to be root anymore, so 62721528Sdavidn * set the user and session context 62821528Sdavidn */ 62941279Sjdp if (setlogin(username) != 0) { 63041279Sjdp syslog(LOG_ERR, "setlogin(%s): %m - exiting", username); 63141279Sjdp exit(1); 63241279Sjdp } 63341279Sjdp if (setusercontext(lc, pwd, pwd->pw_uid, 63474874Smarkm LOGIN_SETALL & ~(LOGIN_SETLOGIN|LOGIN_SETGROUP)) != 0) { 63521528Sdavidn syslog(LOG_ERR, "setusercontext() failed - exiting"); 63621528Sdavidn exit(1); 6373205Spst } 63821528Sdavidn 63923148Sache (void)setenv("SHELL", pwd->pw_shell, 1); 64021528Sdavidn (void)setenv("HOME", pwd->pw_dir, 1); 64123985Sdavidn if (term != NULL && *term != '\0') 64221528Sdavidn (void)setenv("TERM", term, 1); /* Preset overrides */ 64321528Sdavidn else { 64423985Sdavidn (void)setenv("TERM", stypeof(tty), 0); /* Fallback doesn't */ 64521528Sdavidn } 64641279Sjdp (void)setenv("LOGNAME", username, 1); 64741279Sjdp (void)setenv("USER", username, 1); 64821528Sdavidn (void)setenv("PATH", rootlogin ? _PATH_STDPATH : _PATH_DEFPATH, 0); 64921528Sdavidn 6501590Srgrimes if (!quietlog) { 65123985Sdavidn char *cw; 65223985Sdavidn 65323985Sdavidn cw = login_getcapstr(lc, "copyright", NULL, NULL); 65421528Sdavidn if (cw != NULL && access(cw, F_OK) == 0) 65521528Sdavidn motd(cw); 65621528Sdavidn else 65723985Sdavidn (void)printf("%s\n\t%s %s\n", 65823985Sdavidn "Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994", 65923985Sdavidn "The Regents of the University of California. ", 66023985Sdavidn "All rights reserved."); 66123985Sdavidn 66223985Sdavidn (void)printf("\n"); 66323985Sdavidn 66421528Sdavidn cw = login_getcapstr(lc, "welcome", NULL, NULL); 66521528Sdavidn if (cw == NULL || access(cw, F_OK) != 0) 66621528Sdavidn cw = _PATH_MOTDFILE; 66721528Sdavidn motd(cw); 66823985Sdavidn 66921528Sdavidn cw = getenv("MAIL"); /* $MAIL may have been set by class */ 67021528Sdavidn if (cw != NULL) { 67121528Sdavidn strncpy(tbuf, cw, sizeof(tbuf)); 67221528Sdavidn tbuf[sizeof(tbuf)-1] = '\0'; 67321528Sdavidn } else 67423985Sdavidn snprintf(tbuf, sizeof(tbuf), "%s/%s", 67523985Sdavidn _PATH_MAILDIR, pwd->pw_name); 6761590Srgrimes if (stat(tbuf, &st) == 0 && st.st_size != 0) 67723985Sdavidn (void)printf("You have %smail.\n", 67823985Sdavidn (st.st_mtime > st.st_atime) ? "new " : ""); 6791590Srgrimes } 6801590Srgrimes 68121528Sdavidn login_close(lc); 6823205Spst 6831590Srgrimes (void)signal(SIGALRM, SIG_DFL); 6841590Srgrimes (void)signal(SIGQUIT, SIG_DFL); 6851590Srgrimes (void)signal(SIGINT, SIG_DFL); 6861590Srgrimes (void)signal(SIGTSTP, SIG_IGN); 6871590Srgrimes 6884878Sugen if (changepass) { 68921528Sdavidn if (system(_PATH_CHPASS) != 0) 6904878Sugen sleepexit(1); 6914878Sugen } 6924878Sugen 69323985Sdavidn /* 69423985Sdavidn * Login shells have a leading '-' in front of argv[0] 69523985Sdavidn */ 69623985Sdavidn tbuf[0] = '-'; 69723985Sdavidn (void)strcpy(tbuf + 1, (p = strrchr(pwd->pw_shell, '/')) ? p + 1 : pwd->pw_shell); 69823985Sdavidn 69921528Sdavidn execlp(shell, tbuf, 0); 70021528Sdavidn err(1, "%s", shell); 7011590Srgrimes} 7021590Srgrimes 70341279Sjdpstatic int 70441279Sjdpauth_traditional() 70541279Sjdp{ 70641279Sjdp int rval; 70741279Sjdp char *p; 70841279Sjdp char *ep; 70941279Sjdp char *salt; 71041279Sjdp 71141279Sjdp rval = 1; 71241279Sjdp salt = pwd != NULL ? pwd->pw_passwd : "xx"; 71341279Sjdp 71476786Sobrien p = getpass(passwd_prompt); 71541279Sjdp ep = crypt(p, salt); 71641279Sjdp 71741279Sjdp if (pwd) { 71841279Sjdp if (!p[0] && pwd->pw_passwd[0]) 71941279Sjdp ep = ":"; 72041279Sjdp if (strcmp(ep, pwd->pw_passwd) == 0) 72141279Sjdp rval = 0; 72241279Sjdp } 72341279Sjdp 72441279Sjdp /* clear entered password */ 72541279Sjdp memset(p, 0, strlen(p)); 72641279Sjdp return rval; 72741279Sjdp} 72841279Sjdp 72974874Smarkm#ifdef USE_PAM 73041279Sjdp/* 73141279Sjdp * Attempt to authenticate the user using PAM. Returns 0 if the user is 73241279Sjdp * authenticated, or 1 if not authenticated. If some sort of PAM system 73341279Sjdp * error occurs (e.g., the "/etc/pam.conf" file is missing) then this 73441279Sjdp * function returns -1. This can be used as an indication that we should 73541279Sjdp * fall back to a different authentication mechanism. 73641279Sjdp */ 73741279Sjdpstatic int 73841279Sjdpauth_pam() 73941279Sjdp{ 74041279Sjdp const char *tmpl_user; 74141279Sjdp const void *item; 74241279Sjdp int rval; 74341279Sjdp int e; 74441279Sjdp static struct pam_conv conv = { misc_conv, NULL }; 74541279Sjdp 74641279Sjdp if ((e = pam_start("login", username, &conv, &pamh)) != PAM_SUCCESS) { 74741279Sjdp syslog(LOG_ERR, "pam_start: %s", pam_strerror(pamh, e)); 74841279Sjdp return -1; 74941279Sjdp } 75041279Sjdp if ((e = pam_set_item(pamh, PAM_TTY, tty)) != PAM_SUCCESS) { 75141279Sjdp syslog(LOG_ERR, "pam_set_item(PAM_TTY): %s", 75241279Sjdp pam_strerror(pamh, e)); 75341279Sjdp return -1; 75441279Sjdp } 75541279Sjdp if (hostname != NULL && 75641279Sjdp (e = pam_set_item(pamh, PAM_RHOST, full_hostname)) != PAM_SUCCESS) { 75741279Sjdp syslog(LOG_ERR, "pam_set_item(PAM_RHOST): %s", 75841279Sjdp pam_strerror(pamh, e)); 75941279Sjdp return -1; 76041279Sjdp } 76141279Sjdp e = pam_authenticate(pamh, 0); 76241279Sjdp switch (e) { 76341279Sjdp 76441279Sjdp case PAM_SUCCESS: 76541279Sjdp /* 76641279Sjdp * With PAM we support the concept of a "template" 76741279Sjdp * user. The user enters a login name which is 76841279Sjdp * authenticated by PAM, usually via a remote service 76941279Sjdp * such as RADIUS or TACACS+. If authentication 77041279Sjdp * succeeds, a different but related "template" name 77141279Sjdp * is used for setting the credentials, shell, and 77241279Sjdp * home directory. The name the user enters need only 77341279Sjdp * exist on the remote authentication server, but the 77441279Sjdp * template name must be present in the local password 77541279Sjdp * database. 77641279Sjdp * 77741279Sjdp * This is supported by two various mechanisms in the 77841279Sjdp * individual modules. However, from the application's 77941279Sjdp * point of view, the template user is always passed 78041279Sjdp * back as a changed value of the PAM_USER item. 78141279Sjdp */ 78241279Sjdp if ((e = pam_get_item(pamh, PAM_USER, &item)) == 78341279Sjdp PAM_SUCCESS) { 78441279Sjdp tmpl_user = (const char *) item; 78541279Sjdp if (strcmp(username, tmpl_user) != 0) 78641279Sjdp pwd = getpwnam(tmpl_user); 78741279Sjdp } else 78841279Sjdp syslog(LOG_ERR, "Couldn't get PAM_USER: %s", 78941279Sjdp pam_strerror(pamh, e)); 79041279Sjdp rval = 0; 79141279Sjdp break; 79241279Sjdp 79341279Sjdp case PAM_AUTH_ERR: 79441279Sjdp case PAM_USER_UNKNOWN: 79541279Sjdp case PAM_MAXTRIES: 79641279Sjdp rval = 1; 79741279Sjdp break; 79841279Sjdp 79941279Sjdp default: 80074874Smarkm syslog(LOG_ERR, "pam_authenticate: %s", pam_strerror(pamh, e)); 80141279Sjdp rval = -1; 80241279Sjdp break; 80341279Sjdp } 80474874Smarkm 80574874Smarkm if (rval == 0) { 80674874Smarkm e = pam_acct_mgmt(pamh, 0); 80774874Smarkm if (e == PAM_NEW_AUTHTOK_REQD) { 80874874Smarkm e = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK); 80974874Smarkm if (e != PAM_SUCCESS) { 81074874Smarkm syslog(LOG_ERR, "pam_chauthtok: %s", pam_strerror(pamh, e)); 81174874Smarkm rval = 1; 81274874Smarkm } 81374874Smarkm } else if (e != PAM_SUCCESS) { 81474874Smarkm rval = 1; 81574874Smarkm } 81641279Sjdp } 81774874Smarkm 81874874Smarkm if (rval != 0) { 81974874Smarkm if ((e = pam_end(pamh, e)) != PAM_SUCCESS) { 82074874Smarkm syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e)); 82174874Smarkm } 82274874Smarkm pamh = NULL; 82374874Smarkm } 82441279Sjdp return rval; 82541279Sjdp} 82672215Snectar 82772215Snectarstatic int 82872215Snectarexport_pam_environment() 82972215Snectar{ 83072215Snectar char **pp; 83172215Snectar 83272215Snectar for (pp = environ_pam; *pp != NULL; pp++) { 83372215Snectar if (ok_to_export(*pp)) 83472215Snectar (void) putenv(*pp); 83572215Snectar free(*pp); 83672215Snectar } 83772215Snectar return PAM_SUCCESS; 83872215Snectar} 83972215Snectar 84072215Snectar/* 84172215Snectar * Sanity checks on PAM environmental variables: 84272215Snectar * - Make sure there is an '=' in the string. 84372215Snectar * - Make sure the string doesn't run on too long. 84472215Snectar * - Do not export certain variables. This list was taken from the 84572215Snectar * Solaris pam_putenv(3) man page. 84672215Snectar */ 84772215Snectarstatic int 84872215Snectarok_to_export(s) 84972215Snectar const char *s; 85072215Snectar{ 85172215Snectar static const char *noexport[] = { 85272215Snectar "SHELL", "HOME", "LOGNAME", "MAIL", "CDPATH", 85372215Snectar "IFS", "PATH", NULL 85472215Snectar }; 85572215Snectar const char **pp; 85672215Snectar size_t n; 85772215Snectar 85872215Snectar if (strlen(s) > 1024 || strchr(s, '=') == NULL) 85972215Snectar return 0; 86072215Snectar if (strncmp(s, "LD_", 3) == 0) 86172215Snectar return 0; 86272215Snectar for (pp = noexport; *pp != NULL; pp++) { 86372215Snectar n = strlen(*pp); 86472215Snectar if (s[n] == '=' && strncmp(s, *pp, n) == 0) 86572215Snectar return 0; 86672215Snectar } 86772215Snectar return 1; 86872215Snectar} 86974874Smarkm#endif /* USE_PAM */ 87041279Sjdp 87127605Scharnierstatic void 87227605Scharnierusage() 87327605Scharnier{ 87427605Scharnier (void)fprintf(stderr, "usage: login [-fp] [-h hostname] [username]\n"); 87527605Scharnier exit(1); 87627605Scharnier} 8771590Srgrimes 87823985Sdavidn/* 87923985Sdavidn * Allow for authentication style and/or kerberos instance 88074874Smarkm */ 88121528Sdavidn 88221528Sdavidn#define NBUFSIZ UT_NAMESIZE + 64 88321528Sdavidn 8841590Srgrimesvoid 8851590Srgrimesgetloginname() 8861590Srgrimes{ 8871590Srgrimes int ch; 8881590Srgrimes char *p; 8891590Srgrimes static char nbuf[NBUFSIZ]; 8901590Srgrimes 8911590Srgrimes for (;;) { 89276786Sobrien (void)printf(prompt); 8931590Srgrimes for (p = nbuf; (ch = getchar()) != '\n'; ) { 8941590Srgrimes if (ch == EOF) { 8951590Srgrimes badlogin(username); 8961590Srgrimes exit(0); 8971590Srgrimes } 8981590Srgrimes if (p < nbuf + (NBUFSIZ - 1)) 8991590Srgrimes *p++ = ch; 9001590Srgrimes } 90159645Ssheldonh if (p > nbuf) { 9021590Srgrimes if (nbuf[0] == '-') 9031590Srgrimes (void)fprintf(stderr, 9041590Srgrimes "login names may not start with '-'.\n"); 9051590Srgrimes else { 9061590Srgrimes *p = '\0'; 9071590Srgrimes username = nbuf; 9081590Srgrimes break; 9091590Srgrimes } 91059645Ssheldonh } 9111590Srgrimes } 9121590Srgrimes} 9131590Srgrimes 9141590Srgrimesint 9151590Srgrimesrootterm(ttyn) 9161590Srgrimes char *ttyn; 9171590Srgrimes{ 9181590Srgrimes struct ttyent *t; 91923985Sdavidn 9201590Srgrimes return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE); 9211590Srgrimes} 9221590Srgrimes 92321528Sdavidnvolatile int motdinterrupt; 9241590Srgrimes 92521528Sdavidn/* ARGSUSED */ 9261590Srgrimesvoid 92721528Sdavidnsigint(signo) 92821528Sdavidn int signo; 9291590Srgrimes{ 93021528Sdavidn motdinterrupt = 1; 93121528Sdavidn} 93221528Sdavidn 93321528Sdavidnvoid 93421528Sdavidnmotd(motdfile) 93521528Sdavidn char *motdfile; 93621528Sdavidn{ 9371590Srgrimes int fd, nchars; 9381590Srgrimes sig_t oldint; 93921528Sdavidn char tbuf[256]; 9401590Srgrimes 94121528Sdavidn if ((fd = open(motdfile, O_RDONLY, 0)) < 0) 9421590Srgrimes return; 94321528Sdavidn motdinterrupt = 0; 9441590Srgrimes oldint = signal(SIGINT, sigint); 94521528Sdavidn while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0 && !motdinterrupt) 94621528Sdavidn (void)write(fileno(stdout), tbuf, nchars); 9471590Srgrimes (void)signal(SIGINT, oldint); 9481590Srgrimes (void)close(fd); 9491590Srgrimes} 9501590Srgrimes 9511590Srgrimes/* ARGSUSED */ 9521590Srgrimesvoid 9531590Srgrimestimedout(signo) 9541590Srgrimes int signo; 9551590Srgrimes{ 95642272Seivind longjmp(timeout_buf, signo); 9571590Srgrimes} 9581590Srgrimes 9591590Srgrimes 9601590Srgrimesvoid 9611590Srgrimesdolastlog(quiet) 9621590Srgrimes int quiet; 9631590Srgrimes{ 9641590Srgrimes struct lastlog ll; 9651590Srgrimes int fd; 9661590Srgrimes 9671590Srgrimes if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) { 9681590Srgrimes (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); 9691590Srgrimes if (!quiet) { 9701590Srgrimes if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) && 9711590Srgrimes ll.ll_time != 0) { 9721590Srgrimes (void)printf("Last login: %.*s ", 9731590Srgrimes 24-5, (char *)ctime(&ll.ll_time)); 9741590Srgrimes if (*ll.ll_host != '\0') 9751590Srgrimes (void)printf("from %.*s\n", 9761590Srgrimes (int)sizeof(ll.ll_host), 9771590Srgrimes ll.ll_host); 9781590Srgrimes else 9791590Srgrimes (void)printf("on %.*s\n", 9801590Srgrimes (int)sizeof(ll.ll_line), 9811590Srgrimes ll.ll_line); 9821590Srgrimes } 9831590Srgrimes (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); 9841590Srgrimes } 9851590Srgrimes memset((void *)&ll, 0, sizeof(ll)); 9861590Srgrimes (void)time(&ll.ll_time); 9871590Srgrimes (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); 9881590Srgrimes if (hostname) 9891590Srgrimes (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host)); 9901590Srgrimes (void)write(fd, (char *)&ll, sizeof(ll)); 9911590Srgrimes (void)close(fd); 9921590Srgrimes } 9931590Srgrimes} 9941590Srgrimes 9951590Srgrimesvoid 9961590Srgrimesbadlogin(name) 9971590Srgrimes char *name; 9981590Srgrimes{ 9991590Srgrimes 10001590Srgrimes if (failures == 0) 10011590Srgrimes return; 10021590Srgrimes if (hostname) { 10031590Srgrimes syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s", 100416423Sache failures, failures > 1 ? "S" : "", full_hostname); 10051590Srgrimes syslog(LOG_AUTHPRIV|LOG_NOTICE, 10061590Srgrimes "%d LOGIN FAILURE%s FROM %s, %s", 100716423Sache failures, failures > 1 ? "S" : "", full_hostname, name); 10081590Srgrimes } else { 10091590Srgrimes syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s", 10101590Srgrimes failures, failures > 1 ? "S" : "", tty); 10111590Srgrimes syslog(LOG_AUTHPRIV|LOG_NOTICE, 10121590Srgrimes "%d LOGIN FAILURE%s ON %s, %s", 10131590Srgrimes failures, failures > 1 ? "S" : "", tty, name); 10141590Srgrimes } 101542272Seivind failures = 0; 10161590Srgrimes} 10171590Srgrimes 10181590Srgrimes#undef UNKNOWN 10191590Srgrimes#define UNKNOWN "su" 10201590Srgrimes 10211590Srgrimeschar * 10221590Srgrimesstypeof(ttyid) 10231590Srgrimes char *ttyid; 10241590Srgrimes{ 102523985Sdavidn 10261590Srgrimes struct ttyent *t; 102723985Sdavidn 10281590Srgrimes return (ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN); 10291590Srgrimes} 10301590Srgrimes 10311590Srgrimesvoid 103223985Sdavidnrefused(msg, rtype, lout) 103323985Sdavidn char *msg; 103423985Sdavidn char *rtype; 103523985Sdavidn int lout; 103623985Sdavidn{ 103723985Sdavidn 103823985Sdavidn if (msg != NULL) 103923985Sdavidn printf("%s.\n", msg); 104023985Sdavidn if (hostname) 104123985Sdavidn syslog(LOG_NOTICE, "LOGIN %s REFUSED (%s) FROM %s ON TTY %s", 104223985Sdavidn pwd->pw_name, rtype, full_hostname, tty); 104323985Sdavidn else 104423985Sdavidn syslog(LOG_NOTICE, "LOGIN %s REFUSED (%s) ON TTY %s", 104523985Sdavidn pwd->pw_name, rtype, tty); 104623985Sdavidn if (lout) 104723985Sdavidn sleepexit(1); 104823985Sdavidn} 104923985Sdavidn 105023985Sdavidnvoid 10511590Srgrimessleepexit(eval) 10521590Srgrimes int eval; 10531590Srgrimes{ 105423985Sdavidn 10551590Srgrimes (void)sleep(5); 10561590Srgrimes exit(eval); 10571590Srgrimes} 1058