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