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*36523Skarels static char sccsid[] = "@(#)login.c 5.26 (Berkeley) 01/06/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> 3512687Ssam #include <sys/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> 441043Sbill #include <lastlog.h> 4512678Ssam #include <errno.h> 4616453Sroot #include <ttyent.h> 4716453Sroot #include <syslog.h> 4826862Smckusick #include <grp.h> 4936460Sbostic #include <pwd.h> 5036515Sbostic #include <setjmp.h> 5136460Sbostic #include <stdio.h> 5236460Sbostic #include <strings.h> 531043Sbill 5436460Sbostic #define TTYGRPNAME "tty" /* name of group to own ttys */ 5526862Smckusick 5636460Sbostic #define MOTDFILE "/etc/motd" 5736460Sbostic #define MAILDIR "/usr/spool/mail" 5836460Sbostic #define NOLOGIN "/etc/nologin" 5936460Sbostic #define HUSHLOGIN ".hushlogin" 6036460Sbostic #define LASTLOG "/usr/adm/lastlog" 6136460Sbostic #define BSHELL "/bin/sh" 622822Swnj 6312687Ssam /* 6436460Sbostic * This bounds the time given to login. Not a define so it can 6536460Sbostic * be patched on machines where it's too small. 6612687Ssam */ 6731509Sbostic int timeout = 300; 686005Swnj 6936460Sbostic struct passwd *pwd; 7036460Sbostic char term[64], *hostname, *username; 716005Swnj 7236515Sbostic struct sgttyb sgttyb; 7336460Sbostic struct tchars tc = { 7413074Ssam CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK 751365Sbill }; 7636460Sbostic struct ltchars ltc = { 7713074Ssam CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE, CLNEXT 7813074Ssam }; 791365Sbill 801043Sbill main(argc, argv) 8136460Sbostic int argc; 8236460Sbostic char **argv; 831043Sbill { 8436460Sbostic extern int errno, optind; 8536460Sbostic extern char *optarg, **environ; 8636460Sbostic struct group *gr; 8736460Sbostic register int ch; 8836460Sbostic register char *p; 89*36523Skarels int fflag, hflag, pflag, cnt; 9036460Sbostic int quietlog, passwd_req, ioctlval, timedout(); 9136515Sbostic char *domain, *salt, *envinit[1], *ttyn, *tty; 9236460Sbostic char tbuf[MAXPATHLEN + 2]; 9336460Sbostic char *ttyname(), *stypeof(), *crypt(), *getpass(); 9436460Sbostic time_t time(); 9536460Sbostic off_t lseek(); 961043Sbill 9736460Sbostic (void)signal(SIGALRM, timedout); 9836460Sbostic (void)alarm((u_int)timeout); 9936460Sbostic (void)signal(SIGQUIT, SIG_IGN); 10036460Sbostic (void)signal(SIGINT, SIG_IGN); 10136460Sbostic (void)setpriority(PRIO_PROCESS, 0, 0); 10236460Sbostic (void)quota(Q_SETUID, 0, 0, 0); 10336460Sbostic 10412687Ssam /* 10518549Ssam * -p is used by getty to tell login not to destroy the environment 10631695Skarels * -f is used to skip a second login authentication 107*36523Skarels * -h is used by other servers to pass the name of the remote 108*36523Skarels * host to login so that it may be placed in utmp and wtmp 10912687Ssam */ 11036460Sbostic (void)gethostname(tbuf, sizeof(tbuf)); 11136460Sbostic domain = index(tbuf, '.'); 11236460Sbostic 113*36523Skarels fflag = hflag = pflag = 0; 11436460Sbostic passwd_req = 1; 115*36523Skarels while ((ch = getopt(argc, argv, "fh:p")) != EOF) 11636515Sbostic switch (ch) { 11736460Sbostic case 'f': 11836460Sbostic fflag = 1; 11936460Sbostic break; 12036460Sbostic case 'h': 12136460Sbostic if (getuid()) { 12236460Sbostic fprintf(stderr, 12336460Sbostic "login: -h for super-user only.\n"); 12432313Sbostic exit(1); 12531695Skarels } 12636460Sbostic hflag = 1; 12736460Sbostic if (domain && (p = index(optarg, '.')) && 12836460Sbostic strcmp(p, domain) == 0) 12936460Sbostic *p = 0; 13036460Sbostic hostname = optarg; 13136460Sbostic break; 13236460Sbostic case 'p': 13318549Ssam pflag = 1; 13436460Sbostic break; 13536460Sbostic case '?': 13636460Sbostic default: 13736515Sbostic fprintf(stderr, "usage: login [-fp] [username]\n"); 13836460Sbostic exit(1); 13918549Ssam } 14036460Sbostic argc -= optind; 14136460Sbostic argv += optind; 14236460Sbostic if (*argv) 14336460Sbostic username = *argv; 14436460Sbostic 14536460Sbostic ioctlval = 0; 14636460Sbostic (void)ioctl(0, TIOCLSET, &ioctlval); 14736460Sbostic (void)ioctl(0, TIOCNXCL, 0); 14836515Sbostic (void)fcntl(0, F_SETFL, ioctlval); 14936515Sbostic (void)ioctl(0, TIOCGETP, &sgttyb); 15036515Sbostic sgttyb.sg_erase = CERASE; 15136515Sbostic sgttyb.sg_kill = CKILL; 15236460Sbostic (void)ioctl(0, TIOCSLTC, <c); 15336460Sbostic (void)ioctl(0, TIOCSETC, &tc); 15436515Sbostic (void)ioctl(0, TIOCSETP, &sgttyb); 15536460Sbostic 15636460Sbostic for (cnt = getdtablesize(); cnt > 2; cnt--) 15736460Sbostic close(cnt); 15836460Sbostic 1591043Sbill ttyn = ttyname(0); 16036460Sbostic if (ttyn == NULL || *ttyn == '\0') 1611043Sbill ttyn = "/dev/tty??"; 16236460Sbostic if (tty = rindex(ttyn, '/')) 16336460Sbostic ++tty; 16436460Sbostic else 16516453Sroot tty = ttyn; 16636460Sbostic 16724852Seric openlog("login", LOG_ODELAY, LOG_AUTH); 16836460Sbostic 16936460Sbostic for (cnt = 0;; username = NULL) { 17036460Sbostic ioctlval = 0; 17136460Sbostic (void)ioctl(0, TIOCSETD, &ioctlval); 17236460Sbostic 17336515Sbostic if (username == NULL) { 17436515Sbostic fflag = 0; 17536460Sbostic getloginname(); 17636515Sbostic } 17736515Sbostic if (pwd = getpwnam(username)) 17836515Sbostic salt = pwd->pw_passwd; 17936515Sbostic else 18036515Sbostic salt = "xx"; 18136460Sbostic 18236460Sbostic /* if user not super-user, check for disabled logins */ 18336515Sbostic if (pwd == NULL || pwd->pw_uid) 18436460Sbostic checknologin(); 18536460Sbostic 18612687Ssam /* 18736515Sbostic * Disallow automatic login to root; if not invoked by 18836515Sbostic * root, disallow if the uid's differ. 18912687Ssam */ 19036515Sbostic if (fflag && pwd) { 19131695Skarels int uid = getuid(); 19231695Skarels 19336515Sbostic passwd_req = pwd->pw_uid == 0 || 19436515Sbostic (uid && uid != pwd->pw_uid); 19531695Skarels } 19636460Sbostic 19712687Ssam /* 198*36523Skarels * If no pre-authentication and a password exists 19936460Sbostic * for this user, prompt for one and verify it. 20012687Ssam */ 20136515Sbostic if (!passwd_req || pwd && !*pwd->pw_passwd) 20236460Sbostic break; 20312687Ssam 20436460Sbostic setpriority(PRIO_PROCESS, 0, -4); 20536515Sbostic p = crypt(getpass("Password:"), salt); 20636460Sbostic setpriority(PRIO_PROCESS, 0, 0); 20736515Sbostic if (pwd && !strcmp(p, pwd->pw_passwd)) 20836460Sbostic break; 20936460Sbostic 21036460Sbostic printf("Login incorrect\n"); 21136460Sbostic if (++cnt >= 5) { 21236460Sbostic if (hostname) 21336460Sbostic syslog(LOG_ERR, 21436460Sbostic "REPEATED LOGIN FAILURES ON %s FROM %.*s, %.*s", 21536460Sbostic tty, UT_HOSTSIZE, hostname, UT_NAMESIZE, 21636460Sbostic username); 21725230Smckusick else 21836460Sbostic syslog(LOG_ERR, 21936460Sbostic "REPEATED LOGIN FAILURES ON %s, %.*s", 22036460Sbostic tty, UT_NAMESIZE, username); 22136460Sbostic (void)ioctl(0, TIOCHPCL, (struct sgttyb *)NULL); 22236460Sbostic sleepexit(1); 2232822Swnj } 22436460Sbostic } 2251043Sbill 22636460Sbostic /* committed to login -- turn off timeout */ 22736460Sbostic (void)alarm((u_int)0); 22836460Sbostic 22936460Sbostic /* 23036460Sbostic * If valid so far and root is logging in, see if root logins on 23136460Sbostic * this terminal are permitted. 23236460Sbostic */ 23336515Sbostic if (pwd->pw_uid == 0 && !rootterm(tty)) { 23436460Sbostic if (hostname) 23536515Sbostic syslog(LOG_ERR, "ROOT LOGIN REFUSED ON %s FROM %.*s", 23636460Sbostic tty, UT_HOSTSIZE, hostname); 23712678Ssam else 23836515Sbostic syslog(LOG_ERR, "ROOT LOGIN REFUSED ON %s", tty); 23936460Sbostic printf("Login incorrect\n"); 24036460Sbostic sleepexit(1); 24112678Ssam } 2422822Swnj 24336460Sbostic if (quota(Q_SETUID, pwd->pw_uid, 0, 0) < 0 && errno != EINVAL) { 24436460Sbostic switch(errno) { 24536460Sbostic case EUSERS: 24636460Sbostic fprintf(stderr, 24736460Sbostic "Too many users logged on already.\nTry again later.\n"); 24836460Sbostic break; 24936460Sbostic case EPROCLIM: 25036460Sbostic fprintf(stderr, 25136460Sbostic "You have too many processes running.\n"); 25236460Sbostic break; 25336460Sbostic default: 25436460Sbostic perror("quota (Q_SETUID)"); 2552822Swnj } 25636460Sbostic sleepexit(0); 2572822Swnj } 25836460Sbostic 25936515Sbostic if (chdir(pwd->pw_dir) < 0) { 26036515Sbostic printf("No directory %s!\n", pwd->pw_dir); 26136515Sbostic if (chdir("/")) 26236515Sbostic exit(0); 26336515Sbostic pwd->pw_dir = "/"; 26436515Sbostic printf("Logging in with home = \"/\".\n"); 26536515Sbostic } 26636515Sbostic 26736515Sbostic /* nothing else left to fail -- really log in */ 26836460Sbostic { 26936460Sbostic struct utmp utmp; 27036460Sbostic 27136460Sbostic (void)time(&utmp.ut_time); 27236460Sbostic strncpy(utmp.ut_name, username, sizeof(utmp.ut_name)); 27336460Sbostic strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host)); 27436460Sbostic strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line)); 27536460Sbostic login(&utmp); 27636460Sbostic } 27736460Sbostic 27836460Sbostic quietlog = access(HUSHLOGIN, F_OK) == 0; 27936460Sbostic dolastlog(quietlog, tty); 28036460Sbostic 281*36523Skarels if (!hflag) { /* XXX */ 28236460Sbostic static struct winsize win = { 0, 0, 0, 0 }; 28336460Sbostic 28436460Sbostic (void)ioctl(0, TIOCSWINSZ, &win); 28536460Sbostic } 28636460Sbostic 28736460Sbostic (void)chown(ttyn, pwd->pw_uid, 28836460Sbostic (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid); 28936460Sbostic (void)chmod(ttyn, 0620); 29036460Sbostic (void)setgid(pwd->pw_gid); 29136460Sbostic 29236460Sbostic initgroups(username, pwd->pw_gid); 29336460Sbostic 29412678Ssam quota(Q_DOWARN, pwd->pw_uid, (dev_t)-1, 0); 29536460Sbostic (void)setuid(pwd->pw_uid); 29630606Sbostic 29736515Sbostic if (*pwd->pw_shell == '\0') 29836515Sbostic pwd->pw_shell = BSHELL; 29936515Sbostic /* turn on new line discipline for the csh */ 30036515Sbostic else if (!strcmp(pwd->pw_shell, "/bin/csh")) { 30136515Sbostic ioctlval = NTTYDISC; 30236515Sbostic (void)ioctl(0, TIOCSETD, &ioctlval); 30336515Sbostic } 30436515Sbostic 30536460Sbostic /* destroy environment unless user has requested preservation */ 30618549Ssam if (!pflag) 30718549Ssam environ = envinit; 30836515Sbostic (void)setenv("HOME", pwd->pw_dir, 1); 30936515Sbostic (void)setenv("SHELL", pwd->pw_shell, 1); 31018549Ssam if (term[0] == '\0') 31118549Ssam strncpy(term, stypeof(tty), sizeof(term)); 31236515Sbostic (void)setenv("TERM", term, 0); 31336515Sbostic (void)setenv("USER", pwd->pw_name, 1); 31436515Sbostic (void)setenv("PATH", "/usr/ucb:/bin:/usr/bin:", 0); 31518549Ssam 31616453Sroot if (tty[sizeof("tty")-1] == 'd') 31718549Ssam syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name); 31818549Ssam if (pwd->pw_uid == 0) 31936460Sbostic if (hostname) 32025230Smckusick syslog(LOG_NOTICE, "ROOT LOGIN %s FROM %.*s", 32136460Sbostic tty, UT_HOSTSIZE, hostname); 32225230Smckusick else 32325230Smckusick syslog(LOG_NOTICE, "ROOT LOGIN %s", tty); 32436460Sbostic 3256329Swnj if (!quietlog) { 32617664Sserge struct stat st; 32718549Ssam 32836460Sbostic motd(); 32936460Sbostic (void)sprintf(tbuf, "%s/%s", MAILDIR, pwd->pw_name); 33036460Sbostic if (stat(tbuf, &st) == 0 && st.st_size != 0) 33117664Sserge printf("You have %smail.\n", 33236460Sbostic (st.st_mtime > st.st_atime) ? "new " : ""); 3332822Swnj } 33436460Sbostic 33536460Sbostic (void)signal(SIGALRM, SIG_DFL); 33636460Sbostic (void)signal(SIGQUIT, SIG_DFL); 33736460Sbostic (void)signal(SIGINT, SIG_DFL); 33836460Sbostic (void)signal(SIGTSTP, SIG_IGN); 33936460Sbostic 34036460Sbostic tbuf[0] = '-'; 34136460Sbostic strcpy(tbuf + 1, (p = rindex(pwd->pw_shell, '/')) ? 34236460Sbostic p + 1 : pwd->pw_shell); 34336460Sbostic execlp(pwd->pw_shell, tbuf, 0); 34436515Sbostic fprintf(stderr, "login: no shell: "); 3452822Swnj perror(pwd->pw_shell); 3461043Sbill exit(0); 3471043Sbill } 3481043Sbill 34936460Sbostic getloginname() 35012687Ssam { 35136460Sbostic register int ch; 35236460Sbostic register char *p; 35336460Sbostic static char nbuf[UT_NAMESIZE + 1]; 35412687Ssam 35536460Sbostic for (;;) { 35612712Ssam printf("login: "); 35736515Sbostic for (p = nbuf; (ch = getchar()) != '\n'; ) { 35836460Sbostic if (ch == EOF) 35912687Ssam exit(0); 36036515Sbostic if (p < nbuf + UT_NAMESIZE) 36136460Sbostic *p++ = ch; 36212687Ssam } 36336460Sbostic if (p > nbuf) 36436460Sbostic if (nbuf[0] == '-') 36536460Sbostic fprintf(stderr, 36636460Sbostic "login names may not start with '-'.\n"); 36736460Sbostic else { 36836460Sbostic *p = '\0'; 36936460Sbostic username = nbuf; 37036515Sbostic break; 37136460Sbostic } 37212687Ssam } 37312687Ssam } 37412687Ssam 37512687Ssam timedout() 37612687Ssam { 37736460Sbostic fprintf(stderr, "Login timed out after %d seconds\n", timeout); 37812687Ssam exit(0); 37912687Ssam } 38012687Ssam 38136460Sbostic rootterm(tty) 38236460Sbostic char *tty; 3831043Sbill { 38436460Sbostic struct ttyent *t; 3856466Swnj 38636460Sbostic return((t = getttynam(tty)) && t->ty_status&TTY_SECURE); 3871043Sbill } 3881043Sbill 38936515Sbostic jmp_buf motdinterrupt; 39036515Sbostic 39136460Sbostic motd() 3922822Swnj { 39336515Sbostic register int fd, nchars; 39436460Sbostic int (*oldint)(), sigint(); 39536515Sbostic char tbuf[8192]; 3962822Swnj 39736515Sbostic if ((fd = open(MOTDFILE, O_RDONLY, 0)) < 0) 39836460Sbostic return; 39936460Sbostic oldint = signal(SIGINT, sigint); 40036515Sbostic if (setjmp(motdinterrupt) == 0) 40136515Sbostic while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) 40236515Sbostic (void)write(fileno(stdout), tbuf, nchars); 40336460Sbostic (void)signal(SIGINT, oldint); 40436515Sbostic (void)close(fd); 40536460Sbostic } 40636460Sbostic 40736460Sbostic sigint() 40836460Sbostic { 40936515Sbostic longjmp(motdinterrupt, 1); 41036460Sbostic } 41136460Sbostic 41236460Sbostic checknologin() 41336460Sbostic { 41436460Sbostic register int fd, nchars; 41536515Sbostic char tbuf[8192]; 41636460Sbostic 41736460Sbostic if ((fd = open(NOLOGIN, O_RDONLY, 0)) >= 0) { 41836460Sbostic while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) 41936460Sbostic (void)write(fileno(stdout), tbuf, nchars); 42036460Sbostic sleepexit(0); 4212822Swnj } 4222822Swnj } 4232822Swnj 42436460Sbostic dolastlog(quiet, tty) 42536460Sbostic int quiet; 42636460Sbostic char *tty; 4271043Sbill { 42836460Sbostic struct lastlog ll; 42936460Sbostic int fd; 4301043Sbill 43136460Sbostic if ((fd = open(LASTLOG, O_RDWR, 0)) >= 0) { 43236515Sbostic (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); 43336460Sbostic if (!quiet) { 43436460Sbostic if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) && 43536460Sbostic ll.ll_time != 0) { 43636460Sbostic printf("Last login: %.*s ", 43736460Sbostic 24-5, (char *)ctime(&ll.ll_time)); 43836460Sbostic if (*ll.ll_host != '\0') 43936460Sbostic printf("from %.*s\n", 44036460Sbostic sizeof(ll.ll_host), ll.ll_host); 44136460Sbostic else 44236460Sbostic printf("on %.*s\n", 44336460Sbostic sizeof(ll.ll_line), ll.ll_line); 44436460Sbostic } 44536515Sbostic (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); 44636460Sbostic } 44736460Sbostic (void)time(&ll.ll_time); 44836460Sbostic strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); 44936460Sbostic strncpy(ll.ll_host, hostname, sizeof(ll.ll_host)); 45036460Sbostic (void)write(fd, (char *)&ll, sizeof(ll)); 45136460Sbostic (void)close(fd); 4521043Sbill } 4531043Sbill } 4541043Sbill 4552822Swnj #undef UNKNOWN 45636460Sbostic #define UNKNOWN "su" 4571043Sbill 4581043Sbill char * 4591043Sbill stypeof(ttyid) 46012687Ssam char *ttyid; 4611043Sbill { 46236460Sbostic struct ttyent *t; 4631043Sbill 46436460Sbostic return(ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN); 4651043Sbill } 4666005Swnj 4676005Swnj getstr(buf, cnt, err) 46836460Sbostic char *buf, *err; 4696005Swnj int cnt; 4706005Swnj { 47136460Sbostic char ch; 4726005Swnj 4736005Swnj do { 47436460Sbostic if (read(0, &ch, sizeof(ch)) != sizeof(ch)) 4756005Swnj exit(1); 4766005Swnj if (--cnt < 0) { 47736460Sbostic fprintf(stderr, "%s too long\r\n", err); 47836460Sbostic sleepexit(1); 4796005Swnj } 48036460Sbostic *buf++ = ch; 48136460Sbostic } while (ch); 4826005Swnj } 4836329Swnj 48436460Sbostic sleepexit(eval) 48536460Sbostic int eval; 48626862Smckusick { 48736460Sbostic sleep((u_int)5); 48836460Sbostic exit(eval); 48926862Smckusick } 490