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