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