112678Ssam #ifndef lint 2*12687Ssam static char *sccsid = "@(#)login.c 4.25 (Berkeley) 83/05/23"; 312678Ssam #endif 412678Ssam 51043Sbill /* 61043Sbill * login [ name ] 7*12687Ssam * login -r hostname (for rlogind) 8*12687Ssam * login -h hostname (for telnetd, etc.) 91043Sbill */ 101043Sbill 111043Sbill #include <sys/types.h> 12*12687Ssam #define QUOTA 13*12687Ssam #include <sys/quota.h> 14*12687Ssam #include <sys/stat.h> 15*12687Ssam #include <sys/time.h> 16*12687Ssam #include <sys/resource.h> 17*12687Ssam 181043Sbill #include <sgtty.h> 191043Sbill #include <utmp.h> 201043Sbill #include <signal.h> 211043Sbill #include <pwd.h> 221043Sbill #include <stdio.h> 231043Sbill #include <lastlog.h> 2412678Ssam #include <errno.h> 251043Sbill 262822Swnj #define SCPYN(a, b) strncpy(a, b, sizeof(a)) 272822Swnj 286197Sroot #define NMAX sizeof(utmp.ut_name) 291043Sbill 302822Swnj #define FALSE 0 312822Swnj #define TRUE -1 322822Swnj 332822Swnj char nolog[] = "/etc/nologin"; 342822Swnj char qlog[] = ".hushlogin"; 352822Swnj char securetty[] = "/etc/securetty"; 361043Sbill char maildir[30] = "/usr/spool/mail/"; 371043Sbill char lastlog[] = "/usr/adm/lastlog"; 389867Ssam struct passwd nouser = {"", "nope", -1, -1, -1, "", "", "", "" }; 391043Sbill struct sgttyb ttyb; 401043Sbill struct utmp utmp; 411043Sbill char minusnam[16] = "-"; 42*12687Ssam /* 43*12687Ssam * This bounds the time given to login. We initialize it here 44*12687Ssam * so it can be patched on machines where it's too small. 45*12687Ssam */ 46*12687Ssam int timeout = 60; 476005Swnj 481043Sbill char homedir[64] = "HOME="; 491043Sbill char shell[64] = "SHELL="; 501043Sbill char term[64] = "TERM="; 512822Swnj char user[20] = "USER="; 526005Swnj 536005Swnj char *envinit[] = 54*12687Ssam { homedir, shell, "PATH=:/usr/ucb:/bin:/usr/bin", term, user, 0 }; 556005Swnj 561043Sbill struct passwd *pwd; 571043Sbill struct passwd *getpwnam(); 586005Swnj char *strcat(), *rindex(), *index(); 591043Sbill int setpwent(); 60*12687Ssam int timedout(); 611043Sbill char *ttyname(); 621043Sbill char *crypt(); 631043Sbill char *getpass(); 641043Sbill char *stypeof(); 651043Sbill extern char **environ; 6612678Ssam extern int errno; 671043Sbill 689867Ssam struct ttychars tc = { 699867Ssam CERASE, CKILL, CINTR, CQUIT, CSTART, 709867Ssam CSTOP, CEOF, CBRK, CSUSP, CDSUSP, 719867Ssam CRPRNT, CFLUSH, CWERASE,CLNEXT 721365Sbill }; 731365Sbill 746005Swnj int rflag; 756197Sroot char rusername[NMAX+1], lusername[NMAX+1]; 766005Swnj char rpassword[NMAX+1]; 776878Smckusick char name[NMAX+1]; 786197Sroot char *rhost; 796005Swnj 801043Sbill main(argc, argv) 81*12687Ssam char *argv[]; 821043Sbill { 831043Sbill register char *namep; 84*12687Ssam int t, f, c, i; 85*12687Ssam int invalid, quietlog; 862822Swnj FILE *nlfd; 871043Sbill char *ttyn; 886197Sroot int ldisc = 0, zero = 0; 891043Sbill 90*12687Ssam signal(SIGALRM, timedout); 91*12687Ssam alarm(timeout); 921043Sbill signal(SIGQUIT, SIG_IGN); 931043Sbill signal(SIGINT, SIG_IGN); 94*12687Ssam setpriority(PRIO_PROCESS, 0, 0); 9512678Ssam quota(Q_SETUID, 0, 0, 0); 96*12687Ssam /* 97*12687Ssam * -r is used by rlogind to cause the autologin protocol; 98*12687Ssam * -h is used by other servers to pass the name of the 99*12687Ssam * remote host to login so that it may be placed in utmp and wtmp 100*12687Ssam */ 101*12687Ssam if (argc > 1) { 102*12687Ssam if (strcmp(argv[1], "-r") == 0) { 103*12687Ssam rflag = doremotelogin(argv[2]); 104*12687Ssam SCPYN(utmp.ut_host, argv[2]); 105*12687Ssam argc = 0; 1066197Sroot } 107*12687Ssam if (strcmp(argv[1], "-h") == 0 && getuid() == 0) { 108*12687Ssam SCPYN(utmp.ut_host, argv[2]); 109*12687Ssam argc = 0; 1106197Sroot } 1116005Swnj } 1129867Ssam ioctl(0, TIOCLSET, &zero); /* XXX */ 1131547Sbill ioctl(0, TIOCNXCL, 0); 1146329Swnj ioctl(0, FIONBIO, &zero); 1156329Swnj ioctl(0, FIOASYNC, &zero); 1169867Ssam ioctl(0, TIOCGETP, &ttyb); /* XXX */ 117*12687Ssam /* 118*12687Ssam * If talking to an rlogin process, 119*12687Ssam * propagate the terminal type and 120*12687Ssam * baud rate across the network. 121*12687Ssam */ 122*12687Ssam if (rflag) 123*12687Ssam doremoteterm(term, &ttyb); 1249867Ssam ioctl(0, TIOCSETP, &ttyb); /* XXX */ 1259867Ssam ioctl(0, TIOCCSET, &tc); 126*12687Ssam for (t = getdtablesize(); t > 3; t--) 1271043Sbill close(t); 1281043Sbill ttyn = ttyname(0); 1292822Swnj if (ttyn==(char *)0) 1301043Sbill ttyn = "/dev/tty??"; 1312822Swnj do { 1322822Swnj ldisc = 0; 1332822Swnj ioctl(0, TIOCSETD, &ldisc); 1342822Swnj invalid = FALSE; 1352822Swnj SCPYN(utmp.ut_name, ""); 136*12687Ssam /* 137*12687Ssam * Name specified, take it. 138*12687Ssam */ 139*12687Ssam if (argc > 1) { 1402822Swnj SCPYN(utmp.ut_name, argv[1]); 1412822Swnj argc = 0; 1421043Sbill } 143*12687Ssam /* 144*12687Ssam * If remote login take given name, 145*12687Ssam * otherwise prompt user for something. 146*12687Ssam */ 1476329Swnj if (rflag) { 1489867Ssam SCPYN(utmp.ut_name, lusername); 149*12687Ssam /* autologin failed, prompt for passwd */ 1506329Swnj if (rflag == -1) 1516329Swnj rflag = 0; 152*12687Ssam } else { 153*12687Ssam getloginname(&utmp); 1542822Swnj } 1552822Swnj if (!strcmp(pwd->pw_shell, "/bin/csh")) { 1562822Swnj ldisc = NTTYDISC; 1572822Swnj ioctl(0, TIOCSETD, &ldisc); 1582822Swnj } 159*12687Ssam /* 160*12687Ssam * If no remote login authentication and 161*12687Ssam * a password exists for this user, prompt 162*12687Ssam * for one and verify it. 163*12687Ssam */ 164*12687Ssam if (!rflag && *pwd->pw_passwd != '\0') { 165*12687Ssam char *pp; 166*12687Ssam 167*12687Ssam setpriority(PRIO_PROCESS, 0, -4); 168*12687Ssam pp = getpass("Password:"); 169*12687Ssam namep = crypt(pp, pwd->pw_passwd); 170*12687Ssam setpriority(PRIO_PROCESS, 0, 0); 171*12687Ssam if (strcmp(namep, pwd->pw_passwd)) 172*12687Ssam invalid = TRUE; 1732822Swnj } 174*12687Ssam /* 175*12687Ssam * If user not super-user, check for logins disabled. 176*12687Ssam */ 1772822Swnj if (pwd->pw_uid != 0 && (nlfd = fopen(nolog, "r")) > 0) { 1782822Swnj while ((c = getc(nlfd)) != EOF) 1792822Swnj putchar(c); 1802822Swnj fflush(stdout); 1812822Swnj sleep(5); 1822822Swnj exit(0); 1832822Swnj } 184*12687Ssam /* 185*12687Ssam * If valid so far and root is logging in, 186*12687Ssam * see if root logins on this terminal are permitted. 187*12687Ssam */ 1882822Swnj if (!invalid && pwd->pw_uid == 0 && 1892822Swnj !rootterm(ttyn+sizeof("/dev/")-1)) { 1906329Swnj logerr("ROOT LOGIN REFUSED %s", 1916329Swnj ttyn+sizeof("/dev/")-1); 1922822Swnj invalid = TRUE; 1932822Swnj } 1942822Swnj if (invalid) { 1951043Sbill printf("Login incorrect\n"); 1966329Swnj if (ttyn[sizeof("/dev/tty")-1] == 'd') 1976329Swnj logerr("BADDIALUP %s %s\n", 1986329Swnj ttyn+sizeof("/dev/")-1, utmp.ut_name); 1991043Sbill } 2002822Swnj if (*pwd->pw_shell == '\0') 2012822Swnj pwd->pw_shell = "/bin/sh"; 2022822Swnj i = strlen(pwd->pw_shell); 2032822Swnj if (chdir(pwd->pw_dir) < 0 && !invalid ) { 2042822Swnj if (chdir("/") < 0) { 2052822Swnj printf("No directory!\n"); 2062822Swnj invalid = TRUE; 2072822Swnj } else { 208*12687Ssam printf("No directory! %s\n", 209*12687Ssam "Logging in with home=/"); 2102822Swnj pwd->pw_dir = "/"; 2112822Swnj } 2121043Sbill } 213*12687Ssam /* 214*12687Ssam * Remote login invalid must have been because 215*12687Ssam * of a restriction of some sort, no extra chances. 216*12687Ssam */ 2176005Swnj if (rflag && invalid) 2186005Swnj exit(1); 2192822Swnj } while (invalid); 220*12687Ssam /* committed to login turn off timeout */ 221*12687Ssam alarm(0); 2221043Sbill 22312678Ssam if (quota(Q_SETUID, pwd->pw_uid, 0, 0) < 0) { 22412678Ssam if (errno == EUSERS) 22512678Ssam printf("%s.\n%s.\n", 22612678Ssam "Too many users logged on already", 22712678Ssam "Try again later"); 22812678Ssam else if (errno == EPROCLIM) 22912678Ssam printf("You have too many processes running.\n"); 23012678Ssam else 23112678Ssam perror("setuid"); 23212678Ssam sleep(5); 23312678Ssam exit(0); 23412678Ssam } 2351043Sbill time(&utmp.ut_time); 2361043Sbill t = ttyslot(); 237*12687Ssam if (t > 0 && (f = open("/etc/utmp", 1)) >= 0) { 2381043Sbill lseek(f, (long)(t*sizeof(utmp)), 0); 2391043Sbill SCPYN(utmp.ut_line, rindex(ttyn, '/')+1); 2401043Sbill write(f, (char *)&utmp, sizeof(utmp)); 2411043Sbill close(f); 2421043Sbill } 243*12687Ssam if (t > 0 && (f = open("/usr/adm/wtmp", 1)) >= 0) { 2441043Sbill lseek(f, 0L, 2); 2451043Sbill write(f, (char *)&utmp, sizeof(utmp)); 2461043Sbill close(f); 2471043Sbill } 248*12687Ssam quietlog = access(qlog, 0) == 0; 2496329Swnj if ((f = open(lastlog, 2)) >= 0) { 2502822Swnj struct lastlog ll; 2512822Swnj 2522822Swnj lseek(f, (long)pwd->pw_uid * sizeof (struct lastlog), 0); 2532822Swnj if (read(f, (char *) &ll, sizeof ll) == sizeof ll && 254*12687Ssam ll.ll_time != 0 && !quietlog) { 255*12687Ssam printf("Last login: %.*s ", 256*12687Ssam 24-5, (char *)ctime(&ll.ll_time)); 257*12687Ssam if (*ll.ll_host != '\0') 258*12687Ssam printf("from %.*s\n", 259*12687Ssam sizeof (ll.ll_host), ll.ll_host); 260*12687Ssam else 261*12687Ssam printf("on %.*s\n", 262*12687Ssam sizeof (ll.ll_line), ll.ll_line); 2632822Swnj } 2642822Swnj lseek(f, (long)pwd->pw_uid * sizeof (struct lastlog), 0); 2652822Swnj time(&ll.ll_time); 2662822Swnj SCPYN(ll.ll_line, rindex(ttyn, '/')+1); 267*12687Ssam SCPYN(ll.ll_host, utmp.ut_host); 2682822Swnj write(f, (char *) &ll, sizeof ll); 2692822Swnj close(f); 2702822Swnj } 2711043Sbill chown(ttyn, pwd->pw_uid, pwd->pw_gid); 2729867Ssam chmod(ttyn, 0622); 2731043Sbill setgid(pwd->pw_gid); 2746878Smckusick strncpy(name, utmp.ut_name, NMAX); 2756878Smckusick name[NMAX] = '\0'; 2769224Ssam initgroups(name, pwd->pw_gid); 27712678Ssam quota(Q_DOWARN, pwd->pw_uid, (dev_t)-1, 0); 2781043Sbill setuid(pwd->pw_uid); 2791043Sbill environ = envinit; 2801043Sbill strncat(homedir, pwd->pw_dir, sizeof(homedir)-6); 2811043Sbill strncat(shell, pwd->pw_shell, sizeof(shell)-7); 2826329Swnj if (term[strlen("TERM=")] == 0) 2836005Swnj strncat(term, stypeof(ttyn), sizeof(term)-6); 2842822Swnj strncat(user, pwd->pw_name, sizeof(user)-6); 2851043Sbill if ((namep = rindex(pwd->pw_shell, '/')) == NULL) 2861043Sbill namep = pwd->pw_shell; 2871043Sbill else 2881043Sbill namep++; 2891043Sbill strcat(minusnam, namep); 2906197Sroot umask(022); 2916329Swnj if (ttyn[sizeof("/dev/tty")-1] == 'd') 2926329Swnj logerr("DIALUP %s %s\n", ttyn+sizeof("/dev/")-1, pwd->pw_name); 2936329Swnj if (!quietlog) { 2942822Swnj showmotd(); 2952822Swnj strcat(maildir, pwd->pw_name); 2962822Swnj if (access(maildir,4)==0) { 2972822Swnj struct stat statb; 2982822Swnj stat(maildir, &statb); 2992822Swnj if (statb.st_size) 3002822Swnj printf("You have mail.\n"); 3012822Swnj } 3022822Swnj } 303*12687Ssam signal(SIGALRM, SIG_DFL); 3041043Sbill signal(SIGQUIT, SIG_DFL); 3051043Sbill signal(SIGINT, SIG_DFL); 3063935Sroot signal(SIGTSTP, SIG_IGN); 3071043Sbill execlp(pwd->pw_shell, minusnam, 0); 3082822Swnj perror(pwd->pw_shell); 3091043Sbill printf("No shell\n"); 3101043Sbill exit(0); 3111043Sbill } 3121043Sbill 313*12687Ssam getloginname(up) 314*12687Ssam register struct utmp *up; 315*12687Ssam { 316*12687Ssam register char *namep; 317*12687Ssam char hostname[32], c; 318*12687Ssam 319*12687Ssam gethostname(hostname, sizeof (hostname)); 320*12687Ssam while (up->ut_name[0] == '\0') { 321*12687Ssam namep = utmp.ut_name; 322*12687Ssam printf("%s login: ", hostname); 323*12687Ssam while ((c = getchar()) != '\n') { 324*12687Ssam if (c == ' ') 325*12687Ssam c = '_'; 326*12687Ssam if (c == EOF) 327*12687Ssam exit(0); 328*12687Ssam if (namep < up->ut_name+NMAX) 329*12687Ssam *namep++ = c; 330*12687Ssam } 331*12687Ssam } 332*12687Ssam setpwent(); 333*12687Ssam if ((pwd = getpwnam(utmp.ut_name)) == NULL) 334*12687Ssam pwd = &nouser; 335*12687Ssam endpwent(); 336*12687Ssam } 337*12687Ssam 338*12687Ssam timedout() 339*12687Ssam { 340*12687Ssam 341*12687Ssam printf("Login timed out after %d seconds\n", timeout); 342*12687Ssam exit(0); 343*12687Ssam } 344*12687Ssam 3451043Sbill int stopmotd; 3461043Sbill catch() 3471043Sbill { 3486466Swnj 3491043Sbill signal(SIGINT, SIG_IGN); 3501043Sbill stopmotd++; 3511043Sbill } 3521043Sbill 3532822Swnj rootterm(tty) 3546466Swnj char *tty; 3552822Swnj { 3562822Swnj register FILE *fd; 3576466Swnj char buf[100]; 3582822Swnj 3592822Swnj if ((fd = fopen(securetty, "r")) == NULL) 3602822Swnj return(1); 3612822Swnj while (fgets(buf, sizeof buf, fd) != NULL) { 3622822Swnj buf[strlen(buf)-1] = '\0'; 3632822Swnj if (strcmp(tty, buf) == 0) { 3642822Swnj fclose(fd); 3652822Swnj return(1); 3662822Swnj } 3672822Swnj } 3682822Swnj fclose(fd); 3692822Swnj return(0); 3702822Swnj } 3712822Swnj 3721043Sbill showmotd() 3731043Sbill { 3741043Sbill FILE *mf; 3751043Sbill register c; 3761043Sbill 3771043Sbill signal(SIGINT, catch); 3782822Swnj if ((mf = fopen("/etc/motd","r")) != NULL) { 3792822Swnj while ((c = getc(mf)) != EOF && stopmotd == 0) 3801043Sbill putchar(c); 3811043Sbill fclose(mf); 3821043Sbill } 3831043Sbill signal(SIGINT, SIG_IGN); 3841043Sbill } 3851043Sbill 3862822Swnj #undef UNKNOWN 3871043Sbill #define UNKNOWN "su" 3881043Sbill 3891043Sbill char * 3901043Sbill stypeof(ttyid) 391*12687Ssam char *ttyid; 3921043Sbill { 393*12687Ssam static char typebuf[16]; 394*12687Ssam char buf[50]; 395*12687Ssam register FILE *f; 396*12687Ssam register char *p, *t, *q; 3971043Sbill 3981043Sbill if (ttyid == NULL) 3991043Sbill return (UNKNOWN); 4001043Sbill f = fopen("/etc/ttytype", "r"); 4011043Sbill if (f == NULL) 4021043Sbill return (UNKNOWN); 4031043Sbill /* split off end of name */ 4041043Sbill for (p = q = ttyid; *p != 0; p++) 4051043Sbill if (*p == '/') 4061043Sbill q = p + 1; 4071043Sbill 4081043Sbill /* scan the file */ 409*12687Ssam while (fgets(buf, sizeof buf, f) != NULL) { 410*12687Ssam for (t = buf; *t != ' ' && *t != '\t'; t++) 4111043Sbill ; 4121043Sbill *t++ = 0; 4132822Swnj while (*t == ' ' || *t == '\t') 4142822Swnj t++; 415*12687Ssam for (p = t; *p > ' '; p++) 4161043Sbill ; 4171043Sbill *p = 0; 418*12687Ssam if (strcmp(q,t) == 0) { 4191043Sbill strcpy(typebuf, buf); 4201043Sbill fclose(f); 4211043Sbill return (typebuf); 4221043Sbill } 4231043Sbill } 4241043Sbill fclose (f); 4251043Sbill return (UNKNOWN); 4261043Sbill } 4276005Swnj 428*12687Ssam doremotelogin(host) 429*12687Ssam char *host; 430*12687Ssam { 431*12687Ssam FILE *hostf; 432*12687Ssam int first = 1; 433*12687Ssam 434*12687Ssam getstr(rusername, sizeof (rusername), "remuser"); 435*12687Ssam getstr(lusername, sizeof (lusername), "locuser"); 436*12687Ssam getstr(term+5, sizeof(term)-5, "Terminal type"); 437*12687Ssam if (getuid()) 438*12687Ssam goto bad; 439*12687Ssam setpwent(); 440*12687Ssam pwd = getpwnam(lusername); 441*12687Ssam endpwent(); 442*12687Ssam if (pwd == NULL) 443*12687Ssam goto bad; 444*12687Ssam hostf = pwd->pw_uid ? fopen("/etc/hosts.equiv", "r") : 0; 445*12687Ssam again: 446*12687Ssam if (hostf) { 447*12687Ssam char ahost[32]; 448*12687Ssam 449*12687Ssam while (fgets(ahost, sizeof (ahost), hostf)) { 450*12687Ssam char *user; 451*12687Ssam 452*12687Ssam if ((user = index(ahost, '\n')) != 0) 453*12687Ssam *user++ = '\0'; 454*12687Ssam if ((user = index(ahost, ' ')) != 0) 455*12687Ssam *user++ = '\0'; 456*12687Ssam if (!strcmp(host, ahost) && 457*12687Ssam !strcmp(rusername, user ? user : lusername)) { 458*12687Ssam fclose(hostf); 459*12687Ssam return (1); 460*12687Ssam } 461*12687Ssam } 462*12687Ssam fclose(hostf); 463*12687Ssam } 464*12687Ssam if (first == 1) { 465*12687Ssam char *rhosts = ".rhosts"; 466*12687Ssam struct stat sbuf; 467*12687Ssam 468*12687Ssam first = 0; 469*12687Ssam if (chdir(pwd->pw_dir) < 0) 470*12687Ssam goto again; 471*12687Ssam if (lstat(rhosts, &sbuf) < 0) 472*12687Ssam goto again; 473*12687Ssam if ((sbuf.st_mode & S_IFMT) == S_IFLNK) { 474*12687Ssam printf("login: .rhosts is a soft link.\r\n"); 475*12687Ssam goto bad; 476*12687Ssam } 477*12687Ssam hostf = fopen(rhosts, "r"); 478*12687Ssam fstat(fileno(hostf), &sbuf); 479*12687Ssam if (sbuf.st_uid && sbuf.st_uid != pwd->pw_uid) { 480*12687Ssam printf("login: Bad .rhosts ownership.\r\n"); 481*12687Ssam fclose(hostf); 482*12687Ssam goto bad; 483*12687Ssam } 484*12687Ssam goto again; 485*12687Ssam } 486*12687Ssam bad: 487*12687Ssam return (-1); 488*12687Ssam } 489*12687Ssam 4906005Swnj getstr(buf, cnt, err) 4916005Swnj char *buf; 4926005Swnj int cnt; 4936005Swnj char *err; 4946005Swnj { 4956005Swnj char c; 4966005Swnj 4976005Swnj do { 4986005Swnj if (read(0, &c, 1) != 1) 4996005Swnj exit(1); 5006005Swnj if (--cnt < 0) { 5016005Swnj printf("%s too long\r\n", err); 5026005Swnj exit(1); 5036005Swnj } 5046005Swnj *buf++ = c; 5056005Swnj } while (c != 0); 5066005Swnj } 5076329Swnj 508*12687Ssam char *speeds[] = 509*12687Ssam { "0", "50", "75", "110", "134", "150", "200", "300", 510*12687Ssam "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" }; 511*12687Ssam #define NSPEEDS (sizeof (speeds) / sizeof (speeds[0])) 512*12687Ssam 513*12687Ssam doremoteterm(term, tp) 514*12687Ssam char *term; 515*12687Ssam struct sgttyb *tp; 516*12687Ssam { 517*12687Ssam char *cp = index(term, '/'); 518*12687Ssam register int i; 519*12687Ssam 520*12687Ssam if (cp) { 521*12687Ssam *cp++ = 0; 522*12687Ssam for (i = 0; i < NSPEEDS; i++) 523*12687Ssam if (!strcmp(speeds[i], cp)) { 524*12687Ssam tp->sg_ispeed = tp->sg_ospeed = i; 525*12687Ssam break; 526*12687Ssam } 527*12687Ssam } 528*12687Ssam tp->sg_flags = ECHO|CRMOD|ANYP|XTABS; 529*12687Ssam } 530*12687Ssam 5316329Swnj logerr(fmt, a1, a2, a3) 5326329Swnj char *fmt, *a1, *a2, *a3; 5336329Swnj { 5346329Swnj 5356329Swnj } 536