x
[heimdal.git] / appl / login / login.c
blobf7c1b9a09bc5436ca072ad73c656bc01035b5c22
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("$Id$");
47 static int login_timeout = 60;
49 static int
50 start_login_process(void)
52 char *prog, *argv0;
53 prog = login_conf_get_string("login_program");
54 if(prog == NULL)
55 return 0;
56 argv0 = strrchr(prog, '/');
58 if(argv0)
59 argv0++;
60 else
61 argv0 = prog;
63 return simple_execle(prog, argv0, NULL, env);
66 static int
67 start_logout_process(void)
69 char *prog, *argv0;
70 pid_t pid;
72 prog = login_conf_get_string("logout_program");
73 if(prog == NULL)
74 return 0;
75 argv0 = strrchr(prog, '/');
77 if(argv0)
78 argv0++;
79 else
80 argv0 = prog;
82 pid = fork();
83 if(pid == 0) {
84 /* avoid getting signals sent to the shell */
85 setpgid(0, getpid());
86 return 0;
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);
103 } else if(ret < 0)
104 err(1, "waitpid");
108 static void
109 exec_shell(const char *shell, int fallback)
111 char *sh;
112 const char *p;
114 extend_env(NULL);
115 if(start_login_process() < 0)
116 warn("login process");
117 start_logout_process();
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);
133 err(1, "%s", shell);
136 static enum { NONE = 0, AUTH_KRB4 = 1, AUTH_KRB5 = 2, AUTH_OTP = 3 } auth;
138 #ifdef KRB4
139 static krb5_boolean get_v4_tgt = FALSE;
140 #endif
142 #ifdef OTP
143 static OtpContext otp_ctx;
145 static int
146 otp_verify(struct passwd *pwd, const char *password)
148 return (otp_verify_user (&otp_ctx, password));
150 #endif /* OTP */
153 static int pag_set = 0;
155 #ifdef KRB5
156 static krb5_context context;
157 static krb5_ccache id, id2;
159 static int
160 krb5_verify(struct passwd *pwd, const char *password)
162 krb5_error_code ret;
163 krb5_principal princ;
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;
173 ret = krb5_verify_user_lrealm(context,
174 princ,
176 password,
178 NULL);
179 krb5_free_principal(context, princ);
180 return ret;
183 #ifdef KRB4
184 static krb5_error_code
185 krb5_to4 (krb5_ccache id)
187 krb5_error_code ret;
188 krb5_principal princ;
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);
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;
212 krb5_cc_clear_mcred(&mcred);
214 ret = krb5_cc_get_principal (context, id, &princ);
215 if (ret)
216 return ret;
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;
227 mcred.client = princ;
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);
238 memset(&c, 0, sizeof(c));
239 krb5_free_cred_contents(context, &cred);
241 if (ret != 0)
242 get_v4_tgt = FALSE;
243 krb5_free_principal(context, mcred.server);
244 krb5_free_principal(context, mcred.client);
246 return 0;
248 #endif /* KRB4 */
250 static int
251 krb5_start_session (const struct passwd *pwd)
253 krb5_error_code ret;
254 char residual[64];
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;
267 #ifdef KRB4
268 krb5_to4 (id2);
269 #endif
270 krb5_cc_close(context, id2);
271 krb5_cc_destroy(context, id);
272 return 0;
275 static void
276 krb5_finish (void)
278 krb5_free_context(context);
281 static void
282 krb5_get_afs_tokens (const struct passwd *pwd)
284 char cell[64];
285 char *pw_dir;
286 krb5_error_code ret;
288 if (!k_hasafs ())
289 return;
291 ret = krb5_cc_default(context, &id2);
293 if (ret == 0) {
294 pw_dir = pwd->pw_dir;
296 if (!pag_set) {
297 k_setpag();
298 pag_set = 1;
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);
310 #endif /* KRB5 */
312 #ifdef KRB4
314 static int
315 krb4_verify(struct passwd *pwd, const char *password)
317 char lrealm[REALM_SZ];
318 int ret;
319 char ticket_file[MaxPathLen];
321 ret = krb_get_lrealm (lrealm, 1);
322 if (ret)
323 return 1;
325 snprintf (ticket_file, sizeof(ticket_file),
326 "%s%u_%u",
327 TKT_ROOT, (unsigned)pwd->pw_uid, (unsigned)getpid());
329 krb_set_tkt_string (ticket_file);
331 ret = krb_verify_user (pwd->pw_name, "", lrealm, (char *)password,
332 KRB_VERIFY_SECURE_FAIL, NULL);
333 if (ret)
334 return 1;
336 if (chown (ticket_file, pwd->pw_uid, pwd->pw_gid) < 0) {
337 dest_tkt();
338 return 1;
341 add_env ("KRBTKFILE", ticket_file);
342 return 0;
345 static void
346 krb4_get_afs_tokens (const struct passwd *pwd)
348 char cell[64];
349 char *pw_dir;
351 if (!k_hasafs ())
352 return;
354 pw_dir = pwd->pw_dir;
356 if (!pag_set) {
357 k_setpag();
358 pag_set = 1;
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);
364 krb_afslog_uid_home (NULL, NULL, pwd->pw_uid, pwd->pw_dir);
367 #endif /* KRB4 */
369 static int f_flag;
370 static int p_flag;
371 #if 0
372 static int r_flag;
373 #endif
374 static int version_flag;
375 static int help_flag;
376 static char *remote_host;
377 static char *auth_level = NULL;
379 struct 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, }
394 int nargs = sizeof(args) / sizeof(args[0]);
396 static void
397 update_utmp(const char *username, const char *hostname,
398 char *tty, char *ttyn)
401 * Update the utmp files, both BSD and SYSV style.
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);
408 utmp_login(ttyn, username, hostname);
411 static void
412 checknologin(void)
414 FILE *f;
415 char buf[1024];
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);
426 /* print contents of a file */
427 static void
428 show_file(const char *file)
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);
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.
445 static void
446 do_login(const struct passwd *pwd, char *tty, char *ttyn)
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;
457 if(!rootlogin)
458 checknologin();
460 #ifdef HAVE_GETSPNAM
461 sp = getspnam(pwd->pw_name);
462 #endif
464 update_utmp(pwd->pw_name, remote_host ? remote_host : "",
465 tty, ttyn);
467 gr = getgrnam ("tty");
468 if (gr != NULL)
469 tty_gid = gr->gr_gid;
470 else
471 tty_gid = pwd->pw_gid;
473 if (chown (ttyn, pwd->pw_uid, tty_gid) < 0) {
474 warn("chown %s", ttyn);
475 if (rootlogin == 0)
476 exit (1);
479 if (chmod (ttyn, S_IRUSR | S_IWUSR | S_IWGRP) < 0) {
480 warn("chmod %s", ttyn);
481 if (rootlogin == 0)
482 exit (1);
485 #ifdef HAVE_SETLOGIN
486 if(setlogin(pwd->pw_name)){
487 warn("setlogin(%s)", pwd->pw_name);
488 if(rootlogin == 0)
489 exit(1);
491 #endif
492 if(rootlogin == 0) {
493 const char *file = login_conf_get_string("limits");
494 if(file == NULL)
495 file = _PATH_LIMITS_CONF;
497 read_limits_conf(file, pwd);
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);
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);
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);
524 /* make sure signals are set to default actions, apparently some
525 OS:es like to ignore SIGINT, which is not very convenient */
527 for (i = 1; i < NSIG; ++i)
528 signal(i, SIG_DFL);
530 /* all kinds of different magic */
532 #ifdef HAVE_GETSPNAM
533 check_shadow(pwd, sp);
534 #endif
536 #if defined(HAVE_GETUDBNAM) && defined(HAVE_SETLIM)
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;
550 if(limit(C_PROC, 0, L_CPU, t) < 0)
551 warn("limit C_PROC");
553 t = udb->ue_jcpulim[UDBRC_INTER];
554 if(t == 0 || t > maxcpu)
555 t = CPUUNLIM;
556 else
557 t *= 100 * CLOCKS_PER_SEC;
559 if(limit(C_JOBPROCS, 0, L_CPU, t) < 0)
560 warn("limit C_JOBPROCS");
562 nice(udb->ue_nice[UDBRC_INTER]);
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). */
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);
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");
599 #ifdef KRB5
600 if (auth == AUTH_KRB5) {
601 krb5_start_session (pwd);
603 #ifdef KRB4
604 else if (auth == 0) {
605 krb5_error_code ret;
606 krb5_ccache id;
608 ret = krb5_cc_default (context, &id);
609 if (ret == 0) {
610 krb5_to4 (id);
611 krb5_cc_close (context, id);
614 #endif /* KRB4 */
616 krb5_get_afs_tokens (pwd);
618 krb5_finish ();
619 #endif /* KRB5 */
621 #ifdef KRB4
622 if (auth == AUTH_KRB4 || get_v4_tgt)
623 krb4_get_afs_tokens (pwd);
624 #endif /* KRB4 */
626 add_env("PATH", _PATH_DEFPATH);
629 const char *str = login_conf_get_string("environment");
630 char buf[MAXPATHLEN];
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);
643 const char *str = login_conf_get_string("motd");
644 char buf[MAXPATHLEN];
646 if(str != NULL) {
647 while(strsep_copy(&str, ",", buf, sizeof(buf)) != -1) {
648 if(buf[0] == '\0')
649 continue;
650 show_file(buf);
652 } else {
653 str = login_conf_get_string("welcome");
654 if(str != NULL)
655 show_file(str);
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);
665 static int
666 check_password(struct passwd *pwd, const char *password)
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
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;
684 #endif
685 #ifdef KRB4
686 if (krb4_verify (pwd, password) == 0) {
687 auth = AUTH_KRB4;
688 return 0;
690 #endif
691 #ifdef OTP
692 if (otp_verify (pwd, password) == 0) {
693 auth = AUTH_OTP;
694 return 0;
696 #endif
697 return 1;
700 static void
701 usage(int status)
703 arg_printusage(args, nargs, NULL, "[username]");
704 exit(status);
707 static RETSIGTYPE
708 sig_handler(int sig)
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);
719 main(int argc, char **argv)
721 int max_tries = 5;
722 int try;
724 char username[32];
725 int optidx = 0;
727 int ask = 1;
728 struct sigaction sa;
730 setprogname(argv[0]);
732 #ifdef KRB5
734 krb5_error_code ret;
736 ret = krb5_init_context(&context);
737 if (ret)
738 errx (1, "krb5_init_context failed: %d", ret);
740 #endif
742 openlog("login", LOG_ODELAY | LOG_PID, LOG_AUTH);
744 if (getarg (args, sizeof(args) / sizeof(args[0]), argc, argv,
745 &optidx))
746 usage (1);
747 argc -= optidx;
748 argv += optidx;
750 if(help_flag)
751 usage(0);
752 if (version_flag) {
753 print_version (NULL);
754 return 0;
757 if (geteuid() != 0)
758 errx(1, "only root may use login, use su");
760 /* Default tty settings. */
761 stty_default();
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"));
773 if(*argv){
774 if(strchr(*argv, '=') == NULL && strcmp(*argv, "-") != 0){
775 strlcpy (username, *argv, sizeof(username));
776 ask = 0;
780 #if defined(DCE) && defined(AIX)
781 esetenv("AUTHSTATE", "DCE", 1);
782 #endif
784 /* XXX should we care about environment on the command line? */
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);
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
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 */
815 pwd = k_getpwnam(username);
816 #ifdef ALLOW_NULL_PASSWORD
817 if (pwd != NULL && (pwd->pw_passwd[0] == '\0')) {
818 strcpy(password,"");
820 else
821 #endif
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));
834 if (f_flag == 0) {
835 ret = read_string(prompt, password, sizeof(password), 0);
836 if (ret == -3) {
837 ask = 1;
838 continue;
840 if (ret == -2)
841 sig_handler(0);
845 if(pwd == NULL){
846 fprintf(stderr, "Login incorrect.\n");
847 ask = 1;
848 continue;
851 if(f_flag == 0 && check_password(pwd, password)){
852 fprintf(stderr, "Login incorrect.\n");
853 ask = 1;
854 continue;
856 ttyn = ttyname(STDIN_FILENO);
857 if(ttyn == NULL){
858 snprintf(ttname, sizeof(ttname), "%s??", _PATH_TTY);
859 ttyn = ttname;
861 if (strncmp (ttyn, _PATH_DEV, strlen(_PATH_DEV)) == 0)
862 tty = ttyn + strlen(_PATH_DEV);
863 else
864 tty = ttyn;
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());
883 alarm(0);
884 do_login(pwd, tty, ttyn);
886 exit(1);