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