login.c revision 4878
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 341590Srgrimes#ifndef lint 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"; 381590Srgrimes#endif /* not lint */ 391590Srgrimes 401590Srgrimes#ifndef lint 411590Srgrimesstatic char sccsid[] = "@(#)login.c 8.4 (Berkeley) 4/2/94"; 421590Srgrimes#endif /* not lint */ 431590Srgrimes 441590Srgrimes/* 451590Srgrimes * login [ name ] 461590Srgrimes * login -h hostname (for telnetd, etc.) 471590Srgrimes * login -f name (for pre-authenticated login: datakit, xterm, etc.) 481590Srgrimes */ 491590Srgrimes 501590Srgrimes#include <sys/param.h> 511590Srgrimes#include <sys/stat.h> 521590Srgrimes#include <sys/time.h> 531590Srgrimes#include <sys/resource.h> 541590Srgrimes#include <sys/file.h> 551590Srgrimes 561590Srgrimes#include <err.h> 571590Srgrimes#include <errno.h> 581590Srgrimes#include <grp.h> 591590Srgrimes#include <pwd.h> 601590Srgrimes#include <setjmp.h> 611590Srgrimes#include <signal.h> 621590Srgrimes#include <stdio.h> 631590Srgrimes#include <stdlib.h> 641590Srgrimes#include <string.h> 651590Srgrimes#include <syslog.h> 661590Srgrimes#include <ttyent.h> 671590Srgrimes#include <tzfile.h> 681590Srgrimes#include <unistd.h> 691590Srgrimes#include <utmp.h> 701590Srgrimes 713702Spst#ifdef SKEY 723702Spst#include <skey.h> 733702Spst#endif 743702Spst 751590Srgrimes#include "pathnames.h" 761590Srgrimes 771590Srgrimesvoid badlogin __P((char *)); 781590Srgrimesvoid checknologin __P((void)); 791590Srgrimesvoid dolastlog __P((int)); 801590Srgrimesvoid getloginname __P((void)); 811590Srgrimesvoid motd __P((void)); 821590Srgrimesint rootterm __P((char *)); 831590Srgrimesvoid sigint __P((int)); 841590Srgrimesvoid sleepexit __P((int)); 851590Srgrimeschar *stypeof __P((char *)); 861590Srgrimesvoid timedout __P((int)); 872224Sguidovoid login_fbtab __P((char *, uid_t, gid_t)); 881590Srgrimes#ifdef KERBEROS 891590Srgrimesint klogin __P((struct passwd *, char *, char *, char *)); 901590Srgrimes#endif 911590Srgrimes 921590Srgrimesextern void login __P((struct utmp *)); 931590Srgrimes 941590Srgrimes#define TTYGRPNAME "tty" /* name of group to own ttys */ 951590Srgrimes 961590Srgrimes/* 971590Srgrimes * This bounds the time given to login. Not a define so it can 981590Srgrimes * be patched on machines where it's too small. 991590Srgrimes */ 1001590Srgrimesu_int timeout = 300; 1011590Srgrimes 1021590Srgrimes#ifdef KERBEROS 1031590Srgrimesint notickets = 1; 1041590Srgrimeschar *instance; 1051590Srgrimeschar *krbtkfile_env; 1061590Srgrimesint authok; 1071590Srgrimes#endif 1081590Srgrimes 1091590Srgrimesstruct passwd *pwd; 1101590Srgrimesint failures; 1111590Srgrimeschar term[64], *envinit[1], *hostname, *username, *tty; 1121590Srgrimes 1131590Srgrimesint 1141590Srgrimesmain(argc, argv) 1151590Srgrimes int argc; 1161590Srgrimes char *argv[]; 1171590Srgrimes{ 1181590Srgrimes extern char **environ; 1191590Srgrimes struct group *gr; 1201590Srgrimes struct stat st; 1211590Srgrimes struct timeval tp; 1221590Srgrimes struct utmp utmp; 1231590Srgrimes int ask, ch, cnt, fflag, hflag, pflag, quietlog, rootlogin, rval; 1244878Sugen int changepass; 1251590Srgrimes uid_t uid; 1263205Spst char *domain, *p, *ep, *salt, *ttyn; 1271590Srgrimes char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10]; 1281590Srgrimes char localhost[MAXHOSTNAMELEN]; 1293205Spst char full_hostname[MAXHOSTNAMELEN]; 1303205Spst#ifdef SKEY 1313205Spst int permit_passwd = 0; 1323205Spst#endif 1331590Srgrimes 1341590Srgrimes (void)signal(SIGALRM, timedout); 1351590Srgrimes (void)alarm(timeout); 1361590Srgrimes (void)signal(SIGQUIT, SIG_IGN); 1371590Srgrimes (void)signal(SIGINT, SIG_IGN); 1381590Srgrimes (void)setpriority(PRIO_PROCESS, 0, 0); 1391590Srgrimes 1401590Srgrimes openlog("login", LOG_ODELAY, LOG_AUTH); 1411590Srgrimes 1421590Srgrimes /* 1431590Srgrimes * -p is used by getty to tell login not to destroy the environment 1441590Srgrimes * -f is used to skip a second login authentication 1451590Srgrimes * -h is used by other servers to pass the name of the remote 1461590Srgrimes * host to login so that it may be placed in utmp and wtmp 1471590Srgrimes */ 1483205Spst *full_hostname = '\0'; 1491590Srgrimes domain = NULL; 1501590Srgrimes if (gethostname(localhost, sizeof(localhost)) < 0) 1511590Srgrimes syslog(LOG_ERR, "couldn't get local hostname: %m"); 1521590Srgrimes else 1531590Srgrimes domain = strchr(localhost, '.'); 1541590Srgrimes 1551590Srgrimes fflag = hflag = pflag = 0; 1561590Srgrimes uid = getuid(); 1571590Srgrimes while ((ch = getopt(argc, argv, "fh:p")) != EOF) 1581590Srgrimes switch (ch) { 1591590Srgrimes case 'f': 1601590Srgrimes fflag = 1; 1611590Srgrimes break; 1621590Srgrimes case 'h': 1631590Srgrimes if (uid) 1641590Srgrimes errx(1, "-h option: %s", strerror(EPERM)); 1651590Srgrimes hflag = 1; 1663205Spst strncpy(full_hostname, optarg, sizeof(full_hostname)-1); 1671590Srgrimes if (domain && (p = strchr(optarg, '.')) && 1681590Srgrimes strcasecmp(p, domain) == 0) 1691590Srgrimes *p = 0; 1701590Srgrimes hostname = optarg; 1711590Srgrimes break; 1721590Srgrimes case 'p': 1731590Srgrimes pflag = 1; 1741590Srgrimes break; 1751590Srgrimes case '?': 1761590Srgrimes default: 1771590Srgrimes if (!uid) 1781590Srgrimes syslog(LOG_ERR, "invalid flag %c", ch); 1791590Srgrimes (void)fprintf(stderr, 1801590Srgrimes "usage: login [-fp] [-h hostname] [username]\n"); 1811590Srgrimes exit(1); 1821590Srgrimes } 1831590Srgrimes argc -= optind; 1841590Srgrimes argv += optind; 1851590Srgrimes 1861590Srgrimes if (*argv) { 1871590Srgrimes username = *argv; 1881590Srgrimes ask = 0; 1891590Srgrimes } else 1901590Srgrimes ask = 1; 1911590Srgrimes 1921590Srgrimes for (cnt = getdtablesize(); cnt > 2; cnt--) 1931590Srgrimes (void)close(cnt); 1941590Srgrimes 1951590Srgrimes ttyn = ttyname(STDIN_FILENO); 1961590Srgrimes if (ttyn == NULL || *ttyn == '\0') { 1971590Srgrimes (void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY); 1981590Srgrimes ttyn = tname; 1991590Srgrimes } 2001590Srgrimes if (tty = strrchr(ttyn, '/')) 2011590Srgrimes ++tty; 2021590Srgrimes else 2031590Srgrimes tty = ttyn; 2041590Srgrimes 2051590Srgrimes for (cnt = 0;; ask = 1) { 2061590Srgrimes if (ask) { 2071590Srgrimes fflag = 0; 2081590Srgrimes getloginname(); 2091590Srgrimes } 2101590Srgrimes rootlogin = 0; 2111590Srgrimes#ifdef KERBEROS 2121590Srgrimes if ((instance = strchr(username, '.')) != NULL) { 2131590Srgrimes if (strncmp(instance, ".root", 5) == 0) 2141590Srgrimes rootlogin = 1; 2151590Srgrimes *instance++ = '\0'; 2161590Srgrimes } else 2171590Srgrimes instance = ""; 2181590Srgrimes#endif 2191590Srgrimes if (strlen(username) > UT_NAMESIZE) 2201590Srgrimes username[UT_NAMESIZE] = '\0'; 2211590Srgrimes 2221590Srgrimes /* 2231590Srgrimes * Note if trying multiple user names; log failures for 2241590Srgrimes * previous user name, but don't bother logging one failure 2251590Srgrimes * for nonexistent name (mistyped username). 2261590Srgrimes */ 2271590Srgrimes if (failures && strcmp(tbuf, username)) { 2281590Srgrimes if (failures > (pwd ? 0 : 1)) 2291590Srgrimes badlogin(tbuf); 2301590Srgrimes failures = 0; 2311590Srgrimes } 2321590Srgrimes (void)strcpy(tbuf, username); 2331590Srgrimes 2341590Srgrimes if (pwd = getpwnam(username)) 2351590Srgrimes salt = pwd->pw_passwd; 2361590Srgrimes else 2371590Srgrimes salt = "xx"; 2381590Srgrimes 2391590Srgrimes /* 2401590Srgrimes * if we have a valid account name, and it doesn't have a 2411590Srgrimes * password, or the -f option was specified and the caller 2421590Srgrimes * is root or the caller isn't changing their uid, don't 2431590Srgrimes * authenticate. 2441590Srgrimes */ 2453205Spst if (pwd) { 2463205Spst if (pwd->pw_uid == 0) 2473205Spst rootlogin = 1; 2483205Spst 2493205Spst if (fflag && (uid == 0 || uid == pwd->pw_uid)) { 2503205Spst /* already authenticated */ 2513205Spst break; 2523205Spst } else if (pwd->pw_passwd[0] == '\0') { 2533205Spst /* pretend password okay */ 2543205Spst rval = 0; 2553205Spst goto ttycheck; 2563205Spst } 2573205Spst } 2583205Spst 2591590Srgrimes fflag = 0; 2601590Srgrimes 2611590Srgrimes (void)setpriority(PRIO_PROCESS, 0, -4); 2621590Srgrimes 2633205Spst#ifdef SKEY 2643205Spst permit_passwd = skeyaccess(username, tty, 2653702Spst hostname ? full_hostname : NULL, 2663702Spst NULL); 2673205Spst p = skey_getpass("Password:", pwd, permit_passwd); 2683205Spst ep = skey_crypt(p, salt, pwd, permit_passwd); 2693205Spst#else 2701590Srgrimes p = getpass("Password:"); 2713205Spst ep = crypt(p, salt); 2723205Spst#endif 2731590Srgrimes 2741590Srgrimes if (pwd) { 2751590Srgrimes#ifdef KERBEROS 2761590Srgrimes rval = klogin(pwd, instance, localhost, p); 2771590Srgrimes if (rval != 0 && rootlogin && pwd->pw_uid != 0) 2781590Srgrimes rootlogin = 0; 2791590Srgrimes if (rval == 0) 2801590Srgrimes authok = 1; 2811590Srgrimes else if (rval == 1) 2823205Spst rval = strcmp(ep, pwd->pw_passwd); 2831590Srgrimes#else 2843205Spst rval = strcmp(ep, pwd->pw_passwd); 2851590Srgrimes#endif 2861590Srgrimes } 2871590Srgrimes memset(p, 0, strlen(p)); 2881590Srgrimes 2891590Srgrimes (void)setpriority(PRIO_PROCESS, 0, 0); 2901590Srgrimes 2913205Spst ttycheck: 2921590Srgrimes /* 2931590Srgrimes * If trying to log in as root without Kerberos, 2941590Srgrimes * but with insecure terminal, refuse the login attempt. 2951590Srgrimes */ 2961590Srgrimes#ifdef KERBEROS 2971590Srgrimes if (authok == 0) 2981590Srgrimes#endif 2993205Spst if (pwd && !rval && rootlogin && !rootterm(tty)) { 3001590Srgrimes (void)fprintf(stderr, 3011590Srgrimes "%s login refused on this terminal.\n", 3021590Srgrimes pwd->pw_name); 3031590Srgrimes if (hostname) 3041590Srgrimes syslog(LOG_NOTICE, 3051590Srgrimes "LOGIN %s REFUSED FROM %s ON TTY %s", 3061590Srgrimes pwd->pw_name, hostname, tty); 3071590Srgrimes else 3081590Srgrimes syslog(LOG_NOTICE, 3091590Srgrimes "LOGIN %s REFUSED ON TTY %s", 3101590Srgrimes pwd->pw_name, tty); 3111590Srgrimes continue; 3121590Srgrimes } 3131590Srgrimes 3141590Srgrimes if (pwd && !rval) 3151590Srgrimes break; 3161590Srgrimes 3171590Srgrimes (void)printf("Login incorrect\n"); 3181590Srgrimes failures++; 3191590Srgrimes /* we allow 10 tries, but after 3 we start backing off */ 3201590Srgrimes if (++cnt > 3) { 3211590Srgrimes if (cnt >= 10) { 3221590Srgrimes badlogin(username); 3231590Srgrimes sleepexit(1); 3241590Srgrimes } 3251590Srgrimes sleep((u_int)((cnt - 3) * 5)); 3261590Srgrimes } 3271590Srgrimes } 3281590Srgrimes 3291590Srgrimes /* committed to login -- turn off timeout */ 3301590Srgrimes (void)alarm((u_int)0); 3311590Srgrimes 3321590Srgrimes endpwent(); 3331590Srgrimes 3341590Srgrimes /* if user not super-user, check for disabled logins */ 3351590Srgrimes if (!rootlogin) 3361590Srgrimes checknologin(); 3371590Srgrimes 3381590Srgrimes if (chdir(pwd->pw_dir) < 0) { 3391590Srgrimes (void)printf("No home directory %s!\n", pwd->pw_dir); 3401590Srgrimes if (chdir("/")) 3411590Srgrimes exit(0); 3421590Srgrimes pwd->pw_dir = "/"; 3431590Srgrimes (void)printf("Logging in with home = \"/\".\n"); 3441590Srgrimes } 3451590Srgrimes 3461590Srgrimes quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0; 3471590Srgrimes 3481590Srgrimes if (pwd->pw_change || pwd->pw_expire) 3491590Srgrimes (void)gettimeofday(&tp, (struct timezone *)NULL); 3502532Sjkh 3514878Sugen changepass=0; 3521590Srgrimes if (pwd->pw_change) 3531590Srgrimes if (tp.tv_sec >= pwd->pw_change) { 3541590Srgrimes (void)printf("Sorry -- your password has expired.\n"); 3554878Sugen changepass=1; 3561590Srgrimes } else if (pwd->pw_change - tp.tv_sec < 3571590Srgrimes 2 * DAYSPERWEEK * SECSPERDAY && !quietlog) 3581590Srgrimes (void)printf("Warning: your password expires on %s", 3591590Srgrimes ctime(&pwd->pw_change)); 3601590Srgrimes if (pwd->pw_expire) 3611590Srgrimes if (tp.tv_sec >= pwd->pw_expire) { 3621590Srgrimes (void)printf("Sorry -- your account has expired.\n"); 3631590Srgrimes sleepexit(1); 3641590Srgrimes } else if (pwd->pw_expire - tp.tv_sec < 3651590Srgrimes 2 * DAYSPERWEEK * SECSPERDAY && !quietlog) 3661590Srgrimes (void)printf("Warning: your account expires on %s", 3671590Srgrimes ctime(&pwd->pw_expire)); 3681590Srgrimes 3691590Srgrimes /* Nothing else left to fail -- really log in. */ 3701590Srgrimes memset((void *)&utmp, 0, sizeof(utmp)); 3711590Srgrimes (void)time(&utmp.ut_time); 3721590Srgrimes (void)strncpy(utmp.ut_name, username, sizeof(utmp.ut_name)); 3731590Srgrimes if (hostname) 3741590Srgrimes (void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host)); 3751590Srgrimes (void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line)); 3761590Srgrimes login(&utmp); 3771590Srgrimes 3781590Srgrimes dolastlog(quietlog); 3791590Srgrimes 3802224Sguido /* 3812224Sguido * Set device protections, depending on what terminal the 3822224Sguido * user is logged in. This feature is used on Suns to give 3832224Sguido * console users better privacy. 3842224Sguido */ 3852224Sguido login_fbtab(tty, pwd->pw_uid, pwd->pw_gid); 3862224Sguido 3871590Srgrimes (void)chown(ttyn, pwd->pw_uid, 3881590Srgrimes (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid); 3891590Srgrimes (void)setgid(pwd->pw_gid); 3901590Srgrimes 3911590Srgrimes initgroups(username, pwd->pw_gid); 3921590Srgrimes 3931590Srgrimes if (*pwd->pw_shell == '\0') 3941590Srgrimes pwd->pw_shell = _PATH_BSHELL; 3951590Srgrimes 3961590Srgrimes /* Destroy environment unless user has requested its preservation. */ 3971590Srgrimes if (!pflag) 3981590Srgrimes environ = envinit; 3991590Srgrimes (void)setenv("HOME", pwd->pw_dir, 1); 4001590Srgrimes (void)setenv("SHELL", pwd->pw_shell, 1); 4011590Srgrimes if (term[0] == '\0') 4021590Srgrimes (void)strncpy(term, stypeof(tty), sizeof(term)); 4031590Srgrimes (void)setenv("TERM", term, 0); 4041590Srgrimes (void)setenv("LOGNAME", pwd->pw_name, 1); 4051590Srgrimes (void)setenv("USER", pwd->pw_name, 1); 4061590Srgrimes (void)setenv("PATH", _PATH_DEFPATH, 0); 4071590Srgrimes#ifdef KERBEROS 4081590Srgrimes if (krbtkfile_env) 4091590Srgrimes (void)setenv("KRBTKFILE", krbtkfile_env, 1); 4101590Srgrimes#endif 4111590Srgrimes 4121590Srgrimes if (tty[sizeof("tty")-1] == 'd') 4131590Srgrimes syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name); 4141590Srgrimes 4151590Srgrimes /* If fflag is on, assume caller/authenticator has logged root login. */ 4161590Srgrimes if (rootlogin && fflag == 0) 4171590Srgrimes if (hostname) 4181590Srgrimes syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s", 4191590Srgrimes username, tty, hostname); 4201590Srgrimes else 4211590Srgrimes syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s", username, tty); 4221590Srgrimes 4231590Srgrimes#ifdef KERBEROS 4241590Srgrimes if (!quietlog && notickets == 1) 4251590Srgrimes (void)printf("Warning: no Kerberos tickets issued.\n"); 4261590Srgrimes#endif 4271590Srgrimes 4283205Spst#ifdef LOGALL 4293205Spst /* 4303205Spst * Syslog each successful login, so we don't have to watch hundreds 4313205Spst * of wtmp or lastlogin files. 4323205Spst */ 4333205Spst if (hostname) { 4343205Spst syslog(LOG_INFO, "login from %s as %s", hostname, pwd->pw_name); 4353205Spst } else { 4363205Spst syslog(LOG_INFO, "login on %s as %s", tty, pwd->pw_name); 4373205Spst } 4383205Spst#endif 4393205Spst 4401590Srgrimes if (!quietlog) { 4411590Srgrimes (void)printf("%s\n\t%s %s\n\n", 4421590Srgrimes "Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994", 4431590Srgrimes "The Regents of the University of California. ", 4441590Srgrimes "All rights reserved."); 4451590Srgrimes motd(); 4461590Srgrimes (void)snprintf(tbuf, 4471590Srgrimes sizeof(tbuf), "%s/%s", _PATH_MAILDIR, pwd->pw_name); 4481590Srgrimes if (stat(tbuf, &st) == 0 && st.st_size != 0) 4491590Srgrimes (void)printf("You have %smail.\n", 4501590Srgrimes (st.st_mtime > st.st_atime) ? "new " : ""); 4511590Srgrimes } 4521590Srgrimes 4533205Spst#ifdef LOGIN_ACCESS 4543205Spst if (login_access(pwd->pw_name, hostname ? full_hostname : tty) == 0) { 4553205Spst printf("Permission denied\n"); 4563205Spst if (hostname) 4573205Spst syslog(LOG_NOTICE, "%s LOGIN REFUSED FROM %s", 4583205Spst pwd->pw_name, hostname); 4593205Spst else 4603205Spst syslog(LOG_NOTICE, "%s LOGIN REFUSED ON %s", 4613205Spst pwd->pw_name, tty); 4623205Spst sleepexit(1); 4633205Spst } 4643205Spst#endif 4653205Spst 4661590Srgrimes (void)signal(SIGALRM, SIG_DFL); 4671590Srgrimes (void)signal(SIGQUIT, SIG_DFL); 4681590Srgrimes (void)signal(SIGINT, SIG_DFL); 4691590Srgrimes (void)signal(SIGTSTP, SIG_IGN); 4701590Srgrimes 4711590Srgrimes tbuf[0] = '-'; 4721590Srgrimes (void)strcpy(tbuf + 1, (p = strrchr(pwd->pw_shell, '/')) ? 4731590Srgrimes p + 1 : pwd->pw_shell); 4741590Srgrimes 4754878Sugen if (setlogin(pwd->pw_name) < 0) 4764878Sugen syslog(LOG_ERR, "setlogin() failure: %m"); 4771590Srgrimes 4781590Srgrimes /* Discard permissions last so can't get killed and drop core. */ 4791590Srgrimes if (rootlogin) 4801590Srgrimes (void) setuid(0); 4811590Srgrimes else 4821590Srgrimes (void) setuid(pwd->pw_uid); 4831590Srgrimes 4844878Sugen if (changepass) { 4854878Sugen int res; 4864878Sugen if ((res=system(_PATH_CHPASS))) 4874878Sugen sleepexit(1); 4884878Sugen } 4894878Sugen 4901590Srgrimes execlp(pwd->pw_shell, tbuf, 0); 4911590Srgrimes err(1, "%s", pwd->pw_shell); 4921590Srgrimes} 4931590Srgrimes 4941590Srgrimes#ifdef KERBEROS 4951590Srgrimes#define NBUFSIZ (UT_NAMESIZE + 1 + 5) /* .root suffix */ 4961590Srgrimes#else 4971590Srgrimes#define NBUFSIZ (UT_NAMESIZE + 1) 4981590Srgrimes#endif 4991590Srgrimes 5001590Srgrimesvoid 5011590Srgrimesgetloginname() 5021590Srgrimes{ 5031590Srgrimes int ch; 5041590Srgrimes char *p; 5051590Srgrimes static char nbuf[NBUFSIZ]; 5061590Srgrimes 5071590Srgrimes for (;;) { 5081590Srgrimes (void)printf("login: "); 5091590Srgrimes for (p = nbuf; (ch = getchar()) != '\n'; ) { 5101590Srgrimes if (ch == EOF) { 5111590Srgrimes badlogin(username); 5121590Srgrimes exit(0); 5131590Srgrimes } 5141590Srgrimes if (p < nbuf + (NBUFSIZ - 1)) 5151590Srgrimes *p++ = ch; 5161590Srgrimes } 5171590Srgrimes if (p > nbuf) 5181590Srgrimes if (nbuf[0] == '-') 5191590Srgrimes (void)fprintf(stderr, 5201590Srgrimes "login names may not start with '-'.\n"); 5211590Srgrimes else { 5221590Srgrimes *p = '\0'; 5231590Srgrimes username = nbuf; 5241590Srgrimes break; 5251590Srgrimes } 5261590Srgrimes } 5271590Srgrimes} 5281590Srgrimes 5291590Srgrimesint 5301590Srgrimesrootterm(ttyn) 5311590Srgrimes char *ttyn; 5321590Srgrimes{ 5331590Srgrimes struct ttyent *t; 5341590Srgrimes 5351590Srgrimes return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE); 5361590Srgrimes} 5371590Srgrimes 5381590Srgrimesjmp_buf motdinterrupt; 5391590Srgrimes 5401590Srgrimesvoid 5411590Srgrimesmotd() 5421590Srgrimes{ 5431590Srgrimes int fd, nchars; 5441590Srgrimes sig_t oldint; 5451590Srgrimes char tbuf[8192]; 5461590Srgrimes 5471590Srgrimes if ((fd = open(_PATH_MOTDFILE, O_RDONLY, 0)) < 0) 5481590Srgrimes return; 5491590Srgrimes oldint = signal(SIGINT, sigint); 5501590Srgrimes if (setjmp(motdinterrupt) == 0) 5511590Srgrimes while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) 5521590Srgrimes (void)write(fileno(stdout), tbuf, nchars); 5531590Srgrimes (void)signal(SIGINT, oldint); 5541590Srgrimes (void)close(fd); 5551590Srgrimes} 5561590Srgrimes 5571590Srgrimes/* ARGSUSED */ 5581590Srgrimesvoid 5591590Srgrimessigint(signo) 5601590Srgrimes int signo; 5611590Srgrimes{ 5621590Srgrimes 5631590Srgrimes longjmp(motdinterrupt, 1); 5641590Srgrimes} 5651590Srgrimes 5661590Srgrimes/* ARGSUSED */ 5671590Srgrimesvoid 5681590Srgrimestimedout(signo) 5691590Srgrimes int signo; 5701590Srgrimes{ 5711590Srgrimes 5721590Srgrimes (void)fprintf(stderr, "Login timed out after %d seconds\n", timeout); 5731590Srgrimes exit(0); 5741590Srgrimes} 5751590Srgrimes 5761590Srgrimesvoid 5771590Srgrimeschecknologin() 5781590Srgrimes{ 5791590Srgrimes int fd, nchars; 5801590Srgrimes char tbuf[8192]; 5811590Srgrimes 5821590Srgrimes if ((fd = open(_PATH_NOLOGIN, O_RDONLY, 0)) >= 0) { 5831590Srgrimes while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) 5841590Srgrimes (void)write(fileno(stdout), tbuf, nchars); 5851590Srgrimes sleepexit(0); 5861590Srgrimes } 5871590Srgrimes} 5881590Srgrimes 5891590Srgrimesvoid 5901590Srgrimesdolastlog(quiet) 5911590Srgrimes int quiet; 5921590Srgrimes{ 5931590Srgrimes struct lastlog ll; 5941590Srgrimes int fd; 5951590Srgrimes 5961590Srgrimes if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) { 5971590Srgrimes (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); 5981590Srgrimes if (!quiet) { 5991590Srgrimes if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) && 6001590Srgrimes ll.ll_time != 0) { 6011590Srgrimes (void)printf("Last login: %.*s ", 6021590Srgrimes 24-5, (char *)ctime(&ll.ll_time)); 6031590Srgrimes if (*ll.ll_host != '\0') 6041590Srgrimes (void)printf("from %.*s\n", 6051590Srgrimes (int)sizeof(ll.ll_host), 6061590Srgrimes ll.ll_host); 6071590Srgrimes else 6081590Srgrimes (void)printf("on %.*s\n", 6091590Srgrimes (int)sizeof(ll.ll_line), 6101590Srgrimes ll.ll_line); 6111590Srgrimes } 6121590Srgrimes (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); 6131590Srgrimes } 6141590Srgrimes memset((void *)&ll, 0, sizeof(ll)); 6151590Srgrimes (void)time(&ll.ll_time); 6161590Srgrimes (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); 6171590Srgrimes if (hostname) 6181590Srgrimes (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host)); 6191590Srgrimes (void)write(fd, (char *)&ll, sizeof(ll)); 6201590Srgrimes (void)close(fd); 6211590Srgrimes } 6221590Srgrimes} 6231590Srgrimes 6241590Srgrimesvoid 6251590Srgrimesbadlogin(name) 6261590Srgrimes char *name; 6271590Srgrimes{ 6281590Srgrimes 6291590Srgrimes if (failures == 0) 6301590Srgrimes return; 6311590Srgrimes if (hostname) { 6321590Srgrimes syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s", 6331590Srgrimes failures, failures > 1 ? "S" : "", hostname); 6341590Srgrimes syslog(LOG_AUTHPRIV|LOG_NOTICE, 6351590Srgrimes "%d LOGIN FAILURE%s FROM %s, %s", 6361590Srgrimes failures, failures > 1 ? "S" : "", hostname, name); 6371590Srgrimes } else { 6381590Srgrimes syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s", 6391590Srgrimes failures, failures > 1 ? "S" : "", tty); 6401590Srgrimes syslog(LOG_AUTHPRIV|LOG_NOTICE, 6411590Srgrimes "%d LOGIN FAILURE%s ON %s, %s", 6421590Srgrimes failures, failures > 1 ? "S" : "", tty, name); 6431590Srgrimes } 6441590Srgrimes} 6451590Srgrimes 6461590Srgrimes#undef UNKNOWN 6471590Srgrimes#define UNKNOWN "su" 6481590Srgrimes 6491590Srgrimeschar * 6501590Srgrimesstypeof(ttyid) 6511590Srgrimes char *ttyid; 6521590Srgrimes{ 6531590Srgrimes struct ttyent *t; 6541590Srgrimes 6551590Srgrimes return (ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN); 6561590Srgrimes} 6571590Srgrimes 6581590Srgrimesvoid 6591590Srgrimessleepexit(eval) 6601590Srgrimes int eval; 6611590Srgrimes{ 6621590Srgrimes 6631590Srgrimes (void)sleep(5); 6641590Srgrimes exit(eval); 6651590Srgrimes} 6662532Sjkh 6672532Sjkh 668