xref: /freebsd/crypto/heimdal/appl/telnet/libtelnet/spx.c (revision fcb560670601b2a4d87bb31d7531c8dcc37ee71b)
1 /*-
2  * Copyright (c) 1992, 1993
3  *	The Regents of the University of California.  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. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #include <config.h>
35 
36 RCSID("$Id$");
37 
38 #ifdef	SPX
39 /*
40  * COPYRIGHT (C) 1990 DIGITAL EQUIPMENT CORPORATION
41  * ALL RIGHTS RESERVED
42  *
43  * "Digital Equipment Corporation authorizes the reproduction,
44  * distribution and modification of this software subject to the following
45  * restrictions:
46  *
47  * 1.  Any partial or whole copy of this software, or any modification
48  * thereof, must include this copyright notice in its entirety.
49  *
50  * 2.  This software is supplied "as is" with no warranty of any kind,
51  * expressed or implied, for any purpose, including any warranty of fitness
52  * or merchantibility.  DIGITAL assumes no responsibility for the use or
53  * reliability of this software, nor promises to provide any form of
54  * support for it on any basis.
55  *
56  * 3.  Distribution of this software is authorized only if no profit or
57  * remuneration of any kind is received in exchange for such distribution.
58  *
59  * 4.  This software produces public key authentication certificates
60  * bearing an expiration date established by DIGITAL and RSA Data
61  * Security, Inc.  It may cease to generate certificates after the expiration
62  * date.  Any modification of this software that changes or defeats
63  * the expiration date or its effect is unauthorized.
64  *
65  * 5.  Software that will renew or extend the expiration date of
66  * authentication certificates produced by this software may be obtained
67  * from RSA Data Security, Inc., 10 Twin Dolphin Drive, Redwood City, CA
68  * 94065, (415)595-8782, or from DIGITAL"
69  *
70  */
71 
72 #ifdef HAVE_SYS_TYPES_H
73 #include <sys/types.h>
74 #endif
75 #ifdef HAVE_ARPA_TELNET_H
76 #include <arpa/telnet.h>
77 #endif
78 #include <stdio.h>
79 #include "gssapi_defs.h"
80 #include <stdlib.h>
81 #include <string.h>
82 
83 #include <pwd.h>
84 #ifdef SOCKS
85 #include <socks.h>
86 #endif
87 
88 #include "encrypt.h"
89 #include "auth.h"
90 #include "misc.h"
91 
92 extern auth_debug_mode;
93 
94 static unsigned char str_data[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 0,
95 			  		AUTHTYPE_SPX, };
96 static unsigned char str_name[1024] = { IAC, SB, TELOPT_AUTHENTICATION,
97 					TELQUAL_NAME, };
98 
99 #define	SPX_AUTH	0		/* Authentication data follows */
100 #define	SPX_REJECT	1		/* Rejected (reason might follow) */
101 #define SPX_ACCEPT	2		/* Accepted */
102 
103 static des_key_schedule sched;
104 static des_cblock	challenge	= { 0 };
105 
106 
107 /*******************************************************************/
108 
109 gss_OID_set		actual_mechs;
110 gss_OID			actual_mech_type, output_name_type;
111 int			major_status, status, msg_ctx = 0, new_status;
112 int			req_flags = 0, ret_flags, lifetime_rec;
113 gss_cred_id_t		gss_cred_handle;
114 gss_ctx_id_t		actual_ctxhandle, context_handle;
115 gss_buffer_desc		output_token, input_token, input_name_buffer;
116 gss_buffer_desc		status_string;
117 gss_name_t		desired_targname, src_name;
118 gss_channel_bindings	input_chan_bindings;
119 char			lhostname[GSS_C_MAX_PRINTABLE_NAME];
120 char			targ_printable[GSS_C_MAX_PRINTABLE_NAME];
121 int			to_addr=0, from_addr=0;
122 char			*address;
123 gss_buffer_desc		fullname_buffer;
124 gss_OID			fullname_type;
125 gss_cred_id_t		gss_delegated_cred_handle;
126 
127 /*******************************************************************/
128 
129 
130 
131 	static int
132 Data(ap, type, d, c)
133 	Authenticator *ap;
134 	int type;
135 	void *d;
136 	int c;
137 {
138 	unsigned char *p = str_data + 4;
139 	unsigned char *cd = (unsigned char *)d;
140 
141 	if (c == -1)
142 		c = strlen((char *)cd);
143 
144 	if (0) {
145 		printf("%s:%d: [%d] (%d)",
146 			str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY",
147 			str_data[3],
148 			type, c);
149 		printd(d, c);
150 		printf("\r\n");
151 	}
152 	*p++ = ap->type;
153 	*p++ = ap->way;
154 	*p++ = type;
155 	while (c-- > 0) {
156 		if ((*p++ = *cd++) == IAC)
157 			*p++ = IAC;
158 	}
159 	*p++ = IAC;
160 	*p++ = SE;
161 	if (str_data[3] == TELQUAL_IS)
162 		printsub('>', &str_data[2], p - (&str_data[2]));
163 	return(telnet_net_write(str_data, p - str_data));
164 }
165 
166 	int
167 spx_init(ap, server)
168 	Authenticator *ap;
169 	int server;
170 {
171 	gss_cred_id_t	tmp_cred_handle;
172 
173 	if (server) {
174 		str_data[3] = TELQUAL_REPLY;
175 		gethostname(lhostname, sizeof(lhostname));
176 		snprintf (targ_printable, sizeof(targ_printable),
177 			  "SERVICE:rcmd@%s", lhostname);
178 		input_name_buffer.length = strlen(targ_printable);
179 		input_name_buffer.value = targ_printable;
180 		major_status = gss_import_name(&status,
181 					&input_name_buffer,
182 					GSS_C_NULL_OID,
183 					&desired_targname);
184 		major_status = gss_acquire_cred(&status,
185 					desired_targname,
186 					0,
187 					GSS_C_NULL_OID_SET,
188 					GSS_C_ACCEPT,
189 					&tmp_cred_handle,
190 					&actual_mechs,
191 					&lifetime_rec);
192 		if (major_status != GSS_S_COMPLETE) return(0);
193 	} else {
194 		str_data[3] = TELQUAL_IS;
195 	}
196 	return(1);
197 }
198 
199 	int
200 spx_send(ap)
201 	Authenticator *ap;
202 {
203 	des_cblock enckey;
204 	int r;
205 
206 	gss_OID	actual_mech_type, output_name_type;
207 	int	msg_ctx = 0, new_status, status;
208 	int	req_flags = 0, ret_flags, lifetime_rec, major_status;
209 	gss_buffer_desc  output_token, input_token, input_name_buffer;
210 	gss_buffer_desc  output_name_buffer, status_string;
211 	gss_name_t    desired_targname;
212 	gss_channel_bindings  input_chan_bindings;
213 	char targ_printable[GSS_C_MAX_PRINTABLE_NAME];
214 	int  from_addr=0, to_addr=0, myhostlen, j;
215 	int  deleg_flag=1, mutual_flag=0, replay_flag=0, seq_flag=0;
216 	char *address;
217 
218 	printf("[ Trying SPX ... ]\r\n");
219 	snprintf (targ_printable, sizeof(targ_printable),
220 		  "SERVICE:rcmd@%s", RemoteHostName);
221 
222 	input_name_buffer.length = strlen(targ_printable);
223 	input_name_buffer.value = targ_printable;
224 
225 	if (!UserNameRequested) {
226 		return(0);
227 	}
228 
229 	major_status = gss_import_name(&status,
230 					&input_name_buffer,
231 					GSS_C_NULL_OID,
232 					&desired_targname);
233 
234 
235 	major_status = gss_display_name(&status,
236 					desired_targname,
237 					&output_name_buffer,
238 					&output_name_type);
239 
240 	printf("target is '%.*s'\n", (int)output_name_buffer.length,
241 					(char*)output_name_buffer.value);
242 	fflush(stdout);
243 
244 	major_status = gss_release_buffer(&status, &output_name_buffer);
245 
246 	input_chan_bindings = (gss_channel_bindings)
247 	  malloc(sizeof(gss_channel_bindings_desc));
248 
249 	input_chan_bindings->initiator_addrtype = GSS_C_AF_INET;
250 	input_chan_bindings->initiator_address.length = 4;
251 	address = (char *) malloc(4);
252 	input_chan_bindings->initiator_address.value = (char *) address;
253 	address[0] = ((from_addr & 0xff000000) >> 24);
254 	address[1] = ((from_addr & 0xff0000) >> 16);
255 	address[2] = ((from_addr & 0xff00) >> 8);
256 	address[3] = (from_addr & 0xff);
257 	input_chan_bindings->acceptor_addrtype = GSS_C_AF_INET;
258 	input_chan_bindings->acceptor_address.length = 4;
259 	address = (char *) malloc(4);
260 	input_chan_bindings->acceptor_address.value = (char *) address;
261 	address[0] = ((to_addr & 0xff000000) >> 24);
262 	address[1] = ((to_addr & 0xff0000) >> 16);
263 	address[2] = ((to_addr & 0xff00) >> 8);
264 	address[3] = (to_addr & 0xff);
265 	input_chan_bindings->application_data.length = 0;
266 
267 	req_flags = 0;
268 	if (deleg_flag)  req_flags = req_flags | 1;
269 	if (mutual_flag) req_flags = req_flags | 2;
270 	if (replay_flag) req_flags = req_flags | 4;
271 	if (seq_flag)    req_flags = req_flags | 8;
272 
273 	major_status = gss_init_sec_context(&status,         /* minor status */
274 					GSS_C_NO_CREDENTIAL, /* cred handle */
275 					&actual_ctxhandle,   /* ctx handle */
276 					desired_targname,    /* target name */
277 					GSS_C_NULL_OID,      /* mech type */
278 					req_flags,           /* req flags */
279 					0,                   /* time req */
280 					input_chan_bindings, /* chan binding */
281 					GSS_C_NO_BUFFER,     /* input token */
282 					&actual_mech_type,   /* actual mech */
283 					&output_token,       /* output token */
284 					&ret_flags,          /* ret flags */
285 					&lifetime_rec);      /* time rec */
286 
287 	if ((major_status != GSS_S_COMPLETE) &&
288 	    (major_status != GSS_S_CONTINUE_NEEDED)) {
289 	  gss_display_status(&new_status,
290 				status,
291 				GSS_C_MECH_CODE,
292 				GSS_C_NULL_OID,
293 				&msg_ctx,
294 				&status_string);
295 	  printf("%.*s\n", (int)status_string.length,
296 				(char*)status_string.value);
297 	  return(0);
298 	}
299 
300 	if (!auth_sendname(UserNameRequested, strlen(UserNameRequested))) {
301 		return(0);
302 	}
303 
304 	if (!Data(ap, SPX_AUTH, output_token.value, output_token.length)) {
305 		return(0);
306 	}
307 
308 	return(1);
309 }
310 
311 	void
312 spx_is(ap, data, cnt)
313 	Authenticator *ap;
314 	unsigned char *data;
315 	int cnt;
316 {
317 	Session_Key skey;
318 	des_cblock datablock;
319 	int r;
320 
321 	if (cnt-- < 1)
322 		return;
323 	switch (*data++) {
324 	case SPX_AUTH:
325 		input_token.length = cnt;
326 		input_token.value = (char *) data;
327 
328 		gethostname(lhostname, sizeof(lhostname));
329 
330 		snprintf(targ_printable, sizeof(targ_printable),
331 			 "SERVICE:rcmd@%s", lhostname);
332 
333 		input_name_buffer.length = strlen(targ_printable);
334 		input_name_buffer.value = targ_printable;
335 
336 		major_status = gss_import_name(&status,
337 					&input_name_buffer,
338 					GSS_C_NULL_OID,
339 					&desired_targname);
340 
341 		major_status = gss_acquire_cred(&status,
342 					desired_targname,
343 					0,
344 					GSS_C_NULL_OID_SET,
345 					GSS_C_ACCEPT,
346 					&gss_cred_handle,
347 					&actual_mechs,
348 					&lifetime_rec);
349 
350 		major_status = gss_release_name(&status, desired_targname);
351 
352 		input_chan_bindings = (gss_channel_bindings)
353 		  malloc(sizeof(gss_channel_bindings_desc));
354 
355 		input_chan_bindings->initiator_addrtype = GSS_C_AF_INET;
356 		input_chan_bindings->initiator_address.length = 4;
357 		address = (char *) malloc(4);
358 		input_chan_bindings->initiator_address.value = (char *) address;
359 		address[0] = ((from_addr & 0xff000000) >> 24);
360 		address[1] = ((from_addr & 0xff0000) >> 16);
361 		address[2] = ((from_addr & 0xff00) >> 8);
362 		address[3] = (from_addr & 0xff);
363 		input_chan_bindings->acceptor_addrtype = GSS_C_AF_INET;
364 		input_chan_bindings->acceptor_address.length = 4;
365 		address = (char *) malloc(4);
366 		input_chan_bindings->acceptor_address.value = (char *) address;
367 		address[0] = ((to_addr & 0xff000000) >> 24);
368 		address[1] = ((to_addr & 0xff0000) >> 16);
369 		address[2] = ((to_addr & 0xff00) >> 8);
370 		address[3] = (to_addr & 0xff);
371 		input_chan_bindings->application_data.length = 0;
372 
373 		major_status = gss_accept_sec_context(&status,
374 						&context_handle,
375 						gss_cred_handle,
376 						&input_token,
377 						input_chan_bindings,
378 						&src_name,
379 						&actual_mech_type,
380 						&output_token,
381 						&ret_flags,
382 						&lifetime_rec,
383 						&gss_delegated_cred_handle);
384 
385 
386 		if (major_status != GSS_S_COMPLETE) {
387 
388 		  major_status = gss_display_name(&status,
389 					src_name,
390 					&fullname_buffer,
391 					&fullname_type);
392 			Data(ap, SPX_REJECT, "auth failed", -1);
393 			auth_finished(ap, AUTH_REJECT);
394 			return;
395 		}
396 
397 		major_status = gss_display_name(&status,
398 					src_name,
399 					&fullname_buffer,
400 					&fullname_type);
401 
402 
403 		Data(ap, SPX_ACCEPT, output_token.value, output_token.length);
404 		auth_finished(ap, AUTH_USER);
405 		break;
406 
407 	default:
408 		Data(ap, SPX_REJECT, 0, 0);
409 		break;
410 	}
411 }
412 
413 
414 	void
415 spx_reply(ap, data, cnt)
416 	Authenticator *ap;
417 	unsigned char *data;
418 	int cnt;
419 {
420 	Session_Key skey;
421 
422 	if (cnt-- < 1)
423 		return;
424 	switch (*data++) {
425 	case SPX_REJECT:
426 		if (cnt > 0) {
427 			printf("[ SPX refuses authentication because %.*s ]\r\n",
428 				cnt, data);
429 		} else
430 			printf("[ SPX refuses authentication ]\r\n");
431 		auth_send_retry();
432 		return;
433 	case SPX_ACCEPT:
434 		printf("[ SPX accepts you ]\r\n");
435 		if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
436 			/*
437 			 * Send over the encrypted challenge.
438 		 	 */
439 		  input_token.value = (char *) data;
440 		  input_token.length = cnt;
441 
442 		  major_status = gss_init_sec_context(&status, /* minor stat */
443 					GSS_C_NO_CREDENTIAL, /* cred handle */
444 					&actual_ctxhandle,   /* ctx handle */
445 					desired_targname,    /* target name */
446 					GSS_C_NULL_OID,      /* mech type */
447 					req_flags,           /* req flags */
448 					0,                   /* time req */
449 					input_chan_bindings, /* chan binding */
450 					&input_token,        /* input token */
451 					&actual_mech_type,   /* actual mech */
452 					&output_token,       /* output token */
453 					&ret_flags,          /* ret flags */
454 					&lifetime_rec);      /* time rec */
455 
456 		  if (major_status != GSS_S_COMPLETE) {
457 		    gss_display_status(&new_status,
458 					status,
459 					GSS_C_MECH_CODE,
460 					GSS_C_NULL_OID,
461 					&msg_ctx,
462 					&status_string);
463 		    printf("[ SPX mutual response fails ... '%.*s' ]\r\n",
464 			 (int)status_string.length,
465 			 (char*)status_string.value);
466 		    auth_send_retry();
467 		    return;
468 		  }
469 		}
470 		auth_finished(ap, AUTH_USER);
471 		return;
472 
473 	default:
474 		return;
475 	}
476 }
477 
478 	int
479 spx_status(ap, name, name_sz, level)
480 	Authenticator *ap;
481 	char *name;
482 	size_t name_sz;
483 	int level;
484 {
485 
486 	gss_buffer_desc  fullname_buffer, acl_file_buffer;
487 	gss_OID          fullname_type;
488 	char acl_file[160], fullname[160];
489 	int major_status, status = 0;
490 	struct passwd  *pwd;
491 
492 	/*
493 	 * hard code fullname to
494 	 *   "SPX:/C=US/O=Digital/OU=LKG/OU=Sphinx/OU=Users/CN=Kannan Alagappan"
495 	 * and acl_file to "~kannan/.sphinx"
496 	 */
497 
498 	pwd = k_getpwnam(UserNameRequested);
499 	if (pwd == NULL) {
500 	  return(AUTH_USER);   /*  not authenticated  */
501 	}
502 
503 	snprintf (acl_file, sizeof(acl_file),
504 		  "%s/.sphinx", pwd->pw_dir);
505 
506 	acl_file_buffer.value = acl_file;
507 	acl_file_buffer.length = strlen(acl_file);
508 
509 	major_status = gss_display_name(&status,
510 					src_name,
511 					&fullname_buffer,
512 					&fullname_type);
513 
514 	if (level < AUTH_USER)
515 		return(level);
516 
517 	major_status = gss__check_acl(&status, &fullname_buffer,
518 					&acl_file_buffer);
519 
520 	if (major_status == GSS_S_COMPLETE) {
521 	  strlcpy(name, UserNameRequested, name_sz);
522 	  return(AUTH_VALID);
523 	} else {
524 	   return(AUTH_USER);
525 	}
526 
527 }
528 
529 #define	BUMP(buf, len)		while (*(buf)) {++(buf), --(len);}
530 #define	ADDC(buf, len, c)	if ((len) > 0) {*(buf)++ = (c); --(len);}
531 
532 	void
533 spx_printsub(unsigned char *data, size_t cnt,
534 	     unsigned char *buf, size_t buflen)
535 {
536 	size_t i;
537 
538 	buf[buflen-1] = '\0';		/* make sure it's NULL terminated */
539 	buflen -= 1;
540 
541 	switch(data[3]) {
542 	case SPX_REJECT:		/* Rejected (reason might follow) */
543 		strlcpy((char *)buf, " REJECT ", buflen);
544 		goto common;
545 
546 	case SPX_ACCEPT:		/* Accepted (name might follow) */
547 		strlcpy((char *)buf, " ACCEPT ", buflen);
548 	common:
549 		BUMP(buf, buflen);
550 		if (cnt <= 4)
551 			break;
552 		ADDC(buf, buflen, '"');
553 		for (i = 4; i < cnt; i++)
554 			ADDC(buf, buflen, data[i]);
555 		ADDC(buf, buflen, '"');
556 		ADDC(buf, buflen, '\0');
557 		break;
558 
559 	case SPX_AUTH:			/* Authentication data follows */
560 		strlcpy((char *)buf, " AUTH", buflen);
561 		goto common2;
562 
563 	default:
564 		snprintf(buf, buflen, " %d (unknown)", data[3]);
565 	common2:
566 		BUMP(buf, buflen);
567 		for (i = 4; i < cnt; i++) {
568 			snprintf(buf, buflen, " %d", data[i]);
569 			BUMP(buf, buflen);
570 		}
571 		break;
572 	}
573 }
574 
575 #endif
576 
577 #ifdef notdef
578 
579 prkey(msg, key)
580 	char *msg;
581 	unsigned char *key;
582 {
583 	int i;
584 	printf("%s:", msg);
585 	for (i = 0; i < 8; i++)
586 		printf(" %3d", key[i]);
587 	printf("\r\n");
588 }
589 #endif
590