sra.c revision 81965
180016Sobrien/* $FreeBSD: head/contrib/telnet/libtelnet/sra.c 81965 2001-08-20 12:28:40Z markm $ */
280016Sobrien
380016Sobrien#ifdef	SRA
480016Sobrien#include <sys/types.h>
580016Sobrien#include <arpa/telnet.h>
6130561Sobrien#include <stdio.h>
780016Sobrien#ifdef	__STDC__
880016Sobrien#include <stdlib.h>
980016Sobrien#endif
1080016Sobrien#ifdef	NO_STRING_H
1180016Sobrien#include <strings.h>
1280016Sobrien#else
1380016Sobrien#include <string.h>
1480016Sobrien#endif
15
16#if !defined(NOPAM)
17#include <security/pam_appl.h>
18#else
19#include <unistd.h>
20#endif
21
22#include <pwd.h>
23#include <syslog.h>
24#include <ttyent.h>
25
26#include "auth.h"
27#include "misc.h"
28#include "encrypt.h"
29#include "pk.h"
30
31char pka[HEXKEYBYTES+1], ska[HEXKEYBYTES+1], pkb[HEXKEYBYTES+1];
32char *user,*pass,*xuser,*xpass;
33DesData ck;
34IdeaData ik;
35
36extern int auth_debug_mode;
37extern char *line;
38
39static int sra_valid = 0;
40static int passwd_sent = 0;
41
42static unsigned char str_data[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 0,
43			  		AUTHTYPE_SRA, };
44
45#define SRA_KEY	0
46#define SRA_USER 1
47#define SRA_CONTINUE 2
48#define SRA_PASS 3
49#define SRA_ACCEPT 4
50#define SRA_REJECT 5
51
52static int check_user(const char *, const char *);
53
54/* support routine to send out authentication message */
55static int
56Data(Authenticator *ap, int type, void *d, int c)
57{
58        unsigned char *p = str_data + 4;
59	unsigned char *cd = (unsigned char *)d;
60
61	if (c == -1)
62		c = strlen((char *)cd);
63
64        if (auth_debug_mode) {
65                printf("%s:%d: [%d] (%d)",
66                        str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY",
67                        str_data[3],
68                        type, c);
69                printd(d, c);
70                printf("\r\n");
71        }
72	*p++ = ap->type;
73	*p++ = ap->way;
74	*p++ = type;
75        while (c-- > 0) {
76                if ((*p++ = *cd++) == IAC)
77                        *p++ = IAC;
78        }
79        *p++ = IAC;
80        *p++ = SE;
81	if (str_data[3] == TELQUAL_IS)
82		printsub('>', &str_data[2], p - (&str_data[2]));
83        return(net_write(str_data, p - str_data));
84}
85
86int
87sra_init(Authenticator *ap, int server)
88{
89	if (server)
90		str_data[3] = TELQUAL_REPLY;
91	else
92		str_data[3] = TELQUAL_IS;
93
94	user = (char *)malloc(256);
95	xuser = (char *)malloc(513);
96	pass = (char *)malloc(256);
97	xpass = (char *)malloc(513);
98
99	if (user == NULL || xuser == NULL || pass == NULL || xpass ==
100	NULL)
101		return 0; /* malloc failed */
102
103	passwd_sent = 0;
104
105	genkeys(pka,ska);
106	return(1);
107}
108
109/* client received a go-ahead for sra */
110int
111sra_send(Authenticator *ap)
112{
113	/* send PKA */
114
115	if (auth_debug_mode)
116		printf("Sent PKA to server.\r\n" );
117	printf("Trying SRA secure login:\r\n");
118	if (!Data(ap, SRA_KEY, (void *)pka, HEXKEYBYTES)) {
119		if (auth_debug_mode)
120			printf("Not enough room for authentication data\r\n");
121		return(0);
122	}
123
124	return(1);
125}
126
127/* server received an IS -- could be SRA KEY, USER, or PASS */
128void
129sra_is(Authenticator *ap, unsigned char *data, int 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
220/* client received REPLY -- could be SRA KEY, CONTINUE, ACCEPT, or REJECT */
221void
222sra_reply(Authenticator *ap, unsigned char *data, int 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
322sra_status(Authenticator *ap, char *name, int level)
323{
324	if (level < AUTH_USER)
325		return(level);
326	if (UserNameRequested && sra_valid) {
327		strcpy(name, UserNameRequested);
328		return(AUTH_VALID);
329	} else
330		return(AUTH_USER);
331}
332
333#define	BUMP(buf, len)		while (*(buf)) {++(buf), --(len);}
334#define	ADDC(buf, len, c)	if ((len) > 0) {*(buf)++ = (c); --(len);}
335
336void
337sra_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen)
338{
339	char lbuf[32];
340	register int i;
341
342	buf[buflen-1] = '\0';		/* make sure its NULL terminated */
343	buflen -= 1;
344
345	switch(data[3]) {
346
347	case SRA_CONTINUE:
348		strncpy((char *)buf, " CONTINUE ", buflen);
349		goto common;
350
351	case SRA_REJECT:		/* Rejected (reason might follow) */
352		strncpy((char *)buf, " REJECT ", buflen);
353		goto common;
354
355	case SRA_ACCEPT:		/* Accepted (name might follow) */
356		strncpy((char *)buf, " ACCEPT ", buflen);
357
358	common:
359		BUMP(buf, buflen);
360		if (cnt <= 4)
361			break;
362		ADDC(buf, buflen, '"');
363		for (i = 4; i < cnt; i++)
364			ADDC(buf, buflen, data[i]);
365		ADDC(buf, buflen, '"');
366		ADDC(buf, buflen, '\0');
367		break;
368
369	case SRA_KEY:			/* Authentication data follows */
370		strncpy((char *)buf, " KEY ", buflen);
371		goto common2;
372
373	case SRA_USER:
374		strncpy((char *)buf, " USER ", buflen);
375		goto common2;
376
377	case SRA_PASS:
378		strncpy((char *)buf, " PASS ", buflen);
379		goto common2;
380
381	default:
382		sprintf(lbuf, " %d (unknown)", data[3]);
383		strncpy((char *)buf, lbuf, buflen);
384	common2:
385		BUMP(buf, buflen);
386		for (i = 4; i < cnt; i++) {
387			sprintf(lbuf, " %d", data[i]);
388			strncpy((char *)buf, lbuf, buflen);
389			BUMP(buf, buflen);
390		}
391		break;
392	}
393}
394
395struct	passwd *pw;
396
397/*
398 * Helper function for sgetpwnam().
399 */
400char *
401sgetsave(char *s)
402{
403	char *new = malloc((unsigned) strlen(s) + 1);
404
405	if (new == NULL) {
406		return(NULL);
407	}
408	(void) strcpy(new, s);
409	return (new);
410}
411
412struct passwd *
413sgetpwnam(char *name)
414{
415	static struct passwd save;
416	register struct passwd *p;
417	char *sgetsave();
418
419	if ((p = getpwnam(name)) == NULL)
420		return (p);
421	if (save.pw_name) {
422		free(save.pw_name);
423		free(save.pw_passwd);
424		free(save.pw_gecos);
425		free(save.pw_dir);
426		free(save.pw_shell);
427	}
428	save = *p;
429	save.pw_name = sgetsave(p->pw_name);
430	save.pw_passwd = sgetsave(p->pw_passwd);
431	save.pw_gecos = sgetsave(p->pw_gecos);
432	save.pw_dir = sgetsave(p->pw_dir);
433	save.pw_shell = sgetsave(p->pw_shell);
434#if 0
435syslog(LOG_WARNING,"%s\n",save.pw_name);
436syslog(LOG_WARNING,"%s\n",save.pw_passwd);
437syslog(LOG_WARNING,"%s\n",save.pw_gecos);
438syslog(LOG_WARNING,"%s\n",save.pw_dir);
439#endif
440#ifdef USE_SHADOW
441        {
442                struct spwd *sp;
443                sp = getspnam(name);
444                free(save.pw_passwd);
445                save.pw_passwd  = sgetsave(sp->sp_pwdp);
446        }
447#endif
448	return (&save);
449}
450
451static int
452isroot(const char *user)
453{
454	struct passwd *pw;
455
456	if ((pw=getpwnam(user))==NULL)
457		return 0;
458	return (!pw->pw_uid);
459}
460
461static int
462rootterm(char *ttyn)
463{
464	struct ttyent *t;
465
466	return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE);
467}
468
469#ifdef NOPAM
470static int
471check_user(const char *name, const char *pass)
472{
473	register char *cp;
474	char *xpasswd, *salt;
475
476	if (isroot(name) && !rootterm(line))
477	{
478		crypt("AA","*"); /* Waste some time to simulate success */
479		return(0);
480	}
481
482	if (pw = sgetpwnam(name)) {
483		if (pw->pw_shell == NULL) {
484			pw = (struct passwd *) NULL;
485			return(0);
486		}
487
488		salt = pw->pw_passwd;
489		xpasswd = crypt(pass, salt);
490		/* The strcmp does not catch null passwords! */
491		if (pw == NULL || *pw->pw_passwd == '\0' ||
492			strcmp(xpasswd, pw->pw_passwd)) {
493			pw = (struct passwd *) NULL;
494			return(0);
495		}
496		return(1);
497	}
498	return(0);
499}
500#else
501
502/*
503 * The following is stolen from ftpd, which stole it from the imap-uw
504 * PAM module and login.c. It is needed because we can't really
505 * "converse" with the user, having already gone to the trouble of
506 * getting their username and password through an encrypted channel.
507 */
508
509#define COPY_STRING(s) (s ? strdup(s):NULL)
510
511struct cred_t {
512	const char *uname;
513	const char *pass;
514};
515typedef struct cred_t cred_t;
516
517int
518auth_conv(int num_msg, const struct pam_message **msg,
519	struct pam_response **resp, void *appdata)
520{
521	int i;
522	cred_t *cred = (cred_t *) appdata;
523	struct pam_response *reply =
524		malloc(sizeof(struct pam_response) * num_msg);
525
526	if (reply == NULL)
527		return PAM_BUF_ERR;
528
529	for (i = 0; i < num_msg; i++) {
530		switch (msg[i]->msg_style) {
531		case PAM_PROMPT_ECHO_ON:        /* assume want user name */
532			reply[i].resp_retcode = PAM_SUCCESS;
533			reply[i].resp = COPY_STRING(cred->uname);
534			/* PAM frees resp. */
535			break;
536		case PAM_PROMPT_ECHO_OFF:       /* assume want password */
537			reply[i].resp_retcode = PAM_SUCCESS;
538			reply[i].resp = COPY_STRING(cred->pass);
539			/* PAM frees resp. */
540			break;
541		case PAM_TEXT_INFO:
542		case PAM_ERROR_MSG:
543			reply[i].resp_retcode = PAM_SUCCESS;
544			reply[i].resp = NULL;
545			break;
546		default:                        /* unknown message style */
547			free(reply);
548			return PAM_CONV_ERR;
549		}
550	}
551
552	*resp = reply;
553	return PAM_SUCCESS;
554}
555
556/*
557 * The PAM version as a side effect may put a new username in *name.
558 */
559static int
560check_user(const char *name, const char *pass)
561{
562	pam_handle_t *pamh = NULL;
563	const void *item;
564	int rval;
565	int e;
566	cred_t auth_cred = { name, pass };
567	struct pam_conv conv = { &auth_conv, &auth_cred };
568
569	e = pam_start("telnetd", name, &conv, &pamh);
570	if (e != PAM_SUCCESS) {
571		syslog(LOG_ERR, "pam_start: %s", pam_strerror(pamh, e));
572		return 0;
573	}
574
575#if 0 /* Where can we find this value? */
576	e = pam_set_item(pamh, PAM_RHOST, remotehost);
577	if (e != PAM_SUCCESS) {
578		syslog(LOG_ERR, "pam_set_item(PAM_RHOST): %s",
579			pam_strerror(pamh, e));
580		return 0;
581	}
582#endif
583
584	e = pam_authenticate(pamh, 0);
585	switch (e) {
586	case PAM_SUCCESS:
587		/*
588		 * With PAM we support the concept of a "template"
589		 * user.  The user enters a login name which is
590		 * authenticated by PAM, usually via a remote service
591		 * such as RADIUS or TACACS+.  If authentication
592		 * succeeds, a different but related "template" name
593		 * is used for setting the credentials, shell, and
594		 * home directory.  The name the user enters need only
595		 * exist on the remote authentication server, but the
596		 * template name must be present in the local password
597		 * database.
598		 *
599		 * This is supported by two various mechanisms in the
600		 * individual modules.  However, from the application's
601		 * point of view, the template user is always passed
602		 * back as a changed value of the PAM_USER item.
603		 */
604		if ((e = pam_get_item(pamh, PAM_USER, &item)) ==
605		    PAM_SUCCESS) {
606			strcpy((char *) name, (const char *) item);
607		} else
608			syslog(LOG_ERR, "Couldn't get PAM_USER: %s",
609			pam_strerror(pamh, e));
610		if (isroot(name) && !rootterm(line))
611			rval = 0;
612		else
613			rval = 1;
614		break;
615
616	case PAM_AUTH_ERR:
617	case PAM_USER_UNKNOWN:
618	case PAM_MAXTRIES:
619		rval = 0;
620	break;
621
622	default:
623		syslog(LOG_ERR, "auth_pam: %s", pam_strerror(pamh, e));
624		rval = 0;
625		break;
626	}
627
628	if ((e = pam_end(pamh, e)) != PAM_SUCCESS) {
629		syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e));
630		rval = 0;
631	}
632	return rval;
633}
634
635#endif
636
637#endif
638
639