1/* 2 * Copyright (c) 1980 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 */ 6 7#ifndef lint 8char copyright[] = 9"@(#) Copyright (c) 1980 Regents of the University of California.\n\ 10 All rights reserved.\n"; 11#endif not lint 12 13#ifndef lint 14static char sccsid[] = "@(#)login.c.1 5.2 (Berkeley) 05/24/85"; 15#endif not lint 16 17/* 18 * login [ name ] 19 * login -r hostname (for rlogind) 20 * login -h hostname (for telnetd, etc.) 21 */ 22 23#include <sys/param.h> 24#include <sys/quota.h> 25#include <sys/stat.h> 26#include <sys/time.h> 27#include <sys/resource.h> 28#include <sys/file.h> 29 30#include <sgtty.h> 31#include <utmp.h> 32#include <signal.h> 33#include <pwd.h> 34#include <stdio.h> 35#include <lastlog.h> 36#include <errno.h> 37#include <ttyent.h> 38#include <syslog.h> 39 40#define SCMPN(a, b) strncmp(a, b, sizeof(a)) 41#define SCPYN(a, b) strncpy(a, b, sizeof(a)) 42 43#define NMAX sizeof(utmp.ut_name) 44 45#define FALSE 0 46#define TRUE -1 47 48char nolog[] = "/etc/nologin"; 49char qlog[] = ".hushlogin"; 50char maildir[30] = "/usr/spool/mail/"; 51char lastlog[] = "/usr/adm/lastlog"; 52struct passwd nouser = {"", "nope", -1, -1, -1, "", "", "", "" }; 53struct sgttyb ttyb; 54struct utmp utmp; 55char minusnam[16] = "-"; 56char *envinit[] = { 0 }; /* now set by setenv calls */ 57/* 58 * This bounds the time given to login. We initialize it here 59 * so it can be patched on machines where it's too small. 60 */ 61int timeout = 60; 62 63char term[64]; 64 65struct passwd *pwd; 66char *strcat(), *rindex(), *index(), *malloc(), *realloc(); 67int timedout(); 68char *ttyname(); 69char *crypt(); 70char *getpass(); 71char *stypeof(); 72extern char **environ; 73extern int errno; 74 75struct tchars tc = { 76 CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK 77}; 78struct ltchars ltc = { 79 CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE, CLNEXT 80}; 81 82struct winsize win = { 0, 0, 0, 0 }; 83 84int rflag; 85char rusername[NMAX+1], lusername[NMAX+1]; 86char rpassword[NMAX+1]; 87char name[NMAX+1]; 88char *rhost; 89 90main(argc, argv) 91 char *argv[]; 92{ 93 register char *namep; 94 int pflag = 0, hflag = 0, t, f, c; 95 int invalid, quietlog; 96 FILE *nlfd; 97 char *ttyn, *tty; 98 int ldisc = 0, zero = 0, i; 99 char **envnew; 100 101 signal(SIGALRM, timedout); 102 alarm(timeout); 103 signal(SIGQUIT, SIG_IGN); 104 signal(SIGINT, SIG_IGN); 105 setpriority(PRIO_PROCESS, 0, 0); 106 quota(Q_SETUID, 0, 0, 0); 107 /* 108 * -p is used by getty to tell login not to destroy the environment 109 * -r is used by rlogind to cause the autologin protocol; 110 * -h is used by other servers to pass the name of the 111 * remote host to login so that it may be placed in utmp and wtmp 112 */ 113 if (argc > 1) { 114 if (strcmp(argv[1], "-r") == 0) { 115 rflag = doremotelogin(argv[2]); 116 SCPYN(utmp.ut_host, argv[2]); 117 argc = 0; 118 } 119 if (strcmp(argv[1], "-h") == 0 && getuid() == 0) { 120 hflag = 1; 121 SCPYN(utmp.ut_host, argv[2]); 122 argc = 0; 123 } 124 if (strcmp(argv[1], "-p") == 0) { 125 argc--; 126 argv++; 127 pflag = 1; 128 } 129 } 130 ioctl(0, TIOCLSET, &zero); 131 ioctl(0, TIOCNXCL, 0); 132 ioctl(0, FIONBIO, &zero); 133 ioctl(0, FIOASYNC, &zero); 134 ioctl(0, TIOCGETP, &ttyb); 135 /* 136 * If talking to an rlogin process, 137 * propagate the terminal type and 138 * baud rate across the network. 139 */ 140 if (rflag) 141 doremoteterm(term, &ttyb); 142 ioctl(0, TIOCSLTC, <c); 143 ioctl(0, TIOCSETC, &tc); 144 ioctl(0, TIOCSETP, &ttyb); 145 for (t = getdtablesize(); t > 3; t--) 146 close(t); 147 ttyn = ttyname(0); 148 if (ttyn == (char *)0) 149 ttyn = "/dev/tty??"; 150 tty = rindex(ttyn, '/'); 151 if (tty == NULL) 152 tty = ttyn; 153 else 154 tty++; 155 openlog("login", LOG_ODELAY, 0); 156 t = 0; 157 do { 158 ldisc = 0; 159 ioctl(0, TIOCSETD, &ldisc); 160 invalid = FALSE; 161 SCPYN(utmp.ut_name, ""); 162 /* 163 * Name specified, take it. 164 */ 165 if (argc > 1) { 166 SCPYN(utmp.ut_name, argv[1]); 167 argc = 0; 168 } 169 /* 170 * If remote login take given name, 171 * otherwise prompt user for something. 172 */ 173 if (rflag) { 174 SCPYN(utmp.ut_name, lusername); 175 /* autologin failed, prompt for passwd */ 176 if (rflag == -1) 177 rflag = 0; 178 } else 179 getloginname(&utmp); 180 if (!strcmp(pwd->pw_shell, "/bin/csh")) { 181 ldisc = NTTYDISC; 182 ioctl(0, TIOCSETD, &ldisc); 183 } 184 /* 185 * If no remote login authentication and 186 * a password exists for this user, prompt 187 * for one and verify it. 188 */ 189 if (!rflag && *pwd->pw_passwd != '\0') { 190 char *pp; 191 192 setpriority(PRIO_PROCESS, 0, -4); 193 pp = getpass("Password:"); 194 namep = crypt(pp, pwd->pw_passwd); 195 setpriority(PRIO_PROCESS, 0, 0); 196 if (strcmp(namep, pwd->pw_passwd)) 197 invalid = TRUE; 198 } 199 /* 200 * If user not super-user, check for logins disabled. 201 */ 202 if (pwd->pw_uid != 0 && (nlfd = fopen(nolog, "r")) > 0) { 203 while ((c = getc(nlfd)) != EOF) 204 putchar(c); 205 fflush(stdout); 206 sleep(5); 207 exit(0); 208 } 209 /* 210 * If valid so far and root is logging in, 211 * see if root logins on this terminal are permitted. 212 */ 213 if (!invalid && pwd->pw_uid == 0 && !rootterm(tty)) { 214 syslog(LOG_SECURITY, "ROOT LOGIN REFUSED %s", tty); 215 invalid = TRUE; 216 } 217 if (invalid) { 218 printf("Login incorrect\n"); 219 if (++t >= 5) { 220 syslog(LOG_SECURITY, 221 "REPEATED LOGIN FAILURES %s, %s", 222 tty, utmp.ut_name); 223 ioctl(0, TIOCHPCL, (struct sgttyb *) 0); 224 close(0), close(1), close(2); 225 sleep(10); 226 exit(1); 227 } 228 } 229 if (*pwd->pw_shell == '\0') 230 pwd->pw_shell = "/bin/sh"; 231 if (chdir(pwd->pw_dir) < 0 && !invalid ) { 232 if (chdir("/") < 0) { 233 printf("No directory!\n"); 234 invalid = TRUE; 235 } else { 236 printf("No directory! %s\n", 237 "Logging in with home=/"); 238 pwd->pw_dir = "/"; 239 } 240 } 241 /* 242 * Remote login invalid must have been because 243 * of a restriction of some sort, no extra chances. 244 */ 245 if (rflag && invalid) 246 exit(1); 247 } while (invalid); 248/* committed to login turn off timeout */ 249 alarm(0); 250 251 if (quota(Q_SETUID, pwd->pw_uid, 0, 0) < 0 && errno != EINVAL) { 252 if (errno == EUSERS) 253 printf("%s.\n%s.\n", 254 "Too many users logged on already", 255 "Try again later"); 256 else if (errno == EPROCLIM) 257 printf("You have too many processes running.\n"); 258 else 259 perror("quota (Q_SETUID)"); 260 sleep(5); 261 exit(0); 262 } 263 time(&utmp.ut_time); 264 t = ttyslot(); 265 if (t > 0 && (f = open("/etc/utmp", O_WRONLY)) >= 0) { 266 lseek(f, (long)(t*sizeof(utmp)), 0); 267 SCPYN(utmp.ut_line, tty); 268 write(f, (char *)&utmp, sizeof(utmp)); 269 close(f); 270 } 271 if ((f = open("/usr/adm/wtmp", O_WRONLY|O_APPEND)) >= 0) { 272 write(f, (char *)&utmp, sizeof(utmp)); 273 close(f); 274 } 275 quietlog = access(qlog, F_OK) == 0; 276 if ((f = open(lastlog, O_RDWR)) >= 0) { 277 struct lastlog ll; 278 279 lseek(f, (long)pwd->pw_uid * sizeof (struct lastlog), 0); 280 if (read(f, (char *) &ll, sizeof ll) == sizeof ll && 281 ll.ll_time != 0 && !quietlog) { 282 printf("Last login: %.*s ", 283 24-5, (char *)ctime(&ll.ll_time)); 284 if (*ll.ll_host != '\0') 285 printf("from %.*s\n", 286 sizeof (ll.ll_host), ll.ll_host); 287 else 288 printf("on %.*s\n", 289 sizeof (ll.ll_line), ll.ll_line); 290 } 291 lseek(f, (long)pwd->pw_uid * sizeof (struct lastlog), 0); 292 time(&ll.ll_time); 293 SCPYN(ll.ll_line, tty); 294 SCPYN(ll.ll_host, utmp.ut_host); 295 write(f, (char *) &ll, sizeof ll); 296 close(f); 297 } 298 chown(ttyn, pwd->pw_uid, pwd->pw_gid); 299 if (!hflag) /* XXX */ 300 ioctl(0, TIOCSWINSZ, &win); 301 chmod(ttyn, 0622); 302 setgid(pwd->pw_gid); 303 strncpy(name, utmp.ut_name, NMAX); 304 name[NMAX] = '\0'; 305 initgroups(name, pwd->pw_gid); 306 quota(Q_DOWARN, pwd->pw_uid, (dev_t)-1, 0); 307 setuid(pwd->pw_uid); 308 /* destroy environment unless user has asked to preserve it */ 309 if (!pflag) 310 environ = envinit; 311 312 /* set up environment, this time without destruction */ 313 /* copy the environment before setenving */ 314 i = 0; 315 while (environ[i] != NULL) 316 i++; 317 envnew = (char **) malloc(sizeof (char *) * (i + 1)); 318 for (; i >= 0; i--) 319 envnew[i] = environ[i]; 320 environ = envnew; 321 322 setenv("HOME=", pwd->pw_dir); 323 setenv("SHELL=", pwd->pw_shell); 324 if (term[0] == '\0') 325 strncpy(term, stypeof(tty), sizeof(term)); 326 setenv("TERM=", term); 327 setenv("USER=", pwd->pw_name); 328 setenv("PATH=", ":/usr/ucb:/bin:/usr/bin"); 329 330 if ((namep = rindex(pwd->pw_shell, '/')) == NULL) 331 namep = pwd->pw_shell; 332 else 333 namep++; 334 strcat(minusnam, namep); 335 if (tty[sizeof("tty")-1] == 'd') 336 syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name); 337 if (pwd->pw_uid == 0) 338 syslog(LOG_SECURITY, "ROOT LOGIN %s", tty); 339 if (!quietlog) { 340 struct stat st; 341 342 showmotd(); 343 strcat(maildir, pwd->pw_name); 344 if (stat(maildir, &st) == 0 && st.st_size != 0) 345 printf("You have %smail.\n", 346 (st.st_mtime > st.st_atime) ? "new " : ""); 347 } 348 signal(SIGALRM, SIG_DFL); 349 signal(SIGQUIT, SIG_DFL); 350 signal(SIGINT, SIG_DFL); 351 signal(SIGTSTP, SIG_IGN); 352 execlp(pwd->pw_shell, minusnam, 0); 353 perror(pwd->pw_shell); 354 printf("No shell\n"); 355 exit(0); 356} 357 358getloginname(up) 359 register struct utmp *up; 360{ 361 register char *namep; 362 char c; 363 364 while (up->ut_name[0] == '\0') { 365 namep = up->ut_name; 366 printf("login: "); 367 while ((c = getchar()) != '\n') { 368 if (c == ' ') 369 c = '_'; 370 if (c == EOF) 371 exit(0); 372 if (namep < up->ut_name+NMAX) 373 *namep++ = c; 374 } 375 } 376 strncpy(lusername, up->ut_name, NMAX); 377 lusername[NMAX] = 0; 378 if ((pwd = getpwnam(lusername)) == NULL) 379 pwd = &nouser; 380} 381 382timedout() 383{ 384 385 printf("Login timed out after %d seconds\n", timeout); 386 exit(0); 387} 388 389int stopmotd; 390catch() 391{ 392 393 signal(SIGINT, SIG_IGN); 394 stopmotd++; 395} 396 397rootterm(tty) 398 char *tty; 399{ 400 register struct ttyent *t; 401 402 if ((t = getttynam(tty)) != NULL) { 403 if (t->ty_status & TTY_SECURE) 404 return (1); 405 } 406 return (0); 407} 408 409showmotd() 410{ 411 FILE *mf; 412 register c; 413 414 signal(SIGINT, catch); 415 if ((mf = fopen("/etc/motd", "r")) != NULL) { 416 while ((c = getc(mf)) != EOF && stopmotd == 0) 417 putchar(c); 418 fclose(mf); 419 } 420 signal(SIGINT, SIG_IGN); 421} 422 423#undef UNKNOWN 424#define UNKNOWN "su" 425 426char * 427stypeof(ttyid) 428 char *ttyid; 429{ 430 register struct ttyent *t; 431 432 if (ttyid == NULL || (t = getttynam(ttyid)) == NULL) 433 return (UNKNOWN); 434 return (t->ty_type); 435} 436 437doremotelogin(host) 438 char *host; 439{ 440 FILE *hostf; 441 int first = 1; 442 443 getstr(rusername, sizeof (rusername), "remuser"); 444 getstr(lusername, sizeof (lusername), "locuser"); 445 getstr(term, sizeof(term), "Terminal type"); 446 if (getuid()) { 447 pwd = &nouser; 448 goto bad; 449 } 450 pwd = getpwnam(lusername); 451 if (pwd == NULL) { 452 pwd = &nouser; 453 goto bad; 454 } 455 hostf = pwd->pw_uid ? fopen("/etc/hosts.equiv", "r") : 0; 456again: 457 if (hostf) { 458 char ahost[32]; 459 460 while (fgets(ahost, sizeof (ahost), hostf)) { 461 register char *p; 462 char *user; 463 464 p = ahost; 465 while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') 466 p++; 467 if (*p == ' ' || *p == '\t') { 468 *p++ = '\0'; 469 while (*p == ' ' || *p == '\t') 470 p++; 471 user = p; 472 while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') 473 p++; 474 } else 475 user = p; 476 *p = '\0'; 477 if (!strcmp(host, ahost) && 478 !strcmp(rusername, *user ? user : lusername)) { 479 fclose(hostf); 480 return (1); 481 } 482 } 483 fclose(hostf); 484 } 485 if (first == 1) { 486 char *rhosts = ".rhosts"; 487 struct stat sbuf; 488 489 first = 0; 490 if (chdir(pwd->pw_dir) < 0) 491 goto again; 492 if (lstat(rhosts, &sbuf) < 0) 493 goto again; 494 if ((sbuf.st_mode & S_IFMT) == S_IFLNK) { 495 printf("login: .rhosts is a soft link.\r\n"); 496 goto bad; 497 } 498 hostf = fopen(rhosts, "r"); 499 fstat(fileno(hostf), &sbuf); 500 if (sbuf.st_uid && sbuf.st_uid != pwd->pw_uid) { 501 printf("login: Bad .rhosts ownership.\r\n"); 502 fclose(hostf); 503 goto bad; 504 } 505 goto again; 506 } 507bad: 508 return (-1); 509} 510 511getstr(buf, cnt, err) 512 char *buf; 513 int cnt; 514 char *err; 515{ 516 char c; 517 518 do { 519 if (read(0, &c, 1) != 1) 520 exit(1); 521 if (--cnt < 0) { 522 printf("%s too long\r\n", err); 523 exit(1); 524 } 525 *buf++ = c; 526 } while (c != 0); 527} 528 529char *speeds[] = 530 { "0", "50", "75", "110", "134", "150", "200", "300", 531 "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" }; 532#define NSPEEDS (sizeof (speeds) / sizeof (speeds[0])) 533 534doremoteterm(term, tp) 535 char *term; 536 struct sgttyb *tp; 537{ 538 register char *cp = index(term, '/'), **cpp; 539 char *speed; 540 struct winsize ws; 541 542 if (cp) { 543 *cp++ = '\0'; 544 speed = cp; 545 cp = index(speed, '/'); 546 if (cp) 547 *cp++ = '\0'; 548 for (cpp = speeds; cpp < &speeds[NSPEEDS]; cpp++) 549 if (strcmp(*cpp, speed) == 0) { 550 tp->sg_ispeed = tp->sg_ospeed = cpp-speeds; 551 break; 552 } 553 ws.ws_row = ws.ws_col = -1; 554 ws.ws_xpixel = ws.ws_ypixel = -1; 555 if (cp) { 556 ws.ws_row = atoi(cp); 557 cp = index(cp, ','); 558 if (cp == 0) 559 goto done; 560 ws.ws_col = atoi(++cp); 561 cp = index(cp, ','); 562 if (cp == 0) 563 goto done; 564 ws.ws_xpixel = atoi(++cp); 565 cp = index(cp, ','); 566 if (cp == 0) 567 goto done; 568 ws.ws_ypixel = atoi(++cp); 569 } 570done: 571 if (ws.ws_row != -1 && ws.ws_col != -1 && 572 ws.ws_xpixel != -1 && ws.ws_ypixel != -1) 573 win = ws; 574 } 575 tp->sg_flags = ECHO|CRMOD|ANYP|XTABS; 576} 577 578/* 579 * Set the value of var to be arg in the Unix 4.2 BSD environment env. 580 * Var should end with '='. 581 * (bindings are of the form "var=value") 582 * This procedure assumes the memory for the first level of environ 583 * was allocated using malloc. 584 */ 585setenv(var, value) 586 char *var, *value; 587{ 588 extern char **environ; 589 int index = 0; 590 int varlen = strlen(var); 591 int vallen = strlen(value); 592 593 for (index = 0; environ[index] != NULL; index++) { 594 if (strncmp(environ[index], var, varlen) == 0) { 595 /* found it */ 596 environ[index] = malloc(varlen + vallen + 1); 597 strcpy(environ[index], var); 598 strcat(environ[index], value); 599 return; 600 } 601 } 602 environ = (char **) realloc(environ, sizeof (char *) * (index + 2)); 603 if (environ == NULL) { 604 fprintf(stderr, "login: malloc out of memory\n"); 605 exit(1); 606 } 607 environ[index] = malloc(varlen + vallen + 1); 608 strcpy(environ[index], var); 609 strcat(environ[index], value); 610 environ[++index] = NULL; 611} 612