login.c revision 3702
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)); 822532Sjkhvoid change_passwd __P((void)); 831590Srgrimesint rootterm __P((char *)); 841590Srgrimesvoid sigint __P((int)); 851590Srgrimesvoid sleepexit __P((int)); 861590Srgrimeschar *stypeof __P((char *)); 871590Srgrimesvoid timedout __P((int)); 882224Sguidovoid login_fbtab __P((char *, uid_t, gid_t)); 891590Srgrimes#ifdef KERBEROS 901590Srgrimesint klogin __P((struct passwd *, char *, char *, char *)); 911590Srgrimes#endif 921590Srgrimes 931590Srgrimesextern void login __P((struct utmp *)); 941590Srgrimes 951590Srgrimes#define TTYGRPNAME "tty" /* name of group to own ttys */ 961590Srgrimes 971590Srgrimes/* 981590Srgrimes * This bounds the time given to login. Not a define so it can 991590Srgrimes * be patched on machines where it's too small. 1001590Srgrimes */ 1011590Srgrimesu_int timeout = 300; 1021590Srgrimes 1031590Srgrimes#ifdef KERBEROS 1041590Srgrimesint notickets = 1; 1051590Srgrimeschar *instance; 1061590Srgrimeschar *krbtkfile_env; 1071590Srgrimesint authok; 1081590Srgrimes#endif 1091590Srgrimes 1101590Srgrimesstruct passwd *pwd; 1111590Srgrimesint failures; 1121590Srgrimeschar term[64], *envinit[1], *hostname, *username, *tty; 1131590Srgrimes 1141590Srgrimesint 1151590Srgrimesmain(argc, argv) 1161590Srgrimes int argc; 1171590Srgrimes char *argv[]; 1181590Srgrimes{ 1191590Srgrimes extern char **environ; 1201590Srgrimes struct group *gr; 1211590Srgrimes struct stat st; 1221590Srgrimes struct timeval tp; 1231590Srgrimes struct utmp utmp; 1241590Srgrimes int ask, ch, cnt, fflag, hflag, pflag, quietlog, rootlogin, rval; 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 3511590Srgrimes if (pwd->pw_change) 3521590Srgrimes if (tp.tv_sec >= pwd->pw_change) { 3531590Srgrimes (void)printf("Sorry -- your password has expired.\n"); 3542532Sjkh change_passwd(); 3551590Srgrimes } else if (pwd->pw_change - tp.tv_sec < 3561590Srgrimes 2 * DAYSPERWEEK * SECSPERDAY && !quietlog) 3571590Srgrimes (void)printf("Warning: your password expires on %s", 3581590Srgrimes ctime(&pwd->pw_change)); 3591590Srgrimes if (pwd->pw_expire) 3601590Srgrimes if (tp.tv_sec >= pwd->pw_expire) { 3611590Srgrimes (void)printf("Sorry -- your account has expired.\n"); 3621590Srgrimes sleepexit(1); 3631590Srgrimes } else if (pwd->pw_expire - tp.tv_sec < 3641590Srgrimes 2 * DAYSPERWEEK * SECSPERDAY && !quietlog) 3651590Srgrimes (void)printf("Warning: your account expires on %s", 3661590Srgrimes ctime(&pwd->pw_expire)); 3671590Srgrimes 3681590Srgrimes /* Nothing else left to fail -- really log in. */ 3691590Srgrimes memset((void *)&utmp, 0, sizeof(utmp)); 3701590Srgrimes (void)time(&utmp.ut_time); 3711590Srgrimes (void)strncpy(utmp.ut_name, username, sizeof(utmp.ut_name)); 3721590Srgrimes if (hostname) 3731590Srgrimes (void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host)); 3741590Srgrimes (void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line)); 3751590Srgrimes login(&utmp); 3761590Srgrimes 3771590Srgrimes dolastlog(quietlog); 3781590Srgrimes 3792224Sguido /* 3802224Sguido * Set device protections, depending on what terminal the 3812224Sguido * user is logged in. This feature is used on Suns to give 3822224Sguido * console users better privacy. 3832224Sguido */ 3842224Sguido login_fbtab(tty, pwd->pw_uid, pwd->pw_gid); 3852224Sguido 3861590Srgrimes (void)chown(ttyn, pwd->pw_uid, 3871590Srgrimes (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid); 3881590Srgrimes (void)setgid(pwd->pw_gid); 3891590Srgrimes 3901590Srgrimes initgroups(username, pwd->pw_gid); 3911590Srgrimes 3921590Srgrimes if (*pwd->pw_shell == '\0') 3931590Srgrimes pwd->pw_shell = _PATH_BSHELL; 3941590Srgrimes 3951590Srgrimes /* Destroy environment unless user has requested its preservation. */ 3961590Srgrimes if (!pflag) 3971590Srgrimes environ = envinit; 3981590Srgrimes (void)setenv("HOME", pwd->pw_dir, 1); 3991590Srgrimes (void)setenv("SHELL", pwd->pw_shell, 1); 4001590Srgrimes if (term[0] == '\0') 4011590Srgrimes (void)strncpy(term, stypeof(tty), sizeof(term)); 4021590Srgrimes (void)setenv("TERM", term, 0); 4031590Srgrimes (void)setenv("LOGNAME", pwd->pw_name, 1); 4041590Srgrimes (void)setenv("USER", pwd->pw_name, 1); 4051590Srgrimes (void)setenv("PATH", _PATH_DEFPATH, 0); 4061590Srgrimes#ifdef KERBEROS 4071590Srgrimes if (krbtkfile_env) 4081590Srgrimes (void)setenv("KRBTKFILE", krbtkfile_env, 1); 4091590Srgrimes#endif 4101590Srgrimes 4111590Srgrimes if (tty[sizeof("tty")-1] == 'd') 4121590Srgrimes syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name); 4131590Srgrimes 4141590Srgrimes /* If fflag is on, assume caller/authenticator has logged root login. */ 4151590Srgrimes if (rootlogin && fflag == 0) 4161590Srgrimes if (hostname) 4171590Srgrimes syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s", 4181590Srgrimes username, tty, hostname); 4191590Srgrimes else 4201590Srgrimes syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s", username, tty); 4211590Srgrimes 4221590Srgrimes#ifdef KERBEROS 4231590Srgrimes if (!quietlog && notickets == 1) 4241590Srgrimes (void)printf("Warning: no Kerberos tickets issued.\n"); 4251590Srgrimes#endif 4261590Srgrimes 4273205Spst#ifdef LOGALL 4283205Spst /* 4293205Spst * Syslog each successful login, so we don't have to watch hundreds 4303205Spst * of wtmp or lastlogin files. 4313205Spst */ 4323205Spst if (hostname) { 4333205Spst syslog(LOG_INFO, "login from %s as %s", hostname, pwd->pw_name); 4343205Spst } else { 4353205Spst syslog(LOG_INFO, "login on %s as %s", tty, pwd->pw_name); 4363205Spst } 4373205Spst#endif 4383205Spst 4391590Srgrimes if (!quietlog) { 4401590Srgrimes (void)printf("%s\n\t%s %s\n\n", 4411590Srgrimes "Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994", 4421590Srgrimes "The Regents of the University of California. ", 4431590Srgrimes "All rights reserved."); 4441590Srgrimes motd(); 4451590Srgrimes (void)snprintf(tbuf, 4461590Srgrimes sizeof(tbuf), "%s/%s", _PATH_MAILDIR, pwd->pw_name); 4471590Srgrimes if (stat(tbuf, &st) == 0 && st.st_size != 0) 4481590Srgrimes (void)printf("You have %smail.\n", 4491590Srgrimes (st.st_mtime > st.st_atime) ? "new " : ""); 4501590Srgrimes } 4511590Srgrimes 4523205Spst#ifdef LOGIN_ACCESS 4533205Spst if (login_access(pwd->pw_name, hostname ? full_hostname : tty) == 0) { 4543205Spst printf("Permission denied\n"); 4553205Spst if (hostname) 4563205Spst syslog(LOG_NOTICE, "%s LOGIN REFUSED FROM %s", 4573205Spst pwd->pw_name, hostname); 4583205Spst else 4593205Spst syslog(LOG_NOTICE, "%s LOGIN REFUSED ON %s", 4603205Spst pwd->pw_name, tty); 4613205Spst sleepexit(1); 4623205Spst } 4633205Spst#endif 4643205Spst 4651590Srgrimes (void)signal(SIGALRM, SIG_DFL); 4661590Srgrimes (void)signal(SIGQUIT, SIG_DFL); 4671590Srgrimes (void)signal(SIGINT, SIG_DFL); 4681590Srgrimes (void)signal(SIGTSTP, SIG_IGN); 4691590Srgrimes 4701590Srgrimes tbuf[0] = '-'; 4711590Srgrimes (void)strcpy(tbuf + 1, (p = strrchr(pwd->pw_shell, '/')) ? 4721590Srgrimes p + 1 : pwd->pw_shell); 4731590Srgrimes 4741590Srgrimes if (setlogin(pwd->pw_name) < 0) 4751590Srgrimes syslog(LOG_ERR, "setlogin() failure: %m"); 4761590Srgrimes 4771590Srgrimes /* Discard permissions last so can't get killed and drop core. */ 4781590Srgrimes if (rootlogin) 4791590Srgrimes (void) setuid(0); 4801590Srgrimes else 4811590Srgrimes (void) setuid(pwd->pw_uid); 4821590Srgrimes 4831590Srgrimes execlp(pwd->pw_shell, tbuf, 0); 4841590Srgrimes err(1, "%s", pwd->pw_shell); 4851590Srgrimes} 4861590Srgrimes 4871590Srgrimes#ifdef KERBEROS 4881590Srgrimes#define NBUFSIZ (UT_NAMESIZE + 1 + 5) /* .root suffix */ 4891590Srgrimes#else 4901590Srgrimes#define NBUFSIZ (UT_NAMESIZE + 1) 4911590Srgrimes#endif 4921590Srgrimes 4931590Srgrimesvoid 4941590Srgrimesgetloginname() 4951590Srgrimes{ 4961590Srgrimes int ch; 4971590Srgrimes char *p; 4981590Srgrimes static char nbuf[NBUFSIZ]; 4991590Srgrimes 5001590Srgrimes for (;;) { 5011590Srgrimes (void)printf("login: "); 5021590Srgrimes for (p = nbuf; (ch = getchar()) != '\n'; ) { 5031590Srgrimes if (ch == EOF) { 5041590Srgrimes badlogin(username); 5051590Srgrimes exit(0); 5061590Srgrimes } 5071590Srgrimes if (p < nbuf + (NBUFSIZ - 1)) 5081590Srgrimes *p++ = ch; 5091590Srgrimes } 5101590Srgrimes if (p > nbuf) 5111590Srgrimes if (nbuf[0] == '-') 5121590Srgrimes (void)fprintf(stderr, 5131590Srgrimes "login names may not start with '-'.\n"); 5141590Srgrimes else { 5151590Srgrimes *p = '\0'; 5161590Srgrimes username = nbuf; 5171590Srgrimes break; 5181590Srgrimes } 5191590Srgrimes } 5201590Srgrimes} 5211590Srgrimes 5221590Srgrimesint 5231590Srgrimesrootterm(ttyn) 5241590Srgrimes char *ttyn; 5251590Srgrimes{ 5261590Srgrimes struct ttyent *t; 5271590Srgrimes 5281590Srgrimes return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE); 5291590Srgrimes} 5301590Srgrimes 5311590Srgrimesjmp_buf motdinterrupt; 5321590Srgrimes 5331590Srgrimesvoid 5341590Srgrimesmotd() 5351590Srgrimes{ 5361590Srgrimes int fd, nchars; 5371590Srgrimes sig_t oldint; 5381590Srgrimes char tbuf[8192]; 5391590Srgrimes 5401590Srgrimes if ((fd = open(_PATH_MOTDFILE, O_RDONLY, 0)) < 0) 5411590Srgrimes return; 5421590Srgrimes oldint = signal(SIGINT, sigint); 5431590Srgrimes if (setjmp(motdinterrupt) == 0) 5441590Srgrimes while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) 5451590Srgrimes (void)write(fileno(stdout), tbuf, nchars); 5461590Srgrimes (void)signal(SIGINT, oldint); 5471590Srgrimes (void)close(fd); 5481590Srgrimes} 5491590Srgrimes 5501590Srgrimes/* ARGSUSED */ 5511590Srgrimesvoid 5521590Srgrimessigint(signo) 5531590Srgrimes int signo; 5541590Srgrimes{ 5551590Srgrimes 5561590Srgrimes longjmp(motdinterrupt, 1); 5571590Srgrimes} 5581590Srgrimes 5591590Srgrimes/* ARGSUSED */ 5601590Srgrimesvoid 5611590Srgrimestimedout(signo) 5621590Srgrimes int signo; 5631590Srgrimes{ 5641590Srgrimes 5651590Srgrimes (void)fprintf(stderr, "Login timed out after %d seconds\n", timeout); 5661590Srgrimes exit(0); 5671590Srgrimes} 5681590Srgrimes 5691590Srgrimesvoid 5701590Srgrimeschecknologin() 5711590Srgrimes{ 5721590Srgrimes int fd, nchars; 5731590Srgrimes char tbuf[8192]; 5741590Srgrimes 5751590Srgrimes if ((fd = open(_PATH_NOLOGIN, O_RDONLY, 0)) >= 0) { 5761590Srgrimes while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) 5771590Srgrimes (void)write(fileno(stdout), tbuf, nchars); 5781590Srgrimes sleepexit(0); 5791590Srgrimes } 5801590Srgrimes} 5811590Srgrimes 5821590Srgrimesvoid 5831590Srgrimesdolastlog(quiet) 5841590Srgrimes int quiet; 5851590Srgrimes{ 5861590Srgrimes struct lastlog ll; 5871590Srgrimes int fd; 5881590Srgrimes 5891590Srgrimes if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) { 5901590Srgrimes (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); 5911590Srgrimes if (!quiet) { 5921590Srgrimes if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) && 5931590Srgrimes ll.ll_time != 0) { 5941590Srgrimes (void)printf("Last login: %.*s ", 5951590Srgrimes 24-5, (char *)ctime(&ll.ll_time)); 5961590Srgrimes if (*ll.ll_host != '\0') 5971590Srgrimes (void)printf("from %.*s\n", 5981590Srgrimes (int)sizeof(ll.ll_host), 5991590Srgrimes ll.ll_host); 6001590Srgrimes else 6011590Srgrimes (void)printf("on %.*s\n", 6021590Srgrimes (int)sizeof(ll.ll_line), 6031590Srgrimes ll.ll_line); 6041590Srgrimes } 6051590Srgrimes (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); 6061590Srgrimes } 6071590Srgrimes memset((void *)&ll, 0, sizeof(ll)); 6081590Srgrimes (void)time(&ll.ll_time); 6091590Srgrimes (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); 6101590Srgrimes if (hostname) 6111590Srgrimes (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host)); 6121590Srgrimes (void)write(fd, (char *)&ll, sizeof(ll)); 6131590Srgrimes (void)close(fd); 6141590Srgrimes } 6151590Srgrimes} 6161590Srgrimes 6171590Srgrimesvoid 6181590Srgrimesbadlogin(name) 6191590Srgrimes char *name; 6201590Srgrimes{ 6211590Srgrimes 6221590Srgrimes if (failures == 0) 6231590Srgrimes return; 6241590Srgrimes if (hostname) { 6251590Srgrimes syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s", 6261590Srgrimes failures, failures > 1 ? "S" : "", hostname); 6271590Srgrimes syslog(LOG_AUTHPRIV|LOG_NOTICE, 6281590Srgrimes "%d LOGIN FAILURE%s FROM %s, %s", 6291590Srgrimes failures, failures > 1 ? "S" : "", hostname, name); 6301590Srgrimes } else { 6311590Srgrimes syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s", 6321590Srgrimes failures, failures > 1 ? "S" : "", tty); 6331590Srgrimes syslog(LOG_AUTHPRIV|LOG_NOTICE, 6341590Srgrimes "%d LOGIN FAILURE%s ON %s, %s", 6351590Srgrimes failures, failures > 1 ? "S" : "", tty, name); 6361590Srgrimes } 6371590Srgrimes} 6381590Srgrimes 6391590Srgrimes#undef UNKNOWN 6401590Srgrimes#define UNKNOWN "su" 6411590Srgrimes 6421590Srgrimeschar * 6431590Srgrimesstypeof(ttyid) 6441590Srgrimes char *ttyid; 6451590Srgrimes{ 6461590Srgrimes struct ttyent *t; 6471590Srgrimes 6481590Srgrimes return (ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN); 6491590Srgrimes} 6501590Srgrimes 6511590Srgrimesvoid 6521590Srgrimessleepexit(eval) 6531590Srgrimes int eval; 6541590Srgrimes{ 6551590Srgrimes 6561590Srgrimes (void)sleep(5); 6571590Srgrimes exit(eval); 6581590Srgrimes} 6592532Sjkh 6602532Sjkhvoid 6612532Sjkhchange_passwd() 6622532Sjkh{ 6632532Sjkh int pid, status, w; 6642532Sjkh register void (*istat)(), (*qstat)(); 6652532Sjkh 6662532Sjkh if (( pid=fork() ) == 0) 6672532Sjkh { 6682532Sjkh execl( "/usr/bin/passwd", "passwd", NULL ); 6692532Sjkh fprintf( stderr, "ERROR: Can't execute passwd!\n" ); 6702532Sjkh sleepexit( 1 ); 6712532Sjkh } 6722532Sjkh 6732532Sjkh istat = signal( SIGINT, SIG_IGN ); 6742532Sjkh qstat = signal( SIGQUIT, SIG_IGN ); 6752532Sjkh 6762532Sjkh while ((w = wait( &status )) != pid && w != -1) 6772532Sjkh ; 6782532Sjkh 6792532Sjkh signal( SIGINT, istat ); 6802532Sjkh signal( SIGQUIT, qstat ); 6812532Sjkh} 6822532Sjkh 683