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