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