1 /*- 2 * Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #if 0 35 static char copyright[] = 36 "@(#) Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994\n\ 37 The Regents of the University of California. All rights reserved.\n"; 38 #endif 39 40 #ifndef lint 41 #if 0 42 static char sccsid[] = "@(#)login.c 8.4 (Berkeley) 4/2/94"; 43 #endif 44 static const char rcsid[] = 45 "$Id: login.c,v 1.43 1998/11/21 02:22:14 jdp Exp $"; 46 #endif /* not lint */ 47 48 /* 49 * login [ name ] 50 * login -h hostname (for telnetd, etc.) 51 * login -f name (for pre-authenticated login: datakit, xterm, etc.) 52 */ 53 54 #include <sys/copyright.h> 55 #include <sys/param.h> 56 #include <sys/stat.h> 57 #include <sys/time.h> 58 #include <sys/resource.h> 59 #include <sys/file.h> 60 #include <netinet/in.h> 61 #include <arpa/inet.h> 62 63 #include <err.h> 64 #include <errno.h> 65 #include <grp.h> 66 #include <libutil.h> 67 #include <login_cap.h> 68 #include <netdb.h> 69 #include <pwd.h> 70 #include <setjmp.h> 71 #include <signal.h> 72 #include <stdio.h> 73 #include <stdlib.h> 74 #include <string.h> 75 #include <syslog.h> 76 #include <ttyent.h> 77 #include <unistd.h> 78 #include <utmp.h> 79 80 #include <security/pam_appl.h> 81 #include <security/pam_misc.h> 82 83 #include "pathnames.h" 84 85 void badlogin __P((char *)); 86 void checknologin __P((void)); 87 void dolastlog __P((int)); 88 void getloginname __P((void)); 89 void motd __P((char *)); 90 int rootterm __P((char *)); 91 void sigint __P((int)); 92 void sleepexit __P((int)); 93 void refused __P((char *,char *,int)); 94 char *stypeof __P((char *)); 95 void timedout __P((int)); 96 int login_access __P((char *, char *)); 97 void login_fbtab __P((char *, uid_t, gid_t)); 98 99 static int auth_pam __P((void)); 100 static int auth_traditional __P((void)); 101 extern void login __P((struct utmp *)); 102 static void usage __P((void)); 103 104 #define TTYGRPNAME "tty" /* name of group to own ttys */ 105 #define DEFAULT_BACKOFF 3 106 #define DEFAULT_RETRIES 10 107 108 /* 109 * This bounds the time given to login. Not a define so it can 110 * be patched on machines where it's too small. 111 */ 112 u_int timeout = 300; 113 114 /* Buffer for signal handling of timeout */ 115 jmp_buf timeout_buf; 116 117 struct passwd *pwd; 118 int failures; 119 char *term, *envinit[1], *hostname, *username, *tty; 120 char full_hostname[MAXHOSTNAMELEN]; 121 122 int 123 main(argc, argv) 124 int argc; 125 char *argv[]; 126 { 127 extern char **environ; 128 struct group *gr; 129 struct stat st; 130 struct timeval tp; 131 struct utmp utmp; 132 int rootok, retries, backoff; 133 int ask, ch, cnt, fflag, hflag, pflag, quietlog, rootlogin, rval; 134 int changepass; 135 time_t warntime; 136 uid_t uid, euid; 137 char *domain, *p, *ttyn; 138 char tbuf[MAXPATHLEN + 2]; 139 char tname[sizeof(_PATH_TTY) + 10]; 140 char localhost[MAXHOSTNAMELEN]; 141 char *shell = NULL; 142 login_cap_t *lc = NULL; 143 144 (void)signal(SIGQUIT, SIG_IGN); 145 (void)signal(SIGINT, SIG_IGN); 146 if (setjmp(timeout_buf)) { 147 if (failures) 148 badlogin(tbuf); 149 (void)fprintf(stderr, 150 "Login timed out after %d seconds\n", timeout); 151 exit(0); 152 } 153 (void)signal(SIGALRM, timedout); 154 (void)alarm(timeout); 155 (void)setpriority(PRIO_PROCESS, 0, 0); 156 157 openlog("login", LOG_ODELAY, LOG_AUTH); 158 159 /* 160 * -p is used by getty to tell login not to destroy the environment 161 * -f is used to skip a second login authentication 162 * -h is used by other servers to pass the name of the remote 163 * host to login so that it may be placed in utmp and wtmp 164 */ 165 *full_hostname = '\0'; 166 domain = NULL; 167 term = NULL; 168 if (gethostname(localhost, sizeof(localhost)) < 0) 169 syslog(LOG_ERR, "couldn't get local hostname: %m"); 170 else 171 domain = strchr(localhost, '.'); 172 173 fflag = hflag = pflag = 0; 174 uid = getuid(); 175 euid = geteuid(); 176 while ((ch = getopt(argc, argv, "fh:p")) != -1) 177 switch (ch) { 178 case 'f': 179 fflag = 1; 180 break; 181 case 'h': 182 if (uid) 183 errx(1, "-h option: %s", strerror(EPERM)); 184 hflag = 1; 185 strncpy(full_hostname, optarg, sizeof(full_hostname)-1); 186 if (domain && (p = strchr(optarg, '.')) && 187 strcasecmp(p, domain) == 0) 188 *p = 0; 189 190 trimdomain(optarg, UT_HOSTSIZE ); 191 192 if (strlen(optarg) > UT_HOSTSIZE) { 193 struct hostent *hp = gethostbyname(optarg); 194 195 if (hp != NULL) { 196 struct in_addr in; 197 198 memmove(&in, hp->h_addr, sizeof(in)); 199 optarg = strdup(inet_ntoa(in)); 200 } else 201 optarg = "invalid hostname"; 202 } 203 hostname = optarg; 204 break; 205 case 'p': 206 pflag = 1; 207 break; 208 case '?': 209 default: 210 if (!uid) 211 syslog(LOG_ERR, "invalid flag %c", ch); 212 usage(); 213 } 214 argc -= optind; 215 argv += optind; 216 217 if (*argv) { 218 username = *argv; 219 ask = 0; 220 } else 221 ask = 1; 222 223 for (cnt = getdtablesize(); cnt > 2; cnt--) 224 (void)close(cnt); 225 226 ttyn = ttyname(STDIN_FILENO); 227 if (ttyn == NULL || *ttyn == '\0') { 228 (void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY); 229 ttyn = tname; 230 } 231 if ((tty = strrchr(ttyn, '/')) != NULL) 232 ++tty; 233 else 234 tty = ttyn; 235 236 /* 237 * Get "login-retries" & "login-backoff" from default class 238 */ 239 lc = login_getclass(NULL); 240 retries = login_getcapnum(lc, "login-retries", DEFAULT_RETRIES, DEFAULT_RETRIES); 241 backoff = login_getcapnum(lc, "login-backoff", DEFAULT_BACKOFF, DEFAULT_BACKOFF); 242 login_close(lc); 243 lc = NULL; 244 245 for (cnt = 0;; ask = 1) { 246 if (ask) { 247 fflag = 0; 248 getloginname(); 249 } 250 rootlogin = 0; 251 rootok = rootterm(tty); /* Default (auth may change) */ 252 253 if (strlen(username) > UT_NAMESIZE) 254 username[UT_NAMESIZE] = '\0'; 255 256 /* 257 * Note if trying multiple user names; log failures for 258 * previous user name, but don't bother logging one failure 259 * for nonexistent name (mistyped username). 260 */ 261 if (failures && strcmp(tbuf, username)) { 262 if (failures > (pwd ? 0 : 1)) 263 badlogin(tbuf); 264 } 265 (void)strncpy(tbuf, username, sizeof tbuf-1); 266 tbuf[sizeof tbuf-1] = '\0'; 267 268 pwd = getpwnam(username); 269 270 /* 271 * if we have a valid account name, and it doesn't have a 272 * password, or the -f option was specified and the caller 273 * is root or the caller isn't changing their uid, don't 274 * authenticate. 275 */ 276 if (pwd != NULL) { 277 if (pwd->pw_uid == 0) 278 rootlogin = 1; 279 280 if (fflag && (uid == (uid_t)0 || 281 uid == (uid_t)pwd->pw_uid)) { 282 /* already authenticated */ 283 break; 284 } else if (pwd->pw_passwd[0] == '\0') { 285 if (!rootlogin || rootok) { 286 /* pretend password okay */ 287 rval = 0; 288 goto ttycheck; 289 } 290 } 291 } 292 293 fflag = 0; 294 295 (void)setpriority(PRIO_PROCESS, 0, -4); 296 297 /* 298 * Try to authenticate using PAM. If a PAM system error 299 * occurs, perhaps because of a botched configuration, 300 * then fall back to using traditional Unix authentication. 301 */ 302 if ((rval = auth_pam()) == -1) 303 rval = auth_traditional(); 304 305 (void)setpriority(PRIO_PROCESS, 0, 0); 306 307 /* 308 * PAM authentication may have changed "pwd" to the 309 * entry for the template user. Check again to see if 310 * this is a root login after all. 311 */ 312 if (pwd != NULL && pwd->pw_uid == 0) 313 rootlogin = 1; 314 315 ttycheck: 316 /* 317 * If trying to log in as root without Kerberos, 318 * but with insecure terminal, refuse the login attempt. 319 */ 320 if (pwd && !rval) { 321 if (rootlogin && !rootok) 322 refused(NULL, "NOROOT", 0); 323 else /* valid password & authenticated */ 324 break; 325 } 326 327 (void)printf("Login incorrect\n"); 328 failures++; 329 330 /* 331 * we allow up to 'retry' (10) tries, 332 * but after 'backoff' (3) we start backing off 333 */ 334 if (++cnt > backoff) { 335 if (cnt >= retries) { 336 badlogin(username); 337 sleepexit(1); 338 } 339 sleep((u_int)((cnt - backoff) * 5)); 340 } 341 } 342 343 /* committed to login -- turn off timeout */ 344 (void)alarm((u_int)0); 345 346 endpwent(); 347 348 /* 349 * Establish the login class. 350 */ 351 (void)seteuid(rootlogin ? 0 : pwd->pw_uid); 352 lc = login_getpwclass(pwd); 353 seteuid(euid); 354 355 /* if user not super-user, check for disabled logins */ 356 if (!rootlogin) 357 auth_checknologin(lc); 358 359 quietlog = login_getcapbool(lc, "hushlogin", 0); 360 (void)seteuid(rootlogin ? 0 : pwd->pw_uid); 361 if (!*pwd->pw_dir || chdir(pwd->pw_dir) < 0) { 362 if (login_getcapbool(lc, "requirehome", 0)) 363 refused("Home directory not available", "HOMEDIR", 1); 364 if (chdir("/") < 0) 365 refused("Cannot find root directory", "ROOTDIR", 1); 366 pwd->pw_dir = "/"; 367 if (!quietlog || *pwd->pw_dir) 368 printf("No home directory.\nLogging in with home = \"/\".\n"); 369 } 370 (void)seteuid(euid); 371 if (!quietlog) 372 quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0; 373 374 if (pwd->pw_change || pwd->pw_expire) 375 (void)gettimeofday(&tp, (struct timezone *)NULL); 376 377 #define DEFAULT_WARN (2L * 7L * 86400L) /* Two weeks */ 378 379 warntime = login_getcaptime(lc, "warnpassword", 380 DEFAULT_WARN, DEFAULT_WARN); 381 382 changepass=0; 383 if (pwd->pw_change) { 384 if (tp.tv_sec >= pwd->pw_change) { 385 (void)printf("Sorry -- your password has expired.\n"); 386 changepass=1; 387 syslog(LOG_INFO, 388 "%s Password expired - forcing change", 389 pwd->pw_name); 390 } else if (pwd->pw_change - tp.tv_sec < warntime && !quietlog) 391 (void)printf("Warning: your password expires on %s", 392 ctime(&pwd->pw_change)); 393 } 394 395 warntime = login_getcaptime(lc, "warnexpire", 396 DEFAULT_WARN, DEFAULT_WARN); 397 398 if (pwd->pw_expire) { 399 if (tp.tv_sec >= pwd->pw_expire) { 400 refused("Sorry -- your account has expired", 401 "EXPIRED", 1); 402 } else if (pwd->pw_expire - tp.tv_sec < warntime && !quietlog) 403 (void)printf("Warning: your account expires on %s", 404 ctime(&pwd->pw_expire)); 405 } 406 407 if (lc != NULL) { 408 if (hostname) { 409 struct hostent *hp = gethostbyname(full_hostname); 410 411 if (hp == NULL) 412 optarg = NULL; 413 else { 414 struct in_addr in; 415 memmove(&in, hp->h_addr, sizeof(in)); 416 optarg = strdup(inet_ntoa(in)); 417 } 418 if (!auth_hostok(lc, full_hostname, optarg)) 419 refused("Permission denied", "HOST", 1); 420 } 421 422 if (!auth_ttyok(lc, tty)) 423 refused("Permission denied", "TTY", 1); 424 425 if (!auth_timeok(lc, time(NULL))) 426 refused("Logins not available right now", "TIME", 1); 427 } 428 shell=login_getcapstr(lc, "shell", pwd->pw_shell, pwd->pw_shell); 429 if (*pwd->pw_shell == '\0') 430 pwd->pw_shell = _PATH_BSHELL; 431 if (*shell == '\0') /* Not overridden */ 432 shell = pwd->pw_shell; 433 if ((shell = strdup(shell)) == NULL) { 434 syslog(LOG_NOTICE, "memory allocation error"); 435 sleepexit(1); 436 } 437 438 #ifdef LOGIN_ACCESS 439 if (login_access(pwd->pw_name, hostname ? full_hostname : tty) == 0) 440 refused("Permission denied", "ACCESS", 1); 441 #endif /* LOGIN_ACCESS */ 442 443 /* Nothing else left to fail -- really log in. */ 444 memset((void *)&utmp, 0, sizeof(utmp)); 445 (void)time(&utmp.ut_time); 446 (void)strncpy(utmp.ut_name, username, sizeof(utmp.ut_name)); 447 if (hostname) 448 (void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host)); 449 (void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line)); 450 login(&utmp); 451 452 dolastlog(quietlog); 453 454 /* 455 * Set device protections, depending on what terminal the 456 * user is logged in. This feature is used on Suns to give 457 * console users better privacy. 458 */ 459 login_fbtab(tty, pwd->pw_uid, pwd->pw_gid); 460 461 (void)chown(ttyn, pwd->pw_uid, 462 (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid); 463 464 /* 465 * Preserve TERM if it happens to be already set. 466 */ 467 if ((term = getenv("TERM")) != NULL) 468 term = strdup(term); 469 470 /* 471 * Exclude cons/vt/ptys only, assume dialup otherwise 472 * TODO: Make dialup tty determination a library call 473 * for consistency (finger etc.) 474 */ 475 if (hostname==NULL && isdialuptty(tty)) 476 syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name); 477 478 #ifdef LOGALL 479 /* 480 * Syslog each successful login, so we don't have to watch hundreds 481 * of wtmp or lastlogin files. 482 */ 483 if (hostname) 484 syslog(LOG_INFO, "login from %s on %s as %s", 485 full_hostname, tty, pwd->pw_name); 486 else 487 syslog(LOG_INFO, "login on %s as %s", 488 tty, pwd->pw_name); 489 #endif 490 491 /* 492 * If fflag is on, assume caller/authenticator has logged root login. 493 */ 494 if (rootlogin && fflag == 0) 495 { 496 if (hostname) 497 syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s", 498 username, tty, full_hostname); 499 else 500 syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s", 501 username, tty); 502 } 503 504 /* 505 * Destroy environment unless user has requested its preservation. 506 * We need to do this before setusercontext() because that may 507 * set or reset some environment variables. 508 */ 509 if (!pflag) 510 environ = envinit; 511 512 /* 513 * We don't need to be root anymore, so 514 * set the user and session context 515 */ 516 if (setlogin(username) != 0) { 517 syslog(LOG_ERR, "setlogin(%s): %m - exiting", username); 518 exit(1); 519 } 520 if (setusercontext(lc, pwd, pwd->pw_uid, 521 LOGIN_SETALL & ~LOGIN_SETLOGIN) != 0) { 522 syslog(LOG_ERR, "setusercontext() failed - exiting"); 523 exit(1); 524 } 525 526 (void)setenv("SHELL", pwd->pw_shell, 1); 527 (void)setenv("HOME", pwd->pw_dir, 1); 528 if (term != NULL && *term != '\0') 529 (void)setenv("TERM", term, 1); /* Preset overrides */ 530 else { 531 (void)setenv("TERM", stypeof(tty), 0); /* Fallback doesn't */ 532 } 533 (void)setenv("LOGNAME", username, 1); 534 (void)setenv("USER", username, 1); 535 (void)setenv("PATH", rootlogin ? _PATH_STDPATH : _PATH_DEFPATH, 0); 536 537 if (!quietlog) { 538 char *cw; 539 540 cw = login_getcapstr(lc, "copyright", NULL, NULL); 541 if (cw != NULL && access(cw, F_OK) == 0) 542 motd(cw); 543 else 544 (void)printf("%s\n\t%s %s\n", 545 "Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994", 546 "The Regents of the University of California. ", 547 "All rights reserved."); 548 549 (void)printf("\n"); 550 551 cw = login_getcapstr(lc, "welcome", NULL, NULL); 552 if (cw == NULL || access(cw, F_OK) != 0) 553 cw = _PATH_MOTDFILE; 554 motd(cw); 555 556 cw = getenv("MAIL"); /* $MAIL may have been set by class */ 557 if (cw != NULL) { 558 strncpy(tbuf, cw, sizeof(tbuf)); 559 tbuf[sizeof(tbuf)-1] = '\0'; 560 } else 561 snprintf(tbuf, sizeof(tbuf), "%s/%s", 562 _PATH_MAILDIR, pwd->pw_name); 563 if (stat(tbuf, &st) == 0 && st.st_size != 0) 564 (void)printf("You have %smail.\n", 565 (st.st_mtime > st.st_atime) ? "new " : ""); 566 } 567 568 login_close(lc); 569 570 (void)signal(SIGALRM, SIG_DFL); 571 (void)signal(SIGQUIT, SIG_DFL); 572 (void)signal(SIGINT, SIG_DFL); 573 (void)signal(SIGTSTP, SIG_IGN); 574 575 if (changepass) { 576 if (system(_PATH_CHPASS) != 0) 577 sleepexit(1); 578 } 579 580 /* 581 * Login shells have a leading '-' in front of argv[0] 582 */ 583 tbuf[0] = '-'; 584 (void)strcpy(tbuf + 1, (p = strrchr(pwd->pw_shell, '/')) ? p + 1 : pwd->pw_shell); 585 586 execlp(shell, tbuf, 0); 587 err(1, "%s", shell); 588 } 589 590 static int 591 auth_traditional() 592 { 593 int rval; 594 char *p; 595 char *ep; 596 char *salt; 597 598 rval = 1; 599 salt = pwd != NULL ? pwd->pw_passwd : "xx"; 600 601 p = getpass("Password:"); 602 ep = crypt(p, salt); 603 604 if (pwd) { 605 if (!p[0] && pwd->pw_passwd[0]) 606 ep = ":"; 607 if (strcmp(ep, pwd->pw_passwd) == 0) 608 rval = 0; 609 } 610 611 /* clear entered password */ 612 memset(p, 0, strlen(p)); 613 return rval; 614 } 615 616 /* 617 * Attempt to authenticate the user using PAM. Returns 0 if the user is 618 * authenticated, or 1 if not authenticated. If some sort of PAM system 619 * error occurs (e.g., the "/etc/pam.conf" file is missing) then this 620 * function returns -1. This can be used as an indication that we should 621 * fall back to a different authentication mechanism. 622 */ 623 static int 624 auth_pam() 625 { 626 pam_handle_t *pamh = NULL; 627 const char *tmpl_user; 628 const void *item; 629 int rval; 630 int e; 631 static struct pam_conv conv = { misc_conv, NULL }; 632 633 if ((e = pam_start("login", username, &conv, &pamh)) != PAM_SUCCESS) { 634 syslog(LOG_ERR, "pam_start: %s", pam_strerror(pamh, e)); 635 return -1; 636 } 637 if ((e = pam_set_item(pamh, PAM_TTY, tty)) != PAM_SUCCESS) { 638 syslog(LOG_ERR, "pam_set_item(PAM_TTY): %s", 639 pam_strerror(pamh, e)); 640 return -1; 641 } 642 if (hostname != NULL && 643 (e = pam_set_item(pamh, PAM_RHOST, full_hostname)) != PAM_SUCCESS) { 644 syslog(LOG_ERR, "pam_set_item(PAM_RHOST): %s", 645 pam_strerror(pamh, e)); 646 return -1; 647 } 648 e = pam_authenticate(pamh, 0); 649 switch (e) { 650 651 case PAM_SUCCESS: 652 /* 653 * With PAM we support the concept of a "template" 654 * user. The user enters a login name which is 655 * authenticated by PAM, usually via a remote service 656 * such as RADIUS or TACACS+. If authentication 657 * succeeds, a different but related "template" name 658 * is used for setting the credentials, shell, and 659 * home directory. The name the user enters need only 660 * exist on the remote authentication server, but the 661 * template name must be present in the local password 662 * database. 663 * 664 * This is supported by two various mechanisms in the 665 * individual modules. However, from the application's 666 * point of view, the template user is always passed 667 * back as a changed value of the PAM_USER item. 668 */ 669 if ((e = pam_get_item(pamh, PAM_USER, &item)) == 670 PAM_SUCCESS) { 671 tmpl_user = (const char *) item; 672 if (strcmp(username, tmpl_user) != 0) 673 pwd = getpwnam(tmpl_user); 674 } else 675 syslog(LOG_ERR, "Couldn't get PAM_USER: %s", 676 pam_strerror(pamh, e)); 677 rval = 0; 678 break; 679 680 case PAM_AUTH_ERR: 681 case PAM_USER_UNKNOWN: 682 case PAM_MAXTRIES: 683 rval = 1; 684 break; 685 686 default: 687 syslog(LOG_ERR, "auth_pam: %s", pam_strerror(pamh, e)); 688 rval = -1; 689 break; 690 } 691 if ((e = pam_end(pamh, e)) != PAM_SUCCESS) { 692 syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e)); 693 rval = -1; 694 } 695 return rval; 696 } 697 698 static void 699 usage() 700 { 701 (void)fprintf(stderr, "usage: login [-fp] [-h hostname] [username]\n"); 702 exit(1); 703 } 704 705 /* 706 * Allow for authentication style and/or kerberos instance 707 * */ 708 709 #define NBUFSIZ UT_NAMESIZE + 64 710 711 void 712 getloginname() 713 { 714 int ch; 715 char *p; 716 static char nbuf[NBUFSIZ]; 717 718 for (;;) { 719 (void)printf("login: "); 720 for (p = nbuf; (ch = getchar()) != '\n'; ) { 721 if (ch == EOF) { 722 badlogin(username); 723 exit(0); 724 } 725 if (p < nbuf + (NBUFSIZ - 1)) 726 *p++ = ch; 727 } 728 if (p > nbuf) 729 if (nbuf[0] == '-') 730 (void)fprintf(stderr, 731 "login names may not start with '-'.\n"); 732 else { 733 *p = '\0'; 734 username = nbuf; 735 break; 736 } 737 } 738 } 739 740 int 741 rootterm(ttyn) 742 char *ttyn; 743 { 744 struct ttyent *t; 745 746 return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE); 747 } 748 749 volatile int motdinterrupt; 750 751 /* ARGSUSED */ 752 void 753 sigint(signo) 754 int signo; 755 { 756 motdinterrupt = 1; 757 } 758 759 void 760 motd(motdfile) 761 char *motdfile; 762 { 763 int fd, nchars; 764 sig_t oldint; 765 char tbuf[256]; 766 767 if ((fd = open(motdfile, O_RDONLY, 0)) < 0) 768 return; 769 motdinterrupt = 0; 770 oldint = signal(SIGINT, sigint); 771 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0 && !motdinterrupt) 772 (void)write(fileno(stdout), tbuf, nchars); 773 (void)signal(SIGINT, oldint); 774 (void)close(fd); 775 } 776 777 /* ARGSUSED */ 778 void 779 timedout(signo) 780 int signo; 781 { 782 longjmp(timeout_buf, signo); 783 } 784 785 786 void 787 dolastlog(quiet) 788 int quiet; 789 { 790 struct lastlog ll; 791 int fd; 792 793 if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) { 794 (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); 795 if (!quiet) { 796 if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) && 797 ll.ll_time != 0) { 798 (void)printf("Last login: %.*s ", 799 24-5, (char *)ctime(&ll.ll_time)); 800 if (*ll.ll_host != '\0') 801 (void)printf("from %.*s\n", 802 (int)sizeof(ll.ll_host), 803 ll.ll_host); 804 else 805 (void)printf("on %.*s\n", 806 (int)sizeof(ll.ll_line), 807 ll.ll_line); 808 } 809 (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); 810 } 811 memset((void *)&ll, 0, sizeof(ll)); 812 (void)time(&ll.ll_time); 813 (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); 814 if (hostname) 815 (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host)); 816 (void)write(fd, (char *)&ll, sizeof(ll)); 817 (void)close(fd); 818 } 819 } 820 821 void 822 badlogin(name) 823 char *name; 824 { 825 826 if (failures == 0) 827 return; 828 if (hostname) { 829 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s", 830 failures, failures > 1 ? "S" : "", full_hostname); 831 syslog(LOG_AUTHPRIV|LOG_NOTICE, 832 "%d LOGIN FAILURE%s FROM %s, %s", 833 failures, failures > 1 ? "S" : "", full_hostname, name); 834 } else { 835 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s", 836 failures, failures > 1 ? "S" : "", tty); 837 syslog(LOG_AUTHPRIV|LOG_NOTICE, 838 "%d LOGIN FAILURE%s ON %s, %s", 839 failures, failures > 1 ? "S" : "", tty, name); 840 } 841 failures = 0; 842 } 843 844 #undef UNKNOWN 845 #define UNKNOWN "su" 846 847 char * 848 stypeof(ttyid) 849 char *ttyid; 850 { 851 852 struct ttyent *t; 853 854 return (ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN); 855 } 856 857 void 858 refused(msg, rtype, lout) 859 char *msg; 860 char *rtype; 861 int lout; 862 { 863 864 if (msg != NULL) 865 printf("%s.\n", msg); 866 if (hostname) 867 syslog(LOG_NOTICE, "LOGIN %s REFUSED (%s) FROM %s ON TTY %s", 868 pwd->pw_name, rtype, full_hostname, tty); 869 else 870 syslog(LOG_NOTICE, "LOGIN %s REFUSED (%s) ON TTY %s", 871 pwd->pw_name, rtype, tty); 872 if (lout) 873 sleepexit(1); 874 } 875 876 void 877 sleepexit(eval) 878 int eval; 879 { 880 881 (void)sleep(5); 882 exit(eval); 883 } 884