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