login.c revision 72445
1/* 2 * Copyright (c) 1997 - 2001 Kungliga Tekniska H�gskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * 3. Neither the name of the Institute 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 INSTITUTE 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 INSTITUTE 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#include "login_locl.h" 35#ifdef HAVE_CAPABILITY_H 36#include <capability.h> 37#endif 38#ifdef HAVE_SYS_CAPABILITY_H 39#include <sys/capability.h> 40#endif 41 42RCSID("$Id: login.c,v 1.46 2001/01/29 02:18:03 assar Exp $"); 43 44static int login_timeout = 60; 45 46static int 47start_login_process(void) 48{ 49 char *prog, *argv0; 50 prog = login_conf_get_string("login_program"); 51 if(prog == NULL) 52 return 0; 53 argv0 = strrchr(prog, '/'); 54 55 if(argv0) 56 argv0++; 57 else 58 argv0 = prog; 59 60 return simple_execle(prog, argv0, NULL, env); 61} 62 63static int 64start_logout_process(void) 65{ 66 char *prog, *argv0; 67 pid_t pid; 68 69 prog = login_conf_get_string("logout_program"); 70 if(prog == NULL) 71 return 0; 72 argv0 = strrchr(prog, '/'); 73 74 if(argv0) 75 argv0++; 76 else 77 argv0 = prog; 78 79 pid = fork(); 80 if(pid == 0) { 81 /* avoid getting signals sent to the shell */ 82 setpgid(0, getpid()); 83 return 0; 84 } 85 if(pid == -1) 86 err(1, "fork"); 87 /* wait for the real login process to exit */ 88#ifdef HAVE_SETPROCTITLE 89 setproctitle("waitpid %d", pid); 90#endif 91 while(1) { 92 int status; 93 int ret; 94 ret = waitpid(pid, &status, 0); 95 if(ret > 0) { 96 if(WIFEXITED(status) || WIFSIGNALED(status)) { 97 execle(prog, argv0, NULL, env); 98 err(1, "exec %s", prog); 99 } 100 } else if(ret < 0) 101 err(1, "waitpid"); 102 } 103} 104 105static void 106exec_shell(const char *shell, int fallback) 107{ 108 char *sh; 109 const char *p; 110 111 extend_env(NULL); 112 if(start_login_process() < 0) 113 warn("login process"); 114 start_logout_process(); 115 116 p = strrchr(shell, '/'); 117 if(p) 118 p++; 119 else 120 p = shell; 121 asprintf(&sh, "-%s", p); 122 execle(shell, sh, NULL, env); 123 if(fallback){ 124 warnx("Can't exec %s, trying %s", 125 shell, _PATH_BSHELL); 126 execle(_PATH_BSHELL, "-sh", NULL, env); 127 err(1, "%s", _PATH_BSHELL); 128 } 129 err(1, "%s", shell); 130} 131 132static enum { NONE = 0, AUTH_KRB4 = 1, AUTH_KRB5 = 2, AUTH_OTP = 3 } auth; 133 134#ifdef OTP 135static OtpContext otp_ctx; 136 137static int 138otp_verify(struct passwd *pwd, const char *password) 139{ 140 return (otp_verify_user (&otp_ctx, password)); 141} 142#endif /* OTP */ 143 144 145#ifdef KRB5 146static krb5_context context; 147static krb5_ccache id, id2; 148 149static int 150krb5_verify(struct passwd *pwd, const char *password) 151{ 152 krb5_error_code ret; 153 krb5_principal princ; 154 155 ret = krb5_parse_name(context, pwd->pw_name, &princ); 156 if(ret) 157 return 1; 158 ret = krb5_cc_gen_new(context, &krb5_mcc_ops, &id); 159 if(ret) { 160 krb5_free_principal(context, princ); 161 return 1; 162 } 163 ret = krb5_verify_user_lrealm(context, 164 princ, 165 id, 166 password, 167 1, 168 NULL); 169 krb5_free_principal(context, princ); 170 return ret; 171} 172 173#ifdef KRB4 174static krb5_error_code 175krb5_to4 (krb5_ccache id) 176{ 177 if (krb5_config_get_bool(context, NULL, 178 "libdefaults", 179 "krb4_get_tickets", 180 NULL)) { 181 CREDENTIALS c; 182 krb5_creds mcred, cred; 183 char krb4tkfile[MAXPATHLEN]; 184 krb5_error_code ret; 185 krb5_principal princ; 186 187 ret = krb5_cc_get_principal (context, id, &princ); 188 if (ret) 189 return ret; 190 191 ret = krb5_make_principal(context, &mcred.server, 192 princ->realm, 193 "krbtgt", 194 princ->realm, 195 NULL); 196 krb5_free_principal (context, princ); 197 if (ret) 198 return ret; 199 200 ret = krb5_cc_retrieve_cred(context, id, 0, &mcred, &cred); 201 if(ret == 0) { 202 ret = krb524_convert_creds_kdc(context, id, &cred, &c); 203 if(ret == 0) { 204 snprintf(krb4tkfile,sizeof(krb4tkfile),"%s%d",TKT_ROOT, 205 getuid()); 206 krb_set_tkt_string(krb4tkfile); 207 tf_setup(&c, c.pname, c.pinst); 208 } 209 memset(&c, 0, sizeof(c)); 210 krb5_free_creds_contents(context, &cred); 211 } 212 krb5_free_principal(context, mcred.server); 213 } 214 return 0; 215} 216#endif /* KRB4 */ 217 218static int 219krb5_start_session (const struct passwd *pwd) 220{ 221 krb5_error_code ret; 222 char residual[64]; 223 224 /* copy credentials to file cache */ 225 snprintf(residual, sizeof(residual), "FILE:/tmp/krb5cc_%u", 226 (unsigned)pwd->pw_uid); 227 krb5_cc_resolve(context, residual, &id2); 228 ret = krb5_cc_copy_cache(context, id, id2); 229 if (ret == 0) 230 add_env("KRB5CCNAME", residual); 231 else { 232 krb5_cc_destroy (context, id2); 233 return ret; 234 } 235#ifdef KRB4 236 krb5_to4 (id2); 237#endif 238 krb5_cc_close(context, id2); 239 krb5_cc_destroy(context, id); 240 return 0; 241} 242 243static void 244krb5_finish (void) 245{ 246 krb5_free_context(context); 247} 248 249#ifdef KRB4 250 251static int pag_set = 0; 252 253static void 254krb5_get_afs_tokens (const struct passwd *pwd) 255{ 256 char cell[64]; 257 char *pw_dir; 258 krb5_error_code ret; 259 260 if (!k_hasafs ()) 261 return; 262 263 ret = krb5_cc_default(context, &id2); 264 265 if (ret == 0) { 266 pw_dir = pwd->pw_dir; 267 268 if (!pag_set) { 269 k_setpag(); 270 pag_set = 1; 271 } 272 273 if(k_afs_cell_of_file(pw_dir, cell, sizeof(cell)) == 0) 274 krb5_afslog_uid_home (context, id2, 275 cell, NULL, pwd->pw_uid, pwd->pw_dir); 276 krb5_afslog_uid_home (context, id2, NULL, NULL, 277 pwd->pw_uid, pwd->pw_dir); 278 krb5_cc_close (context, id2); 279 } 280} 281 282#endif /* KRB4 */ 283 284#endif /* KRB5 */ 285 286#ifdef KRB4 287 288static int 289krb4_verify(struct passwd *pwd, const char *password) 290{ 291 char lrealm[REALM_SZ]; 292 int ret; 293 char ticket_file[MaxPathLen]; 294 295 ret = krb_get_lrealm (lrealm, 1); 296 if (ret) 297 return 1; 298 299 snprintf (ticket_file, sizeof(ticket_file), 300 "%s%u_%u", 301 TKT_ROOT, (unsigned)pwd->pw_uid, (unsigned)getpid()); 302 303 krb_set_tkt_string (ticket_file); 304 305 ret = krb_verify_user (pwd->pw_name, "", lrealm, (char *)password, 306 KRB_VERIFY_SECURE_FAIL, NULL); 307 if (ret) 308 return 1; 309 310 if (chown (ticket_file, pwd->pw_uid, pwd->pw_gid) < 0) { 311 dest_tkt(); 312 return 1; 313 } 314 315 add_env ("KRBTKFILE", ticket_file); 316 return 0; 317} 318 319static void 320krb4_get_afs_tokens (const struct passwd *pwd) 321{ 322 char cell[64]; 323 char *pw_dir; 324 325 if (!k_hasafs ()) 326 return; 327 328 pw_dir = pwd->pw_dir; 329 330 if (!pag_set) { 331 k_setpag(); 332 pag_set = 1; 333 } 334 335 if(k_afs_cell_of_file(pw_dir, cell, sizeof(cell)) == 0) 336 krb_afslog_uid_home (cell, NULL, pwd->pw_uid, pwd->pw_dir); 337 338 krb_afslog_uid_home (NULL, NULL, pwd->pw_uid, pwd->pw_dir); 339} 340 341#endif /* KRB4 */ 342 343static int f_flag; 344static int p_flag; 345#if 0 346static int r_flag; 347#endif 348static int version_flag; 349static int help_flag; 350static char *remote_host; 351static char *auth_level = NULL; 352 353struct getargs args[] = { 354 { NULL, 'a', arg_string, &auth_level, "authentication mode" }, 355#if 0 356 { NULL, 'd' }, 357#endif 358 { NULL, 'f', arg_flag, &f_flag, "pre-authenticated" }, 359 { NULL, 'h', arg_string, &remote_host, "remote host", "hostname" }, 360 { NULL, 'p', arg_flag, &p_flag, "don't purge environment" }, 361#if 0 362 { NULL, 'r', arg_flag, &r_flag, "rlogin protocol" }, 363#endif 364 { "version", 0, arg_flag, &version_flag }, 365 { "help", 0, arg_flag,&help_flag, } 366}; 367 368int nargs = sizeof(args) / sizeof(args[0]); 369 370static void 371update_utmp(const char *username, const char *hostname, 372 char *tty, char *ttyn) 373{ 374 /* 375 * Update the utmp files, both BSD and SYSV style. 376 */ 377 if (utmpx_login(tty, username, hostname) != 0 && !f_flag) { 378 printf("No utmpx entry. You must exec \"login\" from the " 379 "lowest level shell.\n"); 380 exit(1); 381 } 382 utmp_login(ttyn, username, hostname); 383} 384 385static void 386checknologin(void) 387{ 388 FILE *f; 389 char buf[1024]; 390 391 f = fopen(_PATH_NOLOGIN, "r"); 392 if(f == NULL) 393 return; 394 while(fgets(buf, sizeof(buf), f)) 395 fputs(buf, stdout); 396 fclose(f); 397 exit(0); 398} 399 400/* 401 * Actually log in the user. `pwd' contains all the relevant 402 * information about the user. `ttyn' is the complete name of the tty 403 * and `tty' the short name. 404 */ 405 406static void 407do_login(const struct passwd *pwd, char *tty, char *ttyn) 408{ 409#ifdef HAVE_GETSPNAM 410 struct spwd *sp; 411#endif 412 int rootlogin = (pwd->pw_uid == 0); 413 gid_t tty_gid; 414 struct group *gr; 415 const char *home_dir; 416 417 if(!rootlogin) 418 checknologin(); 419 420#ifdef HAVE_GETSPNAM 421 sp = getspnam(pwd->pw_name); 422#endif 423 424 update_utmp(pwd->pw_name, remote_host ? remote_host : "", 425 tty, ttyn); 426 427 gr = getgrnam ("tty"); 428 if (gr != NULL) 429 tty_gid = gr->gr_gid; 430 else 431 tty_gid = pwd->pw_gid; 432 433 if (chown (ttyn, pwd->pw_uid, tty_gid) < 0) { 434 warn("chown %s", ttyn); 435 if (rootlogin == 0) 436 exit (1); 437 } 438 439 if (chmod (ttyn, S_IRUSR | S_IWUSR | S_IWGRP) < 0) { 440 warn("chmod %s", ttyn); 441 if (rootlogin == 0) 442 exit (1); 443 } 444 445#ifdef HAVE_SETLOGIN 446 if(setlogin(pwd->pw_name)){ 447 warn("setlogin(%s)", pwd->pw_name); 448 if(rootlogin == 0) 449 exit(1); 450 } 451#endif 452#ifdef HAVE_INITGROUPS 453 if(initgroups(pwd->pw_name, pwd->pw_gid)){ 454 warn("initgroups(%s, %u)", pwd->pw_name, (unsigned)pwd->pw_gid); 455 if(rootlogin == 0) 456 exit(1); 457 } 458#endif 459 if(setgid(pwd->pw_gid)){ 460 warn("setgid(%u)", (unsigned)pwd->pw_gid); 461 if(rootlogin == 0) 462 exit(1); 463 } 464 if(setuid(pwd->pw_uid) || (pwd->pw_uid != 0 && setuid(0) == 0)) { 465 warn("setuid(%u)", (unsigned)pwd->pw_uid); 466 if(rootlogin == 0) 467 exit(1); 468 } 469 /* all kinds of different magic */ 470 471#ifdef HAVE_GETSPNAM 472 check_shadow(pwd, sp); 473#endif 474 475 if(do_osfc2_magic(pwd->pw_uid)) 476 exit(1); 477#if defined(HAVE_GETUDBNAM) && defined(HAVE_SETLIM) 478 { 479 struct udb *udb; 480 long t; 481 const long maxcpu = 46116860184; /* some random constant */ 482 udb = getudbnam(pwd->pw_name); 483 if(udb == UDB_NULL) 484 errx(1, "Failed to get UDB entry."); 485 t = udb->ue_pcpulim[UDBRC_INTER]; 486 if(t == 0 || t > maxcpu) 487 t = CPUUNLIM; 488 else 489 t *= 100 * CLOCKS_PER_SEC; 490 491 if(limit(C_PROC, 0, L_CPU, t) < 0) 492 warn("limit C_PROC"); 493 494 t = udb->ue_jcpulim[UDBRC_INTER]; 495 if(t == 0 || t > maxcpu) 496 t = CPUUNLIM; 497 else 498 t *= 100 * CLOCKS_PER_SEC; 499 500 if(limit(C_JOBPROCS, 0, L_CPU, t) < 0) 501 warn("limit C_JOBPROCS"); 502 503 nice(udb->ue_nice[UDBRC_INTER]); 504 } 505#endif 506#if defined(HAVE_SGI_GETCAPABILITYBYNAME) && defined(HAVE_CAP_SET_PROC) 507 /* XXX SGI capability hack IRIX 6.x (x >= 0?) has something 508 called capabilities, that allow you to give away 509 permissions (such as chown) to specific processes. From 6.5 510 this is default on, and the default capability set seems to 511 not always be the empty set. The problem is that the 512 runtime linker refuses to do just about anything if the 513 process has *any* capabilities set, so we have to remove 514 them here (unless otherwise instructed by /etc/capability). 515 In IRIX < 6.5, these functions was called sgi_cap_setproc, 516 etc, but we ignore this fact (it works anyway). */ 517 { 518 struct user_cap *ucap = sgi_getcapabilitybyname(pwd->pw_name); 519 cap_t cap; 520 if(ucap == NULL) 521 cap = cap_from_text("all="); 522 else 523 cap = cap_from_text(ucap->ca_default); 524 if(cap == NULL) 525 err(1, "cap_from_text"); 526 if(cap_set_proc(cap) < 0) 527 err(1, "cap_set_proc"); 528 cap_free(cap); 529 free(ucap); 530 } 531#endif 532 home_dir = pwd->pw_dir; 533 if (chdir(home_dir) < 0) { 534 fprintf(stderr, "No home directory \"%s\"!\n", pwd->pw_dir); 535 if (chdir("/")) 536 exit(0); 537 home_dir = "/"; 538 fprintf(stderr, "Logging in with home = \"/\".\n"); 539 } 540#ifdef KRB5 541 if (auth == AUTH_KRB5) { 542 krb5_start_session (pwd); 543 } 544#ifdef KRB4 545 else if (auth == 0) { 546 krb5_error_code ret; 547 krb5_ccache id; 548 549 ret = krb5_cc_default (context, &id); 550 if (ret == 0) { 551 krb5_to4 (id); 552 krb5_cc_close (context, id); 553 } 554 } 555 556 krb5_get_afs_tokens (pwd); 557#endif /* KRB4 */ 558 krb5_finish (); 559#endif /* KRB5 */ 560 561#ifdef KRB4 562 krb4_get_afs_tokens (pwd); 563#endif /* KRB4 */ 564 565 add_env("PATH", _PATH_DEFPATH); 566 567 { 568 const char *str = login_conf_get_string("environment"); 569 char buf[MAXPATHLEN]; 570 571 if(str == NULL) { 572 login_read_env(_PATH_ETC_ENVIRONMENT); 573 } else { 574 while(strsep_copy(&str, ",", buf, sizeof(buf)) != -1) { 575 if(buf[0] == '\0') 576 continue; 577 login_read_env(buf); 578 } 579 } 580 } 581 add_env("HOME", home_dir); 582 add_env("USER", pwd->pw_name); 583 add_env("LOGNAME", pwd->pw_name); 584 add_env("SHELL", pwd->pw_shell); 585 exec_shell(pwd->pw_shell, rootlogin); 586} 587 588static int 589check_password(struct passwd *pwd, const char *password) 590{ 591 if(pwd->pw_passwd == NULL) 592 return 1; 593 if(pwd->pw_passwd[0] == '\0'){ 594#ifdef ALLOW_NULL_PASSWORD 595 return password[0] != '\0'; 596#else 597 return 1; 598#endif 599 } 600 if(strcmp(pwd->pw_passwd, crypt(password, pwd->pw_passwd)) == 0) 601 return 0; 602#ifdef KRB5 603 if(krb5_verify(pwd, password) == 0) { 604 auth = AUTH_KRB5; 605 return 0; 606 } 607#endif 608#ifdef KRB4 609 if (krb4_verify (pwd, password) == 0) { 610 auth = AUTH_KRB4; 611 return 0; 612 } 613#endif 614#ifdef OTP 615 if (otp_verify (pwd, password) == 0) { 616 auth = AUTH_OTP; 617 return 0; 618 } 619#endif 620 return 1; 621} 622 623static void 624usage(int status) 625{ 626 arg_printusage(args, nargs, NULL, "[username]"); 627 exit(status); 628} 629 630static RETSIGTYPE 631sig_handler(int sig) 632{ 633 if (sig == SIGALRM) 634 fprintf(stderr, "Login timed out after %d seconds\n", 635 login_timeout); 636 else 637 fprintf(stderr, "Login received signal, exiting\n"); 638 exit(0); 639} 640 641int 642main(int argc, char **argv) 643{ 644 int max_tries = 5; 645 int try; 646 647 char username[32]; 648 int optind = 0; 649 650 int ask = 1; 651 struct sigaction sa; 652 653 set_progname(argv[0]); 654 655#ifdef KRB5 656 { 657 krb5_error_code ret; 658 659 ret = krb5_init_context(&context); 660 if (ret) 661 errx (1, "krb5_init_context failed: %d", ret); 662 } 663#endif 664 665 openlog("login", LOG_ODELAY, LOG_AUTH); 666 667 if (getarg (args, sizeof(args) / sizeof(args[0]), argc, argv, 668 &optind)) 669 usage (1); 670 argc -= optind; 671 argv += optind; 672 673 if(help_flag) 674 usage(0); 675 if (version_flag) { 676 print_version (NULL); 677 return 0; 678 } 679 680 if (geteuid() != 0) 681 errx(1, "only root may use login, use su"); 682 683 /* Default tty settings. */ 684 stty_default(); 685 686 if(p_flag) 687 copy_env(); 688 else { 689 /* this set of variables is always preserved by BSD login */ 690 if(getenv("TERM")) 691 add_env("TERM", getenv("TERM")); 692 if(getenv("TZ")) 693 add_env("TZ", getenv("TZ")); 694 } 695 696 if(*argv){ 697 if(strchr(*argv, '=') == NULL && strcmp(*argv, "-") != 0){ 698 strlcpy (username, *argv, sizeof(username)); 699 ask = 0; 700 } 701 } 702 703#if defined(DCE) && defined(AIX) 704 esetenv("AUTHSTATE", "DCE", 1); 705#endif 706 707 /* XXX should we care about environment on the command line? */ 708 709 memset(&sa, 0, sizeof(sa)); 710 sa.sa_handler = sig_handler; 711 sigemptyset(&sa.sa_mask); 712 sa.sa_flags = 0; 713 sigaction(SIGALRM, &sa, NULL); 714 alarm(login_timeout); 715 716 for(try = 0; try < max_tries; try++){ 717 struct passwd *pwd; 718 char password[128]; 719 int ret; 720 char ttname[32]; 721 char *tty, *ttyn; 722 char prompt[128]; 723#ifdef OTP 724 char otp_str[256]; 725#endif 726 727 if(ask){ 728 f_flag = 0; 729#if 0 730 r_flag = 0; 731#endif 732 ret = read_string("login: ", username, sizeof(username), 1); 733 if(ret == -3) 734 exit(0); 735 if(ret == -2) 736 sig_handler(0); /* exit */ 737 } 738 pwd = k_getpwnam(username); 739#ifdef ALLOW_NULL_PASSWORD 740 if (pwd != NULL && (pwd->pw_passwd[0] == '\0')) { 741 strcpy(password,""); 742 } 743 else 744#endif 745 746 { 747#ifdef OTP 748 if(auth_level && strcmp(auth_level, "otp") == 0 && 749 otp_challenge(&otp_ctx, username, 750 otp_str, sizeof(otp_str)) == 0) 751 snprintf (prompt, sizeof(prompt), "%s's %s Password: ", 752 username, otp_str); 753 else 754#endif 755 strncpy(prompt, "Password: ", sizeof(prompt)); 756 757 if (f_flag == 0) { 758 ret = read_string(prompt, password, sizeof(password), 0); 759 if (ret == -3) { 760 ask = 1; 761 continue; 762 } 763 if (ret == -2) 764 sig_handler(0); 765 } 766 } 767 768 if(pwd == NULL){ 769 fprintf(stderr, "Login incorrect.\n"); 770 ask = 1; 771 continue; 772 } 773 774 if(f_flag == 0 && check_password(pwd, password)){ 775 fprintf(stderr, "Login incorrect.\n"); 776 ask = 1; 777 continue; 778 } 779 ttyn = ttyname(STDIN_FILENO); 780 if(ttyn == NULL){ 781 snprintf(ttname, sizeof(ttname), "%s??", _PATH_TTY); 782 ttyn = ttname; 783 } 784 if (strncmp (ttyn, _PATH_DEV, strlen(_PATH_DEV)) == 0) 785 tty = ttyn + strlen(_PATH_DEV); 786 else 787 tty = ttyn; 788 789 if (login_access (pwd, remote_host ? remote_host : tty) == 0) { 790 fprintf(stderr, "Permission denied\n"); 791 if (remote_host) 792 syslog(LOG_NOTICE, "%s LOGIN REFUSED FROM %s", 793 pwd->pw_name, remote_host); 794 else 795 syslog(LOG_NOTICE, "%s LOGIN REFUSED ON %s", 796 pwd->pw_name, tty); 797 exit (1); 798 } 799 alarm(0); 800 do_login(pwd, tty, ttyn); 801 } 802 exit(1); 803} 804