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