login.c revision 8874
152419Sjulian/*- 252419Sjulian * Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994 352419Sjulian * The Regents of the University of California. All rights reserved. 452419Sjulian * 552419Sjulian * Redistribution and use in source and binary forms, with or without 652419Sjulian * modification, are permitted provided that the following conditions 752419Sjulian * are met: 852419Sjulian * 1. Redistributions of source code must retain the above copyright 952419Sjulian * notice, this list of conditions and the following disclaimer. 1052419Sjulian * 2. Redistributions in binary form must reproduce the above copyright 1152419Sjulian * notice, this list of conditions and the following disclaimer in the 1252419Sjulian * documentation and/or other materials provided with the distribution. 1352419Sjulian * 3. All advertising materials mentioning features or use of this software 1452419Sjulian * must display the following acknowledgement: 1552419Sjulian * This product includes software developed by the University of 1652419Sjulian * California, Berkeley and its contributors. 1752419Sjulian * 4. Neither the name of the University nor the names of its contributors 1852419Sjulian * may be used to endorse or promote products derived from this software 1952419Sjulian * without specific prior written permission. 2052419Sjulian * 2152419Sjulian * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2252419Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2352419Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2452419Sjulian * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2552419Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2652419Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2752419Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2852419Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2952419Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3052419Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3152419Sjulian * SUCH DAMAGE. 3252419Sjulian */ 3352419Sjulian 3452419Sjulian#ifndef lint 3552419Sjulianstatic char copyright[] = 3652419Sjulian"@(#) Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994\n\ 3752419Sjulian The Regents of the University of California. All rights reserved.\n"; 3852419Sjulian#endif /* not lint */ 3952419Sjulian 4052419Sjulian#ifndef lint 4152419Sjulianstatic char sccsid[] = "@(#)login.c 8.4 (Berkeley) 4/2/94"; 4252419Sjulian#endif /* not lint */ 4352419Sjulian 4452419Sjulian/* 4552419Sjulian * login [ name ] 4652419Sjulian * login -h hostname (for telnetd, etc.) 4752419Sjulian * login -f name (for pre-authenticated login: datakit, xterm, etc.) 4852419Sjulian */ 4952419Sjulian 5052419Sjulian#include <sys/param.h> 5152419Sjulian#include <sys/stat.h> 5252419Sjulian#include <sys/time.h> 5352419Sjulian#include <sys/resource.h> 5452419Sjulian#include <sys/file.h> 5552419Sjulian 5652419Sjulian#include <err.h> 5752419Sjulian#include <errno.h> 5852843Sphk#include <grp.h> 5952816Sarchie#include <pwd.h> 6052419Sjulian#include <setjmp.h> 6152419Sjulian#include <signal.h> 6252419Sjulian#include <stdio.h> 6352419Sjulian#include <stdlib.h> 6452419Sjulian#include <string.h> 6553913Sarchie#include <syslog.h> 6652419Sjulian#include <ttyent.h> 6752419Sjulian#include <tzfile.h> 6852419Sjulian#include <unistd.h> 6952419Sjulian#include <utmp.h> 7052419Sjulian 7152419Sjulian#ifdef SKEY 7252419Sjulian#include <skey.h> 7352722Sjulian#endif 7452722Sjulian 7552722Sjulian#include "pathnames.h" 7652722Sjulian 7752722Sjulianvoid badlogin __P((char *)); 7852419Sjulianvoid checknologin __P((void)); 7952419Sjulianvoid dolastlog __P((int)); 8052419Sjulianvoid getloginname __P((void)); 8152419Sjulianvoid motd __P((void)); 8252419Sjulianint rootterm __P((char *)); 8352419Sjulianvoid sigint __P((int)); 8452722Sjulianvoid sleepexit __P((int)); 8552419Sjulianchar *stypeof __P((char *)); 8652419Sjulianvoid timedout __P((int)); 8752419Sjulianvoid login_fbtab __P((char *, uid_t, gid_t)); 8852419Sjulian#ifdef KERBEROS 8952419Sjulianint klogin __P((struct passwd *, char *, char *, char *)); 9052419Sjulian#endif 9152419Sjulian 9252419Sjulianextern void login __P((struct utmp *)); 9352419Sjulian 9452419Sjulian#define TTYGRPNAME "tty" /* name of group to own ttys */ 9552419Sjulian 9652722Sjulian/* 9752722Sjulian * This bounds the time given to login. Not a define so it can 9853403Sarchie * be patched on machines where it's too small. 9953403Sarchie */ 10053403Sarchieu_int timeout = 300; 10153403Sarchie 10253403Sarchie#ifdef KERBEROS 10353403Sarchieint notickets = 1; 10453403Sarchieint noticketsdontcomplain = 1; 10553403Sarchiechar *instance; 10653403Sarchiechar *krbtkfile_env; 10753403Sarchieint authok; 10853403Sarchie#endif 10953403Sarchie 11053403Sarchiestruct passwd *pwd; 11153403Sarchieint failures; 11253403Sarchiechar term[64], *envinit[1], *hostname, *username, *tty; 11353403Sarchie 11453403Sarchieint 11552722Sjulianmain(argc, argv) 11653403Sarchie int argc; 11752419Sjulian char *argv[]; 11853913Sarchie{ 11953913Sarchie extern char **environ; 12053913Sarchie struct group *gr; 12153913Sarchie struct stat st; 12253913Sarchie struct timeval tp; 12353913Sarchie struct utmp utmp; 12453913Sarchie int ask, ch, cnt, fflag, hflag, pflag, quietlog, rootlogin, rval; 12553913Sarchie int changepass; 12653913Sarchie uid_t uid; 12753913Sarchie char *domain, *p, *ep, *salt, *ttyn; 12853913Sarchie char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10]; 12953913Sarchie char localhost[MAXHOSTNAMELEN]; 13053913Sarchie char full_hostname[MAXHOSTNAMELEN]; 13153913Sarchie#ifdef SKEY 13253913Sarchie int permit_passwd = 0; 13353913Sarchie#endif 13453913Sarchie 13553913Sarchie (void)signal(SIGALRM, timedout); 13653913Sarchie (void)alarm(timeout); 13753913Sarchie (void)signal(SIGQUIT, SIG_IGN); 13853913Sarchie (void)signal(SIGINT, SIG_IGN); 13953913Sarchie (void)setpriority(PRIO_PROCESS, 0, 0); 14053913Sarchie 14153913Sarchie openlog("login", LOG_ODELAY, LOG_AUTH); 14253913Sarchie 14353913Sarchie /* 14453913Sarchie * -p is used by getty to tell login not to destroy the environment 14553913Sarchie * -f is used to skip a second login authentication 14653913Sarchie * -h is used by other servers to pass the name of the remote 14753913Sarchie * host to login so that it may be placed in utmp and wtmp 14853913Sarchie */ 14953913Sarchie *full_hostname = '\0'; 15053913Sarchie domain = NULL; 15153913Sarchie if (gethostname(localhost, sizeof(localhost)) < 0) 15253913Sarchie syslog(LOG_ERR, "couldn't get local hostname: %m"); 15353913Sarchie else 15453913Sarchie domain = strchr(localhost, '.'); 15553913Sarchie 15653913Sarchie fflag = hflag = pflag = 0; 15753913Sarchie uid = getuid(); 15853913Sarchie while ((ch = getopt(argc, argv, "fh:p")) != EOF) 15953913Sarchie switch (ch) { 16053913Sarchie case 'f': 16153913Sarchie fflag = 1; 16253913Sarchie break; 16353913Sarchie case 'h': 16453913Sarchie if (uid) 16553913Sarchie errx(1, "-h option: %s", strerror(EPERM)); 16653913Sarchie hflag = 1; 16753913Sarchie strncpy(full_hostname, optarg, sizeof(full_hostname)-1); 16853913Sarchie if (domain && (p = strchr(optarg, '.')) && 16953913Sarchie strcasecmp(p, domain) == 0) 17053913Sarchie *p = 0; 17153913Sarchie hostname = optarg; 17253913Sarchie break; 17353913Sarchie case 'p': 17453913Sarchie pflag = 1; 17553913Sarchie break; 17653913Sarchie case '?': 17753913Sarchie default: 17853913Sarchie if (!uid) 17953913Sarchie syslog(LOG_ERR, "invalid flag %c", ch); 18053913Sarchie (void)fprintf(stderr, 18153913Sarchie "usage: login [-fp] [-h hostname] [username]\n"); 18253913Sarchie exit(1); 18353913Sarchie } 18453913Sarchie argc -= optind; 18553913Sarchie argv += optind; 18653913Sarchie 18753913Sarchie if (*argv) { 18853913Sarchie username = *argv; 18953913Sarchie ask = 0; 19053913Sarchie } else 19153913Sarchie ask = 1; 19253913Sarchie 19353913Sarchie for (cnt = getdtablesize(); cnt > 2; cnt--) 19453913Sarchie (void)close(cnt); 19553913Sarchie 19653913Sarchie ttyn = ttyname(STDIN_FILENO); 19753913Sarchie if (ttyn == NULL || *ttyn == '\0') { 19853913Sarchie (void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY); 19953913Sarchie ttyn = tname; 20053913Sarchie } 20153913Sarchie if (tty = strrchr(ttyn, '/')) 20253913Sarchie ++tty; 20353913Sarchie else 20453913Sarchie tty = ttyn; 20553913Sarchie 20653913Sarchie for (cnt = 0;; ask = 1) { 20753913Sarchie if (ask) { 20853913Sarchie fflag = 0; 20953913Sarchie getloginname(); 21053913Sarchie } 21153913Sarchie rootlogin = 0; 21253913Sarchie#ifdef KERBEROS 21353913Sarchie if ((instance = strchr(username, '.')) != NULL) { 21453913Sarchie if (strncmp(instance, ".root", 5) == 0) 21553913Sarchie rootlogin = 1; 21653913Sarchie *instance++ = '\0'; 21753913Sarchie } else 21853913Sarchie instance = ""; 21953913Sarchie#endif 22053913Sarchie if (strlen(username) > UT_NAMESIZE) 22153913Sarchie username[UT_NAMESIZE] = '\0'; 22253913Sarchie 22353913Sarchie /* 22453913Sarchie * Note if trying multiple user names; log failures for 22553913Sarchie * previous user name, but don't bother logging one failure 22653913Sarchie * for nonexistent name (mistyped username). 22753913Sarchie */ 22853913Sarchie if (failures && strcmp(tbuf, username)) { 22953913Sarchie if (failures > (pwd ? 0 : 1)) 23053913Sarchie badlogin(tbuf); 23153913Sarchie failures = 0; 23253913Sarchie } 23353913Sarchie (void)strcpy(tbuf, username); 23453913Sarchie 23553913Sarchie if (pwd = getpwnam(username)) 23653913Sarchie salt = pwd->pw_passwd; 23753913Sarchie else 23853913Sarchie salt = "xx"; 23953913Sarchie 24053913Sarchie /* 24153913Sarchie * if we have a valid account name, and it doesn't have a 24253913Sarchie * password, or the -f option was specified and the caller 24353913Sarchie * is root or the caller isn't changing their uid, don't 24453913Sarchie * authenticate. 24553913Sarchie */ 24653913Sarchie if (pwd) { 24753913Sarchie if (pwd->pw_uid == 0) 24853913Sarchie rootlogin = 1; 24953913Sarchie 25053913Sarchie if (fflag && (uid == 0 || uid == pwd->pw_uid)) { 25153913Sarchie /* already authenticated */ 25253913Sarchie break; 25353913Sarchie } else if (pwd->pw_passwd[0] == '\0') { 25453913Sarchie /* pretend password okay */ 25553913Sarchie rval = 0; 25653913Sarchie goto ttycheck; 25753913Sarchie } 25853913Sarchie } 25953913Sarchie 26053913Sarchie fflag = 0; 26153913Sarchie 26253913Sarchie (void)setpriority(PRIO_PROCESS, 0, -4); 26353913Sarchie 26453913Sarchie#ifdef SKEY 26553913Sarchie permit_passwd = skeyaccess(username, tty, 26653913Sarchie hostname ? full_hostname : NULL, 26753913Sarchie NULL); 26853913Sarchie p = skey_getpass("Password:", pwd, permit_passwd); 26953913Sarchie ep = skey_crypt(p, salt, pwd, permit_passwd); 27053913Sarchie#else 27153913Sarchie p = getpass("Password:"); 27253913Sarchie ep = crypt(p, salt); 27353913Sarchie#endif 27453913Sarchie 27553913Sarchie if (pwd) { 27653913Sarchie#ifdef KERBEROS 27753913Sarchie#ifdef SKEY 27853913Sarchie /* 27953913Sarchie * Do not allow user to type in kerberos password 28053913Sarchie * over the net (actually, this is ok for encrypted 28153913Sarchie * links, but we have no way of determining if the 28253913Sarchie * link is encrypted. 28353913Sarchie */ 28453913Sarchie if (!permit_passwd) { 28553913Sarchie rval = 1; /* failed */ 28653913Sarchie } else 28753913Sarchie#endif 28853913Sarchie rval = klogin(pwd, instance, localhost, p); 28953913Sarchie if (rval != 0 && rootlogin && pwd->pw_uid != 0) 29053913Sarchie rootlogin = 0; 29152419Sjulian if (rval == 0) 29252419Sjulian authok = 1; 29352419Sjulian else if (rval == 1) 29452419Sjulian rval = strcmp(ep, pwd->pw_passwd); 29552419Sjulian#else 29652419Sjulian rval = strcmp(ep, pwd->pw_passwd); 29752419Sjulian#endif 29852419Sjulian } 29952419Sjulian memset(p, 0, strlen(p)); 30052419Sjulian 30152419Sjulian (void)setpriority(PRIO_PROCESS, 0, 0); 30252419Sjulian 30352419Sjulian ttycheck: 30452419Sjulian /* 30552419Sjulian * If trying to log in as root without Kerberos, 30652419Sjulian * but with insecure terminal, refuse the login attempt. 30752419Sjulian */ 30852419Sjulian#ifdef KERBEROS 30952419Sjulian if (authok == 0) 31052419Sjulian#endif 31152419Sjulian if (pwd && !rval && rootlogin && !rootterm(tty)) { 31252419Sjulian (void)fprintf(stderr, 31352419Sjulian "%s login refused on this terminal.\n", 31452419Sjulian pwd->pw_name); 31552419Sjulian if (hostname) 31652419Sjulian syslog(LOG_NOTICE, 31752419Sjulian "LOGIN %s REFUSED FROM %s ON TTY %s", 31852419Sjulian pwd->pw_name, hostname, tty); 31952419Sjulian else 32052419Sjulian syslog(LOG_NOTICE, 32152419Sjulian "LOGIN %s REFUSED ON TTY %s", 32252419Sjulian pwd->pw_name, tty); 32352419Sjulian continue; 32452419Sjulian } 32552419Sjulian 32652419Sjulian if (pwd && !rval) 32752419Sjulian break; 32852419Sjulian 32952419Sjulian (void)printf("Login incorrect\n"); 33052419Sjulian failures++; 33152419Sjulian /* we allow 10 tries, but after 3 we start backing off */ 33252419Sjulian if (++cnt > 3) { 33352419Sjulian if (cnt >= 10) { 33452419Sjulian badlogin(username); 33552419Sjulian sleepexit(1); 33652419Sjulian } 33752419Sjulian sleep((u_int)((cnt - 3) * 5)); 33852419Sjulian } 33952419Sjulian } 34052419Sjulian 34152419Sjulian /* committed to login -- turn off timeout */ 34252419Sjulian (void)alarm((u_int)0); 34352419Sjulian 34452419Sjulian endpwent(); 34552419Sjulian 34652419Sjulian /* if user not super-user, check for disabled logins */ 34752419Sjulian if (!rootlogin) 34852419Sjulian checknologin(); 34952419Sjulian 35052419Sjulian if (chdir(pwd->pw_dir) < 0) { 35152419Sjulian (void)printf("No home directory %s!\n", pwd->pw_dir); 35252419Sjulian if (chdir("/")) 35352419Sjulian exit(0); 35452419Sjulian pwd->pw_dir = "/"; 35552419Sjulian (void)printf("Logging in with home = \"/\".\n"); 35652419Sjulian } 35752419Sjulian 35852419Sjulian quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0; 35952419Sjulian 36052419Sjulian if (pwd->pw_change || pwd->pw_expire) 36152419Sjulian (void)gettimeofday(&tp, (struct timezone *)NULL); 36252419Sjulian 36352419Sjulian changepass=0; 36452419Sjulian if (pwd->pw_change) 36552419Sjulian if (tp.tv_sec >= pwd->pw_change) { 36652419Sjulian (void)printf("Sorry -- your password has expired.\n"); 36752419Sjulian changepass=1; 36852722Sjulian } else if (pwd->pw_change - tp.tv_sec < 36952722Sjulian 2 * DAYSPERWEEK * SECSPERDAY && !quietlog) 37052722Sjulian (void)printf("Warning: your password expires on %s", 37152722Sjulian ctime(&pwd->pw_change)); 37252419Sjulian if (pwd->pw_expire) 37352419Sjulian if (tp.tv_sec >= pwd->pw_expire) { 37452419Sjulian (void)printf("Sorry -- your account has expired.\n"); 37552419Sjulian sleepexit(1); 37652419Sjulian } else if (pwd->pw_expire - tp.tv_sec < 37752419Sjulian 2 * DAYSPERWEEK * SECSPERDAY && !quietlog) 37852419Sjulian (void)printf("Warning: your account expires on %s", 37952419Sjulian ctime(&pwd->pw_expire)); 38052419Sjulian 38152419Sjulian /* Nothing else left to fail -- really log in. */ 38252419Sjulian memset((void *)&utmp, 0, sizeof(utmp)); 38352419Sjulian (void)time(&utmp.ut_time); 38452419Sjulian (void)strncpy(utmp.ut_name, username, sizeof(utmp.ut_name)); 38552419Sjulian if (hostname) 38652419Sjulian (void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host)); 38752419Sjulian (void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line)); 38852419Sjulian login(&utmp); 38952419Sjulian 39052419Sjulian dolastlog(quietlog); 39152419Sjulian 39252419Sjulian /* 39352419Sjulian * Set device protections, depending on what terminal the 39452419Sjulian * user is logged in. This feature is used on Suns to give 39552419Sjulian * console users better privacy. 39652419Sjulian */ 39752419Sjulian login_fbtab(tty, pwd->pw_uid, pwd->pw_gid); 39852419Sjulian 39952419Sjulian (void)chown(ttyn, pwd->pw_uid, 40052419Sjulian (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid); 40152419Sjulian (void)setgid(pwd->pw_gid); 40252419Sjulian 40352419Sjulian initgroups(username, pwd->pw_gid); 40452419Sjulian 40552419Sjulian if (*pwd->pw_shell == '\0') 40652419Sjulian pwd->pw_shell = _PATH_BSHELL; 40752419Sjulian 40852419Sjulian /* Destroy environment unless user has requested its preservation. */ 40952419Sjulian if (!pflag) 41052419Sjulian environ = envinit; 41152419Sjulian (void)setenv("HOME", pwd->pw_dir, 1); 41252419Sjulian (void)setenv("SHELL", pwd->pw_shell, 1); 41352419Sjulian if (term[0] == '\0') 41452419Sjulian (void)strncpy(term, stypeof(tty), sizeof(term)); 41552419Sjulian (void)setenv("TERM", term, 0); 41652419Sjulian (void)setenv("LOGNAME", pwd->pw_name, 1); 41752419Sjulian (void)setenv("USER", pwd->pw_name, 1); 41852419Sjulian (void)setenv("PATH", _PATH_DEFPATH, 0); 41952419Sjulian#ifdef KERBEROS 42052419Sjulian if (krbtkfile_env) 42152419Sjulian (void)setenv("KRBTKFILE", krbtkfile_env, 1); 42252419Sjulian#endif 42352419Sjulian 42452419Sjulian if (tty[sizeof("tty")-1] == 'd') 42552419Sjulian syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name); 42652419Sjulian 42752419Sjulian /* If fflag is on, assume caller/authenticator has logged root login. */ 42852419Sjulian if (rootlogin && fflag == 0) 42952419Sjulian if (hostname) 43052419Sjulian syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s", 43152419Sjulian username, tty, hostname); 43252419Sjulian else 43352419Sjulian syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s", username, tty); 43452419Sjulian 43552419Sjulian#ifdef KERBEROS 43652419Sjulian if (!quietlog && notickets == 1 && !noticketsdontcomplain) 43752419Sjulian (void)printf("Warning: no Kerberos tickets issued.\n"); 43852419Sjulian#endif 43952419Sjulian 44052722Sjulian#ifdef LOGALL 44152419Sjulian /* 44252419Sjulian * Syslog each successful login, so we don't have to watch hundreds 44352419Sjulian * of wtmp or lastlogin files. 44452419Sjulian */ 44552419Sjulian if (hostname) { 44652419Sjulian syslog(LOG_INFO, "login from %s as %s", hostname, pwd->pw_name); 44752419Sjulian } else { 44852419Sjulian syslog(LOG_INFO, "login on %s as %s", tty, pwd->pw_name); 44952419Sjulian } 45052419Sjulian#endif 45152419Sjulian 45252419Sjulian if (!quietlog) { 45352419Sjulian (void)printf("%s\n\t%s %s\n\n", 45452419Sjulian "Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994", 45552419Sjulian "The Regents of the University of California. ", 45652419Sjulian "All rights reserved."); 45752419Sjulian motd(); 45852419Sjulian (void)snprintf(tbuf, 45952419Sjulian sizeof(tbuf), "%s/%s", _PATH_MAILDIR, pwd->pw_name); 46052419Sjulian if (stat(tbuf, &st) == 0 && st.st_size != 0) 46152419Sjulian (void)printf("You have %smail.\n", 46252419Sjulian (st.st_mtime > st.st_atime) ? "new " : ""); 46352419Sjulian } 46452419Sjulian 46552419Sjulian#ifdef LOGIN_ACCESS 46653403Sarchie if (login_access(pwd->pw_name, hostname ? full_hostname : tty) == 0) { 46753403Sarchie printf("Permission denied\n"); 46852419Sjulian if (hostname) 46952419Sjulian syslog(LOG_NOTICE, "%s LOGIN REFUSED FROM %s", 47052419Sjulian pwd->pw_name, hostname); 47152419Sjulian else 47252419Sjulian syslog(LOG_NOTICE, "%s LOGIN REFUSED ON %s", 47352419Sjulian pwd->pw_name, tty); 47452419Sjulian sleepexit(1); 47552419Sjulian } 47652419Sjulian#endif 47752419Sjulian 47852419Sjulian (void)signal(SIGALRM, SIG_DFL); 47952419Sjulian (void)signal(SIGQUIT, SIG_DFL); 48052419Sjulian (void)signal(SIGINT, SIG_DFL); 48152419Sjulian (void)signal(SIGTSTP, SIG_IGN); 48252419Sjulian 48352419Sjulian tbuf[0] = '-'; 48452419Sjulian (void)strcpy(tbuf + 1, (p = strrchr(pwd->pw_shell, '/')) ? 48552419Sjulian p + 1 : pwd->pw_shell); 48652419Sjulian 48752419Sjulian if (setlogin(pwd->pw_name) < 0) 48852419Sjulian syslog(LOG_ERR, "setlogin() failure: %m"); 48952419Sjulian 49052419Sjulian /* Discard permissions last so can't get killed and drop core. */ 49152419Sjulian if (rootlogin) 49252419Sjulian (void) setuid(0); 49352419Sjulian else 49452419Sjulian (void) setuid(pwd->pw_uid); 49552419Sjulian 49652722Sjulian if (changepass) { 49752722Sjulian int res; 49852722Sjulian if ((res=system(_PATH_CHPASS))) 49952722Sjulian sleepexit(1); 50052722Sjulian } 50152722Sjulian 50252722Sjulian execlp(pwd->pw_shell, tbuf, 0); 50352722Sjulian err(1, "%s", pwd->pw_shell); 50452722Sjulian} 50552722Sjulian 50652722Sjulian#ifdef KERBEROS 50752722Sjulian#define NBUFSIZ (UT_NAMESIZE + 1 + 5) /* .root suffix */ 50852722Sjulian#else 50952722Sjulian#define NBUFSIZ (UT_NAMESIZE + 1) 51052722Sjulian#endif 51152722Sjulian 51252722Sjulianvoid 51352722Sjuliangetloginname() 51452722Sjulian{ 51552722Sjulian int ch; 51652419Sjulian char *p; 51752419Sjulian static char nbuf[NBUFSIZ]; 51852419Sjulian 51952419Sjulian for (;;) { 52052419Sjulian (void)printf("login: "); 52152419Sjulian for (p = nbuf; (ch = getchar()) != '\n'; ) { 52252419Sjulian if (ch == EOF) { 52352419Sjulian badlogin(username); 52452419Sjulian exit(0); 52552419Sjulian } 52652419Sjulian if (p < nbuf + (NBUFSIZ - 1)) 52752419Sjulian *p++ = ch; 52852419Sjulian } 52952419Sjulian if (p > nbuf) 53052419Sjulian if (nbuf[0] == '-') 53152419Sjulian (void)fprintf(stderr, 53252419Sjulian "login names may not start with '-'.\n"); 53352419Sjulian else { 53452419Sjulian *p = '\0'; 53552419Sjulian username = nbuf; 53652722Sjulian break; 53752419Sjulian } 53852419Sjulian } 53952419Sjulian} 54052419Sjulian 54152419Sjulianint 54252419Sjulianrootterm(ttyn) 54352419Sjulian char *ttyn; 54452419Sjulian{ 54552419Sjulian struct ttyent *t; 54652419Sjulian 54752419Sjulian return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE); 54852419Sjulian} 54952419Sjulian 55052419Sjulianjmp_buf motdinterrupt; 55152419Sjulian 55252419Sjulianvoid 55352419Sjulianmotd() 55452419Sjulian{ 55552419Sjulian int fd, nchars; 55652419Sjulian sig_t oldint; 55752419Sjulian char tbuf[8192]; 55852419Sjulian 55952419Sjulian if ((fd = open(_PATH_MOTDFILE, O_RDONLY, 0)) < 0) 56052419Sjulian return; 56152419Sjulian oldint = signal(SIGINT, sigint); 56252419Sjulian if (setjmp(motdinterrupt) == 0) 56352419Sjulian while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) 56452419Sjulian (void)write(fileno(stdout), tbuf, nchars); 56552419Sjulian (void)signal(SIGINT, oldint); 56652419Sjulian (void)close(fd); 56752419Sjulian} 56852419Sjulian 56952419Sjulian/* ARGSUSED */ 57052419Sjulianvoid 57152419Sjuliansigint(signo) 57252419Sjulian int signo; 57352419Sjulian{ 57452419Sjulian 57552419Sjulian longjmp(motdinterrupt, 1); 57652722Sjulian} 57752722Sjulian 57852419Sjulian/* ARGSUSED */ 57952419Sjulianvoid 58052419Sjuliantimedout(signo) 58152419Sjulian int signo; 58252419Sjulian{ 58352419Sjulian 58452722Sjulian (void)fprintf(stderr, "Login timed out after %d seconds\n", timeout); 58552722Sjulian exit(0); 58652419Sjulian} 58752419Sjulian 58852419Sjulianvoid 58952419Sjulianchecknologin() 59052419Sjulian{ 59152419Sjulian int fd, nchars; 59252419Sjulian char tbuf[8192]; 59352419Sjulian 59452419Sjulian if ((fd = open(_PATH_NOLOGIN, O_RDONLY, 0)) >= 0) { 59552419Sjulian while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) 59652419Sjulian (void)write(fileno(stdout), tbuf, nchars); 59752722Sjulian sleepexit(0); 59852722Sjulian } 59952419Sjulian} 60052722Sjulian 60152419Sjulianvoid 60252419Sjuliandolastlog(quiet) 60352816Sarchie int quiet; 60453648Sarchie{ 60552816Sarchie struct lastlog ll; 60652419Sjulian int fd; 60752816Sarchie 60852816Sarchie if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) { 60952951Sjulian (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); 61052816Sarchie if (!quiet) { 61152419Sjulian if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) && 61252816Sarchie ll.ll_time != 0) { 61352816Sarchie (void)printf("Last login: %.*s ", 61452951Sjulian 24-5, (char *)ctime(&ll.ll_time)); 61553042Sjulian if (*ll.ll_host != '\0') 61652816Sarchie (void)printf("from %.*s\n", 61752419Sjulian (int)sizeof(ll.ll_host), 61852419Sjulian ll.ll_host); 61952419Sjulian else 62052419Sjulian (void)printf("on %.*s\n", 62152419Sjulian (int)sizeof(ll.ll_line), 62252419Sjulian ll.ll_line); 62352419Sjulian } 62452419Sjulian (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); 62552419Sjulian } 62652419Sjulian memset((void *)&ll, 0, sizeof(ll)); 62752419Sjulian (void)time(&ll.ll_time); 62852419Sjulian (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); 62952419Sjulian if (hostname) 63052419Sjulian (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host)); 63152419Sjulian (void)write(fd, (char *)&ll, sizeof(ll)); 63252419Sjulian (void)close(fd); 63352419Sjulian } 63452419Sjulian} 63552419Sjulian 63652419Sjulianvoid 63752419Sjulianbadlogin(name) 63852419Sjulian char *name; 63952419Sjulian{ 64052419Sjulian 64152419Sjulian if (failures == 0) 64252419Sjulian return; 64352419Sjulian if (hostname) { 64452419Sjulian syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s", 64552419Sjulian failures, failures > 1 ? "S" : "", hostname); 64652419Sjulian syslog(LOG_AUTHPRIV|LOG_NOTICE, 64752419Sjulian "%d LOGIN FAILURE%s FROM %s, %s", 64852419Sjulian failures, failures > 1 ? "S" : "", hostname, name); 64952419Sjulian } else { 65052419Sjulian syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s", 65152419Sjulian failures, failures > 1 ? "S" : "", tty); 65252419Sjulian syslog(LOG_AUTHPRIV|LOG_NOTICE, 65352419Sjulian "%d LOGIN FAILURE%s ON %s, %s", 65452419Sjulian failures, failures > 1 ? "S" : "", tty, name); 65552419Sjulian } 65652419Sjulian} 65752419Sjulian 65852419Sjulian#undef UNKNOWN 65952419Sjulian#define UNKNOWN "su" 66052419Sjulian 66152419Sjulianchar * 66252419Sjulianstypeof(ttyid) 66352419Sjulian char *ttyid; 66452419Sjulian{ 66554096Sarchie struct ttyent *t; 66654096Sarchie 66754096Sarchie return (ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN); 66852419Sjulian} 66952419Sjulian 67052419Sjulianvoid 67152419Sjuliansleepexit(eval) 67252419Sjulian int eval; 67352419Sjulian{ 67452419Sjulian 67552419Sjulian (void)sleep(5); 67652419Sjulian exit(eval); 67752419Sjulian} 67852419Sjulian 67952419Sjulian 68052419Sjulian