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