112678Ssam #ifndef lint 2*12984Ssam static char *sccsid = "@(#)login.c 4.29 (Berkeley) 83/06/10"; 312678Ssam #endif 412678Ssam 51043Sbill /* 61043Sbill * login [ name ] 712687Ssam * login -r hostname (for rlogind) 812687Ssam * login -h hostname (for telnetd, etc.) 91043Sbill */ 101043Sbill 11*12984Ssam #include <sys/param.h> 1212687Ssam #include <sys/quota.h> 1312687Ssam #include <sys/stat.h> 1412687Ssam #include <sys/time.h> 1512687Ssam #include <sys/resource.h> 1612687Ssam 171043Sbill #include <sgtty.h> 181043Sbill #include <utmp.h> 191043Sbill #include <signal.h> 201043Sbill #include <pwd.h> 211043Sbill #include <stdio.h> 221043Sbill #include <lastlog.h> 2312678Ssam #include <errno.h> 241043Sbill 252822Swnj #define SCPYN(a, b) strncpy(a, b, sizeof(a)) 262822Swnj 276197Sroot #define NMAX sizeof(utmp.ut_name) 281043Sbill 292822Swnj #define FALSE 0 302822Swnj #define TRUE -1 312822Swnj 322822Swnj char nolog[] = "/etc/nologin"; 332822Swnj char qlog[] = ".hushlogin"; 342822Swnj char securetty[] = "/etc/securetty"; 351043Sbill char maildir[30] = "/usr/spool/mail/"; 361043Sbill char lastlog[] = "/usr/adm/lastlog"; 379867Ssam struct passwd nouser = {"", "nope", -1, -1, -1, "", "", "", "" }; 381043Sbill struct sgttyb ttyb; 391043Sbill struct utmp utmp; 401043Sbill char minusnam[16] = "-"; 4112687Ssam /* 4212687Ssam * This bounds the time given to login. We initialize it here 4312687Ssam * so it can be patched on machines where it's too small. 4412687Ssam */ 4512687Ssam int timeout = 60; 466005Swnj 471043Sbill char homedir[64] = "HOME="; 481043Sbill char shell[64] = "SHELL="; 491043Sbill char term[64] = "TERM="; 502822Swnj char user[20] = "USER="; 516005Swnj 526005Swnj char *envinit[] = 5312687Ssam { homedir, shell, "PATH=:/usr/ucb:/bin:/usr/bin", term, user, 0 }; 546005Swnj 551043Sbill struct passwd *pwd; 561043Sbill struct passwd *getpwnam(); 576005Swnj char *strcat(), *rindex(), *index(); 581043Sbill int setpwent(); 5912687Ssam int timedout(); 601043Sbill char *ttyname(); 611043Sbill char *crypt(); 621043Sbill char *getpass(); 631043Sbill char *stypeof(); 641043Sbill extern char **environ; 6512678Ssam extern int errno; 661043Sbill 679867Ssam struct ttychars tc = { 689867Ssam CERASE, CKILL, CINTR, CQUIT, CSTART, 699867Ssam CSTOP, CEOF, CBRK, CSUSP, CDSUSP, 709867Ssam CRPRNT, CFLUSH, CWERASE,CLNEXT 711365Sbill }; 721365Sbill 736005Swnj int rflag; 746197Sroot char rusername[NMAX+1], lusername[NMAX+1]; 756005Swnj char rpassword[NMAX+1]; 766878Smckusick char name[NMAX+1]; 776197Sroot char *rhost; 786005Swnj 791043Sbill main(argc, argv) 8012687Ssam char *argv[]; 811043Sbill { 821043Sbill register char *namep; 8312687Ssam int t, f, c, i; 8412687Ssam int invalid, quietlog; 852822Swnj FILE *nlfd; 861043Sbill char *ttyn; 876197Sroot int ldisc = 0, zero = 0; 881043Sbill 8912687Ssam signal(SIGALRM, timedout); 9012687Ssam alarm(timeout); 911043Sbill signal(SIGQUIT, SIG_IGN); 921043Sbill signal(SIGINT, SIG_IGN); 9312687Ssam setpriority(PRIO_PROCESS, 0, 0); 9412678Ssam quota(Q_SETUID, 0, 0, 0); 9512687Ssam /* 9612687Ssam * -r is used by rlogind to cause the autologin protocol; 9712687Ssam * -h is used by other servers to pass the name of the 9812687Ssam * remote host to login so that it may be placed in utmp and wtmp 9912687Ssam */ 10012687Ssam if (argc > 1) { 10112687Ssam if (strcmp(argv[1], "-r") == 0) { 10212687Ssam rflag = doremotelogin(argv[2]); 10312687Ssam SCPYN(utmp.ut_host, argv[2]); 10412687Ssam argc = 0; 1056197Sroot } 10612687Ssam if (strcmp(argv[1], "-h") == 0 && getuid() == 0) { 10712687Ssam SCPYN(utmp.ut_host, argv[2]); 10812687Ssam argc = 0; 1096197Sroot } 1106005Swnj } 1119867Ssam ioctl(0, TIOCLSET, &zero); /* XXX */ 1121547Sbill ioctl(0, TIOCNXCL, 0); 1136329Swnj ioctl(0, FIONBIO, &zero); 1146329Swnj ioctl(0, FIOASYNC, &zero); 1159867Ssam ioctl(0, TIOCGETP, &ttyb); /* XXX */ 11612687Ssam /* 11712687Ssam * If talking to an rlogin process, 11812687Ssam * propagate the terminal type and 11912687Ssam * baud rate across the network. 12012687Ssam */ 12112687Ssam if (rflag) 12212687Ssam doremoteterm(term, &ttyb); 1239867Ssam ioctl(0, TIOCSETP, &ttyb); /* XXX */ 1249867Ssam ioctl(0, TIOCCSET, &tc); 12512687Ssam for (t = getdtablesize(); t > 3; t--) 1261043Sbill close(t); 1271043Sbill ttyn = ttyname(0); 1282822Swnj if (ttyn==(char *)0) 1291043Sbill ttyn = "/dev/tty??"; 1302822Swnj do { 1312822Swnj ldisc = 0; 1322822Swnj ioctl(0, TIOCSETD, &ldisc); 1332822Swnj invalid = FALSE; 1342822Swnj SCPYN(utmp.ut_name, ""); 13512687Ssam /* 13612687Ssam * Name specified, take it. 13712687Ssam */ 13812687Ssam if (argc > 1) { 1392822Swnj SCPYN(utmp.ut_name, argv[1]); 1402822Swnj argc = 0; 1411043Sbill } 14212687Ssam /* 14312687Ssam * If remote login take given name, 14412687Ssam * otherwise prompt user for something. 14512687Ssam */ 1466329Swnj if (rflag) { 1479867Ssam SCPYN(utmp.ut_name, lusername); 14812687Ssam /* autologin failed, prompt for passwd */ 1496329Swnj if (rflag == -1) 1506329Swnj rflag = 0; 15112687Ssam } else { 15212687Ssam getloginname(&utmp); 1532822Swnj } 1542822Swnj if (!strcmp(pwd->pw_shell, "/bin/csh")) { 1552822Swnj ldisc = NTTYDISC; 1562822Swnj ioctl(0, TIOCSETD, &ldisc); 1572822Swnj } 15812687Ssam /* 15912687Ssam * If no remote login authentication and 16012687Ssam * a password exists for this user, prompt 16112687Ssam * for one and verify it. 16212687Ssam */ 16312687Ssam if (!rflag && *pwd->pw_passwd != '\0') { 16412687Ssam char *pp; 16512687Ssam 16612687Ssam setpriority(PRIO_PROCESS, 0, -4); 16712687Ssam pp = getpass("Password:"); 16812687Ssam namep = crypt(pp, pwd->pw_passwd); 16912687Ssam setpriority(PRIO_PROCESS, 0, 0); 17012687Ssam if (strcmp(namep, pwd->pw_passwd)) 17112687Ssam invalid = TRUE; 1722822Swnj } 17312687Ssam /* 17412687Ssam * If user not super-user, check for logins disabled. 17512687Ssam */ 1762822Swnj if (pwd->pw_uid != 0 && (nlfd = fopen(nolog, "r")) > 0) { 1772822Swnj while ((c = getc(nlfd)) != EOF) 1782822Swnj putchar(c); 1792822Swnj fflush(stdout); 1802822Swnj sleep(5); 1812822Swnj exit(0); 1822822Swnj } 18312687Ssam /* 18412687Ssam * If valid so far and root is logging in, 18512687Ssam * see if root logins on this terminal are permitted. 18612687Ssam */ 1872822Swnj if (!invalid && pwd->pw_uid == 0 && 1882822Swnj !rootterm(ttyn+sizeof("/dev/")-1)) { 1896329Swnj logerr("ROOT LOGIN REFUSED %s", 1906329Swnj ttyn+sizeof("/dev/")-1); 1912822Swnj invalid = TRUE; 1922822Swnj } 1932822Swnj if (invalid) { 1941043Sbill printf("Login incorrect\n"); 1956329Swnj if (ttyn[sizeof("/dev/tty")-1] == 'd') 1966329Swnj logerr("BADDIALUP %s %s\n", 1976329Swnj ttyn+sizeof("/dev/")-1, utmp.ut_name); 1981043Sbill } 1992822Swnj if (*pwd->pw_shell == '\0') 2002822Swnj pwd->pw_shell = "/bin/sh"; 2012822Swnj i = strlen(pwd->pw_shell); 2022822Swnj if (chdir(pwd->pw_dir) < 0 && !invalid ) { 2032822Swnj if (chdir("/") < 0) { 2042822Swnj printf("No directory!\n"); 2052822Swnj invalid = TRUE; 2062822Swnj } else { 20712687Ssam printf("No directory! %s\n", 20812687Ssam "Logging in with home=/"); 2092822Swnj pwd->pw_dir = "/"; 2102822Swnj } 2111043Sbill } 21212687Ssam /* 21312687Ssam * Remote login invalid must have been because 21412687Ssam * of a restriction of some sort, no extra chances. 21512687Ssam */ 2166005Swnj if (rflag && invalid) 2176005Swnj exit(1); 2182822Swnj } while (invalid); 21912687Ssam /* committed to login turn off timeout */ 22012687Ssam alarm(0); 2211043Sbill 22212678Ssam if (quota(Q_SETUID, pwd->pw_uid, 0, 0) < 0) { 22312678Ssam if (errno == EUSERS) 22412678Ssam printf("%s.\n%s.\n", 22512678Ssam "Too many users logged on already", 22612678Ssam "Try again later"); 22712678Ssam else if (errno == EPROCLIM) 22812678Ssam printf("You have too many processes running.\n"); 22912678Ssam else 23012678Ssam perror("setuid"); 23112678Ssam sleep(5); 23212678Ssam exit(0); 23312678Ssam } 2341043Sbill time(&utmp.ut_time); 2351043Sbill t = ttyslot(); 23612687Ssam if (t > 0 && (f = open("/etc/utmp", 1)) >= 0) { 2371043Sbill lseek(f, (long)(t*sizeof(utmp)), 0); 2381043Sbill SCPYN(utmp.ut_line, rindex(ttyn, '/')+1); 2391043Sbill write(f, (char *)&utmp, sizeof(utmp)); 2401043Sbill close(f); 2411043Sbill } 24212687Ssam if (t > 0 && (f = open("/usr/adm/wtmp", 1)) >= 0) { 2431043Sbill lseek(f, 0L, 2); 2441043Sbill write(f, (char *)&utmp, sizeof(utmp)); 2451043Sbill close(f); 2461043Sbill } 24712687Ssam quietlog = access(qlog, 0) == 0; 2486329Swnj if ((f = open(lastlog, 2)) >= 0) { 2492822Swnj struct lastlog ll; 2502822Swnj 2512822Swnj lseek(f, (long)pwd->pw_uid * sizeof (struct lastlog), 0); 2522822Swnj if (read(f, (char *) &ll, sizeof ll) == sizeof ll && 25312687Ssam ll.ll_time != 0 && !quietlog) { 25412687Ssam printf("Last login: %.*s ", 25512687Ssam 24-5, (char *)ctime(&ll.ll_time)); 25612687Ssam if (*ll.ll_host != '\0') 25712687Ssam printf("from %.*s\n", 25812687Ssam sizeof (ll.ll_host), ll.ll_host); 25912687Ssam else 26012687Ssam printf("on %.*s\n", 26112687Ssam sizeof (ll.ll_line), ll.ll_line); 2622822Swnj } 2632822Swnj lseek(f, (long)pwd->pw_uid * sizeof (struct lastlog), 0); 2642822Swnj time(&ll.ll_time); 2652822Swnj SCPYN(ll.ll_line, rindex(ttyn, '/')+1); 26612687Ssam SCPYN(ll.ll_host, utmp.ut_host); 2672822Swnj write(f, (char *) &ll, sizeof ll); 2682822Swnj close(f); 2692822Swnj } 2701043Sbill chown(ttyn, pwd->pw_uid, pwd->pw_gid); 2719867Ssam chmod(ttyn, 0622); 2721043Sbill setgid(pwd->pw_gid); 2736878Smckusick strncpy(name, utmp.ut_name, NMAX); 2746878Smckusick name[NMAX] = '\0'; 2759224Ssam initgroups(name, pwd->pw_gid); 27612678Ssam quota(Q_DOWARN, pwd->pw_uid, (dev_t)-1, 0); 2771043Sbill setuid(pwd->pw_uid); 2781043Sbill environ = envinit; 2791043Sbill strncat(homedir, pwd->pw_dir, sizeof(homedir)-6); 2801043Sbill strncat(shell, pwd->pw_shell, sizeof(shell)-7); 2816329Swnj if (term[strlen("TERM=")] == 0) 2826005Swnj strncat(term, stypeof(ttyn), sizeof(term)-6); 2832822Swnj strncat(user, pwd->pw_name, sizeof(user)-6); 2841043Sbill if ((namep = rindex(pwd->pw_shell, '/')) == NULL) 2851043Sbill namep = pwd->pw_shell; 2861043Sbill else 2871043Sbill namep++; 2881043Sbill strcat(minusnam, namep); 2896197Sroot umask(022); 2906329Swnj if (ttyn[sizeof("/dev/tty")-1] == 'd') 2916329Swnj logerr("DIALUP %s %s\n", ttyn+sizeof("/dev/")-1, pwd->pw_name); 2926329Swnj if (!quietlog) { 2932822Swnj showmotd(); 2942822Swnj strcat(maildir, pwd->pw_name); 2952822Swnj if (access(maildir,4)==0) { 2962822Swnj struct stat statb; 2972822Swnj stat(maildir, &statb); 2982822Swnj if (statb.st_size) 2992822Swnj printf("You have mail.\n"); 3002822Swnj } 3012822Swnj } 30212687Ssam signal(SIGALRM, SIG_DFL); 3031043Sbill signal(SIGQUIT, SIG_DFL); 3041043Sbill signal(SIGINT, SIG_DFL); 3053935Sroot signal(SIGTSTP, SIG_IGN); 3061043Sbill execlp(pwd->pw_shell, minusnam, 0); 3072822Swnj perror(pwd->pw_shell); 3081043Sbill printf("No shell\n"); 3091043Sbill exit(0); 3101043Sbill } 3111043Sbill 31212687Ssam getloginname(up) 31312687Ssam register struct utmp *up; 31412687Ssam { 31512687Ssam register char *namep; 31612712Ssam char c; 31712687Ssam 31812687Ssam while (up->ut_name[0] == '\0') { 31912687Ssam namep = utmp.ut_name; 32012712Ssam printf("login: "); 32112687Ssam while ((c = getchar()) != '\n') { 32212687Ssam if (c == ' ') 32312687Ssam c = '_'; 32412687Ssam if (c == EOF) 32512687Ssam exit(0); 32612687Ssam if (namep < up->ut_name+NMAX) 32712687Ssam *namep++ = c; 32812687Ssam } 32912687Ssam } 33012687Ssam setpwent(); 33112687Ssam if ((pwd = getpwnam(utmp.ut_name)) == NULL) 33212687Ssam pwd = &nouser; 33312687Ssam endpwent(); 33412687Ssam } 33512687Ssam 33612687Ssam timedout() 33712687Ssam { 33812687Ssam 33912687Ssam printf("Login timed out after %d seconds\n", timeout); 34012687Ssam exit(0); 34112687Ssam } 34212687Ssam 3431043Sbill int stopmotd; 3441043Sbill catch() 3451043Sbill { 3466466Swnj 3471043Sbill signal(SIGINT, SIG_IGN); 3481043Sbill stopmotd++; 3491043Sbill } 3501043Sbill 3512822Swnj rootterm(tty) 3526466Swnj char *tty; 3532822Swnj { 3542822Swnj register FILE *fd; 3556466Swnj char buf[100]; 3562822Swnj 3572822Swnj if ((fd = fopen(securetty, "r")) == NULL) 3582822Swnj return(1); 3592822Swnj while (fgets(buf, sizeof buf, fd) != NULL) { 3602822Swnj buf[strlen(buf)-1] = '\0'; 3612822Swnj if (strcmp(tty, buf) == 0) { 3622822Swnj fclose(fd); 3632822Swnj return(1); 3642822Swnj } 3652822Swnj } 3662822Swnj fclose(fd); 3672822Swnj return(0); 3682822Swnj } 3692822Swnj 3701043Sbill showmotd() 3711043Sbill { 3721043Sbill FILE *mf; 3731043Sbill register c; 3741043Sbill 3751043Sbill signal(SIGINT, catch); 3762822Swnj if ((mf = fopen("/etc/motd","r")) != NULL) { 3772822Swnj while ((c = getc(mf)) != EOF && stopmotd == 0) 3781043Sbill putchar(c); 3791043Sbill fclose(mf); 3801043Sbill } 3811043Sbill signal(SIGINT, SIG_IGN); 3821043Sbill } 3831043Sbill 3842822Swnj #undef UNKNOWN 3851043Sbill #define UNKNOWN "su" 3861043Sbill 3871043Sbill char * 3881043Sbill stypeof(ttyid) 38912687Ssam char *ttyid; 3901043Sbill { 39112687Ssam static char typebuf[16]; 39212687Ssam char buf[50]; 39312687Ssam register FILE *f; 39412687Ssam register char *p, *t, *q; 3951043Sbill 3961043Sbill if (ttyid == NULL) 3971043Sbill return (UNKNOWN); 3981043Sbill f = fopen("/etc/ttytype", "r"); 3991043Sbill if (f == NULL) 4001043Sbill return (UNKNOWN); 4011043Sbill /* split off end of name */ 4021043Sbill for (p = q = ttyid; *p != 0; p++) 4031043Sbill if (*p == '/') 4041043Sbill q = p + 1; 4051043Sbill 4061043Sbill /* scan the file */ 40712687Ssam while (fgets(buf, sizeof buf, f) != NULL) { 40812687Ssam for (t = buf; *t != ' ' && *t != '\t'; t++) 4091043Sbill ; 4101043Sbill *t++ = 0; 4112822Swnj while (*t == ' ' || *t == '\t') 4122822Swnj t++; 41312687Ssam for (p = t; *p > ' '; p++) 4141043Sbill ; 4151043Sbill *p = 0; 41612687Ssam if (strcmp(q,t) == 0) { 4171043Sbill strcpy(typebuf, buf); 4181043Sbill fclose(f); 4191043Sbill return (typebuf); 4201043Sbill } 4211043Sbill } 4221043Sbill fclose (f); 4231043Sbill return (UNKNOWN); 4241043Sbill } 4256005Swnj 42612687Ssam doremotelogin(host) 42712687Ssam char *host; 42812687Ssam { 42912687Ssam FILE *hostf; 43012687Ssam int first = 1; 43112687Ssam 43212687Ssam getstr(rusername, sizeof (rusername), "remuser"); 43312687Ssam getstr(lusername, sizeof (lusername), "locuser"); 43412687Ssam getstr(term+5, sizeof(term)-5, "Terminal type"); 43512687Ssam if (getuid()) 43612687Ssam goto bad; 43712687Ssam setpwent(); 43812687Ssam pwd = getpwnam(lusername); 43912687Ssam endpwent(); 44012687Ssam if (pwd == NULL) 44112687Ssam goto bad; 44212687Ssam hostf = pwd->pw_uid ? fopen("/etc/hosts.equiv", "r") : 0; 44312687Ssam again: 44412687Ssam if (hostf) { 44512687Ssam char ahost[32]; 44612687Ssam 44712687Ssam while (fgets(ahost, sizeof (ahost), hostf)) { 44812687Ssam char *user; 44912687Ssam 45012687Ssam if ((user = index(ahost, '\n')) != 0) 45112687Ssam *user++ = '\0'; 45212687Ssam if ((user = index(ahost, ' ')) != 0) 45312687Ssam *user++ = '\0'; 45412687Ssam if (!strcmp(host, ahost) && 45512687Ssam !strcmp(rusername, user ? user : lusername)) { 45612687Ssam fclose(hostf); 45712687Ssam return (1); 45812687Ssam } 45912687Ssam } 46012687Ssam fclose(hostf); 46112687Ssam } 46212687Ssam if (first == 1) { 46312687Ssam char *rhosts = ".rhosts"; 46412687Ssam struct stat sbuf; 46512687Ssam 46612687Ssam first = 0; 46712687Ssam if (chdir(pwd->pw_dir) < 0) 46812687Ssam goto again; 46912687Ssam if (lstat(rhosts, &sbuf) < 0) 47012687Ssam goto again; 47112687Ssam if ((sbuf.st_mode & S_IFMT) == S_IFLNK) { 47212687Ssam printf("login: .rhosts is a soft link.\r\n"); 47312687Ssam goto bad; 47412687Ssam } 47512687Ssam hostf = fopen(rhosts, "r"); 47612687Ssam fstat(fileno(hostf), &sbuf); 47712687Ssam if (sbuf.st_uid && sbuf.st_uid != pwd->pw_uid) { 47812687Ssam printf("login: Bad .rhosts ownership.\r\n"); 47912687Ssam fclose(hostf); 48012687Ssam goto bad; 48112687Ssam } 48212687Ssam goto again; 48312687Ssam } 48412687Ssam bad: 48512687Ssam return (-1); 48612687Ssam } 48712687Ssam 4886005Swnj getstr(buf, cnt, err) 4896005Swnj char *buf; 4906005Swnj int cnt; 4916005Swnj char *err; 4926005Swnj { 4936005Swnj char c; 4946005Swnj 4956005Swnj do { 4966005Swnj if (read(0, &c, 1) != 1) 4976005Swnj exit(1); 4986005Swnj if (--cnt < 0) { 4996005Swnj printf("%s too long\r\n", err); 5006005Swnj exit(1); 5016005Swnj } 5026005Swnj *buf++ = c; 5036005Swnj } while (c != 0); 5046005Swnj } 5056329Swnj 50612687Ssam char *speeds[] = 50712687Ssam { "0", "50", "75", "110", "134", "150", "200", "300", 50812687Ssam "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" }; 50912687Ssam #define NSPEEDS (sizeof (speeds) / sizeof (speeds[0])) 51012687Ssam 51112687Ssam doremoteterm(term, tp) 51212687Ssam char *term; 51312687Ssam struct sgttyb *tp; 51412687Ssam { 51512687Ssam char *cp = index(term, '/'); 51612687Ssam register int i; 51712687Ssam 51812687Ssam if (cp) { 51912687Ssam *cp++ = 0; 52012687Ssam for (i = 0; i < NSPEEDS; i++) 52112687Ssam if (!strcmp(speeds[i], cp)) { 52212687Ssam tp->sg_ispeed = tp->sg_ospeed = i; 52312687Ssam break; 52412687Ssam } 52512687Ssam } 52612687Ssam tp->sg_flags = ECHO|CRMOD|ANYP|XTABS; 52712687Ssam } 52812687Ssam 5296329Swnj logerr(fmt, a1, a2, a3) 5306329Swnj char *fmt, *a1, *a2, *a3; 5316329Swnj { 53212690Ssam #ifdef LOGERR 53312690Ssam FILE *cons = fopen("/dev/console", "w"); 5346329Swnj 53512690Ssam if (cons != NULL) { 53612690Ssam fprintf(cons, fmt, a1, a2, a3); 53712690Ssam fputc('\r', cons); 53812690Ssam fclose(cons); 53912690Ssam } 54012690Ssam #endif 5416329Swnj } 542