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