]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - crypto/heimdal/appl/login/login.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / crypto / heimdal / appl / login / login.c
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
45 RCSID("$Id: login.c 16498 2006-01-09 16:26:25Z joda $");
46
47 static int login_timeout = 60;
48
49 static int
50 start_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
66 static int
67 start_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
108 static void
109 exec_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
136 static enum { NONE = 0, AUTH_KRB4 = 1, AUTH_KRB5 = 2, AUTH_OTP = 3 } auth;
137
138 #ifdef KRB4
139 static krb5_boolean get_v4_tgt = FALSE;
140 #endif
141
142 #ifdef OTP
143 static OtpContext otp_ctx;
144
145 static int
146 otp_verify(struct passwd *pwd, const char *password)
147 {
148    return (otp_verify_user (&otp_ctx, password));
149 }
150 #endif /* OTP */
151
152
153 static int pag_set = 0;
154
155 #ifdef KRB5
156 static krb5_context context;
157 static krb5_ccache  id, id2;
158
159 static int
160 krb5_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
184 static krb5_error_code
185 krb5_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
250 static int
251 krb5_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
275 static void
276 krb5_finish (void)
277 {
278     krb5_free_context(context);
279 }
280
281 static void
282 krb5_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
314 static int
315 krb4_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
345 static void
346 krb4_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
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;
378
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, }
392 };
393
394 int nargs = sizeof(args) / sizeof(args[0]);
395
396 static void
397 update_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
411 static void
412 checknologin(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 */
427 static void
428 show_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
445 static void
446 do_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
665 static int
666 check_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
700 static void
701 usage(int status)
702 {
703     arg_printusage(args, nargs, NULL, "[username]");
704     exit(status);
705 }
706
707 static RETSIGTYPE
708 sig_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
718 int
719 main(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 }