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