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