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