1/*-
2 * Copyright (c) 1991, 1993
3 *      Dave Safford.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the University nor the names of its contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 */
30
31#include <sys/cdefs.h>
32
33#ifdef __FBSDID
34__FBSDID("$FreeBSD: src/crypto/telnet/libtelnet/sra.c,v 1.1.2.7 2002/05/16 08:46:49 markm Exp $");
35#endif
36
37#ifdef	SRA
38#ifdef	ENCRYPTION
39#include <sys/types.h>
40#include <arpa/telnet.h>
41#include <pwd.h>
42#include <stdio.h>
43#include <stdlib.h>
44#include <string.h>
45#include <syslog.h>
46#include <ttyent.h>
47
48#ifndef NOPAM
49#include <security/pam_appl.h>
50#else
51#include <unistd.h>
52#endif
53
54#include "auth.h"
55#include "misc.h"
56#include "encrypt.h"
57#include "pk.h"
58
59char pka[HEXKEYBYTES+1], ska[HEXKEYBYTES+1], pkb[HEXKEYBYTES+1];
60char *user, *pass, *xuser, *xpass;
61DesData ck;
62IdeaData ik;
63
64extern int auth_debug_mode;
65extern char line[];
66
67static int sra_valid = 0;
68static int passwd_sent = 0;
69
70static unsigned char str_data[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 0,
71			  		AUTHTYPE_SRA, };
72
73#define SRA_KEY	0
74#define SRA_USER 1
75#define SRA_CONTINUE 2
76#define SRA_PASS 3
77#define SRA_ACCEPT 4
78#define SRA_REJECT 5
79
80static int check_user(char *, char *);
81
82/* support routine to send out authentication message */
83static int
84Data(Authenticator *ap, int type, void *d, int c)
85{
86        unsigned char *p = str_data + 4;
87	unsigned char *cd = (unsigned char *)d;
88
89	if (c == -1)
90		c = strlen((char *)cd);
91
92        if (auth_debug_mode) {
93                printf("%s:%d: [%d] (%d)",
94                        str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY",
95                        str_data[3],
96                        type, c);
97                printd(d, c);
98                printf("\r\n");
99        }
100	*p++ = ap->type;
101	*p++ = ap->way;
102	*p++ = type;
103        while (c-- > 0) {
104                if ((*p++ = *cd++) == IAC)
105                        *p++ = IAC;
106        }
107        *p++ = IAC;
108        *p++ = SE;
109	if (str_data[3] == TELQUAL_IS)
110		printsub('>', &str_data[2], p - (&str_data[2]));
111        return(net_write(str_data, p - str_data));
112}
113
114int
115sra_init(Authenticator *ap __unused, int server)
116{
117	if (server)
118		str_data[3] = TELQUAL_REPLY;
119	else
120		str_data[3] = TELQUAL_IS;
121
122	user = (char *)malloc(256);
123	xuser = (char *)malloc(513);
124	pass = (char *)malloc(256);
125	xpass = (char *)malloc(513);
126
127	if (user == NULL || xuser == NULL || pass == NULL || xpass ==
128	NULL)
129		return 0; /* malloc failed */
130
131	passwd_sent = 0;
132
133	genkeys(pka,ska);
134	return(1);
135}
136
137/* client received a go-ahead for sra */
138int
139sra_send(Authenticator *ap)
140{
141	/* send PKA */
142
143	if (auth_debug_mode)
144		printf("Sent PKA to server.\r\n" );
145	printf("Trying SRA secure login:\r\n");
146	if (!Data(ap, SRA_KEY, (void *)pka, HEXKEYBYTES)) {
147		if (auth_debug_mode)
148			printf("Not enough room for authentication data\r\n");
149		return(0);
150	}
151
152	return(1);
153}
154
155/* server received an IS -- could be SRA KEY, USER, or PASS */
156void
157sra_is(Authenticator *ap, unsigned char *data, int cnt)
158{
159	int valid;
160	Session_Key skey;
161
162	if (cnt-- < 1)
163		goto bad;
164	switch (*data++) {
165
166	case SRA_KEY:
167		if (cnt < HEXKEYBYTES) {
168			Data(ap, SRA_REJECT, (void *)0, 0);
169			auth_finished(ap, AUTH_USER);
170			if (auth_debug_mode) {
171				printf("SRA user rejected for bad PKB\r\n");
172			}
173			return;
174		}
175		if (auth_debug_mode)
176			printf("Sent pka\r\n");
177		if (!Data(ap, SRA_KEY, (void *)pka, HEXKEYBYTES)) {
178			if (auth_debug_mode)
179				printf("Not enough room\r\n");
180			return;
181		}
182		memcpy(pkb,data,HEXKEYBYTES);
183		pkb[HEXKEYBYTES] = '\0';
184		common_key(ska,pkb,&ik,&ck);
185		return;
186
187	case SRA_USER:
188		/* decode KAB(u) */
189		if (cnt > 512) /* Attempted buffer overflow */
190			break;
191		memcpy(xuser,data,cnt);
192		xuser[cnt] = '\0';
193		pk_decode(xuser,user,&ck);
194		auth_encrypt_user(user);
195		Data(ap, SRA_CONTINUE, (void *)0, 0);
196
197		return;
198
199	case SRA_PASS:
200		if (cnt > 512) /* Attempted buffer overflow */
201			break;
202		/* decode KAB(P) */
203		memcpy(xpass,data,cnt);
204		xpass[cnt] = '\0';
205		pk_decode(xpass,pass,&ck);
206
207		/* check user's password */
208		valid = check_user(user,pass);
209
210		if(valid) {
211			Data(ap, SRA_ACCEPT, (void *)0, 0);
212			skey.data = ck;
213			skey.type = SK_DES;
214			skey.length = 8;
215			encrypt_session_key(&skey, 1);
216
217			sra_valid = 1;
218			auth_finished(ap, AUTH_VALID);
219			if (auth_debug_mode) {
220				printf("SRA user accepted\r\n");
221			}
222		}
223		else {
224			Data(ap, SRA_CONTINUE, (void *)0, 0);
225/*
226			Data(ap, SRA_REJECT, (void *)0, 0);
227			sra_valid = 0;
228			auth_finished(ap, AUTH_REJECT);
229*/
230			if (auth_debug_mode) {
231				printf("SRA user failed\r\n");
232			}
233		}
234		return;
235
236	default:
237		if (auth_debug_mode)
238			printf("Unknown SRA option %d\r\n", data[-1]);
239	}
240bad:
241	Data(ap, SRA_REJECT, 0, 0);
242	sra_valid = 0;
243	auth_finished(ap, AUTH_REJECT);
244}
245
246/* client received REPLY -- could be SRA KEY, CONTINUE, ACCEPT, or REJECT */
247void
248sra_reply(Authenticator *ap, unsigned char *data, int cnt)
249{
250	char uprompt[256],tuser[256];
251	Session_Key skey;
252	size_t i;
253
254	if (cnt-- < 1)
255		return;
256	switch (*data++) {
257
258	case SRA_KEY:
259		/* calculate common key */
260		if (cnt < HEXKEYBYTES) {
261			if (auth_debug_mode) {
262				printf("SRA user rejected for bad PKB\r\n");
263			}
264			return;
265		}
266		memcpy(pkb,data,HEXKEYBYTES);
267		pkb[HEXKEYBYTES] = '\0';
268
269		common_key(ska,pkb,&ik,&ck);
270
271	enc_user:
272
273		/* encode user */
274		memset(tuser,0,sizeof(tuser));
275		sprintf(uprompt,"User (%s): ",UserNameRequested);
276		telnet_gets(uprompt,tuser,255,1);
277		if (tuser[0] == '\n' || tuser[0] == '\r' )
278			strcpy(user,UserNameRequested);
279		else {
280			/* telnet_gets leaves the newline on */
281			for(i=0;i<sizeof(tuser);i++) {
282				if (tuser[i] == '\n') {
283					tuser[i] = '\0';
284					break;
285				}
286			}
287			strcpy(user,tuser);
288		}
289		pk_encode(user,xuser,&ck);
290
291		/* send it off */
292		if (auth_debug_mode)
293			printf("Sent KAB(U)\r\n");
294		if (!Data(ap, SRA_USER, (void *)xuser, strlen(xuser))) {
295			if (auth_debug_mode)
296				printf("Not enough room\r\n");
297			return;
298		}
299		break;
300
301	case SRA_CONTINUE:
302		if (passwd_sent) {
303			passwd_sent = 0;
304			printf("[ SRA login failed ]\r\n");
305			goto enc_user;
306		}
307		/* encode password */
308		memset(pass,0,sizeof(pass));
309		telnet_gets("Password: ",pass,255,0);
310		pk_encode(pass,xpass,&ck);
311		/* send it off */
312		if (auth_debug_mode)
313			printf("Sent KAB(P)\r\n");
314		if (!Data(ap, SRA_PASS, (void *)xpass, strlen(xpass))) {
315			if (auth_debug_mode)
316				printf("Not enough room\r\n");
317			return;
318		}
319		passwd_sent = 1;
320		break;
321
322	case SRA_REJECT:
323		printf("[ SRA refuses authentication ]\r\n");
324		printf("Trying plaintext login:\r\n");
325		auth_finished(0,AUTH_REJECT);
326		return;
327
328	case SRA_ACCEPT:
329		printf("[ SRA accepts you ]\r\n");
330		skey.data = ck;
331		skey.type = SK_DES;
332		skey.length = 8;
333		encrypt_session_key(&skey, 0);
334
335		auth_finished(ap, AUTH_VALID);
336		return;
337	default:
338		if (auth_debug_mode)
339			printf("Unknown SRA option %d\r\n", data[-1]);
340		return;
341	}
342}
343
344int
345sra_status(Authenticator *ap __unused, char *name, int level)
346{
347	if (level < AUTH_USER)
348		return(level);
349	if (UserNameRequested && sra_valid) {
350		strcpy(name, UserNameRequested);
351		return(AUTH_VALID);
352	} else
353		return(AUTH_USER);
354}
355
356#define	BUMP(buf, len)		while (*(buf)) {++(buf), --(len);}
357#define	ADDC(buf, len, c)	if ((len) > 0) {*(buf)++ = (c); --(len);}
358
359void
360sra_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen)
361{
362	char lbuf[32];
363	int i;
364
365	buf[buflen-1] = '\0';		/* make sure its NULL terminated */
366	buflen -= 1;
367
368	switch(data[3]) {
369
370	case SRA_CONTINUE:
371		strncpy((char *)buf, " CONTINUE ", buflen);
372		goto common;
373
374	case SRA_REJECT:		/* Rejected (reason might follow) */
375		strncpy((char *)buf, " REJECT ", buflen);
376		goto common;
377
378	case SRA_ACCEPT:		/* Accepted (name might follow) */
379		strncpy((char *)buf, " ACCEPT ", buflen);
380
381	common:
382		BUMP(buf, buflen);
383		if (cnt <= 4)
384			break;
385		ADDC(buf, buflen, '"');
386		for (i = 4; i < cnt; i++)
387			ADDC(buf, buflen, data[i]);
388		ADDC(buf, buflen, '"');
389		ADDC(buf, buflen, '\0');
390		break;
391
392	case SRA_KEY:			/* Authentication data follows */
393		strncpy((char *)buf, " KEY ", buflen);
394		goto common2;
395
396	case SRA_USER:
397		strncpy((char *)buf, " USER ", buflen);
398		goto common2;
399
400	case SRA_PASS:
401		strncpy((char *)buf, " PASS ", buflen);
402		goto common2;
403
404	default:
405		sprintf(lbuf, " %d (unknown)", data[3]);
406		strncpy((char *)buf, lbuf, buflen);
407	common2:
408		BUMP(buf, buflen);
409		for (i = 4; i < cnt; i++) {
410			sprintf(lbuf, " %d", data[i]);
411			strncpy((char *)buf, lbuf, buflen);
412			BUMP(buf, buflen);
413		}
414		break;
415	}
416}
417
418static int
419isroot(const char *usr)
420{
421	struct passwd *pwd;
422
423	if ((pwd=getpwnam(usr))==NULL)
424		return 0;
425	return (!pwd->pw_uid);
426}
427
428static int
429rootterm(char *ttyn)
430{
431	struct ttyent *t;
432
433	return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE);
434}
435
436#ifdef NOPAM
437static int
438check_user(char *name, char *cred)
439{
440	char *cp;
441	char *xpasswd, *salt;
442
443	if (isroot(name) && !rootterm(line))
444	{
445		crypt("AA","*"); /* Waste some time to simulate success */
446		return(0);
447	}
448
449	if (pw = sgetpwnam(name)) {
450		if (pw->pw_shell == NULL) {
451			pw = (struct passwd *) NULL;
452			return(0);
453		}
454
455		salt = pw->pw_passwd;
456		xpasswd = crypt(cred, salt);
457		/* The strcmp does not catch null passwords! */
458		if (pw == NULL || *pw->pw_passwd == '\0' ||
459			strcmp(xpasswd, pw->pw_passwd)) {
460			pw = (struct passwd *) NULL;
461			return(0);
462		}
463		return(1);
464	}
465	return(0);
466}
467#else
468
469/*
470 * The following is stolen from ftpd, which stole it from the imap-uw
471 * PAM module and login.c. It is needed because we can't really
472 * "converse" with the user, having already gone to the trouble of
473 * getting their username and password through an encrypted channel.
474 */
475
476#define COPY_STRING(s) (s ? strdup(s):NULL)
477
478struct cred_t {
479	const char *uname;
480	const char *pass;
481};
482typedef struct cred_t cred_t;
483
484static int
485auth_conv(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata)
486{
487	int i;
488	cred_t *cred = (cred_t *) appdata;
489	struct pam_response *reply =
490		malloc(sizeof(struct pam_response) * num_msg);
491
492	if (reply == NULL)
493		return PAM_BUF_ERR;
494
495	for (i = 0; i < num_msg; i++) {
496		switch (msg[i]->msg_style) {
497		case PAM_PROMPT_ECHO_ON:        /* assume want user name */
498			reply[i].resp_retcode = PAM_SUCCESS;
499			reply[i].resp = COPY_STRING(cred->uname);
500			/* PAM frees resp. */
501			break;
502		case PAM_PROMPT_ECHO_OFF:       /* assume want password */
503			reply[i].resp_retcode = PAM_SUCCESS;
504			reply[i].resp = COPY_STRING(cred->pass);
505			/* PAM frees resp. */
506			break;
507		case PAM_TEXT_INFO:
508		case PAM_ERROR_MSG:
509			reply[i].resp_retcode = PAM_SUCCESS;
510			reply[i].resp = NULL;
511			break;
512		default:                        /* unknown message style */
513			free(reply);
514			return PAM_CONV_ERR;
515		}
516	}
517
518	*resp = reply;
519	return PAM_SUCCESS;
520}
521
522/*
523 * The PAM version as a side effect may put a new username in *name.
524 */
525static int
526check_user(char *name, char *cred)
527{
528	pam_handle_t *pamh = NULL;
529	const void *item;
530	int rval;
531	int e;
532	cred_t auth_cred = { name, cred };
533	struct pam_conv conv = { &auth_conv, &auth_cred };
534
535	e = pam_start("telnetd", name, &conv, &pamh);
536	if (e != PAM_SUCCESS) {
537		syslog(LOG_ERR, "pam_start: %s", pam_strerror(pamh, e));
538		return 0;
539	}
540
541#if 0 /* Where can we find this value? */
542	e = pam_set_item(pamh, PAM_RHOST, remotehost);
543	if (e != PAM_SUCCESS) {
544		syslog(LOG_ERR, "pam_set_item(PAM_RHOST): %s",
545			pam_strerror(pamh, e));
546		return 0;
547	}
548#endif
549
550	e = pam_authenticate(pamh, 0);
551	switch (e) {
552	case PAM_SUCCESS:
553		/*
554		 * With PAM we support the concept of a "template"
555		 * user.  The user enters a login name which is
556		 * authenticated by PAM, usually via a remote service
557		 * such as RADIUS or TACACS+.  If authentication
558		 * succeeds, a different but related "template" name
559		 * is used for setting the credentials, shell, and
560		 * home directory.  The name the user enters need only
561		 * exist on the remote authentication server, but the
562		 * template name must be present in the local password
563		 * database.
564		 *
565		 * This is supported by two various mechanisms in the
566		 * individual modules.  However, from the application's
567		 * point of view, the template user is always passed
568		 * back as a changed value of the PAM_USER item.
569		 */
570		if ((e = pam_get_item(pamh, PAM_USER, &item)) ==
571		    PAM_SUCCESS) {
572			strcpy(name, item);
573		} else
574			syslog(LOG_ERR, "Couldn't get PAM_USER: %s",
575			pam_strerror(pamh, e));
576		if (isroot(name) && !rootterm(line))
577			rval = 0;
578		else
579			rval = 1;
580		break;
581
582	case PAM_AUTH_ERR:
583	case PAM_USER_UNKNOWN:
584	case PAM_MAXTRIES:
585		rval = 0;
586	break;
587
588	default:
589		syslog(LOG_ERR, "auth_pam: %s", pam_strerror(pamh, e));
590		rval = 0;
591		break;
592	}
593
594	if ((e = pam_end(pamh, e)) != PAM_SUCCESS) {
595		syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e));
596		rval = 0;
597	}
598	return rval;
599}
600
601#endif
602
603#endif /* ENCRYPTION */
604#endif /* SRA */
605