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*38726Skfall static char sccsid[] = "@(#)login.c 5.44 (Berkeley) 08/22/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 56*38726Skfall #include <krb.h> 57*38726Skfall #include <sgtty.h> 5838034Skfall #include <netdb.h> 5938034Skfall char realm[REALM_SZ]; 6038034Skfall int kerror = KSUCCESS, notickets = 1; 6138034Skfall KTEXT_ST ticket; 6238034Skfall AUTH_DAT authdata; 6338034Skfall char savehost[MAXHOSTNAMELEN]; 64*38726Skfall char tkfile[MAXPATHLEN]; 6538034Skfall unsigned long faddr; 6638034Skfall struct hostent *hp; 6738034Skfall #define PRINCIPAL_NAME pwd->pw_name 6838034Skfall #define PRINCIPAL_INST "" 6938034Skfall #define INITIAL_TICKET "krbtgt" 7038034Skfall #define VERIFY_SERVICE "rcmd" 7137203Sbostic #endif 7237203Sbostic 7336460Sbostic #define TTYGRPNAME "tty" /* name of group to own ttys */ 7426862Smckusick 7512687Ssam /* 7636460Sbostic * This bounds the time given to login. Not a define so it can 7736460Sbostic * be patched on machines where it's too small. 7812687Ssam */ 7931509Sbostic int timeout = 300; 806005Swnj 8136647Skarels struct passwd *pwd; 8236647Skarels int failures; 8336647Skarels char term[64], *hostname, *username, *tty; 846005Swnj 8536647Skarels struct sgttyb sgttyb; 8636647Skarels struct tchars tc = { 8713074Ssam CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK 881365Sbill }; 8936647Skarels struct ltchars ltc = { 9013074Ssam CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE, CLNEXT 9113074Ssam }; 921365Sbill 9336880Sbostic char *months[] = 9436880Sbostic { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", 9536880Sbostic "Sep", "Oct", "Nov", "Dec" }; 9636880Sbostic 971043Sbill main(argc, argv) 9836460Sbostic int argc; 9936460Sbostic char **argv; 1001043Sbill { 10136460Sbostic extern int errno, optind; 10236460Sbostic extern char *optarg, **environ; 10336880Sbostic struct timeval tp; 10436880Sbostic struct tm *ttp; 10536460Sbostic struct group *gr; 10636460Sbostic register int ch; 10736647Skarels register char *p; 10837203Sbostic int ask, fflag, hflag, pflag, cnt; 10936460Sbostic int quietlog, passwd_req, ioctlval, timedout(); 11036647Skarels char *domain, *salt, *envinit[1], *ttyn, *pp; 11137692Sbostic char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10]; 11238034Skfall char localhost[MAXHOSTNAMELEN]; 11336880Sbostic char *ctime(), *ttyname(), *stypeof(), *crypt(), *getpass(); 11436460Sbostic time_t time(); 11536460Sbostic off_t lseek(); 1161043Sbill 11736460Sbostic (void)signal(SIGALRM, timedout); 11836460Sbostic (void)alarm((u_int)timeout); 11936460Sbostic (void)signal(SIGQUIT, SIG_IGN); 12036460Sbostic (void)signal(SIGINT, SIG_IGN); 12136460Sbostic (void)setpriority(PRIO_PROCESS, 0, 0); 12236460Sbostic (void)quota(Q_SETUID, 0, 0, 0); 12336460Sbostic 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; 13837203Sbostic while ((ch = getopt(argc, argv, "fh:p")) != EOF) 13936515Sbostic switch (ch) { 14036460Sbostic case 'f': 14136460Sbostic fflag = 1; 14236460Sbostic break; 14336460Sbostic case 'h': 14436460Sbostic if (getuid()) { 14537203Sbostic (void)fprintf(stderr, 14636460Sbostic "login: -h for super-user only.\n"); 14732313Sbostic exit(1); 14831695Skarels } 14936460Sbostic hflag = 1; 15036460Sbostic if (domain && (p = index(optarg, '.')) && 15136553Sbostic strcasecmp(p, domain) == 0) 15236460Sbostic *p = 0; 15336460Sbostic hostname = optarg; 15436460Sbostic break; 15536460Sbostic case 'p': 15618549Ssam pflag = 1; 15736460Sbostic break; 15836460Sbostic case '?': 15936460Sbostic default: 160*38726Skfall syslog(LOG_ERR, "invalid flag"); 16137203Sbostic (void)fprintf(stderr, 16237203Sbostic "usage: login [-fp] [username]\n"); 16336460Sbostic exit(1); 16418549Ssam } 16536460Sbostic argc -= optind; 16636460Sbostic argv += optind; 16736549Sbostic if (*argv) { 16836647Skarels username = *argv; 16936549Sbostic ask = 0; 17036647Skarels } else 17136549Sbostic ask = 1; 17236460Sbostic 17336460Sbostic ioctlval = 0; 17436460Sbostic (void)ioctl(0, TIOCLSET, &ioctlval); 17536460Sbostic (void)ioctl(0, TIOCNXCL, 0); 17636515Sbostic (void)fcntl(0, F_SETFL, ioctlval); 17736515Sbostic (void)ioctl(0, TIOCGETP, &sgttyb); 17836515Sbostic sgttyb.sg_erase = CERASE; 17936515Sbostic sgttyb.sg_kill = CKILL; 18036460Sbostic (void)ioctl(0, TIOCSLTC, <c); 18136460Sbostic (void)ioctl(0, TIOCSETC, &tc); 18236515Sbostic (void)ioctl(0, TIOCSETP, &sgttyb); 18336460Sbostic 18436460Sbostic for (cnt = getdtablesize(); cnt > 2; cnt--) 18536460Sbostic close(cnt); 18636460Sbostic 1871043Sbill ttyn = ttyname(0); 18837692Sbostic if (ttyn == NULL || *ttyn == '\0') { 18937692Sbostic (void)sprintf(tname, "%s??", _PATH_TTY); 19037692Sbostic ttyn = tname; 19137692Sbostic } 19236460Sbostic if (tty = rindex(ttyn, '/')) 19336460Sbostic ++tty; 19436460Sbostic else 19516453Sroot tty = ttyn; 19636460Sbostic 19724852Seric openlog("login", LOG_ODELAY, LOG_AUTH); 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 /* 20836647Skarels * Note if trying multiple user names; 20936647Skarels * log failures for previous user name, 21036647Skarels * but don't bother logging one failure 21136647Skarels * for nonexistent name (mistyped username). 21236647Skarels */ 21336647Skarels if (failures && strcmp(tbuf, username)) { 21436647Skarels if (failures > (pwd ? 0 : 1)) 21536549Sbostic badlogin(tbuf); 21636647Skarels failures = 0; 21736549Sbostic } 21836647Skarels (void)strcpy(tbuf, username); 21936515Sbostic if (pwd = getpwnam(username)) 22036515Sbostic salt = pwd->pw_passwd; 22136515Sbostic else 22236515Sbostic salt = "xx"; 22336460Sbostic 22436460Sbostic /* if user not super-user, check for disabled logins */ 22536515Sbostic if (pwd == NULL || pwd->pw_uid) 22636460Sbostic checknologin(); 22736460Sbostic 22812687Ssam /* 22936515Sbostic * Disallow automatic login to root; if not invoked by 23036515Sbostic * root, disallow if the uid's differ. 23112687Ssam */ 23236515Sbostic if (fflag && pwd) { 23331695Skarels int uid = getuid(); 23431695Skarels 235*38726Skfall passwd_req = 236*38726Skfall #ifndef KERBEROS 237*38726Skfall pwd->pw_uid == 0 || 238*38726Skfall #endif 23936515Sbostic (uid && uid != pwd->pw_uid); 24031695Skarels } 24136460Sbostic 24212687Ssam /* 24336523Skarels * If no pre-authentication and a password exists 24436460Sbostic * for this user, prompt for one and verify it. 24512687Ssam */ 24636608Skfall if (!passwd_req || (pwd && !*pwd->pw_passwd)) 24736460Sbostic break; 24812687Ssam 24936460Sbostic setpriority(PRIO_PROCESS, 0, -4); 25036608Skfall pp = getpass("Password:"); 25136608Skfall p = crypt(pp, salt); 25236460Sbostic setpriority(PRIO_PROCESS, 0, 0); 25336608Skfall 25437203Sbostic #ifdef KERBEROS 25537203Sbostic 25637203Sbostic /* 25737203Sbostic * If not present in pw file, act as we normally would. 25837203Sbostic * If we aren't Kerberos-authenticated, try the normal 25937203Sbostic * pw file for a password. If that's ok, log the user 26037203Sbostic * in without issueing any tickets. 26137203Sbostic */ 26237203Sbostic 26338034Skfall if (pwd && (krb_get_lrealm(realm,1) == KSUCCESS)) { 264*38726Skfall 26537203Sbostic /* 266*38726Skfall * get TGT for local realm 267*38726Skfall * convention: store tickets in file 268*38726Skfall * associated with tty name 26937203Sbostic */ 270*38726Skfall 271*38726Skfall (void)sprintf(tkfile, "%s_%s", TKT_ROOT, tty); 272*38726Skfall kerror = INTK_ERR; 273*38726Skfall if (setenv("KRBTKFILE", tkfile, 1) < 0) 274*38726Skfall syslog(LOG_ERR, "couldn't set tkfile environ"); 275*38726Skfall else { 276*38726Skfall kerror = krb_get_pw_in_tkt( 277*38726Skfall PRINCIPAL_NAME, PRINCIPAL_INST, realm, 278*38726Skfall INITIAL_TICKET, realm, DEFAULT_TKT_LIFE, 279*38726Skfall pp); 280*38726Skfall if ((kerror == KSUCCESS) && 281*38726Skfall (chown(tkfile, pwd->pw_uid) < 0)) { 282*38726Skfall syslog(LOG_ERR, 283*38726Skfall "couldn't chown tkfile: %m"); 284*38726Skfall kerror = INTK_ERR; 285*38726Skfall } 286*38726Skfall } 28738034Skfall /* 28838034Skfall * If we got a TGT, get a local "rcmd" ticket and 28938034Skfall * check it so as to ensure that we are not 29038034Skfall * talking to a bogus Kerberos server 291*38726Skfall * 292*38726Skfall * There are 2 cases where we still allow a login: 293*38726Skfall * 1> the VERIFY_SERVICE doesn't exist in the KDC 294*38726Skfall * 2> local host has no srvtab, as (hopefully) 295*38726Skfall * indicated by a return value of RD_AP_UNDEC 296*38726Skfall * from krb_rd_req() 29738034Skfall */ 29837203Sbostic if (kerror == INTK_OK) { 29938034Skfall (void) strncpy(savehost, 30038034Skfall krb_get_phost(localhost), 30138034Skfall sizeof(savehost)); 30238034Skfall savehost[sizeof(savehost)-1] = NULL; 30338034Skfall kerror = krb_mk_req(&ticket, VERIFY_SERVICE, 30438034Skfall savehost, realm, 33); 305*38726Skfall /* 306*38726Skfall * if the "VERIFY_SERVICE" doesn't exist in the 307*38726Skfall * KDC for this host, still allow login, 308*38726Skfall * but log the error condition 309*38726Skfall */ 31038034Skfall if (kerror == KDC_PR_UNKNOWN) { 311*38726Skfall syslog(LOG_NOTICE, 31238034Skfall "Warning: TGT not verified (%s)", 31338034Skfall krb_err_txt[kerror]); 31438034Skfall bzero(pp, strlen(pp)); 31538034Skfall notickets = 0; 31638034Skfall break; /* ok */ 31738034Skfall } else if (kerror != KSUCCESS) { 31838034Skfall printf("Unable to use TGT: (%s)\n", 31938034Skfall krb_err_txt[kerror]); 320*38726Skfall syslog(LOG_NOTICE, 32138034Skfall "Unable to use TGT: (%s)", 32238034Skfall krb_err_txt[kerror]); 32338034Skfall dest_tkt(); 32438034Skfall /* fall thru: no login */ 32538034Skfall } else { 32638034Skfall if (!(hp = gethostbyname(localhost))) { 32738034Skfall syslog(LOG_ERR, "couldn't get local host address"); 32838034Skfall } else { 32938034Skfall bcopy((char *) hp->h_addr, 33038034Skfall (char *) &faddr, sizeof(faddr)); 33138034Skfall if ((kerror = krb_rd_req(&ticket, 33238034Skfall VERIFY_SERVICE, savehost, faddr, 33338034Skfall &authdata, "")) != KSUCCESS) { 334*38726Skfall 335*38726Skfall if (kerror = RD_AP_UNDEC) { 336*38726Skfall syslog(LOG_NOTICE, 337*38726Skfall "krb_rd_req: (%s)\n", 338*38726Skfall krb_err_txt[kerror]); 339*38726Skfall bzero(pp, strlen(pp)); 340*38726Skfall notickets = 0; 341*38726Skfall break; /* ok */ 342*38726Skfall } else { 343*38726Skfall printf("Unable to verify %s ticket: (%s)\n", 344*38726Skfall VERIFY_SERVICE, 34538034Skfall krb_err_txt[kerror]); 346*38726Skfall syslog(LOG_NOTICE, 347*38726Skfall "couldn't verify %s ticket: %s", 348*38726Skfall VERIFY_SERVICE, 34938034Skfall krb_err_txt[kerror]); 350*38726Skfall } 351*38726Skfall /* fall thru: no login */ 35238034Skfall } else { 35338034Skfall bzero(pp, strlen(pp)); 35438034Skfall notickets = 0; /* got ticket */ 35538034Skfall break; /* ok */ 35638034Skfall } 35738034Skfall } 35838034Skfall } 35938034Skfall 36037203Sbostic } 36137203Sbostic } 362*38726Skfall 36337203Sbostic #endif 36436608Skfall (void) bzero(pp, strlen(pp)); 36536515Sbostic if (pwd && !strcmp(p, pwd->pw_passwd)) 36636460Sbostic break; 36736460Sbostic 36837203Sbostic (void)printf("Login incorrect\n"); 36936647Skarels failures++; 37036549Sbostic /* we allow 10 tries, but after 3 we start backing off */ 37136549Sbostic if (++cnt > 3) { 37236549Sbostic if (cnt >= 10) { 37336549Sbostic badlogin(username); 37436549Sbostic (void)ioctl(0, TIOCHPCL, (struct sgttyb *)NULL); 37536549Sbostic sleepexit(1); 37636549Sbostic } 37736549Sbostic sleep((u_int)((cnt - 3) * 5)); 3782822Swnj } 37936460Sbostic } 3801043Sbill 38136460Sbostic /* committed to login -- turn off timeout */ 38236460Sbostic (void)alarm((u_int)0); 38336460Sbostic 38437692Sbostic /* paranoia... */ 38537692Sbostic endpwent(); 38637692Sbostic 38736460Sbostic /* 38836460Sbostic * If valid so far and root is logging in, see if root logins on 38936460Sbostic * this terminal are permitted. 39036460Sbostic */ 39136647Skarels if (pwd->pw_uid == 0 && !rootterm(tty)) { 39236460Sbostic if (hostname) 39336647Skarels syslog(LOG_NOTICE, "ROOT LOGIN REFUSED FROM %s", 39436647Skarels hostname); 39512678Ssam else 39636647Skarels syslog(LOG_NOTICE, "ROOT LOGIN REFUSED ON %s", tty); 39737203Sbostic (void)printf("Login incorrect\n"); 39836460Sbostic sleepexit(1); 39912678Ssam } 4002822Swnj 40136460Sbostic if (quota(Q_SETUID, pwd->pw_uid, 0, 0) < 0 && errno != EINVAL) { 40236460Sbostic switch(errno) { 40336460Sbostic case EUSERS: 40437203Sbostic (void)fprintf(stderr, 40536460Sbostic "Too many users logged on already.\nTry again later.\n"); 40636460Sbostic break; 40736460Sbostic case EPROCLIM: 40837203Sbostic (void)fprintf(stderr, 40936460Sbostic "You have too many processes running.\n"); 41036460Sbostic break; 41136460Sbostic default: 41236460Sbostic perror("quota (Q_SETUID)"); 4132822Swnj } 41436460Sbostic sleepexit(0); 4152822Swnj } 41636460Sbostic 41736515Sbostic if (chdir(pwd->pw_dir) < 0) { 41837203Sbostic (void)printf("No directory %s!\n", pwd->pw_dir); 41936515Sbostic if (chdir("/")) 42036515Sbostic exit(0); 42136515Sbostic pwd->pw_dir = "/"; 42237203Sbostic (void)printf("Logging in with home = \"/\".\n"); 42336515Sbostic } 42436515Sbostic 42537203Sbostic quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0; 42637203Sbostic 42737203Sbostic #ifdef KERBEROS 42837203Sbostic if (notickets && !quietlog) 42937203Sbostic (void)printf("Warning: no Kerberos tickets issued\n"); 43037203Sbostic #endif 43137203Sbostic 432*38726Skfall #if BSD > 43 43336880Sbostic if (pwd->pw_change || pwd->pw_expire) 43436880Sbostic (void)gettimeofday(&tp, (struct timezone *)NULL); 43536880Sbostic if (pwd->pw_change) 43636880Sbostic if (tp.tv_sec >= pwd->pw_change) { 43737203Sbostic (void)printf("Sorry -- your password has expired.\n"); 43836880Sbostic sleepexit(1); 43936880Sbostic } 44038216Sbostic else if (pwd->pw_change - tp.tv_sec < 44138216Sbostic 2 * DAYSPERWEEK * SECSPERDAY && !quietlog) { 44236880Sbostic ttp = localtime(&pwd->pw_change); 44337203Sbostic (void)printf("Warning: your password expires on %s %d, %d\n", 44438216Sbostic months[ttp->tm_mon], ttp->tm_mday, 44538216Sbostic TM_YEAR_BASE + ttp->tm_year); 44636880Sbostic } 44736880Sbostic if (pwd->pw_expire) 44836880Sbostic if (tp.tv_sec >= pwd->pw_expire) { 44937203Sbostic (void)printf("Sorry -- your account has expired.\n"); 45036880Sbostic sleepexit(1); 45136880Sbostic } 45238216Sbostic else if (pwd->pw_expire - tp.tv_sec < 45338216Sbostic 2 * DAYSPERWEEK * SECSPERDAY && !quietlog) { 45436880Sbostic ttp = localtime(&pwd->pw_expire); 45537203Sbostic (void)printf("Warning: your account expires on %s %d, %d\n", 45638216Sbostic months[ttp->tm_mon], ttp->tm_mday, 45738216Sbostic TM_YEAR_BASE + ttp->tm_year); 45836880Sbostic } 459*38726Skfall #endif 46036880Sbostic 46136515Sbostic /* nothing else left to fail -- really log in */ 46236460Sbostic { 46336460Sbostic struct utmp utmp; 46436460Sbostic 46536647Skarels bzero((char *)&utmp, sizeof(utmp)); 46636460Sbostic (void)time(&utmp.ut_time); 46736460Sbostic strncpy(utmp.ut_name, username, sizeof(utmp.ut_name)); 46836591Sbostic if (hostname) 46936591Sbostic strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host)); 47036460Sbostic strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line)); 47136460Sbostic login(&utmp); 47236460Sbostic } 47336460Sbostic 47436549Sbostic dolastlog(quietlog); 47536460Sbostic 47637203Sbostic if (!hflag) { /* XXX */ 47736460Sbostic static struct winsize win = { 0, 0, 0, 0 }; 47836460Sbostic 47936460Sbostic (void)ioctl(0, TIOCSWINSZ, &win); 48036460Sbostic } 48136460Sbostic 48236460Sbostic (void)chown(ttyn, pwd->pw_uid, 48336460Sbostic (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid); 48436460Sbostic (void)chmod(ttyn, 0620); 48536460Sbostic (void)setgid(pwd->pw_gid); 48636460Sbostic 48736460Sbostic initgroups(username, pwd->pw_gid); 48836460Sbostic 48912678Ssam quota(Q_DOWARN, pwd->pw_uid, (dev_t)-1, 0); 49030606Sbostic 49136515Sbostic if (*pwd->pw_shell == '\0') 49237203Sbostic pwd->pw_shell = _PATH_BSHELL; 49336515Sbostic 49436460Sbostic /* destroy environment unless user has requested preservation */ 49518549Ssam if (!pflag) 49618549Ssam environ = envinit; 49736515Sbostic (void)setenv("HOME", pwd->pw_dir, 1); 49836515Sbostic (void)setenv("SHELL", pwd->pw_shell, 1); 49918549Ssam if (term[0] == '\0') 50036647Skarels strncpy(term, stypeof(tty), sizeof(term)); 50136515Sbostic (void)setenv("TERM", term, 0); 50236515Sbostic (void)setenv("USER", pwd->pw_name, 1); 50337252Sbostic (void)setenv("PATH", _PATH_DEFPATH, 0); 50418549Ssam 50516453Sroot if (tty[sizeof("tty")-1] == 'd') 50618549Ssam syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name); 50718549Ssam if (pwd->pw_uid == 0) 50836460Sbostic if (hostname) 50936647Skarels syslog(LOG_NOTICE, "ROOT LOGIN ON %s FROM %s", 51036549Sbostic tty, hostname); 51125230Smckusick else 51236647Skarels syslog(LOG_NOTICE, "ROOT LOGIN ON %s", tty); 51336460Sbostic 5146329Swnj if (!quietlog) { 51517664Sserge struct stat st; 51618549Ssam 51736460Sbostic motd(); 51837203Sbostic (void)sprintf(tbuf, "%s/%s", _PATH_MAILDIR, pwd->pw_name); 51936460Sbostic if (stat(tbuf, &st) == 0 && st.st_size != 0) 52037203Sbostic (void)printf("You have %smail.\n", 52136460Sbostic (st.st_mtime > st.st_atime) ? "new " : ""); 5222822Swnj } 52336460Sbostic 52436460Sbostic (void)signal(SIGALRM, SIG_DFL); 52536460Sbostic (void)signal(SIGQUIT, SIG_DFL); 52636460Sbostic (void)signal(SIGINT, SIG_DFL); 52736460Sbostic (void)signal(SIGTSTP, SIG_IGN); 52836460Sbostic 52936460Sbostic tbuf[0] = '-'; 53036460Sbostic strcpy(tbuf + 1, (p = rindex(pwd->pw_shell, '/')) ? 53136460Sbostic p + 1 : pwd->pw_shell); 53237203Sbostic 533*38726Skfall #if BSD > 43 53437692Sbostic if (setlogname(pwd->pw_name, strlen(pwd->pw_name)) < 0) 53537692Sbostic syslog(LOG_ERR, "setlogname() failure: %m"); 536*38726Skfall #endif 53737692Sbostic 53837203Sbostic /* discard permissions last so can't get killed and drop core */ 53937203Sbostic (void)setuid(pwd->pw_uid); 54037203Sbostic 54136460Sbostic execlp(pwd->pw_shell, tbuf, 0); 54237203Sbostic (void)fprintf(stderr, "login: no shell: %s.\n", strerror(errno)); 5431043Sbill exit(0); 5441043Sbill } 5451043Sbill 54636460Sbostic getloginname() 54712687Ssam { 54836460Sbostic register int ch; 54936460Sbostic register char *p; 55036460Sbostic static char nbuf[UT_NAMESIZE + 1]; 55112687Ssam 55236460Sbostic for (;;) { 55337203Sbostic (void)printf("login: "); 55436515Sbostic for (p = nbuf; (ch = getchar()) != '\n'; ) { 55536549Sbostic if (ch == EOF) { 55636549Sbostic badlogin(username); 55712687Ssam exit(0); 55836549Sbostic } 55936515Sbostic if (p < nbuf + UT_NAMESIZE) 56036460Sbostic *p++ = ch; 56112687Ssam } 56236460Sbostic if (p > nbuf) 56336460Sbostic if (nbuf[0] == '-') 56437203Sbostic (void)fprintf(stderr, 56536460Sbostic "login names may not start with '-'.\n"); 56636460Sbostic else { 56736460Sbostic *p = '\0'; 56836460Sbostic username = nbuf; 56936515Sbostic break; 57036460Sbostic } 57112687Ssam } 57212687Ssam } 57312687Ssam 57412687Ssam timedout() 57512687Ssam { 57637203Sbostic (void)fprintf(stderr, "Login timed out after %d seconds\n", timeout); 57712687Ssam exit(0); 57812687Ssam } 57912687Ssam 58036647Skarels rootterm(ttyn) 58136647Skarels char *ttyn; 5821043Sbill { 58336460Sbostic struct ttyent *t; 5846466Swnj 58536647Skarels return((t = getttynam(ttyn)) && t->ty_status&TTY_SECURE); 5861043Sbill } 5871043Sbill 58836515Sbostic jmp_buf motdinterrupt; 58936515Sbostic 59036460Sbostic motd() 5912822Swnj { 59236515Sbostic register int fd, nchars; 593*38726Skfall sig_t oldint; 594*38726Skfall int sigint(); 59536515Sbostic char tbuf[8192]; 5962822Swnj 59737203Sbostic if ((fd = open(_PATH_MOTDFILE, O_RDONLY, 0)) < 0) 59836460Sbostic return; 59936460Sbostic oldint = signal(SIGINT, sigint); 60036515Sbostic if (setjmp(motdinterrupt) == 0) 60136515Sbostic while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) 60236515Sbostic (void)write(fileno(stdout), tbuf, nchars); 60336460Sbostic (void)signal(SIGINT, oldint); 60436515Sbostic (void)close(fd); 60536460Sbostic } 60636460Sbostic 60736460Sbostic sigint() 60836460Sbostic { 60936515Sbostic longjmp(motdinterrupt, 1); 61036460Sbostic } 61136460Sbostic 61236460Sbostic checknologin() 61336460Sbostic { 61436460Sbostic register int fd, nchars; 61536515Sbostic char tbuf[8192]; 61636460Sbostic 61737203Sbostic if ((fd = open(_PATH_NOLOGIN, O_RDONLY, 0)) >= 0) { 61836460Sbostic while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) 61936460Sbostic (void)write(fileno(stdout), tbuf, nchars); 62036460Sbostic sleepexit(0); 6212822Swnj } 6222822Swnj } 6232822Swnj 62436549Sbostic dolastlog(quiet) 62536460Sbostic int quiet; 6261043Sbill { 62736460Sbostic struct lastlog ll; 62836460Sbostic int fd; 62936880Sbostic char *ctime(); 6301043Sbill 63137203Sbostic if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) { 63236515Sbostic (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); 63336460Sbostic if (!quiet) { 63436460Sbostic if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) && 63536460Sbostic ll.ll_time != 0) { 63637203Sbostic (void)printf("Last login: %.*s ", 63736460Sbostic 24-5, (char *)ctime(&ll.ll_time)); 63836460Sbostic if (*ll.ll_host != '\0') 63937203Sbostic (void)printf("from %.*s\n", 64036460Sbostic sizeof(ll.ll_host), ll.ll_host); 64136460Sbostic else 64237203Sbostic (void)printf("on %.*s\n", 64336460Sbostic sizeof(ll.ll_line), ll.ll_line); 64436460Sbostic } 64536515Sbostic (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); 64636460Sbostic } 64736647Skarels bzero((char *)&ll, sizeof(ll)); 64836460Sbostic (void)time(&ll.ll_time); 64936460Sbostic strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); 65036591Sbostic if (hostname) 65136591Sbostic strncpy(ll.ll_host, hostname, sizeof(ll.ll_host)); 65236460Sbostic (void)write(fd, (char *)&ll, sizeof(ll)); 65336460Sbostic (void)close(fd); 6541043Sbill } 6551043Sbill } 6561043Sbill 65736549Sbostic badlogin(name) 65836549Sbostic char *name; 65936549Sbostic { 66036647Skarels if (failures == 0) 66136549Sbostic return; 66236549Sbostic if (hostname) 66336647Skarels syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s, %s", 66436647Skarels failures, failures > 1 ? "S" : "", hostname, name); 66536549Sbostic else 66636647Skarels syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s, %s", 66736647Skarels failures, failures > 1 ? "S" : "", tty, name); 66836549Sbostic } 66936549Sbostic 6702822Swnj #undef UNKNOWN 67136460Sbostic #define UNKNOWN "su" 6721043Sbill 6731043Sbill char * 67436647Skarels stypeof(ttyid) 67536647Skarels char *ttyid; 6761043Sbill { 67736460Sbostic struct ttyent *t; 6781043Sbill 67936647Skarels return(ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN); 6801043Sbill } 6816005Swnj 6826005Swnj getstr(buf, cnt, err) 68336460Sbostic char *buf, *err; 6846005Swnj int cnt; 6856005Swnj { 68636460Sbostic char ch; 6876005Swnj 6886005Swnj do { 68936460Sbostic if (read(0, &ch, sizeof(ch)) != sizeof(ch)) 6906005Swnj exit(1); 6916005Swnj if (--cnt < 0) { 69237203Sbostic (void)fprintf(stderr, "%s too long\r\n", err); 69336460Sbostic sleepexit(1); 6946005Swnj } 69536460Sbostic *buf++ = ch; 69636460Sbostic } while (ch); 6976005Swnj } 6986329Swnj 69936460Sbostic sleepexit(eval) 70036460Sbostic int eval; 70126862Smckusick { 70236460Sbostic sleep((u_int)5); 70336460Sbostic exit(eval); 70426862Smckusick } 705