xref: /netbsd-src/lib/libtelnet/sra.c (revision b893c4d5e49d0da4b67774beeda8184e18c3b472)
1185393efSchristos /*-
2185393efSchristos  * Copyright (c) 1991, 1993
3185393efSchristos  *      Dave Safford.  All rights reserved.
4185393efSchristos  *
5185393efSchristos  * Redistribution and use in source and binary forms, with or without
6185393efSchristos  * modification, are permitted provided that the following conditions
7185393efSchristos  * are met:
8185393efSchristos  * 1. Redistributions of source code must retain the above copyright
9185393efSchristos  *    notice, this list of conditions and the following disclaimer.
10185393efSchristos  * 2. Redistributions in binary form must reproduce the above copyright
11185393efSchristos  *    notice, this list of conditions and the following disclaimer in the
12185393efSchristos  *    documentation and/or other materials provided with the distribution.
13185393efSchristos  * 3. Neither the name of the University nor the names of its contributors
14185393efSchristos  *    may be used to endorse or promote products derived from this software
15185393efSchristos  *    without specific prior written permission.
16185393efSchristos  *
17185393efSchristos  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18185393efSchristos  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19185393efSchristos  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20185393efSchristos  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21185393efSchristos  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22185393efSchristos  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23185393efSchristos  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24185393efSchristos  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25185393efSchristos  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26185393efSchristos  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27185393efSchristos  * SUCH DAMAGE.
28185393efSchristos  *
29185393efSchristos  */
30185393efSchristos 
31185393efSchristos #include <sys/cdefs.h>
32185393efSchristos #ifdef notdef
33185393efSchristos __FBSDID("$FreeBSD: src/contrib/telnet/libtelnet/sra.c,v 1.16 2002/05/06 09:48:02 markm Exp $");
34185393efSchristos #else
35*b893c4d5Snia __RCSID("$NetBSD: sra.c,v 1.12 2021/10/30 10:46:57 nia Exp $");
36185393efSchristos #endif
37185393efSchristos 
38185393efSchristos #ifdef	SRA
39185393efSchristos #ifdef	ENCRYPTION
40185393efSchristos #include <sys/types.h>
41185393efSchristos #include <arpa/telnet.h>
4294b84ac8Slukem #include <paths.h>
43185393efSchristos #include <pwd.h>
44185393efSchristos #include <stdio.h>
45185393efSchristos #include <stdlib.h>
46185393efSchristos #include <string.h>
47185393efSchristos #include <syslog.h>
48185393efSchristos #include <ttyent.h>
49185393efSchristos 
50185393efSchristos #ifndef NOPAM
51185393efSchristos #include <security/pam_appl.h>
52185393efSchristos #else
53185393efSchristos #include <unistd.h>
54185393efSchristos #endif
55185393efSchristos 
56185393efSchristos #include "auth.h"
57185393efSchristos #include "misc.h"
58185393efSchristos #include "encrypt.h"
59185393efSchristos #include "pk.h"
60185393efSchristos 
61185393efSchristos char pka[HEXKEYBYTES+1], ska[HEXKEYBYTES+1], pkb[HEXKEYBYTES+1];
62185393efSchristos char *user, *pass, *xuser, *xpass;
6364fe9d91Schristos char *passprompt, *xpassprompt;
64185393efSchristos DesData ck;
65185393efSchristos IdeaData ik;
66185393efSchristos 
67185393efSchristos extern int auth_debug_mode;
6894b84ac8Slukem extern char *line; 		/* see sys_term.c */
69185393efSchristos 
70185393efSchristos static int sra_valid = 0;
71185393efSchristos static int passwd_sent = 0;
72185393efSchristos 
73185393efSchristos static unsigned char str_data[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 0,
74185393efSchristos 			  		AUTHTYPE_SRA, };
75185393efSchristos 
76cdf62a44Schristos #define SMALL_LEN	256
77cdf62a44Schristos #define XSMALL_LEN	513
78185393efSchristos #define SRA_KEY	0
79185393efSchristos #define SRA_USER 1
80185393efSchristos #define SRA_CONTINUE 2
81185393efSchristos #define SRA_PASS 3
82185393efSchristos #define SRA_ACCEPT 4
83185393efSchristos #define SRA_REJECT 5
84185393efSchristos 
856a6c8f61Schristos static int check_user(char *, const char *);
86185393efSchristos 
87185393efSchristos /* support routine to send out authentication message */
88185393efSchristos static int
Data(Authenticator * ap,int type,void * d,int c)89185393efSchristos Data(Authenticator *ap, int type, void *d, int c)
90185393efSchristos {
91185393efSchristos         unsigned char *p = str_data + 4;
92cdf62a44Schristos 	unsigned char *cd = d;
93185393efSchristos 
94185393efSchristos 	if (c == -1)
95cdf62a44Schristos 		c = strlen(d);
96185393efSchristos 
97185393efSchristos         if (auth_debug_mode) {
98185393efSchristos                 printf("%s:%d: [%d] (%d)",
99185393efSchristos 		    str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY",
100cdf62a44Schristos 		    str_data[3], type, c);
101185393efSchristos                 printd(d, c);
102185393efSchristos                 printf("\r\n");
103185393efSchristos         }
104185393efSchristos 	*p++ = ap->type;
105185393efSchristos 	*p++ = ap->way;
106185393efSchristos 	*p++ = type;
107185393efSchristos         while (c-- > 0) {
108185393efSchristos                 if ((*p++ = *cd++) == IAC)
109185393efSchristos                         *p++ = IAC;
110185393efSchristos         }
111185393efSchristos         *p++ = IAC;
112185393efSchristos         *p++ = SE;
113185393efSchristos 	if (str_data[3] == TELQUAL_IS)
114185393efSchristos 		printsub('>', &str_data[2], p - (&str_data[2]));
115cdf62a44Schristos         return telnet_net_write(str_data, p - str_data);
116185393efSchristos }
117185393efSchristos 
118185393efSchristos int
sra_init(Authenticator * ap __unused,int server)119185393efSchristos sra_init(Authenticator *ap __unused, int server)
120185393efSchristos {
121185393efSchristos 	if (server)
122185393efSchristos 		str_data[3] = TELQUAL_REPLY;
123185393efSchristos 	else
124185393efSchristos 		str_data[3] = TELQUAL_IS;
125185393efSchristos 
126cdf62a44Schristos 	user = malloc(SMALL_LEN);
127cdf62a44Schristos 	xuser = malloc(XSMALL_LEN);
128cdf62a44Schristos 	pass = malloc(SMALL_LEN);
129cdf62a44Schristos 	xpass = malloc(XSMALL_LEN);
130cdf62a44Schristos 	passprompt = malloc(SMALL_LEN);
131cdf62a44Schristos 	xpassprompt = malloc(XSMALL_LEN);
132185393efSchristos 
133185393efSchristos 	if (user == NULL || xuser == NULL || pass == NULL || xpass ==
13464fe9d91Schristos 	    NULL || passprompt == NULL || xpassprompt == NULL)
135185393efSchristos 		return 0; /* malloc failed */
136185393efSchristos 
137185393efSchristos 	passwd_sent = 0;
138185393efSchristos 
139185393efSchristos 	genkeys(pka, ska);
140cdf62a44Schristos 	return 1;
141185393efSchristos }
142185393efSchristos 
143185393efSchristos /* client received a go-ahead for sra */
144185393efSchristos int
sra_send(Authenticator * ap)145185393efSchristos sra_send(Authenticator *ap)
146185393efSchristos {
147185393efSchristos 	/* send PKA */
148185393efSchristos 
149185393efSchristos 	if (auth_debug_mode)
150185393efSchristos 		printf("Sent PKA to server.\r\n" );
151185393efSchristos 	printf("Trying SRA secure login:\r\n");
152185393efSchristos 	if (!Data(ap, SRA_KEY, (void *)pka, HEXKEYBYTES)) {
153185393efSchristos 		if (auth_debug_mode)
154185393efSchristos 			printf("Not enough room for authentication data\r\n");
155cdf62a44Schristos 		return 0;
156185393efSchristos 	}
157185393efSchristos 
158cdf62a44Schristos 	return 1;
159185393efSchristos }
160185393efSchristos 
161185393efSchristos /* server received an IS -- could be SRA KEY, USER, or PASS */
162185393efSchristos void
sra_is(Authenticator * ap,unsigned char * data,int cnt)163185393efSchristos sra_is(Authenticator *ap, unsigned char *data, int cnt)
164185393efSchristos {
165185393efSchristos 	int valid;
166185393efSchristos 	Session_Key skey;
167185393efSchristos 
168185393efSchristos 	if (cnt-- < 1)
169185393efSchristos 		goto bad;
170185393efSchristos 	switch (*data++) {
171185393efSchristos 
172185393efSchristos 	case SRA_KEY:
173185393efSchristos 		if (cnt < HEXKEYBYTES) {
174185393efSchristos 			Data(ap, SRA_REJECT, (void *)0, 0);
175185393efSchristos 			auth_finished(ap, AUTH_USER);
176185393efSchristos 			if (auth_debug_mode) {
177185393efSchristos 				printf("SRA user rejected for bad PKB\r\n");
178185393efSchristos 			}
179185393efSchristos 			return;
180185393efSchristos 		}
181185393efSchristos 		if (auth_debug_mode)
182185393efSchristos 			printf("Sent pka\r\n");
183185393efSchristos 		if (!Data(ap, SRA_KEY, (void *)pka, HEXKEYBYTES)) {
184185393efSchristos 			if (auth_debug_mode)
185185393efSchristos 				printf("Not enough room\r\n");
186185393efSchristos 			return;
187185393efSchristos 		}
188185393efSchristos 		memcpy(pkb, data, HEXKEYBYTES);
189185393efSchristos 		pkb[HEXKEYBYTES] = '\0';
190185393efSchristos 		common_key(ska, pkb, &ik, &ck);
191185393efSchristos 		return;
192185393efSchristos 
193185393efSchristos 	case SRA_USER:
194185393efSchristos 		/* decode KAB(u) */
195cdf62a44Schristos 		if (cnt > XSMALL_LEN - 1) /* Attempted buffer overflow */
196185393efSchristos 			break;
197185393efSchristos 		memcpy(xuser, data, cnt);
198185393efSchristos 		xuser[cnt] = '\0';
199185393efSchristos 		pk_decode(xuser, user, &ck);
200185393efSchristos 		auth_encrypt_user(user);
20164fe9d91Schristos #ifndef NOPAM
20264fe9d91Schristos 		(void)check_user(user, "*");
20364fe9d91Schristos #endif
20464fe9d91Schristos 		pk_encode(passprompt, xpassprompt, &ck);
205cdf62a44Schristos 		Data(ap, SRA_CONTINUE, xpassprompt, XSMALL_LEN - 1);
206185393efSchristos 
207185393efSchristos 		return;
208185393efSchristos 
209185393efSchristos 	case SRA_PASS:
210cdf62a44Schristos 		if (cnt > XSMALL_LEN - 1) /* Attempted buffer overflow */
211185393efSchristos 			break;
212185393efSchristos 		/* decode KAB(P) */
213185393efSchristos 		memcpy(xpass, data, cnt);
214185393efSchristos 		xpass[cnt] = '\0';
215185393efSchristos 		pk_decode(xpass, pass, &ck);
216185393efSchristos 
217185393efSchristos 		/* check user's password */
218185393efSchristos 		valid = check_user(user, pass);
219185393efSchristos 
220185393efSchristos 		if(valid) {
221f4ee0854Slukem 			/* PAM (via check_user()) may have changed 'user' */
222f4ee0854Slukem 			auth_encrypt_user(user);
223185393efSchristos 			Data(ap, SRA_ACCEPT, (void *)0, 0);
224185393efSchristos 			skey.data = ck;
225185393efSchristos 			skey.type = SK_DES;
226185393efSchristos 			skey.length = 8;
227185393efSchristos 			encrypt_session_key(&skey, 1);
228185393efSchristos 
229185393efSchristos 			sra_valid = 1;
230185393efSchristos 			auth_finished(ap, AUTH_VALID);
231185393efSchristos 			if (auth_debug_mode) {
232185393efSchristos 				printf("SRA user accepted\r\n");
233185393efSchristos 			}
234185393efSchristos 		}
235185393efSchristos 		else {
23664fe9d91Schristos 			pk_encode(passprompt, xpassprompt, &ck);
237cdf62a44Schristos 			Data(ap, SRA_CONTINUE, (void *)xpassprompt,
238cdf62a44Schristos 			    XSMALL_LEN - 1);
239185393efSchristos 			if (auth_debug_mode) {
240185393efSchristos 				printf("SRA user failed\r\n");
241185393efSchristos 			}
242185393efSchristos 		}
243185393efSchristos 		return;
244185393efSchristos 
245185393efSchristos 	default:
246185393efSchristos 		if (auth_debug_mode)
247185393efSchristos 			printf("Unknown SRA option %d\r\n", data[-1]);
248185393efSchristos 	}
249185393efSchristos bad:
250185393efSchristos 	Data(ap, SRA_REJECT, 0, 0);
251185393efSchristos 	sra_valid = 0;
252185393efSchristos 	auth_finished(ap, AUTH_REJECT);
253185393efSchristos }
254185393efSchristos 
255185393efSchristos /* client received REPLY -- could be SRA KEY, CONTINUE, ACCEPT, or REJECT */
256185393efSchristos void
sra_reply(Authenticator * ap,unsigned char * data,int cnt)257185393efSchristos sra_reply(Authenticator *ap, unsigned char *data, int cnt)
258185393efSchristos {
259cdf62a44Schristos 	char uprompt[SMALL_LEN], tuser[SMALL_LEN];
260185393efSchristos 	Session_Key skey;
261185393efSchristos 	size_t i;
262185393efSchristos 
263185393efSchristos 	if (cnt-- < 1)
264185393efSchristos 		return;
265185393efSchristos 	switch (*data++) {
266185393efSchristos 
267185393efSchristos 	case SRA_KEY:
268185393efSchristos 		/* calculate common key */
269185393efSchristos 		if (cnt < HEXKEYBYTES) {
270185393efSchristos 			if (auth_debug_mode) {
271185393efSchristos 				printf("SRA user rejected for bad PKB\r\n");
272185393efSchristos 			}
273185393efSchristos 			return;
274185393efSchristos 		}
275185393efSchristos 		memcpy(pkb, data, HEXKEYBYTES);
276185393efSchristos 		pkb[HEXKEYBYTES] = '\0';
277185393efSchristos 
278185393efSchristos 		common_key(ska, pkb, &ik, &ck);
279185393efSchristos 
280185393efSchristos 	enc_user:
281185393efSchristos 
282185393efSchristos 		/* encode user */
283185393efSchristos 		memset(tuser, 0, sizeof(tuser));
284cdf62a44Schristos 		snprintf(uprompt, sizeof(uprompt), "User (%s): ",
285cdf62a44Schristos 		    UserNameRequested);
286cdf62a44Schristos 		if (telnet_gets(uprompt, tuser, SMALL_LEN - 1, 1) == NULL) {
28764fe9d91Schristos 			printf("\n");
28864fe9d91Schristos 			exit(1);
28964fe9d91Schristos 		}
290185393efSchristos 		if (tuser[0] == '\n' || tuser[0] == '\r' )
291cdf62a44Schristos 			strlcpy(user, UserNameRequested, SMALL_LEN);
292185393efSchristos 		else {
293185393efSchristos 			/* telnet_gets leaves the newline on */
294185393efSchristos 			for(i = 0; i < sizeof(tuser); i++) {
295185393efSchristos 				if (tuser[i] == '\n') {
296185393efSchristos 					tuser[i] = '\0';
297185393efSchristos 					break;
298185393efSchristos 				}
299185393efSchristos 			}
300cdf62a44Schristos 			strlcpy(user, tuser, SMALL_LEN);
301185393efSchristos 		}
302185393efSchristos 		pk_encode(user, xuser, &ck);
303185393efSchristos 
304185393efSchristos 		/* send it off */
305185393efSchristos 		if (auth_debug_mode)
306185393efSchristos 			printf("Sent KAB(U)\r\n");
307185393efSchristos 		if (!Data(ap, SRA_USER, (void *)xuser, strlen(xuser))) {
308185393efSchristos 			if (auth_debug_mode)
309185393efSchristos 				printf("Not enough room\r\n");
310185393efSchristos 			return;
311185393efSchristos 		}
312185393efSchristos 		break;
313185393efSchristos 
314185393efSchristos 	case SRA_CONTINUE:
315185393efSchristos 		if (passwd_sent) {
316185393efSchristos 			passwd_sent = 0;
317185393efSchristos 			printf("[ SRA login failed ]\r\n");
318185393efSchristos 			goto enc_user;
319185393efSchristos 		}
320cdf62a44Schristos 		if (cnt > XSMALL_LEN - 1) {
32164fe9d91Schristos 			break;
32223dfb0b1Schristos 		} else if (cnt > 0) {
32323dfb0b1Schristos 			(void)memcpy(xpassprompt, data, cnt);
32464fe9d91Schristos 			pk_decode(xpassprompt, passprompt, &ck);
32523dfb0b1Schristos 		} else {
326cdf62a44Schristos 			(void)strlcpy(passprompt, "Password: ", SMALL_LEN);
32723dfb0b1Schristos 		}
328185393efSchristos 		/* encode password */
329cdf62a44Schristos 		memset(pass, 0, SMALL_LEN);
330cdf62a44Schristos 		if (telnet_gets(passprompt, pass, SMALL_LEN - 1, 0) == NULL) {
33164fe9d91Schristos 			printf("\n");
33264fe9d91Schristos 			exit(1);
33364fe9d91Schristos 		}
334185393efSchristos 		pk_encode(pass, xpass, &ck);
335185393efSchristos 		/* send it off */
336185393efSchristos 		if (auth_debug_mode)
337185393efSchristos 			printf("Sent KAB(P)\r\n");
338185393efSchristos 		if (!Data(ap, SRA_PASS, (void *)xpass, strlen(xpass))) {
339185393efSchristos 			if (auth_debug_mode)
340185393efSchristos 				printf("Not enough room\r\n");
341185393efSchristos 			return;
342185393efSchristos 		}
343185393efSchristos 		passwd_sent = 1;
344185393efSchristos 		break;
345185393efSchristos 
346185393efSchristos 	case SRA_REJECT:
347185393efSchristos 		printf("[ SRA refuses authentication ]\r\n");
348185393efSchristos 		printf("Trying plaintext login:\r\n");
349185393efSchristos 		auth_finished(0, AUTH_REJECT);
350185393efSchristos 		return;
351185393efSchristos 
352185393efSchristos 	case SRA_ACCEPT:
353185393efSchristos 		printf("[ SRA accepts you ]\r\n");
354185393efSchristos 		skey.data = ck;
355185393efSchristos 		skey.type = SK_DES;
356185393efSchristos 		skey.length = 8;
357185393efSchristos 		encrypt_session_key(&skey, 0);
358185393efSchristos 
359185393efSchristos 		auth_finished(ap, AUTH_VALID);
360185393efSchristos 		return;
361185393efSchristos 	default:
362185393efSchristos 		if (auth_debug_mode)
363185393efSchristos 			printf("Unknown SRA option %d\r\n", data[-1]);
364185393efSchristos 		return;
365185393efSchristos 	}
366185393efSchristos }
367185393efSchristos 
368185393efSchristos int
sra_status(Authenticator * ap __unused,char * name,size_t len,int level)369185393efSchristos sra_status(Authenticator *ap __unused, char *name, size_t len, int level)
370185393efSchristos {
371185393efSchristos 	if (level < AUTH_USER)
372cdf62a44Schristos 		return level;
373185393efSchristos 	if (UserNameRequested && sra_valid) {
374185393efSchristos 		strlcpy(name, UserNameRequested, len);
375cdf62a44Schristos 		return AUTH_VALID;
376185393efSchristos 	} else
377cdf62a44Schristos 		return AUTH_USER;
378185393efSchristos }
379185393efSchristos 
380185393efSchristos #define	BUMP(buf, len)		while (*(buf)) { ++(buf), --(len); }
381185393efSchristos #define	ADDC(buf, len, c)	if ((len) > 0) { *(buf)++ = (c); --(len); }
382185393efSchristos 
383185393efSchristos void
sra_printsub(unsigned char * data,int cnt,unsigned char * ubuf,int buflen)384cdf62a44Schristos sra_printsub(unsigned char *data, int cnt, unsigned char *ubuf, int buflen)
385185393efSchristos {
386cdf62a44Schristos 	char lbuf[32], *buf = (char *)ubuf;
387185393efSchristos 	int i;
388185393efSchristos 
389185393efSchristos 	buf[buflen - 1] = '\0'; 		/* make sure its NULL terminated */
390185393efSchristos 	buflen -= 1;
391185393efSchristos 
392185393efSchristos 	switch(data[3]) {
393185393efSchristos 
394185393efSchristos 	case SRA_CONTINUE:
395cdf62a44Schristos 		strncpy(buf, " CONTINUE ", buflen);
396185393efSchristos 		goto common;
397185393efSchristos 
398185393efSchristos 	case SRA_REJECT:		/* Rejected (reason might follow) */
399cdf62a44Schristos 		strncpy(buf, " REJECT ", buflen);
400185393efSchristos 		goto common;
401185393efSchristos 
402185393efSchristos 	case SRA_ACCEPT:		/* Accepted (name might follow) */
403cdf62a44Schristos 		strncpy(buf, " ACCEPT ", buflen);
404185393efSchristos 
405185393efSchristos 	common:
406185393efSchristos 		BUMP(buf, buflen);
407185393efSchristos 		if (cnt <= 4)
408185393efSchristos 			break;
409185393efSchristos 		ADDC(buf, buflen, '"');
410185393efSchristos 		for (i = 4; i < cnt; i++)
411185393efSchristos 			ADDC(buf, buflen, data[i]);
412185393efSchristos 		ADDC(buf, buflen, '"');
413185393efSchristos 		ADDC(buf, buflen, '\0');
414185393efSchristos 		break;
415185393efSchristos 
416185393efSchristos 	case SRA_KEY:			/* Authentication data follows */
417cdf62a44Schristos 		strncpy(buf, " KEY ", buflen);
418185393efSchristos 		goto common2;
419185393efSchristos 
420185393efSchristos 	case SRA_USER:
421cdf62a44Schristos 		strncpy(buf, " USER ", buflen);
422185393efSchristos 		goto common2;
423185393efSchristos 
424185393efSchristos 	case SRA_PASS:
425cdf62a44Schristos 		strncpy(buf, " PASS ", buflen);
426185393efSchristos 		goto common2;
427185393efSchristos 
428185393efSchristos 	default:
429cdf62a44Schristos 		snprintf(lbuf, sizeof(lbuf), " %d (unknown)", data[3]);
430cdf62a44Schristos 		strncpy(buf, lbuf, buflen);
431185393efSchristos 	common2:
432185393efSchristos 		BUMP(buf, buflen);
433185393efSchristos 		for (i = 4; i < cnt; i++) {
434cdf62a44Schristos 			snprintf(lbuf, sizeof(lbuf), " %d", data[i]);
435cdf62a44Schristos 			strncpy(buf, lbuf, buflen);
436185393efSchristos 			BUMP(buf, buflen);
437185393efSchristos 		}
438185393efSchristos 		break;
439185393efSchristos 	}
440185393efSchristos }
441185393efSchristos 
4420d885c3aSlukem #ifdef NOPAM
443185393efSchristos static int
isroot(const char * usr)444185393efSchristos isroot(const char *usr)
445185393efSchristos {
446382db3edSchristos 	struct passwd pws, *pwd;
447382db3edSchristos 	char pwbuf[1024];
448185393efSchristos 
449262b0ba9Schristos 	if (getpwnam_r(usr, &pws, pwbuf, sizeof(pwbuf), &pwd) != 0 ||
450262b0ba9Schristos 	    pwd == NULL)
451185393efSchristos 		return 0;
452185393efSchristos 	return (!pwd->pw_uid);
453185393efSchristos }
454185393efSchristos 
455185393efSchristos static int
rootterm(const char * ttyname)45694b84ac8Slukem rootterm(const char *ttyname)
457185393efSchristos {
458185393efSchristos 	struct ttyent *t;
45994b84ac8Slukem 	const char *ttyn;
46094b84ac8Slukem 
46194b84ac8Slukem 	ttyn = ttyname;
46294b84ac8Slukem 	if (strncmp(ttyn, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
46394b84ac8Slukem 		ttyn += sizeof(_PATH_DEV) - 1;
464185393efSchristos 
465185393efSchristos 	return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE);
466185393efSchristos }
467185393efSchristos 
468185393efSchristos static int
check_user(char * name,const char * cred)4696a6c8f61Schristos check_user(char *name, const char *cred)
470185393efSchristos {
4710d885c3aSlukem 	struct passwd pws, *pw;
4720d885c3aSlukem 	char pwbuf[1024];
473185393efSchristos 	char *xpasswd, *salt;
474185393efSchristos 
475185393efSchristos 	if (isroot(name) && !rootterm(line))
476185393efSchristos 	{
477185393efSchristos 		crypt("AA", "*"); /* Waste some time to simulate success */
478cdf62a44Schristos 		return 0;
479185393efSchristos 	}
480185393efSchristos 
4810d885c3aSlukem 	if (getpwnam_r(name, &pws, pwbuf, sizeof(pwbuf), &pw) == 0 &&
4820d885c3aSlukem 	    pw != NULL) {
483185393efSchristos 		if (pw->pw_shell == NULL) {
484cdf62a44Schristos 			return 0;
485185393efSchristos 		}
486185393efSchristos 
487185393efSchristos 		salt = pw->pw_passwd;
488185393efSchristos 		xpasswd = crypt(cred, salt);
489185393efSchristos 		/* The strcmp does not catch null passwords! */
4900d885c3aSlukem 		if (*pw->pw_passwd == '\0' || strcmp(xpasswd, pw->pw_passwd)) {
491cdf62a44Schristos 			return 0;
492185393efSchristos 		}
493cdf62a44Schristos 		return 1;
494185393efSchristos 	}
495cdf62a44Schristos 	return 0;
496185393efSchristos }
4970d885c3aSlukem #else	/* !NOPAM */
498185393efSchristos 
499185393efSchristos /*
500185393efSchristos  * The following is stolen from ftpd, which stole it from the imap-uw
501185393efSchristos  * PAM module and login.c. It is needed because we can't really
502185393efSchristos  * "converse" with the user, having already gone to the trouble of
503185393efSchristos  * getting their username and password through an encrypted channel.
504185393efSchristos  */
505185393efSchristos 
506185393efSchristos #define COPY_STRING(s) (s ? strdup(s) : NULL)
507185393efSchristos 
508185393efSchristos struct cred_t {
509185393efSchristos 	const char *uname;
510185393efSchristos 	const char *pass;
511185393efSchristos };
512185393efSchristos typedef struct cred_t cred_t;
513185393efSchristos 
514185393efSchristos static int
auth_conv(int num_msg,const struct pam_message ** msg,struct pam_response ** resp,void * appdata)515cdf62a44Schristos auth_conv(int num_msg, const struct pam_message **msg,
516cdf62a44Schristos     struct pam_response **resp, void *appdata)
517185393efSchristos {
518185393efSchristos 	int i;
519cdf62a44Schristos 	cred_t *cred = appdata;
520*b893c4d5Snia 	struct pam_response *reply = NULL;
521185393efSchristos 
522*b893c4d5Snia 	if (reallocarr(&reply, num_msg, sizeof(*reply)) != 0)
523185393efSchristos 		return PAM_BUF_ERR;
524185393efSchristos 
525185393efSchristos 	for (i = 0; i < num_msg; i++) {
526185393efSchristos 		switch (msg[i]->msg_style) {
527185393efSchristos 		case PAM_PROMPT_ECHO_ON:        /* assume want user name */
528185393efSchristos 			reply[i].resp_retcode = PAM_SUCCESS;
529185393efSchristos 			reply[i].resp = COPY_STRING(cred->uname);
530185393efSchristos 			/* PAM frees resp. */
531185393efSchristos 			break;
532185393efSchristos 		case PAM_PROMPT_ECHO_OFF:       /* assume want password */
533cdf62a44Schristos 		    (void)strlcpy(passprompt, msg[i]->msg, SMALL_LEN);
534185393efSchristos 		    reply[i].resp_retcode = PAM_SUCCESS;
535185393efSchristos 		    reply[i].resp = COPY_STRING(cred->pass);
536185393efSchristos 		    /* PAM frees resp. */
537185393efSchristos 		    break;
538185393efSchristos 		case PAM_TEXT_INFO:
539185393efSchristos 		case PAM_ERROR_MSG:
540185393efSchristos 			reply[i].resp_retcode = PAM_SUCCESS;
541185393efSchristos 			reply[i].resp = NULL;
542185393efSchristos 			break;
543185393efSchristos 		default:                        /* unknown message style */
544185393efSchristos 			free(reply);
545185393efSchristos 			return PAM_CONV_ERR;
546185393efSchristos 		}
547185393efSchristos 	}
548185393efSchristos 
549185393efSchristos 	*resp = reply;
550185393efSchristos 	return PAM_SUCCESS;
551185393efSchristos }
552185393efSchristos 
553185393efSchristos /*
554185393efSchristos  * The PAM version as a side effect may put a new username in *name.
555185393efSchristos  */
556185393efSchristos static int
check_user(char * name,const char * cred)5576a6c8f61Schristos check_user(char *name, const char *cred)
558185393efSchristos {
559185393efSchristos 	pam_handle_t *pamh = NULL;
560185393efSchristos 	const void *item;
561185393efSchristos 	int rval;
562185393efSchristos 	int e;
563185393efSchristos 	cred_t auth_cred = { name, cred };
564185393efSchristos 	struct pam_conv conv = { &auth_conv, &auth_cred };
565185393efSchristos 
566185393efSchristos 	e = pam_start("telnetd", name, &conv, &pamh);
567185393efSchristos 	if (e != PAM_SUCCESS) {
568185393efSchristos 		syslog(LOG_ERR, "pam_start: %s", pam_strerror(pamh, e));
569185393efSchristos 		return 0;
570185393efSchristos 	}
571185393efSchristos 
572185393efSchristos #if 0 /* Where can we find this value? */
573185393efSchristos 	e = pam_set_item(pamh, PAM_RHOST, remotehost);
574185393efSchristos 	if (e != PAM_SUCCESS) {
575185393efSchristos 		syslog(LOG_ERR, "pam_set_item(PAM_RHOST): %s",
576185393efSchristos 			pam_strerror(pamh, e));
577185393efSchristos 		return 0;
578185393efSchristos 	}
579185393efSchristos #endif
580185393efSchristos 
581185393efSchristos 	e = pam_authenticate(pamh, 0);
582185393efSchristos 	switch (e) {
583185393efSchristos 	case PAM_SUCCESS:
584185393efSchristos 		/*
585185393efSchristos 		 * With PAM we support the concept of a "template"
586185393efSchristos 		 * user.  The user enters a login name which is
587185393efSchristos 		 * authenticated by PAM, usually via a remote service
588185393efSchristos 		 * such as RADIUS or TACACS+.  If authentication
589185393efSchristos 		 * succeeds, a different but related "template" name
590185393efSchristos 		 * is used for setting the credentials, shell, and
591185393efSchristos 		 * home directory.  The name the user enters need only
592185393efSchristos 		 * exist on the remote authentication server, but the
593185393efSchristos 		 * template name must be present in the local password
594185393efSchristos 		 * database.
595185393efSchristos 		 *
596185393efSchristos 		 * This is supported by two various mechanisms in the
597185393efSchristos 		 * individual modules.  However, from the application's
598185393efSchristos 		 * point of view, the template user is always passed
599185393efSchristos 		 * back as a changed value of the PAM_USER item.
600185393efSchristos 		 */
601185393efSchristos 		if ((e = pam_get_item(pamh, PAM_USER, &item)) ==
602185393efSchristos 		    PAM_SUCCESS) {
603cdf62a44Schristos 			strlcpy(name, item, SMALL_LEN);
604185393efSchristos 		} else
605185393efSchristos 			syslog(LOG_ERR, "Couldn't get PAM_USER: %s",
606185393efSchristos 			pam_strerror(pamh, e));
6070d885c3aSlukem #if 0	/* pam_securetty(8) should be used to enforce this */
608185393efSchristos 		if (isroot(name) && !rootterm(line))
609185393efSchristos 			rval = 0;
610185393efSchristos 		else
6110d885c3aSlukem #endif
612185393efSchristos 			rval = 1;
613185393efSchristos 		break;
614185393efSchristos 
615185393efSchristos 	case PAM_AUTH_ERR:
616185393efSchristos 	case PAM_USER_UNKNOWN:
617185393efSchristos 	case PAM_MAXTRIES:
618185393efSchristos 		rval = 0;
619185393efSchristos 	break;
620185393efSchristos 
621185393efSchristos 	default:
622185393efSchristos 		syslog(LOG_ERR, "auth_pam: %s", pam_strerror(pamh, e));
623185393efSchristos 		rval = 0;
624185393efSchristos 		break;
625185393efSchristos 	}
626185393efSchristos 
627185393efSchristos 	if ((e = pam_end(pamh, e)) != PAM_SUCCESS) {
628185393efSchristos 		syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e));
629185393efSchristos 		rval = 0;
630185393efSchristos 	}
631185393efSchristos 	return rval;
632185393efSchristos }
633185393efSchristos 
6340d885c3aSlukem #endif /* !NOPAM */
635185393efSchristos 
636185393efSchristos #endif /* ENCRYPTION */
637185393efSchristos #endif /* SRA */
638