119843Sdist /* 236515Sbostic * Copyright (c) 1980, 1987, 1988 The Regents of the University of California. 336515Sbostic * All rights reserved. 436515Sbostic * 536515Sbostic * Redistribution and use in source and binary forms are permitted 636515Sbostic * provided that the above copyright notice and this paragraph are 736515Sbostic * duplicated in all such forms and that any documentation, 836515Sbostic * advertising materials, and other materials related to such 936515Sbostic * distribution and use acknowledge that the software was developed 1036515Sbostic * by the University of California, Berkeley. The name of the 1136515Sbostic * University may not be used to endorse or promote products derived 1236515Sbostic * from this software without specific prior written permission. 1336515Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1436515Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1536515Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1619843Sdist */ 1719843Sdist 1812678Ssam #ifndef lint 1919843Sdist char copyright[] = 2036515Sbostic "@(#) Copyright (c) 1980, 1987, 1988 The Regents of the University of California.\n\ 2119843Sdist All rights reserved.\n"; 2236515Sbostic #endif /* not lint */ 2312678Ssam 2419843Sdist #ifndef lint 25*38034Skfall static char sccsid[] = "@(#)login.c 5.41 (Berkeley) 05/17/89"; 2636515Sbostic #endif /* not lint */ 2719843Sdist 281043Sbill /* 291043Sbill * login [ name ] 3031695Skarels * login -h hostname (for telnetd, etc.) 3131695Skarels * login -f name (for pre-authenticated login: datakit, xterm, etc.) 321043Sbill */ 331043Sbill 3412984Ssam #include <sys/param.h> 3537692Sbostic #include <ufs/quota.h> 3612687Ssam #include <sys/stat.h> 3712687Ssam #include <sys/time.h> 3812687Ssam #include <sys/resource.h> 3916453Sroot #include <sys/file.h> 4036460Sbostic #include <sys/ioctl.h> 4112687Ssam 421043Sbill #include <utmp.h> 431043Sbill #include <signal.h> 4412678Ssam #include <errno.h> 4516453Sroot #include <ttyent.h> 4616453Sroot #include <syslog.h> 4726862Smckusick #include <grp.h> 4836460Sbostic #include <pwd.h> 4936515Sbostic #include <setjmp.h> 5036460Sbostic #include <stdio.h> 5136460Sbostic #include <strings.h> 5237203Sbostic #include <tzfile.h> 5337203Sbostic #include "pathnames.h" 541043Sbill 5537203Sbostic #ifdef KERBEROS 5637203Sbostic #include <kerberos/krb.h> 5737203Sbostic #include <sys/termios.h> 58*38034Skfall #include <netdb.h> 59*38034Skfall char realm[REALM_SZ]; 60*38034Skfall int kerror = KSUCCESS, notickets = 1; 61*38034Skfall KTEXT_ST ticket; 62*38034Skfall AUTH_DAT authdata; 63*38034Skfall char savehost[MAXHOSTNAMELEN]; 64*38034Skfall unsigned long faddr; 65*38034Skfall struct hostent *hp; 66*38034Skfall #define PRINCIPAL_NAME pwd->pw_name 67*38034Skfall #define PRINCIPAL_INST "" 68*38034Skfall #define INITIAL_TICKET "krbtgt" 69*38034Skfall #define VERIFY_SERVICE "rcmd" 7037203Sbostic #endif 7137203Sbostic 7236460Sbostic #define TTYGRPNAME "tty" /* name of group to own ttys */ 7326862Smckusick 7412687Ssam /* 7536460Sbostic * This bounds the time given to login. Not a define so it can 7636460Sbostic * be patched on machines where it's too small. 7712687Ssam */ 7831509Sbostic int timeout = 300; 796005Swnj 8036647Skarels struct passwd *pwd; 8136647Skarels int failures; 8236647Skarels char term[64], *hostname, *username, *tty; 836005Swnj 8436647Skarels struct sgttyb sgttyb; 8536647Skarels struct tchars tc = { 8613074Ssam CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK 871365Sbill }; 8836647Skarels struct ltchars ltc = { 8913074Ssam CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE, CLNEXT 9013074Ssam }; 911365Sbill 9236880Sbostic char *months[] = 9336880Sbostic { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", 9436880Sbostic "Sep", "Oct", "Nov", "Dec" }; 9536880Sbostic 961043Sbill main(argc, argv) 9736460Sbostic int argc; 9836460Sbostic char **argv; 991043Sbill { 10036460Sbostic extern int errno, optind; 10136460Sbostic extern char *optarg, **environ; 10236880Sbostic struct timeval tp; 10336880Sbostic struct tm *ttp; 10436460Sbostic struct group *gr; 10536460Sbostic register int ch; 10636647Skarels register char *p; 10737203Sbostic int ask, fflag, hflag, pflag, cnt; 10836460Sbostic int quietlog, passwd_req, ioctlval, timedout(); 10936647Skarels char *domain, *salt, *envinit[1], *ttyn, *pp; 11037692Sbostic char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10]; 111*38034Skfall char localhost[MAXHOSTNAMELEN]; 11236880Sbostic char *ctime(), *ttyname(), *stypeof(), *crypt(), *getpass(); 11336460Sbostic time_t time(); 11436460Sbostic off_t lseek(); 1151043Sbill 11636460Sbostic (void)signal(SIGALRM, timedout); 11736460Sbostic (void)alarm((u_int)timeout); 11836460Sbostic (void)signal(SIGQUIT, SIG_IGN); 11936460Sbostic (void)signal(SIGINT, SIG_IGN); 12036460Sbostic (void)setpriority(PRIO_PROCESS, 0, 0); 12136460Sbostic (void)quota(Q_SETUID, 0, 0, 0); 12236460Sbostic 12312687Ssam /* 12418549Ssam * -p is used by getty to tell login not to destroy the environment 12531695Skarels * -f is used to skip a second login authentication 12636523Skarels * -h is used by other servers to pass the name of the remote 12736523Skarels * host to login so that it may be placed in utmp and wtmp 12812687Ssam */ 129*38034Skfall domain = NULL; 130*38034Skfall if (gethostname(localhost, sizeof(localhost)) < 0) 131*38034Skfall syslog(LOG_ERR, "couldn't get local hostname: %m"); 132*38034Skfall else 133*38034Skfall domain = index(localhost, '.'); 13436460Sbostic 13537203Sbostic fflag = hflag = pflag = 0; 13636460Sbostic passwd_req = 1; 13737203Sbostic while ((ch = getopt(argc, argv, "fh:p")) != EOF) 13836515Sbostic switch (ch) { 13936460Sbostic case 'f': 14036460Sbostic fflag = 1; 14136460Sbostic break; 14236460Sbostic case 'h': 14336460Sbostic if (getuid()) { 14437203Sbostic (void)fprintf(stderr, 14536460Sbostic "login: -h for super-user only.\n"); 14632313Sbostic exit(1); 14731695Skarels } 14836460Sbostic hflag = 1; 14936460Sbostic if (domain && (p = index(optarg, '.')) && 15036553Sbostic strcasecmp(p, domain) == 0) 15136460Sbostic *p = 0; 15236460Sbostic hostname = optarg; 15336460Sbostic break; 15436460Sbostic case 'p': 15518549Ssam pflag = 1; 15636460Sbostic break; 15736460Sbostic case '?': 15836460Sbostic default: 15937203Sbostic (void)fprintf(stderr, 16037203Sbostic "usage: login [-fp] [username]\n"); 16136460Sbostic exit(1); 16218549Ssam } 16336460Sbostic argc -= optind; 16436460Sbostic argv += optind; 16536549Sbostic if (*argv) { 16636647Skarels username = *argv; 16736549Sbostic ask = 0; 16836647Skarels } else 16936549Sbostic ask = 1; 17036460Sbostic 17136460Sbostic ioctlval = 0; 17236460Sbostic (void)ioctl(0, TIOCLSET, &ioctlval); 17336460Sbostic (void)ioctl(0, TIOCNXCL, 0); 17436515Sbostic (void)fcntl(0, F_SETFL, ioctlval); 17536515Sbostic (void)ioctl(0, TIOCGETP, &sgttyb); 17636515Sbostic sgttyb.sg_erase = CERASE; 17736515Sbostic sgttyb.sg_kill = CKILL; 17836460Sbostic (void)ioctl(0, TIOCSLTC, <c); 17936460Sbostic (void)ioctl(0, TIOCSETC, &tc); 18036515Sbostic (void)ioctl(0, TIOCSETP, &sgttyb); 18136460Sbostic 18236460Sbostic for (cnt = getdtablesize(); cnt > 2; cnt--) 18336460Sbostic close(cnt); 18436460Sbostic 1851043Sbill ttyn = ttyname(0); 18637692Sbostic if (ttyn == NULL || *ttyn == '\0') { 18737692Sbostic (void)sprintf(tname, "%s??", _PATH_TTY); 18837692Sbostic ttyn = tname; 18937692Sbostic } 19036460Sbostic if (tty = rindex(ttyn, '/')) 19136460Sbostic ++tty; 19236460Sbostic else 19316453Sroot tty = ttyn; 19436460Sbostic 19524852Seric openlog("login", LOG_ODELAY, LOG_AUTH); 19636460Sbostic 19736549Sbostic for (cnt = 0;; ask = 1) { 19836460Sbostic ioctlval = 0; 19936460Sbostic (void)ioctl(0, TIOCSETD, &ioctlval); 20036460Sbostic 20136549Sbostic if (ask) { 20236515Sbostic fflag = 0; 20336460Sbostic getloginname(); 20436515Sbostic } 20536647Skarels /* 20636647Skarels * Note if trying multiple user names; 20736647Skarels * log failures for previous user name, 20836647Skarels * but don't bother logging one failure 20936647Skarels * for nonexistent name (mistyped username). 21036647Skarels */ 21136647Skarels if (failures && strcmp(tbuf, username)) { 21236647Skarels if (failures > (pwd ? 0 : 1)) 21336549Sbostic badlogin(tbuf); 21436647Skarels failures = 0; 21536549Sbostic } 21636647Skarels (void)strcpy(tbuf, username); 21736515Sbostic if (pwd = getpwnam(username)) 21836515Sbostic salt = pwd->pw_passwd; 21936515Sbostic else 22036515Sbostic salt = "xx"; 22136460Sbostic 22236460Sbostic /* if user not super-user, check for disabled logins */ 22336515Sbostic if (pwd == NULL || pwd->pw_uid) 22436460Sbostic checknologin(); 22536460Sbostic 22612687Ssam /* 22736515Sbostic * Disallow automatic login to root; if not invoked by 22836515Sbostic * root, disallow if the uid's differ. 22912687Ssam */ 23036515Sbostic if (fflag && pwd) { 23131695Skarels int uid = getuid(); 23231695Skarels 23336515Sbostic passwd_req = pwd->pw_uid == 0 || 23436515Sbostic (uid && uid != pwd->pw_uid); 23531695Skarels } 23636460Sbostic 23712687Ssam /* 23836523Skarels * If no pre-authentication and a password exists 23936460Sbostic * for this user, prompt for one and verify it. 24012687Ssam */ 24136608Skfall if (!passwd_req || (pwd && !*pwd->pw_passwd)) 24236460Sbostic break; 24312687Ssam 24436460Sbostic setpriority(PRIO_PROCESS, 0, -4); 24536608Skfall pp = getpass("Password:"); 24636608Skfall p = crypt(pp, salt); 24736460Sbostic setpriority(PRIO_PROCESS, 0, 0); 24836608Skfall 24937203Sbostic #ifdef KERBEROS 25037203Sbostic 25137203Sbostic /* 25237203Sbostic * If not present in pw file, act as we normally would. 25337203Sbostic * If we aren't Kerberos-authenticated, try the normal 25437203Sbostic * pw file for a password. If that's ok, log the user 25537203Sbostic * in without issueing any tickets. 25637203Sbostic */ 25737203Sbostic 258*38034Skfall if (pwd && (krb_get_lrealm(realm,1) == KSUCCESS)) { 25937203Sbostic /* 26037203Sbostic * get TGT for local realm; be careful about uid's 26137203Sbostic * here for ticket file ownership 26237203Sbostic */ 26337203Sbostic (void)setreuid(geteuid(),pwd->pw_uid); 264*38034Skfall kerror = krb_get_pw_in_tkt( 265*38034Skfall PRINCIPAL_NAME, PRINCIPAL_INST, realm, 266*38034Skfall INITIAL_TICKET, realm, DEFAULT_TKT_LIFE, pp); 26737203Sbostic (void)setuid(0); 268*38034Skfall /* 269*38034Skfall * If we got a TGT, get a local "rcmd" ticket and 270*38034Skfall * check it so as to ensure that we are not 271*38034Skfall * talking to a bogus Kerberos server 272*38034Skfall */ 27337203Sbostic if (kerror == INTK_OK) { 274*38034Skfall (void) strncpy(savehost, 275*38034Skfall krb_get_phost(localhost), 276*38034Skfall sizeof(savehost)); 277*38034Skfall savehost[sizeof(savehost)-1] = NULL; 278*38034Skfall kerror = krb_mk_req(&ticket, VERIFY_SERVICE, 279*38034Skfall savehost, realm, 33); 280*38034Skfall if (kerror == KDC_PR_UNKNOWN) { 281*38034Skfall syslog(LOG_WARNING, 282*38034Skfall "Warning: TGT not verified (%s)", 283*38034Skfall krb_err_txt[kerror]); 284*38034Skfall bzero(pp, strlen(pp)); 285*38034Skfall notickets = 0; 286*38034Skfall break; /* ok */ 287*38034Skfall } else if (kerror != KSUCCESS) { 288*38034Skfall printf("Unable to use TGT: (%s)\n", 289*38034Skfall krb_err_txt[kerror]); 290*38034Skfall syslog(LOG_WARNING, 291*38034Skfall "Unable to use TGT: (%s)", 292*38034Skfall krb_err_txt[kerror]); 293*38034Skfall dest_tkt(); 294*38034Skfall /* fall thru: no login */ 295*38034Skfall } else { 296*38034Skfall if (!(hp = gethostbyname(localhost))) { 297*38034Skfall syslog(LOG_ERR, "couldn't get local host address"); 298*38034Skfall } else { 299*38034Skfall bcopy((char *) hp->h_addr, 300*38034Skfall (char *) &faddr, sizeof(faddr)); 301*38034Skfall if ((kerror = krb_rd_req(&ticket, 302*38034Skfall VERIFY_SERVICE, savehost, faddr, 303*38034Skfall &authdata, "")) != KSUCCESS) { 304*38034Skfall printf("Unable to verify rcmd ticket: (%s)\n", 305*38034Skfall krb_err_txt[kerror]); 306*38034Skfall syslog(LOG_WARNING, "couldn't verify rcmd ticket: %s", 307*38034Skfall krb_err_txt[kerror]); 308*38034Skfall } else { 309*38034Skfall bzero(pp, strlen(pp)); 310*38034Skfall notickets = 0; /* got ticket */ 311*38034Skfall break; /* ok */ 312*38034Skfall } 313*38034Skfall } 314*38034Skfall } 315*38034Skfall 31637203Sbostic } 31737203Sbostic } 31837203Sbostic #endif 31936608Skfall (void) bzero(pp, strlen(pp)); 32036515Sbostic if (pwd && !strcmp(p, pwd->pw_passwd)) 32136460Sbostic break; 32236460Sbostic 32337203Sbostic (void)printf("Login incorrect\n"); 32436647Skarels failures++; 32536549Sbostic /* we allow 10 tries, but after 3 we start backing off */ 32636549Sbostic if (++cnt > 3) { 32736549Sbostic if (cnt >= 10) { 32836549Sbostic badlogin(username); 32936549Sbostic (void)ioctl(0, TIOCHPCL, (struct sgttyb *)NULL); 33036549Sbostic sleepexit(1); 33136549Sbostic } 33236549Sbostic sleep((u_int)((cnt - 3) * 5)); 3332822Swnj } 33436460Sbostic } 3351043Sbill 33636460Sbostic /* committed to login -- turn off timeout */ 33736460Sbostic (void)alarm((u_int)0); 33836460Sbostic 33937692Sbostic /* paranoia... */ 34037692Sbostic endpwent(); 34137692Sbostic 34236460Sbostic /* 34336460Sbostic * If valid so far and root is logging in, see if root logins on 34436460Sbostic * this terminal are permitted. 34536460Sbostic */ 34636647Skarels if (pwd->pw_uid == 0 && !rootterm(tty)) { 34736460Sbostic if (hostname) 34836647Skarels syslog(LOG_NOTICE, "ROOT LOGIN REFUSED FROM %s", 34936647Skarels hostname); 35012678Ssam else 35136647Skarels syslog(LOG_NOTICE, "ROOT LOGIN REFUSED ON %s", tty); 35237203Sbostic (void)printf("Login incorrect\n"); 35336460Sbostic sleepexit(1); 35412678Ssam } 3552822Swnj 35636460Sbostic if (quota(Q_SETUID, pwd->pw_uid, 0, 0) < 0 && errno != EINVAL) { 35736460Sbostic switch(errno) { 35836460Sbostic case EUSERS: 35937203Sbostic (void)fprintf(stderr, 36036460Sbostic "Too many users logged on already.\nTry again later.\n"); 36136460Sbostic break; 36236460Sbostic case EPROCLIM: 36337203Sbostic (void)fprintf(stderr, 36436460Sbostic "You have too many processes running.\n"); 36536460Sbostic break; 36636460Sbostic default: 36736460Sbostic perror("quota (Q_SETUID)"); 3682822Swnj } 36936460Sbostic sleepexit(0); 3702822Swnj } 37136460Sbostic 37236515Sbostic if (chdir(pwd->pw_dir) < 0) { 37337203Sbostic (void)printf("No directory %s!\n", pwd->pw_dir); 37436515Sbostic if (chdir("/")) 37536515Sbostic exit(0); 37636515Sbostic pwd->pw_dir = "/"; 37737203Sbostic (void)printf("Logging in with home = \"/\".\n"); 37836515Sbostic } 37936515Sbostic 38037203Sbostic quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0; 38137203Sbostic 38237203Sbostic #ifdef KERBEROS 38337203Sbostic if (notickets && !quietlog) 38437203Sbostic (void)printf("Warning: no Kerberos tickets issued\n"); 38537203Sbostic #endif 38637203Sbostic 38736880Sbostic #define TWOWEEKS (14*24*60*60) 38836880Sbostic if (pwd->pw_change || pwd->pw_expire) 38936880Sbostic (void)gettimeofday(&tp, (struct timezone *)NULL); 39036880Sbostic if (pwd->pw_change) 39136880Sbostic if (tp.tv_sec >= pwd->pw_change) { 39237203Sbostic (void)printf("Sorry -- your password has expired.\n"); 39336880Sbostic sleepexit(1); 39436880Sbostic } 39537203Sbostic else if (tp.tv_sec - pwd->pw_change < TWOWEEKS && !quietlog) { 39636880Sbostic ttp = localtime(&pwd->pw_change); 39737203Sbostic (void)printf("Warning: your password expires on %s %d, %d\n", 39837203Sbostic months[ttp->tm_mon], ttp->tm_mday, TM_YEAR_BASE + ttp->tm_year); 39936880Sbostic } 40036880Sbostic if (pwd->pw_expire) 40136880Sbostic if (tp.tv_sec >= pwd->pw_expire) { 40237203Sbostic (void)printf("Sorry -- your account has expired.\n"); 40336880Sbostic sleepexit(1); 40436880Sbostic } 40537203Sbostic else if (tp.tv_sec - pwd->pw_expire < TWOWEEKS && !quietlog) { 40636880Sbostic ttp = localtime(&pwd->pw_expire); 40737203Sbostic (void)printf("Warning: your account expires on %s %d, %d\n", 40837203Sbostic months[ttp->tm_mon], ttp->tm_mday, TM_YEAR_BASE + ttp->tm_year); 40936880Sbostic } 41036880Sbostic 41136515Sbostic /* nothing else left to fail -- really log in */ 41236460Sbostic { 41336460Sbostic struct utmp utmp; 41436460Sbostic 41536647Skarels bzero((char *)&utmp, sizeof(utmp)); 41636460Sbostic (void)time(&utmp.ut_time); 41736460Sbostic strncpy(utmp.ut_name, username, sizeof(utmp.ut_name)); 41836591Sbostic if (hostname) 41936591Sbostic strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host)); 42036460Sbostic strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line)); 42136460Sbostic login(&utmp); 42236460Sbostic } 42336460Sbostic 42436549Sbostic dolastlog(quietlog); 42536460Sbostic 42637203Sbostic if (!hflag) { /* XXX */ 42736460Sbostic static struct winsize win = { 0, 0, 0, 0 }; 42836460Sbostic 42936460Sbostic (void)ioctl(0, TIOCSWINSZ, &win); 43036460Sbostic } 43136460Sbostic 43236460Sbostic (void)chown(ttyn, pwd->pw_uid, 43336460Sbostic (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid); 43436460Sbostic (void)chmod(ttyn, 0620); 43536460Sbostic (void)setgid(pwd->pw_gid); 43636460Sbostic 43736460Sbostic initgroups(username, pwd->pw_gid); 43836460Sbostic 43912678Ssam quota(Q_DOWARN, pwd->pw_uid, (dev_t)-1, 0); 44030606Sbostic 44136515Sbostic if (*pwd->pw_shell == '\0') 44237203Sbostic pwd->pw_shell = _PATH_BSHELL; 44336515Sbostic /* turn on new line discipline for the csh */ 44437203Sbostic else if (!strcmp(pwd->pw_shell, _PATH_CSHELL)) { 44536515Sbostic ioctlval = NTTYDISC; 44636515Sbostic (void)ioctl(0, TIOCSETD, &ioctlval); 44736515Sbostic } 44836515Sbostic 44936460Sbostic /* destroy environment unless user has requested preservation */ 45018549Ssam if (!pflag) 45118549Ssam environ = envinit; 45236515Sbostic (void)setenv("HOME", pwd->pw_dir, 1); 45336515Sbostic (void)setenv("SHELL", pwd->pw_shell, 1); 45418549Ssam if (term[0] == '\0') 45536647Skarels strncpy(term, stypeof(tty), sizeof(term)); 45636515Sbostic (void)setenv("TERM", term, 0); 45736515Sbostic (void)setenv("USER", pwd->pw_name, 1); 45837252Sbostic (void)setenv("PATH", _PATH_DEFPATH, 0); 45918549Ssam 46016453Sroot if (tty[sizeof("tty")-1] == 'd') 46118549Ssam syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name); 46218549Ssam if (pwd->pw_uid == 0) 46336460Sbostic if (hostname) 46436647Skarels syslog(LOG_NOTICE, "ROOT LOGIN ON %s FROM %s", 46536549Sbostic tty, hostname); 46625230Smckusick else 46736647Skarels syslog(LOG_NOTICE, "ROOT LOGIN ON %s", tty); 46836460Sbostic 4696329Swnj if (!quietlog) { 47017664Sserge struct stat st; 47118549Ssam 47236460Sbostic motd(); 47337203Sbostic (void)sprintf(tbuf, "%s/%s", _PATH_MAILDIR, pwd->pw_name); 47436460Sbostic if (stat(tbuf, &st) == 0 && st.st_size != 0) 47537203Sbostic (void)printf("You have %smail.\n", 47636460Sbostic (st.st_mtime > st.st_atime) ? "new " : ""); 4772822Swnj } 47836460Sbostic 47936460Sbostic (void)signal(SIGALRM, SIG_DFL); 48036460Sbostic (void)signal(SIGQUIT, SIG_DFL); 48136460Sbostic (void)signal(SIGINT, SIG_DFL); 48236460Sbostic (void)signal(SIGTSTP, SIG_IGN); 48336460Sbostic 48436460Sbostic tbuf[0] = '-'; 48536460Sbostic strcpy(tbuf + 1, (p = rindex(pwd->pw_shell, '/')) ? 48636460Sbostic p + 1 : pwd->pw_shell); 48737203Sbostic 48837692Sbostic if (setlogname(pwd->pw_name, strlen(pwd->pw_name)) < 0) 48937692Sbostic syslog(LOG_ERR, "setlogname() failure: %m"); 49037692Sbostic 49137203Sbostic /* discard permissions last so can't get killed and drop core */ 49237203Sbostic (void)setuid(pwd->pw_uid); 49337203Sbostic 49436460Sbostic execlp(pwd->pw_shell, tbuf, 0); 49537203Sbostic (void)fprintf(stderr, "login: no shell: %s.\n", strerror(errno)); 4961043Sbill exit(0); 4971043Sbill } 4981043Sbill 49936460Sbostic getloginname() 50012687Ssam { 50136460Sbostic register int ch; 50236460Sbostic register char *p; 50336460Sbostic static char nbuf[UT_NAMESIZE + 1]; 50412687Ssam 50536460Sbostic for (;;) { 50637203Sbostic (void)printf("login: "); 50736515Sbostic for (p = nbuf; (ch = getchar()) != '\n'; ) { 50836549Sbostic if (ch == EOF) { 50936549Sbostic badlogin(username); 51012687Ssam exit(0); 51136549Sbostic } 51236515Sbostic if (p < nbuf + UT_NAMESIZE) 51336460Sbostic *p++ = ch; 51412687Ssam } 51536460Sbostic if (p > nbuf) 51636460Sbostic if (nbuf[0] == '-') 51737203Sbostic (void)fprintf(stderr, 51836460Sbostic "login names may not start with '-'.\n"); 51936460Sbostic else { 52036460Sbostic *p = '\0'; 52136460Sbostic username = nbuf; 52236515Sbostic break; 52336460Sbostic } 52412687Ssam } 52512687Ssam } 52612687Ssam 52712687Ssam timedout() 52812687Ssam { 52937203Sbostic (void)fprintf(stderr, "Login timed out after %d seconds\n", timeout); 53012687Ssam exit(0); 53112687Ssam } 53212687Ssam 53336647Skarels rootterm(ttyn) 53436647Skarels char *ttyn; 5351043Sbill { 53636460Sbostic struct ttyent *t; 5376466Swnj 53836647Skarels return((t = getttynam(ttyn)) && t->ty_status&TTY_SECURE); 5391043Sbill } 5401043Sbill 54136515Sbostic jmp_buf motdinterrupt; 54236515Sbostic 54336460Sbostic motd() 5442822Swnj { 54536515Sbostic register int fd, nchars; 54636460Sbostic int (*oldint)(), sigint(); 54736515Sbostic char tbuf[8192]; 5482822Swnj 54937203Sbostic if ((fd = open(_PATH_MOTDFILE, O_RDONLY, 0)) < 0) 55036460Sbostic return; 55136460Sbostic oldint = signal(SIGINT, sigint); 55236515Sbostic if (setjmp(motdinterrupt) == 0) 55336515Sbostic while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) 55436515Sbostic (void)write(fileno(stdout), tbuf, nchars); 55536460Sbostic (void)signal(SIGINT, oldint); 55636515Sbostic (void)close(fd); 55736460Sbostic } 55836460Sbostic 55936460Sbostic sigint() 56036460Sbostic { 56136515Sbostic longjmp(motdinterrupt, 1); 56236460Sbostic } 56336460Sbostic 56436460Sbostic checknologin() 56536460Sbostic { 56636460Sbostic register int fd, nchars; 56736515Sbostic char tbuf[8192]; 56836460Sbostic 56937203Sbostic if ((fd = open(_PATH_NOLOGIN, O_RDONLY, 0)) >= 0) { 57036460Sbostic while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) 57136460Sbostic (void)write(fileno(stdout), tbuf, nchars); 57236460Sbostic sleepexit(0); 5732822Swnj } 5742822Swnj } 5752822Swnj 57636549Sbostic dolastlog(quiet) 57736460Sbostic int quiet; 5781043Sbill { 57936460Sbostic struct lastlog ll; 58036460Sbostic int fd; 58136880Sbostic char *ctime(); 5821043Sbill 58337203Sbostic if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) { 58436515Sbostic (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); 58536460Sbostic if (!quiet) { 58636460Sbostic if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) && 58736460Sbostic ll.ll_time != 0) { 58837203Sbostic (void)printf("Last login: %.*s ", 58936460Sbostic 24-5, (char *)ctime(&ll.ll_time)); 59036460Sbostic if (*ll.ll_host != '\0') 59137203Sbostic (void)printf("from %.*s\n", 59236460Sbostic sizeof(ll.ll_host), ll.ll_host); 59336460Sbostic else 59437203Sbostic (void)printf("on %.*s\n", 59536460Sbostic sizeof(ll.ll_line), ll.ll_line); 59636460Sbostic } 59736515Sbostic (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); 59836460Sbostic } 59936647Skarels bzero((char *)&ll, sizeof(ll)); 60036460Sbostic (void)time(&ll.ll_time); 60136460Sbostic strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); 60236591Sbostic if (hostname) 60336591Sbostic strncpy(ll.ll_host, hostname, sizeof(ll.ll_host)); 60436460Sbostic (void)write(fd, (char *)&ll, sizeof(ll)); 60536460Sbostic (void)close(fd); 6061043Sbill } 6071043Sbill } 6081043Sbill 60936549Sbostic badlogin(name) 61036549Sbostic char *name; 61136549Sbostic { 61236647Skarels if (failures == 0) 61336549Sbostic return; 61436549Sbostic if (hostname) 61536647Skarels syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s, %s", 61636647Skarels failures, failures > 1 ? "S" : "", hostname, name); 61736549Sbostic else 61836647Skarels syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s, %s", 61936647Skarels failures, failures > 1 ? "S" : "", tty, name); 62036549Sbostic } 62136549Sbostic 6222822Swnj #undef UNKNOWN 62336460Sbostic #define UNKNOWN "su" 6241043Sbill 6251043Sbill char * 62636647Skarels stypeof(ttyid) 62736647Skarels char *ttyid; 6281043Sbill { 62936460Sbostic struct ttyent *t; 6301043Sbill 63136647Skarels return(ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN); 6321043Sbill } 6336005Swnj 6346005Swnj getstr(buf, cnt, err) 63536460Sbostic char *buf, *err; 6366005Swnj int cnt; 6376005Swnj { 63836460Sbostic char ch; 6396005Swnj 6406005Swnj do { 64136460Sbostic if (read(0, &ch, sizeof(ch)) != sizeof(ch)) 6426005Swnj exit(1); 6436005Swnj if (--cnt < 0) { 64437203Sbostic (void)fprintf(stderr, "%s too long\r\n", err); 64536460Sbostic sleepexit(1); 6466005Swnj } 64736460Sbostic *buf++ = ch; 64836460Sbostic } while (ch); 6496005Swnj } 6506329Swnj 65136460Sbostic sleepexit(eval) 65236460Sbostic int eval; 65326862Smckusick { 65436460Sbostic sleep((u_int)5); 65536460Sbostic exit(eval); 65626862Smckusick } 657