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*42502Sbostic static char sccsid[] = "@(#)login.c 5.55 (Berkeley) 05/31/90"; 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> 3512687Ssam #include <sys/stat.h> 3612687Ssam #include <sys/time.h> 3712687Ssam #include <sys/resource.h> 3816453Sroot #include <sys/file.h> 3939271Skfall #include <sgtty.h> 4012687Ssam 411043Sbill #include <utmp.h> 421043Sbill #include <signal.h> 4312678Ssam #include <errno.h> 4416453Sroot #include <ttyent.h> 4516453Sroot #include <syslog.h> 4626862Smckusick #include <grp.h> 4736460Sbostic #include <pwd.h> 4836515Sbostic #include <setjmp.h> 4936460Sbostic #include <stdio.h> 5042063Sbostic #include <string.h> 5137203Sbostic #include <tzfile.h> 5237203Sbostic #include "pathnames.h" 531043Sbill 5437203Sbostic #ifdef KERBEROS 5541759Skfall #include <kerberosIV/des.h> 5640678Sbostic #include <kerberosIV/krb.h> 5738034Skfall #include <netdb.h> 5838034Skfall char realm[REALM_SZ]; 5938034Skfall int kerror = KSUCCESS, notickets = 1; 6038034Skfall KTEXT_ST ticket; 6138034Skfall AUTH_DAT authdata; 6238034Skfall char savehost[MAXHOSTNAMELEN]; 6338726Skfall char tkfile[MAXPATHLEN]; 6438034Skfall unsigned long faddr; 6538034Skfall struct hostent *hp; 6638034Skfall #define PRINCIPAL_NAME pwd->pw_name 6738034Skfall #define PRINCIPAL_INST "" 6838034Skfall #define INITIAL_TICKET "krbtgt" 6938034Skfall #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; 8240490Sbostic char term[64], *envinit[1], *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; 10739271Skfall int ask, fflag, hflag, pflag, cnt, uid; 10836460Sbostic int quietlog, passwd_req, ioctlval, timedout(); 10940490Sbostic char *domain, *salt, *ttyn, *pp; 11037692Sbostic char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10]; 11138034Skfall 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 122*42502Sbostic openlog("login", LOG_ODELAY, LOG_AUTH); 123*42502Sbostic 12412687Ssam /* 12518549Ssam * -p is used by getty to tell login not to destroy the environment 12631695Skarels * -f is used to skip a second login authentication 12736523Skarels * -h is used by other servers to pass the name of the remote 12836523Skarels * host to login so that it may be placed in utmp and wtmp 12912687Ssam */ 13038034Skfall domain = NULL; 13138034Skfall if (gethostname(localhost, sizeof(localhost)) < 0) 13238034Skfall syslog(LOG_ERR, "couldn't get local hostname: %m"); 13338034Skfall else 13438034Skfall domain = index(localhost, '.'); 13536460Sbostic 13637203Sbostic fflag = hflag = pflag = 0; 13736460Sbostic passwd_req = 1; 13839271Skfall uid = getuid(); 13937203Sbostic while ((ch = getopt(argc, argv, "fh:p")) != EOF) 14036515Sbostic switch (ch) { 14136460Sbostic case 'f': 14236460Sbostic fflag = 1; 14336460Sbostic break; 14436460Sbostic case 'h': 14539271Skfall if (uid) { 14637203Sbostic (void)fprintf(stderr, 14736460Sbostic "login: -h for super-user only.\n"); 14832313Sbostic exit(1); 14931695Skarels } 15036460Sbostic hflag = 1; 15136460Sbostic if (domain && (p = index(optarg, '.')) && 15236553Sbostic strcasecmp(p, domain) == 0) 15336460Sbostic *p = 0; 15436460Sbostic hostname = optarg; 15536460Sbostic break; 15636460Sbostic case 'p': 15718549Ssam pflag = 1; 15836460Sbostic break; 15936460Sbostic case '?': 16036460Sbostic default: 16139271Skfall if (!uid) 16239271Skfall syslog(LOG_ERR, "invalid flag %c", ch); 16337203Sbostic (void)fprintf(stderr, 16437203Sbostic "usage: login [-fp] [username]\n"); 16536460Sbostic exit(1); 16618549Ssam } 16736460Sbostic argc -= optind; 16836460Sbostic argv += optind; 16936549Sbostic if (*argv) { 17036647Skarels username = *argv; 17136549Sbostic ask = 0; 17236647Skarels } else 17336549Sbostic ask = 1; 17436460Sbostic 17536460Sbostic ioctlval = 0; 17636460Sbostic (void)ioctl(0, TIOCLSET, &ioctlval); 17736460Sbostic (void)ioctl(0, TIOCNXCL, 0); 17836515Sbostic (void)fcntl(0, F_SETFL, ioctlval); 17936515Sbostic (void)ioctl(0, TIOCGETP, &sgttyb); 18036515Sbostic sgttyb.sg_erase = CERASE; 18136515Sbostic sgttyb.sg_kill = CKILL; 18236460Sbostic (void)ioctl(0, TIOCSLTC, <c); 18336460Sbostic (void)ioctl(0, TIOCSETC, &tc); 18436515Sbostic (void)ioctl(0, TIOCSETP, &sgttyb); 18536460Sbostic 18636460Sbostic for (cnt = getdtablesize(); cnt > 2; cnt--) 18736460Sbostic close(cnt); 18836460Sbostic 1891043Sbill ttyn = ttyname(0); 19037692Sbostic if (ttyn == NULL || *ttyn == '\0') { 19137692Sbostic (void)sprintf(tname, "%s??", _PATH_TTY); 19237692Sbostic ttyn = tname; 19337692Sbostic } 19436460Sbostic if (tty = rindex(ttyn, '/')) 19536460Sbostic ++tty; 19636460Sbostic else 19716453Sroot tty = ttyn; 19836460Sbostic 19936549Sbostic for (cnt = 0;; ask = 1) { 20038602Sbostic ioctlval = TTYDISC; 20136460Sbostic (void)ioctl(0, TIOCSETD, &ioctlval); 20236460Sbostic 20336549Sbostic if (ask) { 20436515Sbostic fflag = 0; 20536460Sbostic getloginname(); 20636515Sbostic } 20736647Skarels /* 20839271Skfall * Note if trying multiple user names; log failures for 20939271Skfall * previous user name, but don't bother logging one failure 21036647Skarels * for nonexistent name (mistyped username). 21136647Skarels */ 21236647Skarels if (failures && strcmp(tbuf, username)) { 21336647Skarels if (failures > (pwd ? 0 : 1)) 21436549Sbostic badlogin(tbuf); 21536647Skarels failures = 0; 21636549Sbostic } 21736647Skarels (void)strcpy(tbuf, username); 21836515Sbostic if (pwd = getpwnam(username)) 21936515Sbostic salt = pwd->pw_passwd; 22036515Sbostic else 22136515Sbostic salt = "xx"; 22236460Sbostic 22336460Sbostic /* if user not super-user, check for disabled logins */ 22436515Sbostic if (pwd == NULL || pwd->pw_uid) 22536460Sbostic checknologin(); 22636460Sbostic 22712687Ssam /* 22836515Sbostic * Disallow automatic login to root; if not invoked by 22936515Sbostic * root, disallow if the uid's differ. 23012687Ssam */ 23136515Sbostic if (fflag && pwd) { 23238726Skfall passwd_req = 23338726Skfall #ifndef KERBEROS 23438726Skfall pwd->pw_uid == 0 || 23538726Skfall #endif 23636515Sbostic (uid && uid != pwd->pw_uid); 23731695Skarels } 23836460Sbostic 23912687Ssam /* 24036523Skarels * If no pre-authentication and a password exists 24136460Sbostic * for this user, prompt for one and verify it. 24212687Ssam */ 24336608Skfall if (!passwd_req || (pwd && !*pwd->pw_passwd)) 24436460Sbostic break; 24512687Ssam 24639271Skfall /* 24739271Skfall * If trying to log in as root, but with insecure terminal, 24839271Skfall * refuse the login attempt. 24939271Skfall */ 25039271Skfall if (pwd->pw_uid == 0 && !rootterm(tty)) { 25139271Skfall (void)fprintf(stderr, 25239271Skfall "%s login refused on this terminal.\n", 25339271Skfall pwd->pw_name); 25439271Skfall if (hostname) 25539271Skfall syslog(LOG_NOTICE, 25639271Skfall "LOGIN %s REFUSED FROM %s ON TTY %s", 25739271Skfall pwd->pw_name, hostname, tty); 25839271Skfall else 25939271Skfall syslog(LOG_NOTICE, 26039271Skfall "LOGIN %s REFUSED ON TTY %s", 26139271Skfall pwd->pw_name, tty); 26239271Skfall continue; 26339271Skfall } 26439271Skfall 26536460Sbostic setpriority(PRIO_PROCESS, 0, -4); 26636608Skfall pp = getpass("Password:"); 26736608Skfall p = crypt(pp, salt); 26836460Sbostic setpriority(PRIO_PROCESS, 0, 0); 26936608Skfall 27037203Sbostic #ifdef KERBEROS 27137203Sbostic 27237203Sbostic /* 27338755Skfall * If not present in pw file, act as old login would. 27437203Sbostic * If we aren't Kerberos-authenticated, try the normal 27537203Sbostic * pw file for a password. If that's ok, log the user 27637203Sbostic * in without issueing any tickets. 27737203Sbostic */ 27837203Sbostic 27938034Skfall if (pwd && (krb_get_lrealm(realm,1) == KSUCCESS)) { 28038726Skfall 28137203Sbostic /* 28238726Skfall * get TGT for local realm 28339271Skfall * convention: store tickets in file associated 28439271Skfall * with tty name, which should be available 28537203Sbostic */ 28638726Skfall (void)sprintf(tkfile, "%s_%s", TKT_ROOT, tty); 28738726Skfall kerror = INTK_ERR; 28838726Skfall if (setenv("KRBTKFILE", tkfile, 1) < 0) 28938726Skfall syslog(LOG_ERR, "couldn't set tkfile environ"); 29038726Skfall else { 29138755Skfall (void) unlink(tkfile); 29238726Skfall kerror = krb_get_pw_in_tkt( 29338755Skfall PRINCIPAL_NAME, /* user */ 29438755Skfall PRINCIPAL_INST, /* (null) */ 29538755Skfall realm, 29638755Skfall INITIAL_TICKET, realm, 29738755Skfall DEFAULT_TKT_LIFE, 29838726Skfall pp); 29938726Skfall } 30038034Skfall /* 30138034Skfall * If we got a TGT, get a local "rcmd" ticket and 30238034Skfall * check it so as to ensure that we are not 30338034Skfall * talking to a bogus Kerberos server 30438726Skfall * 30538726Skfall * There are 2 cases where we still allow a login: 30638726Skfall * 1> the VERIFY_SERVICE doesn't exist in the KDC 30738726Skfall * 2> local host has no srvtab, as (hopefully) 30838726Skfall * indicated by a return value of RD_AP_UNDEC 30938726Skfall * from krb_rd_req() 31038034Skfall */ 31137203Sbostic if (kerror == INTK_OK) { 31239271Skfall if (chown(tkfile, pwd->pw_uid, pwd->pw_gid) < 0) 31339271Skfall syslog(LOG_ERR, "chown tkfile: %m"); 31438034Skfall (void) strncpy(savehost, 31538034Skfall krb_get_phost(localhost), 31638034Skfall sizeof(savehost)); 31738034Skfall savehost[sizeof(savehost)-1] = NULL; 31838034Skfall kerror = krb_mk_req(&ticket, VERIFY_SERVICE, 31938034Skfall savehost, realm, 33); 32038726Skfall /* 32138755Skfall * if the "VERIFY_SERVICE" doesn't exist in 32238755Skfall * the KDC for this host, still allow login, 32338726Skfall * but log the error condition 32438726Skfall */ 32538034Skfall if (kerror == KDC_PR_UNKNOWN) { 32638726Skfall syslog(LOG_NOTICE, 32738034Skfall "Warning: TGT not verified (%s)", 32838034Skfall krb_err_txt[kerror]); 32938034Skfall bzero(pp, strlen(pp)); 33038034Skfall notickets = 0; 33138034Skfall break; /* ok */ 33238034Skfall } else if (kerror != KSUCCESS) { 33338034Skfall printf("Unable to use TGT: (%s)\n", 33438034Skfall krb_err_txt[kerror]); 33538726Skfall syslog(LOG_NOTICE, 33638034Skfall "Unable to use TGT: (%s)", 33738034Skfall krb_err_txt[kerror]); 33838034Skfall dest_tkt(); 33938034Skfall /* fall thru: no login */ 34038034Skfall } else { 34138034Skfall if (!(hp = gethostbyname(localhost))) { 34238755Skfall syslog(LOG_ERR, 34338755Skfall "couldn't get local host address"); 34438034Skfall } else { 34538034Skfall bcopy((char *) hp->h_addr, 34638034Skfall (char *) &faddr, sizeof(faddr)); 34738034Skfall if ((kerror = krb_rd_req(&ticket, 34838034Skfall VERIFY_SERVICE, savehost, faddr, 34938034Skfall &authdata, "")) != KSUCCESS) { 35038726Skfall 35138726Skfall if (kerror = RD_AP_UNDEC) { 35238726Skfall syslog(LOG_NOTICE, 35338726Skfall "krb_rd_req: (%s)\n", 35438726Skfall krb_err_txt[kerror]); 35538726Skfall bzero(pp, strlen(pp)); 35638726Skfall notickets = 0; 35738726Skfall break; /* ok */ 35838726Skfall } else { 35938726Skfall printf("Unable to verify %s ticket: (%s)\n", 36038726Skfall VERIFY_SERVICE, 36138034Skfall krb_err_txt[kerror]); 36238726Skfall syslog(LOG_NOTICE, 36338726Skfall "couldn't verify %s ticket: %s", 36438726Skfall VERIFY_SERVICE, 36538034Skfall krb_err_txt[kerror]); 36638726Skfall } 36738726Skfall /* fall thru: no login */ 36838034Skfall } else { 36938034Skfall bzero(pp, strlen(pp)); 37038034Skfall notickets = 0; /* got ticket */ 37138034Skfall break; /* ok */ 37238034Skfall } 37338034Skfall } 37438034Skfall } 37538034Skfall 37638755Skfall } else { 37738755Skfall (void) unlink(tkfile); 37839271Skfall if ((kerror != INTK_BADPW) && 37939271Skfall kerror != KDC_PR_UNKNOWN) 38038755Skfall syslog(LOG_ERR, 38138755Skfall "Kerberos intkt error: %s", 38238755Skfall krb_err_txt[kerror]); 38337203Sbostic } 38437203Sbostic } 38538726Skfall 38637203Sbostic #endif 38736608Skfall (void) bzero(pp, strlen(pp)); 38836515Sbostic if (pwd && !strcmp(p, pwd->pw_passwd)) 38936460Sbostic break; 39036460Sbostic 39137203Sbostic (void)printf("Login incorrect\n"); 39236647Skarels failures++; 39336549Sbostic /* we allow 10 tries, but after 3 we start backing off */ 39436549Sbostic if (++cnt > 3) { 39536549Sbostic if (cnt >= 10) { 39636549Sbostic badlogin(username); 39736549Sbostic (void)ioctl(0, TIOCHPCL, (struct sgttyb *)NULL); 39836549Sbostic sleepexit(1); 39936549Sbostic } 40036549Sbostic sleep((u_int)((cnt - 3) * 5)); 4012822Swnj } 40236460Sbostic } 4031043Sbill 40436460Sbostic /* committed to login -- turn off timeout */ 40536460Sbostic (void)alarm((u_int)0); 40636460Sbostic 40737692Sbostic /* paranoia... */ 40837692Sbostic endpwent(); 40937692Sbostic 41036515Sbostic if (chdir(pwd->pw_dir) < 0) { 41137203Sbostic (void)printf("No directory %s!\n", pwd->pw_dir); 41236515Sbostic if (chdir("/")) 41336515Sbostic exit(0); 41436515Sbostic pwd->pw_dir = "/"; 41537203Sbostic (void)printf("Logging in with home = \"/\".\n"); 41636515Sbostic } 41736515Sbostic 41837203Sbostic quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0; 41937203Sbostic 42037203Sbostic #ifdef KERBEROS 42137203Sbostic if (notickets && !quietlog) 42237203Sbostic (void)printf("Warning: no Kerberos tickets issued\n"); 42337203Sbostic #endif 42437203Sbostic 42536880Sbostic if (pwd->pw_change || pwd->pw_expire) 42636880Sbostic (void)gettimeofday(&tp, (struct timezone *)NULL); 42736880Sbostic if (pwd->pw_change) 42836880Sbostic if (tp.tv_sec >= pwd->pw_change) { 42937203Sbostic (void)printf("Sorry -- your password has expired.\n"); 43036880Sbostic sleepexit(1); 43136880Sbostic } 43238216Sbostic else if (pwd->pw_change - tp.tv_sec < 43338216Sbostic 2 * DAYSPERWEEK * SECSPERDAY && !quietlog) { 43436880Sbostic ttp = localtime(&pwd->pw_change); 43537203Sbostic (void)printf("Warning: your password expires on %s %d, %d\n", 43638216Sbostic months[ttp->tm_mon], ttp->tm_mday, 43738216Sbostic TM_YEAR_BASE + ttp->tm_year); 43836880Sbostic } 43936880Sbostic if (pwd->pw_expire) 44036880Sbostic if (tp.tv_sec >= pwd->pw_expire) { 44137203Sbostic (void)printf("Sorry -- your account has expired.\n"); 44236880Sbostic sleepexit(1); 44336880Sbostic } 44438216Sbostic else if (pwd->pw_expire - tp.tv_sec < 44538216Sbostic 2 * DAYSPERWEEK * SECSPERDAY && !quietlog) { 44636880Sbostic ttp = localtime(&pwd->pw_expire); 44737203Sbostic (void)printf("Warning: your account expires on %s %d, %d\n", 44838216Sbostic months[ttp->tm_mon], ttp->tm_mday, 44938216Sbostic TM_YEAR_BASE + ttp->tm_year); 45036880Sbostic } 45136880Sbostic 45236515Sbostic /* nothing else left to fail -- really log in */ 45336460Sbostic { 45436460Sbostic struct utmp utmp; 45536460Sbostic 45636647Skarels bzero((char *)&utmp, sizeof(utmp)); 45736460Sbostic (void)time(&utmp.ut_time); 45836460Sbostic strncpy(utmp.ut_name, username, sizeof(utmp.ut_name)); 45936591Sbostic if (hostname) 46036591Sbostic strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host)); 46136460Sbostic strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line)); 46236460Sbostic login(&utmp); 46336460Sbostic } 46436460Sbostic 46536549Sbostic dolastlog(quietlog); 46636460Sbostic 46737203Sbostic if (!hflag) { /* XXX */ 46836460Sbostic static struct winsize win = { 0, 0, 0, 0 }; 46936460Sbostic 47036460Sbostic (void)ioctl(0, TIOCSWINSZ, &win); 47136460Sbostic } 47236460Sbostic 47336460Sbostic (void)chown(ttyn, pwd->pw_uid, 47436460Sbostic (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid); 47536460Sbostic (void)chmod(ttyn, 0620); 47636460Sbostic (void)setgid(pwd->pw_gid); 47736460Sbostic 47836460Sbostic initgroups(username, pwd->pw_gid); 47936460Sbostic 48036515Sbostic if (*pwd->pw_shell == '\0') 48137203Sbostic pwd->pw_shell = _PATH_BSHELL; 48236515Sbostic 48336460Sbostic /* destroy environment unless user has requested preservation */ 48418549Ssam if (!pflag) 48518549Ssam environ = envinit; 48636515Sbostic (void)setenv("HOME", pwd->pw_dir, 1); 48736515Sbostic (void)setenv("SHELL", pwd->pw_shell, 1); 48818549Ssam if (term[0] == '\0') 48936647Skarels strncpy(term, stypeof(tty), sizeof(term)); 49036515Sbostic (void)setenv("TERM", term, 0); 49136515Sbostic (void)setenv("USER", pwd->pw_name, 1); 49237252Sbostic (void)setenv("PATH", _PATH_DEFPATH, 0); 49318549Ssam 49416453Sroot if (tty[sizeof("tty")-1] == 'd') 49518549Ssam syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name); 49618549Ssam if (pwd->pw_uid == 0) 49736460Sbostic if (hostname) 49836647Skarels syslog(LOG_NOTICE, "ROOT LOGIN ON %s FROM %s", 49936549Sbostic tty, hostname); 50025230Smckusick else 50136647Skarels syslog(LOG_NOTICE, "ROOT LOGIN ON %s", tty); 50236460Sbostic 5036329Swnj if (!quietlog) { 50417664Sserge struct stat st; 50518549Ssam 50636460Sbostic motd(); 50737203Sbostic (void)sprintf(tbuf, "%s/%s", _PATH_MAILDIR, pwd->pw_name); 50836460Sbostic if (stat(tbuf, &st) == 0 && st.st_size != 0) 50937203Sbostic (void)printf("You have %smail.\n", 51036460Sbostic (st.st_mtime > st.st_atime) ? "new " : ""); 5112822Swnj } 51236460Sbostic 51336460Sbostic (void)signal(SIGALRM, SIG_DFL); 51436460Sbostic (void)signal(SIGQUIT, SIG_DFL); 51536460Sbostic (void)signal(SIGINT, SIG_DFL); 51636460Sbostic (void)signal(SIGTSTP, SIG_IGN); 51736460Sbostic 51836460Sbostic tbuf[0] = '-'; 51936460Sbostic strcpy(tbuf + 1, (p = rindex(pwd->pw_shell, '/')) ? 52036460Sbostic p + 1 : pwd->pw_shell); 52137203Sbostic 52240009Ssklower if (setlogin(pwd->pw_name) < 0) 52340009Ssklower syslog(LOG_ERR, "setlogin() failure: %m"); 52437692Sbostic 52537203Sbostic /* discard permissions last so can't get killed and drop core */ 52637203Sbostic (void)setuid(pwd->pw_uid); 52737203Sbostic 52836460Sbostic execlp(pwd->pw_shell, tbuf, 0); 52937203Sbostic (void)fprintf(stderr, "login: no shell: %s.\n", strerror(errno)); 5301043Sbill exit(0); 5311043Sbill } 5321043Sbill 53336460Sbostic getloginname() 53412687Ssam { 53536460Sbostic register int ch; 53636460Sbostic register char *p; 53736460Sbostic static char nbuf[UT_NAMESIZE + 1]; 53812687Ssam 53936460Sbostic for (;;) { 54037203Sbostic (void)printf("login: "); 54136515Sbostic for (p = nbuf; (ch = getchar()) != '\n'; ) { 54236549Sbostic if (ch == EOF) { 54336549Sbostic badlogin(username); 54412687Ssam exit(0); 54536549Sbostic } 54636515Sbostic if (p < nbuf + UT_NAMESIZE) 54736460Sbostic *p++ = ch; 54812687Ssam } 54936460Sbostic if (p > nbuf) 55036460Sbostic if (nbuf[0] == '-') 55137203Sbostic (void)fprintf(stderr, 55236460Sbostic "login names may not start with '-'.\n"); 55336460Sbostic else { 55436460Sbostic *p = '\0'; 55536460Sbostic username = nbuf; 55636515Sbostic break; 55736460Sbostic } 55812687Ssam } 55912687Ssam } 56012687Ssam 56112687Ssam timedout() 56212687Ssam { 56337203Sbostic (void)fprintf(stderr, "Login timed out after %d seconds\n", timeout); 56412687Ssam exit(0); 56512687Ssam } 56612687Ssam 56736647Skarels rootterm(ttyn) 56836647Skarels char *ttyn; 5691043Sbill { 57036460Sbostic struct ttyent *t; 5716466Swnj 57236647Skarels return((t = getttynam(ttyn)) && t->ty_status&TTY_SECURE); 5731043Sbill } 5741043Sbill 57536515Sbostic jmp_buf motdinterrupt; 57636515Sbostic 57736460Sbostic motd() 5782822Swnj { 57936515Sbostic register int fd, nchars; 58038726Skfall sig_t oldint; 58138726Skfall int sigint(); 58236515Sbostic char tbuf[8192]; 5832822Swnj 58437203Sbostic if ((fd = open(_PATH_MOTDFILE, O_RDONLY, 0)) < 0) 58536460Sbostic return; 58636460Sbostic oldint = signal(SIGINT, sigint); 58736515Sbostic if (setjmp(motdinterrupt) == 0) 58836515Sbostic while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) 58936515Sbostic (void)write(fileno(stdout), tbuf, nchars); 59036460Sbostic (void)signal(SIGINT, oldint); 59136515Sbostic (void)close(fd); 59236460Sbostic } 59336460Sbostic 59436460Sbostic sigint() 59536460Sbostic { 59636515Sbostic longjmp(motdinterrupt, 1); 59736460Sbostic } 59836460Sbostic 59936460Sbostic checknologin() 60036460Sbostic { 60136460Sbostic register int fd, nchars; 60236515Sbostic char tbuf[8192]; 60336460Sbostic 60437203Sbostic if ((fd = open(_PATH_NOLOGIN, O_RDONLY, 0)) >= 0) { 60536460Sbostic while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) 60636460Sbostic (void)write(fileno(stdout), tbuf, nchars); 60736460Sbostic sleepexit(0); 6082822Swnj } 6092822Swnj } 6102822Swnj 61136549Sbostic dolastlog(quiet) 61236460Sbostic int quiet; 6131043Sbill { 61436460Sbostic struct lastlog ll; 61536460Sbostic int fd; 61636880Sbostic char *ctime(); 6171043Sbill 61837203Sbostic if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) { 61936515Sbostic (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); 62036460Sbostic if (!quiet) { 62136460Sbostic if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) && 62236460Sbostic ll.ll_time != 0) { 62337203Sbostic (void)printf("Last login: %.*s ", 62436460Sbostic 24-5, (char *)ctime(&ll.ll_time)); 62536460Sbostic if (*ll.ll_host != '\0') 62637203Sbostic (void)printf("from %.*s\n", 62736460Sbostic sizeof(ll.ll_host), ll.ll_host); 62836460Sbostic else 62937203Sbostic (void)printf("on %.*s\n", 63036460Sbostic sizeof(ll.ll_line), ll.ll_line); 63136460Sbostic } 63236515Sbostic (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); 63336460Sbostic } 63436647Skarels bzero((char *)&ll, sizeof(ll)); 63536460Sbostic (void)time(&ll.ll_time); 63636460Sbostic strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); 63736591Sbostic if (hostname) 63836591Sbostic strncpy(ll.ll_host, hostname, sizeof(ll.ll_host)); 63936460Sbostic (void)write(fd, (char *)&ll, sizeof(ll)); 64036460Sbostic (void)close(fd); 6411043Sbill } 6421043Sbill } 6431043Sbill 64436549Sbostic badlogin(name) 64536549Sbostic char *name; 64636549Sbostic { 64736647Skarels if (failures == 0) 64836549Sbostic return; 64936549Sbostic if (hostname) 65036647Skarels syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s, %s", 65136647Skarels failures, failures > 1 ? "S" : "", hostname, name); 65236549Sbostic else 65336647Skarels syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s, %s", 65436647Skarels failures, failures > 1 ? "S" : "", tty, name); 65536549Sbostic } 65636549Sbostic 6572822Swnj #undef UNKNOWN 65836460Sbostic #define UNKNOWN "su" 6591043Sbill 6601043Sbill char * 66136647Skarels stypeof(ttyid) 66236647Skarels char *ttyid; 6631043Sbill { 66436460Sbostic struct ttyent *t; 6651043Sbill 66636647Skarels return(ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN); 6671043Sbill } 6686005Swnj 6696005Swnj getstr(buf, cnt, err) 67036460Sbostic char *buf, *err; 6716005Swnj int cnt; 6726005Swnj { 67336460Sbostic char ch; 6746005Swnj 6756005Swnj do { 67636460Sbostic if (read(0, &ch, sizeof(ch)) != sizeof(ch)) 6776005Swnj exit(1); 6786005Swnj if (--cnt < 0) { 67937203Sbostic (void)fprintf(stderr, "%s too long\r\n", err); 68036460Sbostic sleepexit(1); 6816005Swnj } 68236460Sbostic *buf++ = ch; 68336460Sbostic } while (ch); 6846005Swnj } 6856329Swnj 68636460Sbostic sleepexit(eval) 68736460Sbostic int eval; 68826862Smckusick { 68936460Sbostic sleep((u_int)5); 69036460Sbostic exit(eval); 69126862Smckusick } 692