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