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