login.c revision 3205
1100894Srwatson/*- 2100894Srwatson * Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994 3100894Srwatson * The Regents of the University of California. All rights reserved. 4100894Srwatson * 5100894Srwatson * Redistribution and use in source and binary forms, with or without 6100894Srwatson * modification, are permitted provided that the following conditions 7100894Srwatson * are met: 8100894Srwatson * 1. Redistributions of source code must retain the above copyright 9100894Srwatson * notice, this list of conditions and the following disclaimer. 10100894Srwatson * 2. Redistributions in binary form must reproduce the above copyright 11100894Srwatson * notice, this list of conditions and the following disclaimer in the 12100894Srwatson * documentation and/or other materials provided with the distribution. 13100894Srwatson * 3. All advertising materials mentioning features or use of this software 14100894Srwatson * must display the following acknowledgement: 15100894Srwatson * This product includes software developed by the University of 16100894Srwatson * California, Berkeley and its contributors. 17100894Srwatson * 4. Neither the name of the University nor the names of its contributors 18100894Srwatson * may be used to endorse or promote products derived from this software 19100894Srwatson * without specific prior written permission. 20100894Srwatson * 21100894Srwatson * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22100894Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23100894Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24100894Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25100894Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26100894Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27100894Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28100894Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29100894Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30100894Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31100894Srwatson * SUCH DAMAGE. 32100894Srwatson */ 33100894Srwatson 34100894Srwatson#ifndef lint 35100894Srwatsonstatic char copyright[] = 36100894Srwatson"@(#) Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994\n\ 37100894Srwatson The Regents of the University of California. All rights reserved.\n"; 38100894Srwatson#endif /* not lint */ 39100894Srwatson 40100894Srwatson#ifndef lint 41100894Srwatsonstatic char sccsid[] = "@(#)login.c 8.4 (Berkeley) 4/2/94"; 42100894Srwatson#endif /* not lint */ 43100894Srwatson 44100894Srwatson/* 45100894Srwatson * login [ name ] 46100894Srwatson * login -h hostname (for telnetd, etc.) 47100894Srwatson * login -f name (for pre-authenticated login: datakit, xterm, etc.) 48100894Srwatson */ 49104300Sphk 50101173Srwatson#include <sys/param.h> 51100894Srwatson#include <sys/stat.h> 52100979Srwatson#include <sys/time.h> 53100979Srwatson#include <sys/resource.h> 54100979Srwatson#include <sys/file.h> 55102949Sbde 56100979Srwatson#include <err.h> 57100979Srwatson#include <errno.h> 58101712Srwatson#include <grp.h> 59100979Srwatson#include <pwd.h> 60100979Srwatson#include <setjmp.h> 61100894Srwatson#include <signal.h> 62100894Srwatson#include <stdio.h> 63100979Srwatson#include <stdlib.h> 64100979Srwatson#include <string.h> 65100979Srwatson#include <syslog.h> 66100979Srwatson#include <ttyent.h> 67100979Srwatson#include <tzfile.h> 68100979Srwatson#include <unistd.h> 69100979Srwatson#include <utmp.h> 70100979Srwatson 71100894Srwatson#include "pathnames.h" 72100979Srwatson 73100979Srwatsonvoid badlogin __P((char *)); 74100979Srwatsonvoid checknologin __P((void)); 75100979Srwatsonvoid dolastlog __P((int)); 76100979Srwatsonvoid getloginname __P((void)); 77100979Srwatsonvoid motd __P((void)); 78100979Srwatsonvoid change_passwd __P((void)); 79100979Srwatsonint rootterm __P((char *)); 80100979Srwatsonvoid sigint __P((int)); 81100979Srwatsonvoid sleepexit __P((int)); 82100979Srwatsonchar *stypeof __P((char *)); 83100979Srwatsonvoid timedout __P((int)); 84100979Srwatsonvoid login_fbtab __P((char *, uid_t, gid_t)); 85100979Srwatson#ifdef KERBEROS 86100979Srwatsonint klogin __P((struct passwd *, char *, char *, char *)); 87100979Srwatson#endif 88100979Srwatson 89100979Srwatsonextern void login __P((struct utmp *)); 90101712Srwatson 91101712Srwatson#define TTYGRPNAME "tty" /* name of group to own ttys */ 92101712Srwatson 93101712Srwatson/* 94101712Srwatson * This bounds the time given to login. Not a define so it can 95101712Srwatson * be patched on machines where it's too small. 96101712Srwatson */ 97100979Srwatsonu_int timeout = 300; 98100979Srwatson 99100979Srwatson#ifdef KERBEROS 100100979Srwatsonint notickets = 1; 101100979Srwatsonchar *instance; 102100979Srwatsonchar *krbtkfile_env; 103100979Srwatsonint authok; 104100979Srwatson#endif 105100979Srwatson 106100979Srwatsonstruct passwd *pwd; 107100979Srwatsonint failures; 108100979Srwatsonchar term[64], *envinit[1], *hostname, *username, *tty; 109100979Srwatson 110100979Srwatsonint 111100979Srwatsonmain(argc, argv) 112100979Srwatson int argc; 113100979Srwatson char *argv[]; 114100979Srwatson{ 115100979Srwatson extern char **environ; 116100979Srwatson struct group *gr; 117100979Srwatson struct stat st; 118100979Srwatson struct timeval tp; 119100979Srwatson struct utmp utmp; 120100979Srwatson int ask, ch, cnt, fflag, hflag, pflag, quietlog, rootlogin, rval; 121100979Srwatson uid_t uid; 122100979Srwatson char *domain, *p, *ep, *salt, *ttyn; 123100979Srwatson char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10]; 124103513Srwatson char localhost[MAXHOSTNAMELEN]; 125103513Srwatson char full_hostname[MAXHOSTNAMELEN]; 126103513Srwatson#ifdef SKEY 127104236Srwatson int permit_passwd = 0; 128103513Srwatson char *skey_getpass(), *skey_crypt(); 129100979Srwatson#endif 130100979Srwatson 131100979Srwatson (void)signal(SIGALRM, timedout); 132100979Srwatson (void)alarm(timeout); 133100979Srwatson (void)signal(SIGQUIT, SIG_IGN); 134100979Srwatson (void)signal(SIGINT, SIG_IGN); 135100979Srwatson (void)setpriority(PRIO_PROCESS, 0, 0); 136100979Srwatson 137100979Srwatson openlog("login", LOG_ODELAY, LOG_AUTH); 138100979Srwatson 139103514Srwatson /* 140103514Srwatson * -p is used by getty to tell login not to destroy the environment 141103514Srwatson * -f is used to skip a second login authentication 142104236Srwatson * -h is used by other servers to pass the name of the remote 143103514Srwatson * host to login so that it may be placed in utmp and wtmp 144100979Srwatson */ 145100979Srwatson *full_hostname = '\0'; 146100979Srwatson domain = NULL; 147100979Srwatson if (gethostname(localhost, sizeof(localhost)) < 0) 148100979Srwatson syslog(LOG_ERR, "couldn't get local hostname: %m"); 149100979Srwatson else 150100979Srwatson domain = strchr(localhost, '.'); 151100979Srwatson 152100979Srwatson fflag = hflag = pflag = 0; 153100979Srwatson uid = getuid(); 154100979Srwatson while ((ch = getopt(argc, argv, "fh:p")) != EOF) 155100979Srwatson switch (ch) { 156100979Srwatson case 'f': 157100979Srwatson fflag = 1; 158100979Srwatson break; 159100979Srwatson case 'h': 160103136Srwatson if (uid) 161103136Srwatson errx(1, "-h option: %s", strerror(EPERM)); 162103136Srwatson hflag = 1; 163103136Srwatson strncpy(full_hostname, optarg, sizeof(full_hostname)-1); 164103136Srwatson if (domain && (p = strchr(optarg, '.')) && 165101892Srwatson strcasecmp(p, domain) == 0) 166100979Srwatson *p = 0; 167100979Srwatson hostname = optarg; 168100979Srwatson break; 169100979Srwatson case 'p': 170101988Srwatson pflag = 1; 171104268Srwatson break; 172104268Srwatson case '?': 173104268Srwatson default: 174104268Srwatson if (!uid) 175104268Srwatson syslog(LOG_ERR, "invalid flag %c", ch); 176104268Srwatson (void)fprintf(stderr, 177104268Srwatson "usage: login [-fp] [-h hostname] [username]\n"); 178104268Srwatson exit(1); 179104268Srwatson } 180104268Srwatson argc -= optind; 181100979Srwatson argv += optind; 182100979Srwatson 183100979Srwatson if (*argv) { 184100979Srwatson username = *argv; 185100979Srwatson ask = 0; 186100979Srwatson } else 187100979Srwatson ask = 1; 188100979Srwatson 189100979Srwatson for (cnt = getdtablesize(); cnt > 2; cnt--) 190100979Srwatson (void)close(cnt); 191100979Srwatson 192100979Srwatson ttyn = ttyname(STDIN_FILENO); 193100979Srwatson if (ttyn == NULL || *ttyn == '\0') { 194100979Srwatson (void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY); 195100979Srwatson ttyn = tname; 196100979Srwatson } 197100979Srwatson if (tty = strrchr(ttyn, '/')) 198100979Srwatson ++tty; 199100979Srwatson else 200100979Srwatson tty = ttyn; 201100979Srwatson 202100979Srwatson for (cnt = 0;; ask = 1) { 203100979Srwatson if (ask) { 204100979Srwatson fflag = 0; 205100979Srwatson getloginname(); 206101988Srwatson } 207100979Srwatson rootlogin = 0; 208100979Srwatson#ifdef KERBEROS 209100979Srwatson if ((instance = strchr(username, '.')) != NULL) { 210100979Srwatson if (strncmp(instance, ".root", 5) == 0) 211100979Srwatson rootlogin = 1; 212100979Srwatson *instance++ = '\0'; 213100979Srwatson } else 214100979Srwatson instance = ""; 215100979Srwatson#endif 216100979Srwatson if (strlen(username) > UT_NAMESIZE) 217100979Srwatson username[UT_NAMESIZE] = '\0'; 218100979Srwatson 219100979Srwatson /* 220100979Srwatson * Note if trying multiple user names; log failures for 221100979Srwatson * previous user name, but don't bother logging one failure 222100979Srwatson * for nonexistent name (mistyped username). 223100979Srwatson */ 224100979Srwatson if (failures && strcmp(tbuf, username)) { 225100979Srwatson if (failures > (pwd ? 0 : 1)) 226100979Srwatson badlogin(tbuf); 227100979Srwatson failures = 0; 228100979Srwatson } 229100979Srwatson (void)strcpy(tbuf, username); 230100979Srwatson 231100979Srwatson if (pwd = getpwnam(username)) 232100979Srwatson salt = pwd->pw_passwd; 233100979Srwatson else 234100979Srwatson salt = "xx"; 235100979Srwatson 236100979Srwatson /* 237100979Srwatson * if we have a valid account name, and it doesn't have a 238100979Srwatson * password, or the -f option was specified and the caller 239100979Srwatson * is root or the caller isn't changing their uid, don't 240100979Srwatson * authenticate. 241100979Srwatson */ 242100979Srwatson if (pwd) { 243100979Srwatson if (pwd->pw_uid == 0) 244100979Srwatson rootlogin = 1; 245100979Srwatson 246100979Srwatson if (fflag && (uid == 0 || uid == pwd->pw_uid)) { 247100979Srwatson /* already authenticated */ 248100979Srwatson break; 249100979Srwatson } else if (pwd->pw_passwd[0] == '\0') { 250100979Srwatson /* pretend password okay */ 251100979Srwatson rval = 0; 252100979Srwatson goto ttycheck; 253100979Srwatson } 254100979Srwatson } 255100979Srwatson 256100979Srwatson fflag = 0; 257100979Srwatson 258100979Srwatson (void)setpriority(PRIO_PROCESS, 0, -4); 259100979Srwatson 260100979Srwatson#ifdef SKEY 261100979Srwatson permit_passwd = skeyaccess(username, tty, 262100979Srwatson hostname ? full_hostname : NULL); 263100979Srwatson p = skey_getpass("Password:", pwd, permit_passwd); 264100979Srwatson ep = skey_crypt(p, salt, pwd, permit_passwd); 265100979Srwatson#else 266100979Srwatson p = getpass("Password:"); 267100979Srwatson ep = crypt(p, salt); 268100979Srwatson#endif 269100979Srwatson 270100979Srwatson if (pwd) { 271100979Srwatson#ifdef KERBEROS 272100979Srwatson rval = klogin(pwd, instance, localhost, p); 273100979Srwatson if (rval != 0 && rootlogin && pwd->pw_uid != 0) 274100979Srwatson rootlogin = 0; 275100979Srwatson if (rval == 0) 276100979Srwatson authok = 1; 277100979Srwatson else if (rval == 1) 278100979Srwatson rval = strcmp(ep, pwd->pw_passwd); 279100979Srwatson#else 280100979Srwatson rval = strcmp(ep, pwd->pw_passwd); 281100979Srwatson#endif 282100979Srwatson } 283100979Srwatson memset(p, 0, strlen(p)); 284100979Srwatson 285100979Srwatson (void)setpriority(PRIO_PROCESS, 0, 0); 286100979Srwatson 287100979Srwatson ttycheck: 288100979Srwatson /* 289100979Srwatson * If trying to log in as root without Kerberos, 290100979Srwatson * but with insecure terminal, refuse the login attempt. 291100979Srwatson */ 292100979Srwatson#ifdef KERBEROS 293100979Srwatson if (authok == 0) 294100979Srwatson#endif 295100979Srwatson if (pwd && !rval && rootlogin && !rootterm(tty)) { 296100979Srwatson (void)fprintf(stderr, 297100979Srwatson "%s login refused on this terminal.\n", 298100979Srwatson pwd->pw_name); 299100979Srwatson if (hostname) 300100979Srwatson syslog(LOG_NOTICE, 301100979Srwatson "LOGIN %s REFUSED FROM %s ON TTY %s", 302100979Srwatson pwd->pw_name, hostname, tty); 303100979Srwatson else 304100979Srwatson syslog(LOG_NOTICE, 305100979Srwatson "LOGIN %s REFUSED ON TTY %s", 306100979Srwatson pwd->pw_name, tty); 307100979Srwatson continue; 308100979Srwatson } 309100979Srwatson 310100979Srwatson if (pwd && !rval) 311100979Srwatson break; 312100979Srwatson 313100979Srwatson (void)printf("Login incorrect\n"); 314100979Srwatson failures++; 315100979Srwatson /* we allow 10 tries, but after 3 we start backing off */ 316100979Srwatson if (++cnt > 3) { 317100979Srwatson if (cnt >= 10) { 318100979Srwatson badlogin(username); 319100979Srwatson sleepexit(1); 320100979Srwatson } 321100979Srwatson sleep((u_int)((cnt - 3) * 5)); 322100979Srwatson } 323100979Srwatson } 324100979Srwatson 325100979Srwatson /* committed to login -- turn off timeout */ 326100979Srwatson (void)alarm((u_int)0); 327100979Srwatson 328100979Srwatson endpwent(); 329100979Srwatson 330100979Srwatson /* if user not super-user, check for disabled logins */ 331100979Srwatson if (!rootlogin) 332100979Srwatson checknologin(); 333100894Srwatson 334100979Srwatson if (chdir(pwd->pw_dir) < 0) { 335100979Srwatson (void)printf("No home directory %s!\n", pwd->pw_dir); 336100979Srwatson if (chdir("/")) 337100979Srwatson exit(0); 338100979Srwatson pwd->pw_dir = "/"; 339100979Srwatson (void)printf("Logging in with home = \"/\".\n"); 340100979Srwatson } 341100979Srwatson 342100979Srwatson quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0; 343100979Srwatson 344100979Srwatson if (pwd->pw_change || pwd->pw_expire) 345100979Srwatson (void)gettimeofday(&tp, (struct timezone *)NULL); 346100979Srwatson 347100979Srwatson if (pwd->pw_change) 348100979Srwatson if (tp.tv_sec >= pwd->pw_change) { 349100979Srwatson (void)printf("Sorry -- your password has expired.\n"); 350100979Srwatson change_passwd(); 351100979Srwatson } else if (pwd->pw_change - tp.tv_sec < 352100979Srwatson 2 * DAYSPERWEEK * SECSPERDAY && !quietlog) 353100979Srwatson (void)printf("Warning: your password expires on %s", 354100979Srwatson ctime(&pwd->pw_change)); 355100979Srwatson if (pwd->pw_expire) 356100979Srwatson if (tp.tv_sec >= pwd->pw_expire) { 357100979Srwatson (void)printf("Sorry -- your account has expired.\n"); 358100979Srwatson sleepexit(1); 359100979Srwatson } else if (pwd->pw_expire - tp.tv_sec < 360100979Srwatson 2 * DAYSPERWEEK * SECSPERDAY && !quietlog) 361100979Srwatson (void)printf("Warning: your account expires on %s", 362100979Srwatson ctime(&pwd->pw_expire)); 363100979Srwatson 364100979Srwatson /* Nothing else left to fail -- really log in. */ 365100979Srwatson memset((void *)&utmp, 0, sizeof(utmp)); 366100979Srwatson (void)time(&utmp.ut_time); 367100979Srwatson (void)strncpy(utmp.ut_name, username, sizeof(utmp.ut_name)); 368100979Srwatson if (hostname) 369100979Srwatson (void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host)); 370100979Srwatson (void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line)); 371100979Srwatson login(&utmp); 372100979Srwatson 373100979Srwatson dolastlog(quietlog); 374100979Srwatson 375103570Srwatson /* 376103570Srwatson * Set device protections, depending on what terminal the 377100979Srwatson * user is logged in. This feature is used on Suns to give 378100979Srwatson * console users better privacy. 379100979Srwatson */ 380100979Srwatson login_fbtab(tty, pwd->pw_uid, pwd->pw_gid); 381100979Srwatson 382100979Srwatson (void)chown(ttyn, pwd->pw_uid, 383100979Srwatson (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid); 384100979Srwatson (void)setgid(pwd->pw_gid); 385100979Srwatson 386100979Srwatson initgroups(username, pwd->pw_gid); 387100979Srwatson 388100979Srwatson if (*pwd->pw_shell == '\0') 389100979Srwatson pwd->pw_shell = _PATH_BSHELL; 390100979Srwatson 391100979Srwatson /* Destroy environment unless user has requested its preservation. */ 392100979Srwatson if (!pflag) 393102123Srwatson environ = envinit; 394102123Srwatson (void)setenv("HOME", pwd->pw_dir, 1); 395102123Srwatson (void)setenv("SHELL", pwd->pw_shell, 1); 396102123Srwatson if (term[0] == '\0') 397104514Srwatson (void)strncpy(term, stypeof(tty), sizeof(term)); 398104514Srwatson (void)setenv("TERM", term, 0); 399100979Srwatson (void)setenv("LOGNAME", pwd->pw_name, 1); 400100979Srwatson (void)setenv("USER", pwd->pw_name, 1); 401104514Srwatson (void)setenv("PATH", _PATH_DEFPATH, 0); 402104514Srwatson#ifdef KERBEROS 403100979Srwatson if (krbtkfile_env) 404100979Srwatson (void)setenv("KRBTKFILE", krbtkfile_env, 1); 405104514Srwatson#endif 406104514Srwatson 407100979Srwatson if (tty[sizeof("tty")-1] == 'd') 408100979Srwatson syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name); 409104514Srwatson 410104514Srwatson /* If fflag is on, assume caller/authenticator has logged root login. */ 411100979Srwatson if (rootlogin && fflag == 0) 412100979Srwatson if (hostname) 413104514Srwatson syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s", 414104514Srwatson username, tty, hostname); 415100979Srwatson else 416100979Srwatson syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s", username, tty); 417104514Srwatson 418104514Srwatson#ifdef KERBEROS 419100979Srwatson if (!quietlog && notickets == 1) 420100979Srwatson (void)printf("Warning: no Kerberos tickets issued.\n"); 421104514Srwatson#endif 422104514Srwatson 423100979Srwatson#ifdef LOGALL 424100979Srwatson /* 425104514Srwatson * Syslog each successful login, so we don't have to watch hundreds 426104514Srwatson * of wtmp or lastlogin files. 427100979Srwatson */ 428100979Srwatson if (hostname) { 429104514Srwatson syslog(LOG_INFO, "login from %s as %s", hostname, pwd->pw_name); 430104514Srwatson } else { 431100979Srwatson syslog(LOG_INFO, "login on %s as %s", tty, pwd->pw_name); 432100979Srwatson } 433104514Srwatson#endif 434104514Srwatson 435100979Srwatson if (!quietlog) { 436100979Srwatson (void)printf("%s\n\t%s %s\n\n", 437104514Srwatson "Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994", 438104514Srwatson "The Regents of the University of California. ", 439100979Srwatson "All rights reserved."); 440100979Srwatson motd(); 441104514Srwatson (void)snprintf(tbuf, 442104514Srwatson sizeof(tbuf), "%s/%s", _PATH_MAILDIR, pwd->pw_name); 443100979Srwatson if (stat(tbuf, &st) == 0 && st.st_size != 0) 444100979Srwatson (void)printf("You have %smail.\n", 445104514Srwatson (st.st_mtime > st.st_atime) ? "new " : ""); 446104514Srwatson } 447100979Srwatson 448100979Srwatson#ifdef LOGIN_ACCESS 449104514Srwatson if (login_access(pwd->pw_name, hostname ? full_hostname : tty) == 0) { 450104514Srwatson printf("Permission denied\n"); 451100979Srwatson if (hostname) 452100979Srwatson syslog(LOG_NOTICE, "%s LOGIN REFUSED FROM %s", 453104514Srwatson pwd->pw_name, hostname); 454104514Srwatson else 455100979Srwatson syslog(LOG_NOTICE, "%s LOGIN REFUSED ON %s", 456100979Srwatson pwd->pw_name, tty); 457104514Srwatson sleepexit(1); 458104514Srwatson } 459100979Srwatson#endif 460100979Srwatson 461104514Srwatson (void)signal(SIGALRM, SIG_DFL); 462104514Srwatson (void)signal(SIGQUIT, SIG_DFL); 463100979Srwatson (void)signal(SIGINT, SIG_DFL); 464100979Srwatson (void)signal(SIGTSTP, SIG_IGN); 465104514Srwatson 466104514Srwatson tbuf[0] = '-'; 467100979Srwatson (void)strcpy(tbuf + 1, (p = strrchr(pwd->pw_shell, '/')) ? 468100979Srwatson p + 1 : pwd->pw_shell); 469104514Srwatson 470104514Srwatson if (setlogin(pwd->pw_name) < 0) 471100979Srwatson syslog(LOG_ERR, "setlogin() failure: %m"); 472100979Srwatson 473104514Srwatson /* Discard permissions last so can't get killed and drop core. */ 474104514Srwatson if (rootlogin) 475100979Srwatson (void) setuid(0); 476100979Srwatson else 477104514Srwatson (void) setuid(pwd->pw_uid); 478104514Srwatson 479100979Srwatson execlp(pwd->pw_shell, tbuf, 0); 480100979Srwatson err(1, "%s", pwd->pw_shell); 481104514Srwatson} 482104514Srwatson 483100979Srwatson#ifdef KERBEROS 484100979Srwatson#define NBUFSIZ (UT_NAMESIZE + 1 + 5) /* .root suffix */ 485104514Srwatson#else 486104514Srwatson#define NBUFSIZ (UT_NAMESIZE + 1) 487104514Srwatson#endif 488104514Srwatson 489104514Srwatsonvoid 490104514Srwatsongetloginname() 491104514Srwatson{ 492104514Srwatson int ch; 493104514Srwatson char *p; 494104514Srwatson static char nbuf[NBUFSIZ]; 495104514Srwatson 496104514Srwatson for (;;) { 497104514Srwatson (void)printf("login: "); 498104514Srwatson for (p = nbuf; (ch = getchar()) != '\n'; ) { 499104514Srwatson if (ch == EOF) { 500104514Srwatson badlogin(username); 501100979Srwatson exit(0); 502100979Srwatson } 503100979Srwatson if (p < nbuf + (NBUFSIZ - 1)) 504100979Srwatson *p++ = ch; 505100979Srwatson } 506100979Srwatson if (p > nbuf) 507100979Srwatson if (nbuf[0] == '-') 508100979Srwatson (void)fprintf(stderr, 509100979Srwatson "login names may not start with '-'.\n"); 510100979Srwatson else { 511100979Srwatson *p = '\0'; 512100979Srwatson username = nbuf; 513100979Srwatson break; 514100979Srwatson } 515100979Srwatson } 516100979Srwatson} 517100979Srwatson 518100979Srwatsonint 519100979Srwatsonrootterm(ttyn) 520100979Srwatson char *ttyn; 521100979Srwatson{ 522100979Srwatson struct ttyent *t; 523100979Srwatson 524100979Srwatson return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE); 525100979Srwatson} 526100979Srwatson 527100979Srwatsonjmp_buf motdinterrupt; 528100979Srwatson 529100979Srwatsonvoid 530100979Srwatsonmotd() 531100979Srwatson{ 532100979Srwatson int fd, nchars; 533100979Srwatson sig_t oldint; 534100979Srwatson char tbuf[8192]; 535100979Srwatson 536100979Srwatson if ((fd = open(_PATH_MOTDFILE, O_RDONLY, 0)) < 0) 537100979Srwatson return; 538100979Srwatson oldint = signal(SIGINT, sigint); 539100979Srwatson if (setjmp(motdinterrupt) == 0) 540100979Srwatson while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) 541100979Srwatson (void)write(fileno(stdout), tbuf, nchars); 542100979Srwatson (void)signal(SIGINT, oldint); 543100979Srwatson (void)close(fd); 544100979Srwatson} 545100979Srwatson 546100979Srwatson/* ARGSUSED */ 547100979Srwatsonvoid 548100979Srwatsonsigint(signo) 549100979Srwatson int signo; 550100979Srwatson{ 551100979Srwatson 552100979Srwatson longjmp(motdinterrupt, 1); 553100979Srwatson} 554100979Srwatson 555100979Srwatson/* ARGSUSED */ 556100979Srwatsonvoid 557100979Srwatsontimedout(signo) 558100979Srwatson int signo; 559100979Srwatson{ 560100979Srwatson 561100979Srwatson (void)fprintf(stderr, "Login timed out after %d seconds\n", timeout); 562100979Srwatson exit(0); 563100979Srwatson} 564100979Srwatson 565100979Srwatsonvoid 566100979Srwatsonchecknologin() 567100979Srwatson{ 568100979Srwatson int fd, nchars; 569100979Srwatson char tbuf[8192]; 570100979Srwatson 571100979Srwatson if ((fd = open(_PATH_NOLOGIN, O_RDONLY, 0)) >= 0) { 572100979Srwatson while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) 573100979Srwatson (void)write(fileno(stdout), tbuf, nchars); 574100979Srwatson sleepexit(0); 575100979Srwatson } 576100979Srwatson} 577100979Srwatson 578100979Srwatsonvoid 579100979Srwatsondolastlog(quiet) 580100979Srwatson int quiet; 581100979Srwatson{ 582100979Srwatson struct lastlog ll; 583100979Srwatson int fd; 584100979Srwatson 585100979Srwatson if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) { 586100979Srwatson (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); 587100979Srwatson if (!quiet) { 588100979Srwatson if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) && 589100979Srwatson ll.ll_time != 0) { 590100979Srwatson (void)printf("Last login: %.*s ", 591100979Srwatson 24-5, (char *)ctime(&ll.ll_time)); 592100979Srwatson if (*ll.ll_host != '\0') 593100979Srwatson (void)printf("from %.*s\n", 594100979Srwatson (int)sizeof(ll.ll_host), 595100979Srwatson ll.ll_host); 596100979Srwatson else 597100979Srwatson (void)printf("on %.*s\n", 598100979Srwatson (int)sizeof(ll.ll_line), 599100979Srwatson ll.ll_line); 600100979Srwatson } 601100979Srwatson (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); 602100979Srwatson } 603100979Srwatson memset((void *)&ll, 0, sizeof(ll)); 604100979Srwatson (void)time(&ll.ll_time); 605100979Srwatson (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); 606100979Srwatson if (hostname) 607100979Srwatson (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host)); 608100979Srwatson (void)write(fd, (char *)&ll, sizeof(ll)); 609100979Srwatson (void)close(fd); 610100979Srwatson } 611100979Srwatson} 612100979Srwatson 613100979Srwatsonvoid 614100979Srwatsonbadlogin(name) 615100979Srwatson char *name; 616100979Srwatson{ 617100979Srwatson 618100979Srwatson if (failures == 0) 619100979Srwatson return; 620100979Srwatson if (hostname) { 621100979Srwatson syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s", 622100979Srwatson failures, failures > 1 ? "S" : "", hostname); 623100979Srwatson syslog(LOG_AUTHPRIV|LOG_NOTICE, 624100979Srwatson "%d LOGIN FAILURE%s FROM %s, %s", 625100979Srwatson failures, failures > 1 ? "S" : "", hostname, name); 626100979Srwatson } else { 627100979Srwatson syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s", 628100979Srwatson failures, failures > 1 ? "S" : "", tty); 629100979Srwatson syslog(LOG_AUTHPRIV|LOG_NOTICE, 630100979Srwatson "%d LOGIN FAILURE%s ON %s, %s", 631100979Srwatson failures, failures > 1 ? "S" : "", tty, name); 632100979Srwatson } 633100979Srwatson} 634100979Srwatson 635100979Srwatson#undef UNKNOWN 636100979Srwatson#define UNKNOWN "su" 637100979Srwatson 638100979Srwatsonchar * 639100979Srwatsonstypeof(ttyid) 640100979Srwatson char *ttyid; 641100979Srwatson{ 642100979Srwatson struct ttyent *t; 643100979Srwatson 644100979Srwatson return (ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN); 645100979Srwatson} 646100979Srwatson 647100979Srwatsonvoid 648100979Srwatsonsleepexit(eval) 649100979Srwatson int eval; 650100979Srwatson{ 651100979Srwatson 652100979Srwatson (void)sleep(5); 653100979Srwatson exit(eval); 654100979Srwatson} 655100979Srwatson 656100979Srwatsonvoid 657100979Srwatsonchange_passwd() 658100979Srwatson{ 659100979Srwatson int pid, status, w; 660100979Srwatson register void (*istat)(), (*qstat)(); 661100979Srwatson 662100979Srwatson if (( pid=fork() ) == 0) 663100979Srwatson { 664100979Srwatson execl( "/usr/bin/passwd", "passwd", NULL ); 665100979Srwatson fprintf( stderr, "ERROR: Can't execute passwd!\n" ); 666100979Srwatson sleepexit( 1 ); 667100979Srwatson } 668100979Srwatson 669100979Srwatson istat = signal( SIGINT, SIG_IGN ); 670100979Srwatson qstat = signal( SIGQUIT, SIG_IGN ); 671104338Srwatson 672104338Srwatson while ((w = wait( &status )) != pid && w != -1) 673104338Srwatson ; 674104338Srwatson 675100979Srwatson signal( SIGINT, istat ); 676100979Srwatson signal( SIGQUIT, qstat ); 677100979Srwatson} 678100979Srwatson 679100979Srwatson