1/* 2 * Copyright (c) 1980, 1987, 1988 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 */ 17 18#ifndef lint 19char copyright[] = 20"@(#) Copyright (c) 1980, 1987, 1988 The Regents of the University of California.\n\ 21 All rights reserved.\n"; 22#endif /* not lint */ 23 24#ifndef lint 25static char sccsid[] = "@(#)login.c.1 5.34 (Berkeley) 02/23/89"; 26#endif /* not lint */ 27 28/* 29 * login [ name ] 30 * login -h hostname (for telnetd, etc.) 31 * login -f name (for pre-authenticated login: datakit, xterm, etc.) 32 */ 33 34#include <sys/param.h> 35#include <sys/quota.h> 36#include <sys/stat.h> 37#include <sys/time.h> 38#include <sys/resource.h> 39#include <sys/file.h> 40#include <sys/ioctl.h> 41 42#include <utmp.h> 43#include <signal.h> 44#include <lastlog.h> 45#include <errno.h> 46#include <ttyent.h> 47#include <syslog.h> 48#include <grp.h> 49#include <pwd.h> 50#include <setjmp.h> 51#include <stdio.h> 52#include <strings.h> 53 54#ifdef KERBEROS 55#include <kerberos/krb.h> 56#include <sys/termios.h> 57char realm[REALM_SZ]; 58int kerror = KSUCCESS, notickets = 1; 59#endif 60 61#define TTYGRPNAME "tty" /* name of group to own ttys */ 62 63#define MOTDFILE "/etc/motd" 64#define MAILDIR "/usr/spool/mail" 65#define NOLOGIN "/etc/nologin" 66#define HUSHLOGIN ".hushlogin" 67#define LASTLOG "/usr/adm/lastlog" 68#define BSHELL "/bin/sh" 69 70/* 71 * This bounds the time given to login. Not a define so it can 72 * be patched on machines where it's too small. 73 */ 74int timeout = 300; 75 76struct passwd *pwd; 77int failures; 78char term[64], *hostname, *username, *tty; 79 80struct sgttyb sgttyb; 81struct tchars tc = { 82 CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK 83}; 84struct ltchars ltc = { 85 CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE, CLNEXT 86}; 87 88char *months[] = 89 { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", 90 "Sep", "Oct", "Nov", "Dec" }; 91 92main(argc, argv) 93 int argc; 94 char **argv; 95{ 96 extern int errno, optind; 97 extern char *optarg, **environ; 98 struct timeval tp; 99 struct tm *ttp; 100 struct group *gr; 101 register int ch; 102 register char *p; 103 int ask, fflag, hflag, pflag, cnt; 104 int quietlog, passwd_req, ioctlval, timedout(); 105 char *domain, *salt, *envinit[1], *ttyn, *pp; 106 char tbuf[MAXPATHLEN + 2]; 107 char *ctime(), *ttyname(), *stypeof(), *crypt(), *getpass(); 108 time_t time(); 109 off_t lseek(); 110 111 (void)signal(SIGALRM, timedout); 112 (void)alarm((u_int)timeout); 113 (void)signal(SIGQUIT, SIG_IGN); 114 (void)signal(SIGINT, SIG_IGN); 115 (void)setpriority(PRIO_PROCESS, 0, 0); 116 (void)quota(Q_SETUID, 0, 0, 0); 117 118 /* 119 * -p is used by getty to tell login not to destroy the environment 120 * -f is used to skip a second login authentication 121 * -h is used by other servers to pass the name of the remote 122 * host to login so that it may be placed in utmp and wtmp 123 */ 124 (void)gethostname(tbuf, sizeof(tbuf)); 125 domain = index(tbuf, '.'); 126 127 fflag = hflag = pflag = 0; 128 passwd_req = 1; 129 while ((ch = getopt(argc, argv, "fh:p")) != EOF) 130 switch (ch) { 131 case 'f': 132 fflag = 1; 133 break; 134 case 'h': 135 if (getuid()) { 136 fprintf(stderr, 137 "login: -h for super-user only.\n"); 138 exit(1); 139 } 140 hflag = 1; 141 if (domain && (p = index(optarg, '.')) && 142 strcasecmp(p, domain) == 0) 143 *p = 0; 144 hostname = optarg; 145 break; 146 case 'p': 147 pflag = 1; 148 break; 149 case '?': 150 default: 151 fprintf(stderr, "usage: login [-fp] [username]\n"); 152 exit(1); 153 } 154 argc -= optind; 155 argv += optind; 156 if (*argv) { 157 username = *argv; 158 ask = 0; 159 } else 160 ask = 1; 161 162 ioctlval = 0; 163 (void)ioctl(0, TIOCLSET, &ioctlval); 164 (void)ioctl(0, TIOCNXCL, 0); 165 (void)fcntl(0, F_SETFL, ioctlval); 166 (void)ioctl(0, TIOCGETP, &sgttyb); 167 sgttyb.sg_erase = CERASE; 168 sgttyb.sg_kill = CKILL; 169 (void)ioctl(0, TIOCSLTC, <c); 170 (void)ioctl(0, TIOCSETC, &tc); 171 (void)ioctl(0, TIOCSETP, &sgttyb); 172 173 for (cnt = getdtablesize(); cnt > 2; cnt--) 174 close(cnt); 175 176 ttyn = ttyname(0); 177 if (ttyn == NULL || *ttyn == '\0') 178 ttyn = "/dev/tty??"; 179 if (tty = rindex(ttyn, '/')) 180 ++tty; 181 else 182 tty = ttyn; 183 184 openlog("login", LOG_ODELAY, LOG_AUTH); 185 186 for (cnt = 0;; ask = 1) { 187 ioctlval = 0; 188 (void)ioctl(0, TIOCSETD, &ioctlval); 189 190 if (ask) { 191 fflag = 0; 192 getloginname(); 193 } 194 /* 195 * Note if trying multiple user names; 196 * log failures for previous user name, 197 * but don't bother logging one failure 198 * for nonexistent name (mistyped username). 199 */ 200 if (failures && strcmp(tbuf, username)) { 201 if (failures > (pwd ? 0 : 1)) 202 badlogin(tbuf); 203 failures = 0; 204 } 205 (void)strcpy(tbuf, username); 206 if (pwd = getpwnam(username)) 207 salt = pwd->pw_passwd; 208 else 209 salt = "xx"; 210 211 /* if user not super-user, check for disabled logins */ 212 if (pwd == NULL || pwd->pw_uid) 213 checknologin(); 214 215 /* 216 * Disallow automatic login to root; if not invoked by 217 * root, disallow if the uid's differ. 218 */ 219 if (fflag && pwd) { 220 int uid = getuid(); 221 222 passwd_req = pwd->pw_uid == 0 || 223 (uid && uid != pwd->pw_uid); 224 } 225 226 /* 227 * If no pre-authentication and a password exists 228 * for this user, prompt for one and verify it. 229 */ 230 if (!passwd_req || (pwd && !*pwd->pw_passwd)) 231 break; 232 233 setpriority(PRIO_PROCESS, 0, -4); 234 pp = getpass("Password:"); 235 p = crypt(pp, salt); 236 setpriority(PRIO_PROCESS, 0, 0); 237 238#ifdef KERBEROS 239 240 /* 241 * If not present in pw file, act as we normally would. 242 * If we aren't Kerberos-authenticated, try the normal 243 * pw file for a password. If that's ok, log the user 244 * in without issueing any tickets. 245 */ 246 247 if (pwd && !krb_get_lrealm(realm,1)) { 248 /* get TGT for local realm 249 * be careful about uid's here for ticket 250 * file ownership 251 */ 252 (void) setreuid(geteuid(),pwd->pw_uid); 253 kerror = krb_get_pw_in_tkt( 254 pwd->pw_name, "", realm, 255 "krbtgt", realm, DEFAULT_TKT_LIFE, pp); 256 (void) setuid(0); 257 if (kerror == INTK_OK) { 258 bzero(pp, strlen(pp)); 259 notickets = 0; /* user got ticket */ 260 break; 261 } 262 } 263#endif 264 (void) bzero(pp, strlen(pp)); 265 if (pwd && !strcmp(p, pwd->pw_passwd)) 266 break; 267 268 printf("Login incorrect\n"); 269 failures++; 270 /* we allow 10 tries, but after 3 we start backing off */ 271 if (++cnt > 3) { 272 if (cnt >= 10) { 273 badlogin(username); 274 (void)ioctl(0, TIOCHPCL, (struct sgttyb *)NULL); 275 sleepexit(1); 276 } 277 sleep((u_int)((cnt - 3) * 5)); 278 } 279 } 280 281 /* committed to login -- turn off timeout */ 282 (void)alarm((u_int)0); 283 284 /* 285 * If valid so far and root is logging in, see if root logins on 286 * this terminal are permitted. 287 */ 288 if (pwd->pw_uid == 0 && !rootterm(tty)) { 289 if (hostname) 290 syslog(LOG_NOTICE, "ROOT LOGIN REFUSED FROM %s", 291 hostname); 292 else 293 syslog(LOG_NOTICE, "ROOT LOGIN REFUSED ON %s", tty); 294 printf("Login incorrect\n"); 295 sleepexit(1); 296 } 297 298 if (quota(Q_SETUID, pwd->pw_uid, 0, 0) < 0 && errno != EINVAL) { 299 switch(errno) { 300 case EUSERS: 301 fprintf(stderr, 302 "Too many users logged on already.\nTry again later.\n"); 303 break; 304 case EPROCLIM: 305 fprintf(stderr, 306 "You have too many processes running.\n"); 307 break; 308 default: 309 perror("quota (Q_SETUID)"); 310 } 311 sleepexit(0); 312 } 313 314 if (chdir(pwd->pw_dir) < 0) { 315 printf("No directory %s!\n", pwd->pw_dir); 316 if (chdir("/")) 317 exit(0); 318 pwd->pw_dir = "/"; 319 printf("Logging in with home = \"/\".\n"); 320 } 321 322#ifdef KERBEROS 323 if (notickets) 324 printf("Warning: no Kerberos tickets issued\n"); 325#endif 326 327#define TWOWEEKS (14*24*60*60) 328 if (pwd->pw_change || pwd->pw_expire) 329 (void)gettimeofday(&tp, (struct timezone *)NULL); 330 if (pwd->pw_change) 331 if (tp.tv_sec >= pwd->pw_change) { 332 printf("Sorry -- your password has expired.\n"); 333 sleepexit(1); 334 } 335 else if (tp.tv_sec - pwd->pw_change < TWOWEEKS) { 336 ttp = localtime(&pwd->pw_change); 337 printf("Warning: your password expires on %s %d, 19%d\n", 338 months[ttp->tm_mon], ttp->tm_mday, ttp->tm_year); 339 } 340 if (pwd->pw_expire) 341 if (tp.tv_sec >= pwd->pw_expire) { 342 printf("Sorry -- your account has expired.\n"); 343 sleepexit(1); 344 } 345 else if (tp.tv_sec - pwd->pw_expire < TWOWEEKS) { 346 ttp = localtime(&pwd->pw_expire); 347 printf("Warning: your account expires on %s %d, 19%d\n", 348 months[ttp->tm_mon], ttp->tm_mday, ttp->tm_year); 349 } 350 351 /* nothing else left to fail -- really log in */ 352 { 353 struct utmp utmp; 354 355 bzero((char *)&utmp, sizeof(utmp)); 356 (void)time(&utmp.ut_time); 357 strncpy(utmp.ut_name, username, sizeof(utmp.ut_name)); 358 if (hostname) 359 strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host)); 360 strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line)); 361 login(&utmp); 362 } 363 364 quietlog = access(HUSHLOGIN, F_OK) == 0; 365 dolastlog(quietlog); 366 367 if (!hflag) { /* XXX */ 368 static struct winsize win = { 0, 0, 0, 0 }; 369 370 (void)ioctl(0, TIOCSWINSZ, &win); 371 } 372 373 (void)chown(ttyn, pwd->pw_uid, 374 (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid); 375 (void)chmod(ttyn, 0620); 376 (void)setgid(pwd->pw_gid); 377 378 initgroups(username, pwd->pw_gid); 379 380 quota(Q_DOWARN, pwd->pw_uid, (dev_t)-1, 0); 381 (void)setuid(pwd->pw_uid); 382 383 if (*pwd->pw_shell == '\0') 384 pwd->pw_shell = BSHELL; 385 /* turn on new line discipline for the csh */ 386 else if (!strcmp(pwd->pw_shell, "/bin/csh")) { 387 ioctlval = NTTYDISC; 388 (void)ioctl(0, TIOCSETD, &ioctlval); 389 } 390 391 /* destroy environment unless user has requested preservation */ 392 if (!pflag) 393 environ = envinit; 394 (void)setenv("HOME", pwd->pw_dir, 1); 395 (void)setenv("SHELL", pwd->pw_shell, 1); 396 if (term[0] == '\0') 397 strncpy(term, stypeof(tty), sizeof(term)); 398 (void)setenv("TERM", term, 0); 399 (void)setenv("USER", pwd->pw_name, 1); 400 (void)setenv("PATH", "/usr/ucb:/bin:/usr/bin:", 0); 401 402 if (tty[sizeof("tty")-1] == 'd') 403 syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name); 404 if (pwd->pw_uid == 0) 405 if (hostname) 406 syslog(LOG_NOTICE, "ROOT LOGIN ON %s FROM %s", 407 tty, hostname); 408 else 409 syslog(LOG_NOTICE, "ROOT LOGIN ON %s", tty); 410 411 if (!quietlog) { 412 struct stat st; 413 414 motd(); 415 (void)sprintf(tbuf, "%s/%s", MAILDIR, pwd->pw_name); 416 if (stat(tbuf, &st) == 0 && st.st_size != 0) 417 printf("You have %smail.\n", 418 (st.st_mtime > st.st_atime) ? "new " : ""); 419 } 420 421 (void)signal(SIGALRM, SIG_DFL); 422 (void)signal(SIGQUIT, SIG_DFL); 423 (void)signal(SIGINT, SIG_DFL); 424 (void)signal(SIGTSTP, SIG_IGN); 425 426 tbuf[0] = '-'; 427 strcpy(tbuf + 1, (p = rindex(pwd->pw_shell, '/')) ? 428 p + 1 : pwd->pw_shell); 429 execlp(pwd->pw_shell, tbuf, 0); 430 fprintf(stderr, "login: no shell: "); 431 perror(pwd->pw_shell); 432 exit(0); 433} 434 435getloginname() 436{ 437 register int ch; 438 register char *p; 439 static char nbuf[UT_NAMESIZE + 1]; 440 441 for (;;) { 442 printf("login: "); 443 for (p = nbuf; (ch = getchar()) != '\n'; ) { 444 if (ch == EOF) { 445 badlogin(username); 446 exit(0); 447 } 448 if (p < nbuf + UT_NAMESIZE) 449 *p++ = ch; 450 } 451 if (p > nbuf) 452 if (nbuf[0] == '-') 453 fprintf(stderr, 454 "login names may not start with '-'.\n"); 455 else { 456 *p = '\0'; 457 username = nbuf; 458 break; 459 } 460 } 461} 462 463timedout() 464{ 465 fprintf(stderr, "Login timed out after %d seconds\n", timeout); 466 exit(0); 467} 468 469rootterm(ttyn) 470 char *ttyn; 471{ 472 struct ttyent *t; 473 474 return((t = getttynam(ttyn)) && t->ty_status&TTY_SECURE); 475} 476 477jmp_buf motdinterrupt; 478 479motd() 480{ 481 register int fd, nchars; 482 int (*oldint)(), sigint(); 483 char tbuf[8192]; 484 485 if ((fd = open(MOTDFILE, O_RDONLY, 0)) < 0) 486 return; 487 oldint = signal(SIGINT, sigint); 488 if (setjmp(motdinterrupt) == 0) 489 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) 490 (void)write(fileno(stdout), tbuf, nchars); 491 (void)signal(SIGINT, oldint); 492 (void)close(fd); 493} 494 495sigint() 496{ 497 longjmp(motdinterrupt, 1); 498} 499 500checknologin() 501{ 502 register int fd, nchars; 503 char tbuf[8192]; 504 505 if ((fd = open(NOLOGIN, O_RDONLY, 0)) >= 0) { 506 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) 507 (void)write(fileno(stdout), tbuf, nchars); 508 sleepexit(0); 509 } 510} 511 512dolastlog(quiet) 513 int quiet; 514{ 515 struct lastlog ll; 516 int fd; 517 char *ctime(); 518 519 if ((fd = open(LASTLOG, O_RDWR, 0)) >= 0) { 520 (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); 521 if (!quiet) { 522 if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) && 523 ll.ll_time != 0) { 524 printf("Last login: %.*s ", 525 24-5, (char *)ctime(&ll.ll_time)); 526 if (*ll.ll_host != '\0') 527 printf("from %.*s\n", 528 sizeof(ll.ll_host), ll.ll_host); 529 else 530 printf("on %.*s\n", 531 sizeof(ll.ll_line), ll.ll_line); 532 } 533 (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); 534 } 535 bzero((char *)&ll, sizeof(ll)); 536 (void)time(&ll.ll_time); 537 strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); 538 if (hostname) 539 strncpy(ll.ll_host, hostname, sizeof(ll.ll_host)); 540 (void)write(fd, (char *)&ll, sizeof(ll)); 541 (void)close(fd); 542 } 543} 544 545badlogin(name) 546 char *name; 547{ 548 if (failures == 0) 549 return; 550 if (hostname) 551 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s, %s", 552 failures, failures > 1 ? "S" : "", hostname, name); 553 else 554 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s, %s", 555 failures, failures > 1 ? "S" : "", tty, name); 556} 557 558#undef UNKNOWN 559#define UNKNOWN "su" 560 561char * 562stypeof(ttyid) 563 char *ttyid; 564{ 565 struct ttyent *t; 566 567 return(ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN); 568} 569 570getstr(buf, cnt, err) 571 char *buf, *err; 572 int cnt; 573{ 574 char ch; 575 576 do { 577 if (read(0, &ch, sizeof(ch)) != sizeof(ch)) 578 exit(1); 579 if (--cnt < 0) { 580 fprintf(stderr, "%s too long\r\n", err); 581 sleepexit(1); 582 } 583 *buf++ = ch; 584 } while (ch); 585} 586 587sleepexit(eval) 588 int eval; 589{ 590 sleep((u_int)5); 591 exit(eval); 592} 593