1 /*- 2 * Copyright (c) 1980, 1987, 1988 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 char copyright[] = 10 "@(#) Copyright (c) 1980, 1987, 1988 The Regents of the University of California.\n\ 11 All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)login.c 5.66 (Berkeley) 03/01/91"; 16 #endif /* not lint */ 17 18 /* 19 * login [ name ] 20 * login -h hostname (for telnetd, etc.) 21 * login -f name (for pre-authenticated login: datakit, xterm, etc.) 22 */ 23 24 #include <sys/param.h> 25 #include <sys/stat.h> 26 #include <sys/time.h> 27 #include <sys/resource.h> 28 #include <sys/file.h> 29 30 #include <utmp.h> 31 #include <signal.h> 32 #include <errno.h> 33 #include <ttyent.h> 34 #include <syslog.h> 35 #include <grp.h> 36 #include <pwd.h> 37 #include <setjmp.h> 38 #include <stdio.h> 39 #include <string.h> 40 #include <tzfile.h> 41 #include "pathnames.h" 42 43 #define TTYGRPNAME "tty" /* name of group to own ttys */ 44 45 /* 46 * This bounds the time given to login. Not a define so it can 47 * be patched on machines where it's too small. 48 */ 49 int timeout = 300; 50 #ifdef KERBEROS 51 int notickets = 1; 52 #endif 53 54 struct passwd *pwd; 55 int failures; 56 char term[64], *envinit[1], *hostname, *username, *tty; 57 58 main(argc, argv) 59 int argc; 60 char **argv; 61 { 62 extern int optind; 63 extern char *optarg, **environ; 64 struct timeval tp; 65 struct group *gr; 66 register int ch; 67 register char *p; 68 int ask, fflag, hflag, pflag, cnt, uid; 69 int quietlog, rval; 70 char *domain, *salt, *ttyn; 71 char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10]; 72 char localhost[MAXHOSTNAMELEN]; 73 char *ctime(), *ttyname(), *stypeof(), *crypt(), *getpass(); 74 time_t time(); 75 off_t lseek(); 76 void timedout(); 77 78 (void)signal(SIGALRM, timedout); 79 (void)alarm((u_int)timeout); 80 (void)signal(SIGQUIT, SIG_IGN); 81 (void)signal(SIGINT, SIG_IGN); 82 (void)setpriority(PRIO_PROCESS, 0, 0); 83 84 openlog("login", LOG_ODELAY, LOG_AUTH); 85 86 /* 87 * -p is used by getty to tell login not to destroy the environment 88 * -f is used to skip a second login authentication 89 * -h is used by other servers to pass the name of the remote 90 * host to login so that it may be placed in utmp and wtmp 91 */ 92 domain = NULL; 93 if (gethostname(localhost, sizeof(localhost)) < 0) 94 syslog(LOG_ERR, "couldn't get local hostname: %m"); 95 else 96 domain = index(localhost, '.'); 97 98 fflag = hflag = pflag = 0; 99 uid = getuid(); 100 while ((ch = getopt(argc, argv, "fh:p")) != EOF) 101 switch (ch) { 102 case 'f': 103 fflag = 1; 104 break; 105 case 'h': 106 if (uid) { 107 (void)fprintf(stderr, 108 "login: -h for super-user only.\n"); 109 exit(1); 110 } 111 hflag = 1; 112 if (domain && (p = index(optarg, '.')) && 113 strcasecmp(p, domain) == 0) 114 *p = 0; 115 hostname = optarg; 116 break; 117 case 'p': 118 pflag = 1; 119 break; 120 case '?': 121 default: 122 if (!uid) 123 syslog(LOG_ERR, "invalid flag %c", ch); 124 (void)fprintf(stderr, 125 "usage: login [-fp] [username]\n"); 126 exit(1); 127 } 128 argc -= optind; 129 argv += optind; 130 if (*argv) { 131 username = *argv; 132 if (strlen(username) > UT_NAMESIZE) 133 username[UT_NAMESIZE] = '\0'; 134 ask = 0; 135 } else 136 ask = 1; 137 138 for (cnt = getdtablesize(); cnt > 2; cnt--) 139 close(cnt); 140 141 ttyn = ttyname(0); 142 if (ttyn == NULL || *ttyn == '\0') { 143 (void)sprintf(tname, "%s??", _PATH_TTY); 144 ttyn = tname; 145 } 146 if (tty = rindex(ttyn, '/')) 147 ++tty; 148 else 149 tty = ttyn; 150 151 for (cnt = 0;; ask = 1) { 152 if (ask) { 153 fflag = 0; 154 getloginname(); 155 } 156 /* 157 * Note if trying multiple user names; log failures for 158 * previous user name, but don't bother logging one failure 159 * for nonexistent name (mistyped username). 160 */ 161 if (failures && strcmp(tbuf, username)) { 162 if (failures > (pwd ? 0 : 1)) 163 badlogin(tbuf); 164 failures = 0; 165 } 166 (void)strcpy(tbuf, username); 167 168 if (pwd = getpwnam(username)) 169 salt = pwd->pw_passwd; 170 else 171 salt = "xx"; 172 173 /* 174 * if we have a valid account name, and it doesn't have a 175 * password, or the -f option was specified and the caller 176 * is root or the caller isn't changing their uid, don't 177 * authenticate. 178 */ 179 if (pwd && (*pwd->pw_passwd == '\0' || 180 fflag && (uid == 0 || uid == pwd->pw_uid))) 181 break; 182 fflag = 0; 183 184 /* 185 * If trying to log in as root, but with insecure terminal, 186 * refuse the login attempt. 187 */ 188 if (pwd && pwd->pw_uid == 0 && !rootterm(tty)) { 189 (void)fprintf(stderr, 190 "%s login refused on this terminal.\n", 191 pwd->pw_name); 192 if (hostname) 193 syslog(LOG_NOTICE, 194 "LOGIN %s REFUSED FROM %s ON TTY %s", 195 pwd->pw_name, hostname, tty); 196 else 197 syslog(LOG_NOTICE, 198 "LOGIN %s REFUSED ON TTY %s", 199 pwd->pw_name, tty); 200 continue; 201 } 202 203 (void)setpriority(PRIO_PROCESS, 0, -4); 204 205 p = getpass("Password:"); 206 207 if (pwd) { 208 #ifdef KERBEROS 209 rval = klogin(pwd, localhost, p); 210 if (rval == 1) 211 rval = strcmp(crypt(p, salt), pwd->pw_passwd); 212 #else 213 rval = strcmp(crypt(p, salt), pwd->pw_passwd); 214 #endif 215 } 216 bzero(p, strlen(p)); 217 218 (void)setpriority(PRIO_PROCESS, 0, 0); 219 220 if (pwd && !rval) 221 break; 222 223 (void)printf("Login incorrect\n"); 224 failures++; 225 /* we allow 10 tries, but after 3 we start backing off */ 226 if (++cnt > 3) { 227 if (cnt >= 10) { 228 badlogin(username); 229 sleepexit(1); 230 } 231 sleep((u_int)((cnt - 3) * 5)); 232 } 233 } 234 235 /* committed to login -- turn off timeout */ 236 (void)alarm((u_int)0); 237 238 /* paranoia... */ 239 endpwent(); 240 241 /* if user not super-user, check for disabled logins */ 242 if (pwd->pw_uid) 243 checknologin(); 244 245 if (chdir(pwd->pw_dir) < 0) { 246 (void)printf("No directory %s!\n", pwd->pw_dir); 247 if (chdir("/")) 248 exit(0); 249 pwd->pw_dir = "/"; 250 (void)printf("Logging in with home = \"/\".\n"); 251 } 252 253 quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0; 254 255 if (pwd->pw_change || pwd->pw_expire) 256 (void)gettimeofday(&tp, (struct timezone *)NULL); 257 if (pwd->pw_change) 258 if (tp.tv_sec >= pwd->pw_change) { 259 (void)printf("Sorry -- your password has expired.\n"); 260 sleepexit(1); 261 } 262 else if (pwd->pw_change - tp.tv_sec < 263 2 * DAYSPERWEEK * SECSPERDAY && !quietlog) 264 (void)printf("Warning: your password expires on %s", 265 ctime(&pwd->pw_expire)); 266 if (pwd->pw_expire) 267 if (tp.tv_sec >= pwd->pw_expire) { 268 (void)printf("Sorry -- your account has expired.\n"); 269 sleepexit(1); 270 } 271 else if (pwd->pw_expire - tp.tv_sec < 272 2 * DAYSPERWEEK * SECSPERDAY && !quietlog) 273 (void)printf("Warning: your account expires on %s", 274 ctime(&pwd->pw_expire)); 275 276 /* nothing else left to fail -- really log in */ 277 { 278 struct utmp utmp; 279 280 bzero((void *)&utmp, sizeof(utmp)); 281 (void)time(&utmp.ut_time); 282 strncpy(utmp.ut_name, username, sizeof(utmp.ut_name)); 283 if (hostname) 284 strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host)); 285 strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line)); 286 login(&utmp); 287 } 288 289 dolastlog(quietlog); 290 291 (void)chown(ttyn, pwd->pw_uid, 292 (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid); 293 (void)chmod(ttyn, 0620); 294 (void)setgid(pwd->pw_gid); 295 296 initgroups(username, pwd->pw_gid); 297 298 if (*pwd->pw_shell == '\0') 299 pwd->pw_shell = _PATH_BSHELL; 300 301 /* destroy environment unless user has requested preservation */ 302 if (!pflag) 303 environ = envinit; 304 (void)setenv("HOME", pwd->pw_dir, 1); 305 (void)setenv("SHELL", pwd->pw_shell, 1); 306 if (term[0] == '\0') 307 strncpy(term, stypeof(tty), sizeof(term)); 308 (void)setenv("TERM", term, 0); 309 (void)setenv("USER", pwd->pw_name, 1); 310 (void)setenv("PATH", _PATH_DEFPATH, 0); 311 312 if (tty[sizeof("tty")-1] == 'd') 313 syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name); 314 /* if fflag is on, assume caller/authenticator has logged root login */ 315 if (pwd->pw_uid == 0 && fflag == 0) 316 if (hostname) 317 syslog(LOG_NOTICE, "ROOT LOGIN ON %s FROM %s", 318 tty, hostname); 319 else 320 syslog(LOG_NOTICE, "ROOT LOGIN ON %s", tty); 321 322 #ifdef KERBEROS 323 if (!quietlog && notickets == 1) 324 (void)printf("Warning: no Kerberos tickets issued.\n"); 325 #endif 326 327 if (!quietlog) { 328 struct stat st; 329 330 motd(); 331 (void)sprintf(tbuf, "%s/%s", _PATH_MAILDIR, pwd->pw_name); 332 if (stat(tbuf, &st) == 0 && st.st_size != 0) 333 (void)printf("You have %smail.\n", 334 (st.st_mtime > st.st_atime) ? "new " : ""); 335 } 336 337 (void)signal(SIGALRM, SIG_DFL); 338 (void)signal(SIGQUIT, SIG_DFL); 339 (void)signal(SIGINT, SIG_DFL); 340 (void)signal(SIGTSTP, SIG_IGN); 341 342 tbuf[0] = '-'; 343 strcpy(tbuf + 1, (p = rindex(pwd->pw_shell, '/')) ? 344 p + 1 : pwd->pw_shell); 345 346 if (setlogin(pwd->pw_name) < 0) 347 syslog(LOG_ERR, "setlogin() failure: %m"); 348 349 /* discard permissions last so can't get killed and drop core */ 350 (void)setuid(pwd->pw_uid); 351 352 execlp(pwd->pw_shell, tbuf, 0); 353 (void)fprintf(stderr, "login: no shell: %s.\n", strerror(errno)); 354 exit(0); 355 } 356 357 getloginname() 358 { 359 register int ch; 360 register char *p; 361 static char nbuf[UT_NAMESIZE + 1]; 362 363 for (;;) { 364 (void)printf("login: "); 365 for (p = nbuf; (ch = getchar()) != '\n'; ) { 366 if (ch == EOF) { 367 badlogin(username); 368 exit(0); 369 } 370 if (p < nbuf + UT_NAMESIZE) 371 *p++ = ch; 372 } 373 if (p > nbuf) 374 if (nbuf[0] == '-') 375 (void)fprintf(stderr, 376 "login names may not start with '-'.\n"); 377 else { 378 *p = '\0'; 379 username = nbuf; 380 break; 381 } 382 } 383 } 384 385 void 386 timedout() 387 { 388 (void)fprintf(stderr, "Login timed out after %d seconds\n", timeout); 389 exit(0); 390 } 391 392 rootterm(ttyn) 393 char *ttyn; 394 { 395 struct ttyent *t; 396 397 return((t = getttynam(ttyn)) && t->ty_status&TTY_SECURE); 398 } 399 400 jmp_buf motdinterrupt; 401 402 motd() 403 { 404 register int fd, nchars; 405 sig_t oldint; 406 void sigint(); 407 char tbuf[8192]; 408 409 if ((fd = open(_PATH_MOTDFILE, O_RDONLY, 0)) < 0) 410 return; 411 oldint = signal(SIGINT, sigint); 412 if (setjmp(motdinterrupt) == 0) 413 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) 414 (void)write(fileno(stdout), tbuf, nchars); 415 (void)signal(SIGINT, oldint); 416 (void)close(fd); 417 } 418 419 void 420 sigint() 421 { 422 longjmp(motdinterrupt, 1); 423 } 424 425 checknologin() 426 { 427 register int fd, nchars; 428 char tbuf[8192]; 429 430 if ((fd = open(_PATH_NOLOGIN, O_RDONLY, 0)) >= 0) { 431 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) 432 (void)write(fileno(stdout), tbuf, nchars); 433 sleepexit(0); 434 } 435 } 436 437 dolastlog(quiet) 438 int quiet; 439 { 440 struct lastlog ll; 441 int fd; 442 char *ctime(); 443 444 if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) { 445 (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); 446 if (!quiet) { 447 if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) && 448 ll.ll_time != 0) { 449 (void)printf("Last login: %.*s ", 450 24-5, (char *)ctime(&ll.ll_time)); 451 if (*ll.ll_host != '\0') 452 (void)printf("from %.*s\n", 453 sizeof(ll.ll_host), ll.ll_host); 454 else 455 (void)printf("on %.*s\n", 456 sizeof(ll.ll_line), ll.ll_line); 457 } 458 (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); 459 } 460 bzero((void *)&ll, sizeof(ll)); 461 (void)time(&ll.ll_time); 462 strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); 463 if (hostname) 464 strncpy(ll.ll_host, hostname, sizeof(ll.ll_host)); 465 (void)write(fd, (char *)&ll, sizeof(ll)); 466 (void)close(fd); 467 } 468 } 469 470 badlogin(name) 471 char *name; 472 { 473 if (failures == 0) 474 return; 475 if (hostname) { 476 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s", 477 failures, failures > 1 ? "S" : "", hostname); 478 syslog(LOG_AUTHPRIV|LOG_NOTICE, 479 "%d LOGIN FAILURE%s FROM %s, %s", 480 failures, failures > 1 ? "S" : "", hostname, name); 481 } else { 482 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s", 483 failures, failures > 1 ? "S" : "", tty); 484 syslog(LOG_AUTHPRIV|LOG_NOTICE, 485 "%d LOGIN FAILURE%s ON %s, %s", 486 failures, failures > 1 ? "S" : "", tty, name); 487 } 488 } 489 490 #undef UNKNOWN 491 #define UNKNOWN "su" 492 493 char * 494 stypeof(ttyid) 495 char *ttyid; 496 { 497 struct ttyent *t; 498 499 return(ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN); 500 } 501 502 sleepexit(eval) 503 int eval; 504 { 505 sleep((u_int)5); 506 exit(eval); 507 } 508