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