sra.c revision 81965
162587Sitojun/* $FreeBSD: head/contrib/telnet/libtelnet/sra.c 81965 2001-08-20 12:28:40Z markm $ */
278064Sume
362587Sitojun#ifdef	SRA
4139823Simp#include <sys/types.h>
554263Sshin#include <arpa/telnet.h>
654263Sshin#include <stdio.h>
754263Sshin#ifdef	__STDC__
854263Sshin#include <stdlib.h>
954263Sshin#endif
1054263Sshin#ifdef	NO_STRING_H
1154263Sshin#include <strings.h>
1254263Sshin#else
1354263Sshin#include <string.h>
1454263Sshin#endif
1554263Sshin
1654263Sshin#if !defined(NOPAM)
1754263Sshin#include <security/pam_appl.h>
1854263Sshin#else
1954263Sshin#include <unistd.h>
2054263Sshin#endif
2154263Sshin
2254263Sshin#include <pwd.h>
2354263Sshin#include <syslog.h>
2454263Sshin#include <ttyent.h>
2554263Sshin
2654263Sshin#include "auth.h"
2754263Sshin#include "misc.h"
2854263Sshin#include "encrypt.h"
2954263Sshin#include "pk.h"
3054263Sshin
3154263Sshinchar pka[HEXKEYBYTES+1], ska[HEXKEYBYTES+1], pkb[HEXKEYBYTES+1];
3254263Sshinchar *user,*pass,*xuser,*xpass;
3354263SshinDesData ck;
3462587SitojunIdeaData ik;
3554263Sshin
3654263Sshinextern int auth_debug_mode;
3754263Sshinextern char *line;
3854263Sshin
3954263Sshinstatic int sra_valid = 0;
4054263Sshinstatic int passwd_sent = 0;
4154263Sshin
4254263Sshinstatic unsigned char str_data[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 0,
4354263Sshin			  		AUTHTYPE_SRA, };
4454263Sshin
45105293Sume#define SRA_KEY	0
4654263Sshin#define SRA_USER 1
4762587Sitojun#define SRA_CONTINUE 2
4862587Sitojun#define SRA_PASS 3
4954263Sshin#define SRA_ACCEPT 4
5054263Sshin#define SRA_REJECT 5
5154263Sshin
5254263Sshinstatic int check_user(const char *, const char *);
5354263Sshin
5454263Sshin/* support routine to send out authentication message */
5554263Sshinstatic int
5654263SshinData(Authenticator *ap, int type, void *d, int c)
5762587Sitojun{
5862587Sitojun        unsigned char *p = str_data + 4;
5955009Sshin	unsigned char *cd = (unsigned char *)d;
6062587Sitojun
6154263Sshin	if (c == -1)
6262587Sitojun		c = strlen((char *)cd);
6354263Sshin
6454263Sshin        if (auth_debug_mode) {
6554263Sshin                printf("%s:%d: [%d] (%d)",
6654263Sshin                        str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY",
6754263Sshin                        str_data[3],
6854263Sshin                        type, c);
6962587Sitojun                printd(d, c);
7054263Sshin                printf("\r\n");
71105293Sume        }
72105293Sume	*p++ = ap->type;
73105293Sume	*p++ = ap->way;
74105293Sume	*p++ = type;
75152242Sru        while (c-- > 0) {
76152242Sru                if ((*p++ = *cd++) == IAC)
77152242Sru                        *p++ = IAC;
78152242Sru        }
79152242Sru        *p++ = IAC;
80152242Sru        *p++ = SE;
81152242Sru	if (str_data[3] == TELQUAL_IS)
82152242Sru		printsub('>', &str_data[2], p - (&str_data[2]));
83152242Sru        return(net_write(str_data, p - str_data));
84105293Sume}
85105293Sume
8691324Sbrooksint
8754263Sshinsra_init(Authenticator *ap, int server)
8854263Sshin{
8954263Sshin	if (server)
9054263Sshin		str_data[3] = TELQUAL_REPLY;
91169454Srwatson	else
9254263Sshin		str_data[3] = TELQUAL_IS;
93147256Sbrooks
9454263Sshin	user = (char *)malloc(256);
9554263Sshin	xuser = (char *)malloc(513);
9654263Sshin	pass = (char *)malloc(256);
9754263Sshin	xpass = (char *)malloc(513);
98153621Sthompsa
9954263Sshin	if (user == NULL || xuser == NULL || pass == NULL || xpass ==
10054263Sshin	NULL)
10154263Sshin		return 0; /* malloc failed */
102155037Sglebius
103155037Sglebius	passwd_sent = 0;
10454263Sshin
10554263Sshin	genkeys(pka,ska);
10654263Sshin	return(1);
10754263Sshin}
10854263Sshin
10954263Sshin/* client received a go-ahead for sra */
11054263Sshinint
11154263Sshinsra_send(Authenticator *ap)
11262587Sitojun{
11354263Sshin	/* send PKA */
11454263Sshin
11554263Sshin	if (auth_debug_mode)
11654263Sshin		printf("Sent PKA to server.\r\n" );
11754263Sshin	printf("Trying SRA secure login:\r\n");
11854263Sshin	if (!Data(ap, SRA_KEY, (void *)pka, HEXKEYBYTES)) {
11954263Sshin		if (auth_debug_mode)
12054263Sshin			printf("Not enough room for authentication data\r\n");
12154263Sshin		return(0);
12254263Sshin	}
12354263Sshin
12454263Sshin	return(1);
12554263Sshin}
12654263Sshin
12795023Ssuz/* server received an IS -- could be SRA KEY, USER, or PASS */
12854263Sshinvoid
12954263Sshinsra_is(Authenticator *ap, unsigned char *data, int cnt)
13054263Sshin{
13162587Sitojun	int valid;
13254263Sshin	Session_Key skey;
13354263Sshin
13454263Sshin	if (cnt-- < 1)
13554263Sshin		goto bad;
13654263Sshin	switch (*data++) {
13754263Sshin
13854263Sshin	case SRA_KEY:
13954263Sshin		if (cnt < HEXKEYBYTES) {
14054263Sshin			Data(ap, SRA_REJECT, (void *)0, 0);
14154263Sshin			auth_finished(ap, AUTH_USER);
14295023Ssuz			if (auth_debug_mode) {
143153621Sthompsa				printf("SRA user rejected for bad PKB\r\n");
144153621Sthompsa			}
145153621Sthompsa			return;
146153621Sthompsa		}
147153621Sthompsa		if (auth_debug_mode)
148153621Sthompsa			printf("Sent pka\r\n");
149153621Sthompsa		if (!Data(ap, SRA_KEY, (void *)pka, HEXKEYBYTES)) {
150153621Sthompsa			if (auth_debug_mode)
151153621Sthompsa				printf("Not enough room\r\n");
152153621Sthompsa			return;
153153621Sthompsa		}
154153621Sthompsa		memcpy(pkb,data,HEXKEYBYTES);
155153621Sthompsa		pkb[HEXKEYBYTES] = '\0';
156153621Sthompsa		common_key(ska,pkb,&ik,&ck);
15754263Sshin		return;
15862587Sitojun
15954263Sshin	case SRA_USER:
16054263Sshin		/* decode KAB(u) */
16154263Sshin		if (cnt > 512) /* Attempted buffer overflow */
16254263Sshin			break;
16354263Sshin		memcpy(xuser,data,cnt);
16454263Sshin		xuser[cnt] = '\0';
16554263Sshin		pk_decode(xuser,user,&ck);
16654263Sshin		auth_encrypt_user(user);
16754263Sshin		Data(ap, SRA_CONTINUE, (void *)0, 0);
16878064Sume
16978064Sume		return;
17078064Sume
17178064Sume	case SRA_PASS:
17278064Sume		if (cnt > 512) /* Attempted buffer overflow */
17378064Sume			break;
17454263Sshin		/* decode KAB(P) */
17554263Sshin		memcpy(xpass,data,cnt);
17654263Sshin		xpass[cnt] = '\0';
17754263Sshin		pk_decode(xpass,pass,&ck);
17854263Sshin
179121684Sume		/* check user's password */
180121684Sume		valid = check_user(user,pass);
18154263Sshin
18254263Sshin		if(valid) {
183111119Simp			Data(ap, SRA_ACCEPT, (void *)0, 0);
18454263Sshin#ifdef DES_ENCRYPTION
18554263Sshin			skey.data = ck;
18654263Sshin			skey.type = SK_DES;
18754263Sshin			skey.length = 8;
18854263Sshin			encrypt_session_key(&skey, 1);
18954263Sshin#endif
19062587Sitojun
19154263Sshin			sra_valid = 1;
19254263Sshin			auth_finished(ap, AUTH_VALID);
19354263Sshin			if (auth_debug_mode) {
19454263Sshin				printf("SRA user accepted\r\n");
195130662Sbms			}
19654263Sshin		}
19754263Sshin		else {
19854263Sshin			Data(ap, SRA_CONTINUE, (void *)0, 0);
19954263Sshin/*
20054263Sshin			Data(ap, SRA_REJECT, (void *)0, 0);
20154263Sshin			sra_valid = 0;
20254263Sshin			auth_finished(ap, AUTH_REJECT);
20362587Sitojun*/
204147256Sbrooks			if (auth_debug_mode) {
20562587Sitojun				printf("SRA user failed\r\n");
20654263Sshin			}
20754263Sshin		}
20854263Sshin		return;
209128210Sluigi
21054263Sshin	default:
21154263Sshin		if (auth_debug_mode)
21254263Sshin			printf("Unknown SRA option %d\r\n", data[-1]);
21354263Sshin	}
21462587Sitojunbad:
21562587Sitojun	Data(ap, SRA_REJECT, 0, 0);
21662587Sitojun	sra_valid = 0;
21762587Sitojun	auth_finished(ap, AUTH_REJECT);
21895023Ssuz}
21962587Sitojun
22062587Sitojun/* client received REPLY -- could be SRA KEY, CONTINUE, ACCEPT, or REJECT */
22162587Sitojunvoid
22262587Sitojunsra_reply(Authenticator *ap, unsigned char *data, int cnt)
22362587Sitojun{
22454263Sshin	extern char *telnet_gets();
22554263Sshin	char uprompt[256],tuser[256];
226105194Ssam	Session_Key skey;
227138470Sglebius	int i;
228147256Sbrooks
229138653Sglebius	if (cnt-- < 1)
230138470Sglebius		return;
231138470Sglebius	switch (*data++) {
232138470Sglebius
233138470Sglebius	case SRA_KEY:
234120885Sume		/* calculate common key */
23554263Sshin		if (cnt < HEXKEYBYTES) {
23654263Sshin			if (auth_debug_mode) {
23754263Sshin				printf("SRA user rejected for bad PKB\r\n");
238169454Srwatson			}
23954263Sshin			return;
24054263Sshin		}
241147503Sbz		memcpy(pkb,data,HEXKEYBYTES);
24254263Sshin		pkb[HEXKEYBYTES] = '\0';
24362587Sitojun
24455009Sshin		common_key(ska,pkb,&ik,&ck);
24582884Sjulian
24654263Sshin	enc_user:
24754263Sshin
24882884Sjulian		/* encode user */
24954263Sshin		memset(tuser,0,sizeof(tuser));
250147503Sbz		sprintf(uprompt,"User (%s): ",UserNameRequested);
251147503Sbz		telnet_gets(uprompt,tuser,255,1);
252147503Sbz		if (tuser[0] == '\n' || tuser[0] == '\r' )
253147503Sbz			strcpy(user,UserNameRequested);
254147503Sbz		else {
255147503Sbz			/* telnet_gets leaves the newline on */
25654263Sshin			for(i=0;i<sizeof(tuser);i++) {
257147503Sbz				if (tuser[i] == '\n') {
25862587Sitojun					tuser[i] = '\0';
25954263Sshin					break;
26054263Sshin				}
26154263Sshin			}
26254263Sshin			strcpy(user,tuser);
26354263Sshin		}
26455009Sshin		pk_encode(user,xuser,&ck);
26554263Sshin
26654263Sshin		/* send it off */
26754263Sshin		if (auth_debug_mode)
26862587Sitojun			printf("Sent KAB(U)\r\n");
26954263Sshin		if (!Data(ap, SRA_USER, (void *)xuser, strlen(xuser))) {
27054263Sshin			if (auth_debug_mode)
27154263Sshin				printf("Not enough room\r\n");
27254263Sshin			return;
27354263Sshin		}
27454263Sshin		break;
27554263Sshin
27654263Sshin	case SRA_CONTINUE:
27754263Sshin		if (passwd_sent) {
27854263Sshin			passwd_sent = 0;
279121684Sume			printf("[ SRA login failed ]\r\n");
280121684Sume			goto enc_user;
281121684Sume		}
282121684Sume		/* encode password */
283121684Sume		memset(pass,0,sizeof(pass));
284121684Sume		telnet_gets("Password: ",pass,255,0);
28554263Sshin		pk_encode(pass,xpass,&ck);
28654263Sshin		/* send it off */
28762587Sitojun		if (auth_debug_mode)
28854263Sshin			printf("Sent KAB(P)\r\n");
28954263Sshin		if (!Data(ap, SRA_PASS, (void *)xpass, strlen(xpass))) {
29054263Sshin			if (auth_debug_mode)
29154263Sshin				printf("Not enough room\r\n");
292121684Sume			return;
293121684Sume		}
29454263Sshin		passwd_sent = 1;
29554263Sshin		break;
29654263Sshin
29754263Sshin	case SRA_REJECT:
29854263Sshin		printf("[ SRA refuses authentication ]\r\n");
29954263Sshin		printf("Trying plaintext login:\r\n");
30054263Sshin		auth_finished(0,AUTH_REJECT);
301121684Sume		return;
302121684Sume
303121684Sume	case SRA_ACCEPT:
304121684Sume		printf("[ SRA accepts you ]\r\n");
305121684Sume#ifdef DES_ENCRYPTION
306121684Sume		skey.data = ck;
307121684Sume		skey.type = SK_DES;
308121684Sume		skey.length = 8;
309121684Sume		encrypt_session_key(&skey, 0);
310121684Sume#endif
311121684Sume
31254263Sshin		auth_finished(ap, AUTH_VALID);
31354263Sshin		return;
31454263Sshin	default:
315153621Sthompsa		if (auth_debug_mode)
316153621Sthompsa			printf("Unknown SRA option %d\r\n", data[-1]);
317153621Sthompsa		return;
318153621Sthompsa	}
31954263Sshin}
32054263Sshin
32154263Sshinint
32254263Sshinsra_status(Authenticator *ap, char *name, int level)
32354263Sshin{
32454263Sshin	if (level < AUTH_USER)
32554263Sshin		return(level);
32654263Sshin	if (UserNameRequested && sra_valid) {
32762587Sitojun		strcpy(name, UserNameRequested);
32862587Sitojun		return(AUTH_VALID);
329105293Sume	} else
33062587Sitojun		return(AUTH_USER);
331105293Sume}
332169454Srwatson
33362587Sitojun#define	BUMP(buf, len)		while (*(buf)) {++(buf), --(len);}
33462587Sitojun#define	ADDC(buf, len, c)	if ((len) > 0) {*(buf)++ = (c); --(len);}
33562587Sitojun
33662587Sitojunvoid
33762587Sitojunsra_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen)
33862587Sitojun{
33962587Sitojun	char lbuf[32];
34062587Sitojun	register int i;
341105293Sume
342105293Sume	buf[buflen-1] = '\0';		/* make sure its NULL terminated */
34362587Sitojun	buflen -= 1;
34462587Sitojun
34562587Sitojun	switch(data[3]) {
346105293Sume
34762587Sitojun	case SRA_CONTINUE:
348105293Sume		strncpy((char *)buf, " CONTINUE ", buflen);
34962587Sitojun		goto common;
35062587Sitojun
35162587Sitojun	case SRA_REJECT:		/* Rejected (reason might follow) */
35262587Sitojun		strncpy((char *)buf, " REJECT ", buflen);
353120891Sume		goto common;
35462587Sitojun
35562587Sitojun	case SRA_ACCEPT:		/* Accepted (name might follow) */
356105293Sume		strncpy((char *)buf, " ACCEPT ", buflen);
35762587Sitojun
35862587Sitojun	common:
35962587Sitojun		BUMP(buf, buflen);
36062587Sitojun		if (cnt <= 4)
361147256Sbrooks			break;
36262587Sitojun		ADDC(buf, buflen, '"');
36362587Sitojun		for (i = 4; i < cnt; i++)
36462587Sitojun			ADDC(buf, buflen, data[i]);
36562587Sitojun		ADDC(buf, buflen, '"');
36662587Sitojun		ADDC(buf, buflen, '\0');
36762587Sitojun		break;
368105293Sume
36962587Sitojun	case SRA_KEY:			/* Authentication data follows */
370105293Sume		strncpy((char *)buf, " KEY ", buflen);
37178064Sume		goto common2;
37278064Sume
373147256Sbrooks	case SRA_USER:
37478064Sume		strncpy((char *)buf, " USER ", buflen);
37578064Sume		goto common2;
37678064Sume
37778064Sume	case SRA_PASS:
37862587Sitojun		strncpy((char *)buf, " PASS ", buflen);
37962587Sitojun		goto common2;
38062587Sitojun
38162587Sitojun	default:
38262587Sitojun		sprintf(lbuf, " %d (unknown)", data[3]);
38378064Sume		strncpy((char *)buf, lbuf, buflen);
38462587Sitojun	common2:
385105293Sume		BUMP(buf, buflen);
386105293Sume		for (i = 4; i < cnt; i++) {
387105293Sume			sprintf(lbuf, " %d", data[i]);
388105293Sume			strncpy((char *)buf, lbuf, buflen);
389105293Sume			BUMP(buf, buflen);
390105293Sume		}
391169454Srwatson		break;
392105293Sume	}
393105293Sume}
394105293Sume
395105293Sumestruct	passwd *pw;
396105293Sume
397105293Sume/*
398105293Sume * Helper function for sgetpwnam().
399105293Sume */
400105293Sumechar *
401105293Sumesgetsave(char *s)
402105293Sume{
403105293Sume	char *new = malloc((unsigned) strlen(s) + 1);
404105293Sume
405105293Sume	if (new == NULL) {
406105293Sume		return(NULL);
407105293Sume	}
408169454Srwatson	(void) strcpy(new, s);
409105293Sume	return (new);
410105293Sume}
411105293Sume
412105293Sumestruct passwd *
413105293Sumesgetpwnam(char *name)
414105293Sume{
415105293Sume	static struct passwd save;
416105293Sume	register struct passwd *p;
417105293Sume	char *sgetsave();
418169454Srwatson
419105293Sume	if ((p = getpwnam(name)) == NULL)
420105293Sume		return (p);
421105293Sume	if (save.pw_name) {
422105293Sume		free(save.pw_name);
423105293Sume		free(save.pw_passwd);
424105293Sume		free(save.pw_gecos);
425105293Sume		free(save.pw_dir);
426105293Sume		free(save.pw_shell);
427	}
428	save = *p;
429	save.pw_name = sgetsave(p->pw_name);
430	save.pw_passwd = sgetsave(p->pw_passwd);
431	save.pw_gecos = sgetsave(p->pw_gecos);
432	save.pw_dir = sgetsave(p->pw_dir);
433	save.pw_shell = sgetsave(p->pw_shell);
434#if 0
435syslog(LOG_WARNING,"%s\n",save.pw_name);
436syslog(LOG_WARNING,"%s\n",save.pw_passwd);
437syslog(LOG_WARNING,"%s\n",save.pw_gecos);
438syslog(LOG_WARNING,"%s\n",save.pw_dir);
439#endif
440#ifdef USE_SHADOW
441        {
442                struct spwd *sp;
443                sp = getspnam(name);
444                free(save.pw_passwd);
445                save.pw_passwd  = sgetsave(sp->sp_pwdp);
446        }
447#endif
448	return (&save);
449}
450
451static int
452isroot(const char *user)
453{
454	struct passwd *pw;
455
456	if ((pw=getpwnam(user))==NULL)
457		return 0;
458	return (!pw->pw_uid);
459}
460
461static int
462rootterm(char *ttyn)
463{
464	struct ttyent *t;
465
466	return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE);
467}
468
469#ifdef NOPAM
470static int
471check_user(const char *name, const char *pass)
472{
473	register char *cp;
474	char *xpasswd, *salt;
475
476	if (isroot(name) && !rootterm(line))
477	{
478		crypt("AA","*"); /* Waste some time to simulate success */
479		return(0);
480	}
481
482	if (pw = sgetpwnam(name)) {
483		if (pw->pw_shell == NULL) {
484			pw = (struct passwd *) NULL;
485			return(0);
486		}
487
488		salt = pw->pw_passwd;
489		xpasswd = crypt(pass, salt);
490		/* The strcmp does not catch null passwords! */
491		if (pw == NULL || *pw->pw_passwd == '\0' ||
492			strcmp(xpasswd, pw->pw_passwd)) {
493			pw = (struct passwd *) NULL;
494			return(0);
495		}
496		return(1);
497	}
498	return(0);
499}
500#else
501
502/*
503 * The following is stolen from ftpd, which stole it from the imap-uw
504 * PAM module and login.c. It is needed because we can't really
505 * "converse" with the user, having already gone to the trouble of
506 * getting their username and password through an encrypted channel.
507 */
508
509#define COPY_STRING(s) (s ? strdup(s):NULL)
510
511struct cred_t {
512	const char *uname;
513	const char *pass;
514};
515typedef struct cred_t cred_t;
516
517int
518auth_conv(int num_msg, const struct pam_message **msg,
519	struct pam_response **resp, void *appdata)
520{
521	int i;
522	cred_t *cred = (cred_t *) appdata;
523	struct pam_response *reply =
524		malloc(sizeof(struct pam_response) * num_msg);
525
526	if (reply == NULL)
527		return PAM_BUF_ERR;
528
529	for (i = 0; i < num_msg; i++) {
530		switch (msg[i]->msg_style) {
531		case PAM_PROMPT_ECHO_ON:        /* assume want user name */
532			reply[i].resp_retcode = PAM_SUCCESS;
533			reply[i].resp = COPY_STRING(cred->uname);
534			/* PAM frees resp. */
535			break;
536		case PAM_PROMPT_ECHO_OFF:       /* assume want password */
537			reply[i].resp_retcode = PAM_SUCCESS;
538			reply[i].resp = COPY_STRING(cred->pass);
539			/* PAM frees resp. */
540			break;
541		case PAM_TEXT_INFO:
542		case PAM_ERROR_MSG:
543			reply[i].resp_retcode = PAM_SUCCESS;
544			reply[i].resp = NULL;
545			break;
546		default:                        /* unknown message style */
547			free(reply);
548			return PAM_CONV_ERR;
549		}
550	}
551
552	*resp = reply;
553	return PAM_SUCCESS;
554}
555
556/*
557 * The PAM version as a side effect may put a new username in *name.
558 */
559static int
560check_user(const char *name, const char *pass)
561{
562	pam_handle_t *pamh = NULL;
563	const void *item;
564	int rval;
565	int e;
566	cred_t auth_cred = { name, pass };
567	struct pam_conv conv = { &auth_conv, &auth_cred };
568
569	e = pam_start("telnetd", name, &conv, &pamh);
570	if (e != PAM_SUCCESS) {
571		syslog(LOG_ERR, "pam_start: %s", pam_strerror(pamh, e));
572		return 0;
573	}
574
575#if 0 /* Where can we find this value? */
576	e = pam_set_item(pamh, PAM_RHOST, remotehost);
577	if (e != PAM_SUCCESS) {
578		syslog(LOG_ERR, "pam_set_item(PAM_RHOST): %s",
579			pam_strerror(pamh, e));
580		return 0;
581	}
582#endif
583
584	e = pam_authenticate(pamh, 0);
585	switch (e) {
586	case PAM_SUCCESS:
587		/*
588		 * With PAM we support the concept of a "template"
589		 * user.  The user enters a login name which is
590		 * authenticated by PAM, usually via a remote service
591		 * such as RADIUS or TACACS+.  If authentication
592		 * succeeds, a different but related "template" name
593		 * is used for setting the credentials, shell, and
594		 * home directory.  The name the user enters need only
595		 * exist on the remote authentication server, but the
596		 * template name must be present in the local password
597		 * database.
598		 *
599		 * This is supported by two various mechanisms in the
600		 * individual modules.  However, from the application's
601		 * point of view, the template user is always passed
602		 * back as a changed value of the PAM_USER item.
603		 */
604		if ((e = pam_get_item(pamh, PAM_USER, &item)) ==
605		    PAM_SUCCESS) {
606			strcpy((char *) name, (const char *) item);
607		} else
608			syslog(LOG_ERR, "Couldn't get PAM_USER: %s",
609			pam_strerror(pamh, e));
610		if (isroot(name) && !rootterm(line))
611			rval = 0;
612		else
613			rval = 1;
614		break;
615
616	case PAM_AUTH_ERR:
617	case PAM_USER_UNKNOWN:
618	case PAM_MAXTRIES:
619		rval = 0;
620	break;
621
622	default:
623		syslog(LOG_ERR, "auth_pam: %s", pam_strerror(pamh, e));
624		rval = 0;
625		break;
626	}
627
628	if ((e = pam_end(pamh, e)) != PAM_SUCCESS) {
629		syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e));
630		rval = 0;
631	}
632	return rval;
633}
634
635#endif
636
637#endif
638
639