xref: /freebsd/contrib/telnet/libtelnet/kerberos5.c (revision aa1a8ff2d6dbc51ef058f46f3db5a8bb77967145)
1 /*-
2  * Copyright (c) 1991, 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. 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  * Copyright (C) 1990 by the Massachusetts Institute of Technology
32  *
33  * Export of this software from the United States of America may
34  * require a specific license from the United States Government.
35  * It is the responsibility of any person or organization contemplating
36  * export to obtain such a license before exporting.
37  *
38  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
39  * distribute this software and its documentation for any purpose and
40  * without fee is hereby granted, provided that the above copyright
41  * notice appear in all copies and that both that copyright notice and
42  * this permission notice appear in supporting documentation, and that
43  * the name of M.I.T. not be used in advertising or publicity pertaining
44  * to distribution of the software without specific, written prior
45  * permission.  M.I.T. makes no representations about the suitability of
46  * this software for any purpose.  It is provided "as is" without express
47  * or implied warranty.
48  */
49 
50 #ifdef	KRB5
51 
52 #include <arpa/telnet.h>
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <string.h>
56 #include <unistd.h>
57 #include <netdb.h>
58 #include <ctype.h>
59 #include <pwd.h>
60 #define Authenticator k5_Authenticator
61 #include <krb5.h>
62 #undef Authenticator
63 
64 #include "encrypt.h"
65 #include "auth.h"
66 #include "misc.h"
67 
68 int forward_flags = 0;  /* Flags get set in telnet/main.c on -f and -F */
69 
70 /* These values need to be the same as those defined in telnet/main.c. */
71 /* Either define them in both places, or put in some common header file. */
72 #define OPTS_FORWARD_CREDS	0x00000002
73 #define OPTS_FORWARDABLE_CREDS	0x00000001
74 
75 void kerberos5_forward (Authenticator *);
76 
77 static unsigned char str_data[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 0,
78 			  		AUTHTYPE_KERBEROS_V5, };
79 
80 #define	KRB_AUTH		0	/* Authentication data follows */
81 #define	KRB_REJECT		1	/* Rejected (reason might follow) */
82 #define	KRB_ACCEPT		2	/* Accepted */
83 #define	KRB_RESPONSE		3	/* Response for mutual auth. */
84 
85 #define KRB_FORWARD     	4       /* Forwarded credentials follow */
86 #define KRB_FORWARD_ACCEPT     	5       /* Forwarded credentials accepted */
87 #define KRB_FORWARD_REJECT     	6       /* Forwarded credentials rejected */
88 
89 static	krb5_data auth;
90 static  krb5_ticket *ticket;
91 
92 static krb5_context context;
93 static krb5_auth_context auth_context;
94 
95 static void
96 print_krb5_error(krb5_context context, krb5_error_code code, const char *msg)
97 {
98 	const char *error_message;
99 
100 	error_message = krb5_get_error_message(context, code);
101 	printf(msg, error_message);
102 	krb5_free_error_message(context, error_message);
103 }
104 
105 static int
106 Data(Authenticator *ap, int type, const char *d, int c)
107 {
108     unsigned char *p = str_data + 4;
109     const unsigned char *cd = d;
110 
111     if (c == -1)
112 	c = strlen(cd);
113 
114     if (auth_debug_mode) {
115 	printf("%s:%d: [%d] (%d)",
116 	       str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY",
117 	       str_data[3],
118 	       type, c);
119 	printd(d, c);
120 	printf("\r\n");
121     }
122     *p++ = ap->type;
123     *p++ = ap->way;
124     *p++ = type;
125     while (c-- > 0) {
126 	if ((*p++ = *cd++) == IAC)
127 	    *p++ = IAC;
128     }
129     *p++ = IAC;
130     *p++ = SE;
131     if (str_data[3] == TELQUAL_IS)
132 	printsub('>', &str_data[2], p - &str_data[2]);
133     return(net_write(str_data, p - str_data));
134 }
135 
136 int
137 kerberos5_init(Authenticator *ap __unused, int server)
138 {
139     krb5_error_code ret;
140 
141     ret = krb5_init_context(&context);
142     if (ret)
143 	return 0;
144     if (server) {
145 	krb5_keytab kt;
146 	krb5_kt_cursor cursor;
147 
148 	ret = krb5_kt_default(context, &kt);
149 	if (ret)
150 	    return 0;
151 
152 	ret = krb5_kt_start_seq_get (context, kt, &cursor);
153 	if (ret) {
154 	    krb5_kt_close (context, kt);
155 	    return 0;
156 	}
157 	krb5_kt_end_seq_get (context, kt, &cursor);
158 	krb5_kt_close (context, kt);
159 
160 	str_data[3] = TELQUAL_REPLY;
161     } else
162 	str_data[3] = TELQUAL_IS;
163     return(1);
164 }
165 
166 extern int net;
167 
168 static int
169 kerberos5_send(const char *name, Authenticator *ap)
170 {
171     krb5_error_code ret;
172     krb5_ccache ccache;
173     int ap_opts;
174     krb5_data cksum_data;
175     char foo[2];
176 
177     if (!UserNameRequested) {
178 	if (auth_debug_mode) {
179 	    printf("Kerberos V5: no user name supplied\r\n");
180 	}
181 	return(0);
182     }
183 
184     ret = krb5_cc_default(context, &ccache);
185     if (ret) {
186 	if (auth_debug_mode) {
187 	    print_krb5_error(context, ret, "Kerberos V5: could not get default ccache: %s\r\n");
188 	}
189 	return 0;
190     }
191 
192     if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL)
193 	ap_opts = AP_OPTS_MUTUAL_REQUIRED;
194     else
195 	ap_opts = 0;
196     ap_opts |= AP_OPTS_USE_SUBKEY;
197 
198     ret = krb5_auth_con_init (context, &auth_context);
199     if (ret) {
200 	if (auth_debug_mode) {
201 	    print_krb5_error(context, ret, "Kerberos V5: krb5_auth_con_init failed (%s)\r\n");
202 	}
203 	return(0);
204     }
205 
206     ret = krb5_auth_con_setaddrs_from_fd (context,
207 					  auth_context,
208 					  &net);
209     if (ret) {
210 	if (auth_debug_mode) {
211 	    print_krb5_error(context, ret, "Kerberos V5:"
212 		    " krb5_auth_con_setaddrs_from_fd failed (%s)\r\n");
213 	}
214 	return(0);
215     }
216 
217     krb5_auth_con_setkeytype (context, auth_context, KEYTYPE_DES);
218 
219     foo[0] = ap->type;
220     foo[1] = ap->way;
221 
222     cksum_data.length = sizeof(foo);
223     cksum_data.data   = foo;
224 
225 
226     {
227 	krb5_principal service;
228 	char sname[128];
229 
230 
231 	ret = krb5_sname_to_principal (context,
232 				       RemoteHostName,
233 				       NULL,
234 				       KRB5_NT_SRV_HST,
235 				       &service);
236 	if(ret) {
237 	    if (auth_debug_mode) {
238 		const char *err_str;
239 
240 		err_str = krb5_get_error_message(context, ret);
241 		printf("Kerberosr V5:"
242 			" krb5_sname_to_principal(%s) failed (%s)\r\n",
243 			RemoteHostName, err_str);
244 		krb5_free_error_message(context, err_str);
245 	    }
246 	    return 0;
247 	}
248 	ret = krb5_unparse_name_fixed(context, service, sname, sizeof(sname));
249 	if(ret) {
250 	    if (auth_debug_mode) {
251 		print_krb5_error(context, ret, "Kerberos V5:"
252 			" krb5_unparse_name_fixed failed (%s)\r\n");
253 	    }
254 	    return 0;
255 	}
256 	printf("[ Trying %s (%s)... ]\r\n", name, sname);
257 	ret = krb5_mk_req_exact(context, &auth_context, ap_opts,
258 				service,
259 				&cksum_data, ccache, &auth);
260 	krb5_free_principal (context, service);
261 
262     }
263     if (ret) {
264 	if (1 || auth_debug_mode) {
265 	    print_krb5_error(context, ret, "Kerberos V5: mk_req failed (%s)\r\n");
266 	}
267 	return(0);
268     }
269 
270     if (!auth_sendname((unsigned char *)UserNameRequested,
271 		       strlen(UserNameRequested))) {
272 	if (auth_debug_mode)
273 	    printf("Not enough room for user name\r\n");
274 	return(0);
275     }
276     if (!Data(ap, KRB_AUTH, auth.data, auth.length)) {
277 	if (auth_debug_mode)
278 	    printf("Not enough room for authentication data\r\n");
279 	return(0);
280     }
281     if (auth_debug_mode) {
282 	printf("Sent Kerberos V5 credentials to server\r\n");
283     }
284     return(1);
285 }
286 
287 int
288 kerberos5_send_mutual(Authenticator *ap)
289 {
290     return kerberos5_send("mutual KERBEROS5", ap);
291 }
292 
293 int
294 kerberos5_send_oneway(Authenticator *ap)
295 {
296     return kerberos5_send("KERBEROS5", ap);
297 }
298 
299 void
300 kerberos5_is(Authenticator *ap, unsigned char *data, int cnt)
301 {
302     krb5_error_code ret;
303     krb5_data outbuf;
304     krb5_keyblock *key_block;
305     char *name;
306     krb5_principal server;
307     int zero = 0;
308 
309     if (cnt-- < 1)
310 	return;
311     switch (*data++) {
312     case KRB_AUTH:
313 	auth.data = (char *)data;
314 	auth.length = cnt;
315 
316 	auth_context = NULL;
317 
318 	ret = krb5_auth_con_init (context, &auth_context);
319 	if (ret) {
320 	    Data(ap, KRB_REJECT, "krb5_auth_con_init failed", -1);
321 	    auth_finished(ap, AUTH_REJECT);
322 	    if (auth_debug_mode)
323 		print_krb5_error(context, ret, "Kerberos V5: krb5_auth_con_init failed (%s)\r\n");
324 	    return;
325 	}
326 
327 	ret = krb5_auth_con_setaddrs_from_fd (context,
328 					      auth_context,
329 					      &zero);
330 	if (ret) {
331 	    Data(ap, KRB_REJECT, "krb5_auth_con_setaddrs_from_fd failed", -1);
332 	    auth_finished(ap, AUTH_REJECT);
333 	    if (auth_debug_mode)
334 		print_krb5_error(context, ret, "Kerberos V5: "
335 		       "krb5_auth_con_setaddrs_from_fd failed (%s)\r\n");
336 	    return;
337 	}
338 
339 	ret = krb5_sock_to_principal (context,
340 				      0,
341 				      "host",
342 				      KRB5_NT_SRV_HST,
343 				      &server);
344 	if (ret) {
345 	    Data(ap, KRB_REJECT, "krb5_sock_to_principal failed", -1);
346 	    auth_finished(ap, AUTH_REJECT);
347 	    if (auth_debug_mode)
348 		print_krb5_error(context, ret, "Kerberos V5: "
349 		       "krb5_sock_to_principal failed (%s)\r\n");
350 	    return;
351 	}
352 
353 	ret = krb5_rd_req(context,
354 			  &auth_context,
355 			  &auth,
356 			  server,
357 			  NULL,
358 			  NULL,
359 			  &ticket);
360 
361 	krb5_free_principal (context, server);
362 	if (ret) {
363 	    char *errbuf;
364 	    const char *err_str;
365 
366 	    err_str = krb5_get_error_message(context, ret);
367 	    asprintf(&errbuf,
368 		     "Read req failed: %s", err_str);
369 	    krb5_free_error_message(context, err_str);
370 	    Data(ap, KRB_REJECT, errbuf, -1);
371 	    if (auth_debug_mode)
372 		printf("%s\r\n", errbuf);
373 	    free (errbuf);
374 	    return;
375 	}
376 
377 	{
378 	    char foo[2];
379 
380 	    foo[0] = ap->type;
381 	    foo[1] = ap->way;
382 
383 	    ret = krb5_verify_authenticator_checksum(context,
384 						     auth_context,
385 						     foo,
386 						     sizeof(foo));
387 
388 	    if (ret) {
389 		char *errbuf;
390 		const char *err_str;
391 
392 		err_str = krb5_get_error_message(context, ret);
393 		asprintf(&errbuf, "Bad checksum: %s", err_str);
394 		krb5_free_error_message(context, err_str);
395 		Data(ap, KRB_REJECT, errbuf, -1);
396 		if (auth_debug_mode)
397 		    printf ("%s\r\n", errbuf);
398 		free(errbuf);
399 		return;
400 	    }
401 	}
402 	ret = krb5_auth_con_getremotesubkey (context,
403 					     auth_context,
404 					     &key_block);
405 
406 	if (ret) {
407 	    Data(ap, KRB_REJECT, "krb5_auth_con_getremotesubkey failed", -1);
408 	    auth_finished(ap, AUTH_REJECT);
409 	    if (auth_debug_mode)
410 		print_krb5_error(context, ret, "Kerberos V5: "
411 		       "krb5_auth_con_getremotesubkey failed (%s)\r\n");
412 	    return;
413 	}
414 
415 	if (key_block == NULL) {
416 	    ret = krb5_auth_con_getkey(context,
417 				       auth_context,
418 				       &key_block);
419 	}
420 	if (ret) {
421 	    Data(ap, KRB_REJECT, "krb5_auth_con_getkey failed", -1);
422 	    auth_finished(ap, AUTH_REJECT);
423 	    if (auth_debug_mode)
424 		print_krb5_error(context, ret, "Kerberos V5: "
425 		       "krb5_auth_con_getkey failed (%s)\r\n");
426 	    return;
427 	}
428 	if (key_block == NULL) {
429 	    Data(ap, KRB_REJECT, "no subkey received", -1);
430 	    auth_finished(ap, AUTH_REJECT);
431 	    if (auth_debug_mode)
432 		printf("Kerberos V5: "
433 		       "krb5_auth_con_getremotesubkey returned NULL key\r\n");
434 	    return;
435 	}
436 
437 	if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
438 	    ret = krb5_mk_rep(context, auth_context, &outbuf);
439 	    if (ret) {
440 		Data(ap, KRB_REJECT,
441 		     "krb5_mk_rep failed", -1);
442 		auth_finished(ap, AUTH_REJECT);
443 		if (auth_debug_mode)
444 		    print_krb5_error(context, ret, "Kerberos V5: "
445 			   "krb5_mk_rep failed (%s)\r\n");
446 		return;
447 	    }
448 	    Data(ap, KRB_RESPONSE, outbuf.data, outbuf.length);
449 	}
450 	if (krb5_unparse_name(context, ticket->client, &name))
451 	    name = 0;
452 
453 	if(UserNameRequested && krb5_kuserok(context,
454 					     ticket->client,
455 					     UserNameRequested)) {
456 	    Data(ap, KRB_ACCEPT, name, name ? -1 : 0);
457 	    if (auth_debug_mode) {
458 		printf("Kerberos5 identifies him as ``%s''\r\n",
459 		       name ? name : "");
460 	    }
461 
462 	    if(key_block->keytype == ETYPE_DES_CBC_MD5 ||
463 	       key_block->keytype == ETYPE_DES_CBC_MD4 ||
464 	       key_block->keytype == ETYPE_DES_CBC_CRC) {
465 		Session_Key skey;
466 
467 		skey.type = SK_DES;
468 		skey.length = 8;
469 		skey.data = key_block->keyvalue.data;
470 		encrypt_session_key(&skey, 0);
471 	    }
472 
473 	} else {
474 	    char *msg;
475 
476 	    asprintf (&msg, "user `%s' is not authorized to "
477 		      "login as `%s'",
478 		      name ? name : "<unknown>",
479 		      UserNameRequested ? UserNameRequested : "<nobody>");
480 	    if (msg == NULL)
481 		Data(ap, KRB_REJECT, NULL, 0);
482 	    else {
483 		Data(ap, KRB_REJECT, (void *)msg, -1);
484 		free(msg);
485 	    }
486 	    auth_finished (ap, AUTH_REJECT);
487 	    krb5_free_keyblock_contents(context, key_block);
488 	    break;
489 	}
490 	auth_finished(ap, AUTH_USER);
491 	krb5_free_keyblock_contents(context, key_block);
492 
493 	break;
494     case KRB_FORWARD: {
495 	struct passwd *pwd;
496 	char ccname[1024];	/* XXX */
497 	krb5_data inbuf;
498 	krb5_ccache ccache;
499 	inbuf.data = (char *)data;
500 	inbuf.length = cnt;
501 
502 	pwd = getpwnam (UserNameRequested);
503 	if (pwd == NULL)
504 	    break;
505 
506 	snprintf (ccname, sizeof(ccname),
507 		  "FILE:/tmp/krb5cc_%u", pwd->pw_uid);
508 
509 	ret = krb5_cc_resolve (context, ccname, &ccache);
510 	if (ret) {
511 	    if (auth_debug_mode)
512 		print_krb5_error(context, ret, "Kerberos V5: could not get ccache: %s\r\n");
513 	    break;
514 	}
515 
516 	ret = krb5_cc_initialize (context,
517 				  ccache,
518 				  ticket->client);
519 	if (ret) {
520 	    if (auth_debug_mode)
521 		print_krb5_error(context, ret, "Kerberos V5: could not init ccache: %s\r\n");
522 	    break;
523 	}
524 
525 #if defined(DCE)
526 	esetenv("KRB5CCNAME", ccname, 1);
527 #endif
528 	ret = krb5_rd_cred2 (context,
529 			     auth_context,
530 			     ccache,
531 			     &inbuf);
532 	if(ret) {
533 	    char *errbuf;
534 	    const char *err_str;
535 
536 	    err_str = krb5_get_error_message(context, ret);
537 	    asprintf (&errbuf,
538 		      "Read forwarded creds failed: %s", err_str);
539 	    krb5_free_error_message(context, err_str);
540 	    if(errbuf == NULL)
541 		Data(ap, KRB_FORWARD_REJECT, NULL, 0);
542 	    else
543 		Data(ap, KRB_FORWARD_REJECT, errbuf, -1);
544 	    if (auth_debug_mode)
545 		printf("Could not read forwarded credentials: %s\r\n",
546 		       errbuf);
547 	    free (errbuf);
548 	} else {
549 	    Data(ap, KRB_FORWARD_ACCEPT, 0, 0);
550 #if defined(DCE)
551 	    dfsfwd = 1;
552 #endif
553 	}
554 	chown (ccname + 5, pwd->pw_uid, -1);
555 	if (auth_debug_mode)
556 	    printf("Forwarded credentials obtained\r\n");
557 	break;
558     }
559     default:
560 	if (auth_debug_mode)
561 	    printf("Unknown Kerberos option %d\r\n", data[-1]);
562 	Data(ap, KRB_REJECT, 0, 0);
563 	break;
564     }
565 }
566 
567 void
568 kerberos5_reply(Authenticator *ap, unsigned char *data, int cnt)
569 {
570     static int mutual_complete = 0;
571 
572     if (cnt-- < 1)
573 	return;
574     switch (*data++) {
575     case KRB_REJECT:
576 	if (cnt > 0) {
577 	    printf("[ Kerberos V5 refuses authentication because %.*s ]\r\n",
578 		   cnt, data);
579 	} else
580 	    printf("[ Kerberos V5 refuses authentication ]\r\n");
581 	auth_send_retry();
582 	return;
583     case KRB_ACCEPT: {
584 	krb5_error_code ret;
585 	Session_Key skey;
586 	krb5_keyblock *keyblock;
587 
588 	if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL &&
589 	    !mutual_complete) {
590 	    printf("[ Kerberos V5 accepted you, but didn't provide mutual authentication! ]\r\n");
591 	    auth_send_retry();
592 	    return;
593 	}
594 	if (cnt)
595 	    printf("[ Kerberos V5 accepts you as ``%.*s'' ]\r\n", cnt, data);
596 	else
597 	    printf("[ Kerberos V5 accepts you ]\r\n");
598 
599 	ret = krb5_auth_con_getlocalsubkey (context,
600 					    auth_context,
601 					    &keyblock);
602 	if (ret)
603 	    ret = krb5_auth_con_getkey (context,
604 					auth_context,
605 					&keyblock);
606 	if(ret) {
607 	    print_krb5_error(context, ret, "[ krb5_auth_con_getkey: %s ]\r\n");
608 	    auth_send_retry();
609 	    return;
610 	}
611 
612 	skey.type = SK_DES;
613 	skey.length = 8;
614 	skey.data = keyblock->keyvalue.data;
615 	encrypt_session_key(&skey, 0);
616 	krb5_free_keyblock_contents (context, keyblock);
617 	auth_finished(ap, AUTH_USER);
618 	if (forward_flags & OPTS_FORWARD_CREDS)
619 	    kerberos5_forward(ap);
620 	break;
621     }
622     case KRB_RESPONSE:
623 	if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
624 	    /* the rest of the reply should contain a krb_ap_rep */
625 	  krb5_ap_rep_enc_part *reply;
626 	  krb5_data inbuf;
627 	  krb5_error_code ret;
628 
629 	  inbuf.length = cnt;
630 	  inbuf.data = (char *)data;
631 
632 	  ret = krb5_rd_rep(context, auth_context, &inbuf, &reply);
633 	  if (ret) {
634 	      print_krb5_error(context, ret, "[ Mutual authentication failed: %s ]\r\n");
635 	      auth_send_retry();
636 	      return;
637 	  }
638 	  krb5_free_ap_rep_enc_part(context, reply);
639 	  mutual_complete = 1;
640 	}
641 	return;
642     case KRB_FORWARD_ACCEPT:
643 	printf("[ Kerberos V5 accepted forwarded credentials ]\r\n");
644 	return;
645     case KRB_FORWARD_REJECT:
646 	printf("[ Kerberos V5 refuses forwarded credentials because %.*s ]\r\n",
647 	       cnt, data);
648 	return;
649     default:
650 	if (auth_debug_mode)
651 	    printf("Unknown Kerberos option %d\r\n", data[-1]);
652 	return;
653     }
654 }
655 
656 int
657 kerberos5_status(Authenticator *ap __unused, char *name, int level)
658 {
659     if (level < AUTH_USER)
660 	return(level);
661 
662     if (UserNameRequested &&
663 	krb5_kuserok(context,
664 		     ticket->client,
665 		     UserNameRequested))
666 	{
667 	    strcpy(name, UserNameRequested);
668 	    return(AUTH_VALID);
669 	} else
670 	    return(AUTH_USER);
671 }
672 
673 #define	BUMP(buf, len)		while (*(buf)) {++(buf), --(len);}
674 #define	ADDC(buf, len, c)	if ((len) > 0) {*(buf)++ = (c); --(len);}
675 
676 void
677 kerberos5_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen)
678 {
679     int i;
680 
681     buf[buflen-1] = '\0';		/* make sure its NULL terminated */
682     buflen -= 1;
683 
684     switch(data[3]) {
685     case KRB_REJECT:		/* Rejected (reason might follow) */
686 	strlcpy((char *)buf, " REJECT ", buflen);
687 	goto common;
688 
689     case KRB_ACCEPT:		/* Accepted (name might follow) */
690 	strlcpy((char *)buf, " ACCEPT ", buflen);
691     common:
692 	BUMP(buf, buflen);
693 	if (cnt <= 4)
694 	    break;
695 	ADDC(buf, buflen, '"');
696 	for (i = 4; i < cnt; i++)
697 	    ADDC(buf, buflen, data[i]);
698 	ADDC(buf, buflen, '"');
699 	ADDC(buf, buflen, '\0');
700 	break;
701 
702 
703     case KRB_AUTH:			/* Authentication data follows */
704 	strlcpy((char *)buf, " AUTH", buflen);
705 	goto common2;
706 
707     case KRB_RESPONSE:
708 	strlcpy((char *)buf, " RESPONSE", buflen);
709 	goto common2;
710 
711     case KRB_FORWARD:		/* Forwarded credentials follow */
712 	strlcpy((char *)buf, " FORWARD", buflen);
713 	goto common2;
714 
715     case KRB_FORWARD_ACCEPT:	/* Forwarded credentials accepted */
716 	strlcpy((char *)buf, " FORWARD_ACCEPT", buflen);
717 	goto common2;
718 
719     case KRB_FORWARD_REJECT:	/* Forwarded credentials rejected */
720 	/* (reason might follow) */
721 	strlcpy((char *)buf, " FORWARD_REJECT", buflen);
722 	goto common2;
723 
724     default:
725 	snprintf(buf, buflen, " %d (unknown)", data[3]);
726     common2:
727 	BUMP(buf, buflen);
728 	for (i = 4; i < cnt; i++) {
729 	    snprintf(buf, buflen, " %d", data[i]);
730 	    BUMP(buf, buflen);
731 	}
732 	break;
733     }
734 }
735 
736 void
737 kerberos5_forward(Authenticator *ap)
738 {
739     krb5_error_code ret;
740     krb5_ccache     ccache;
741     krb5_creds      creds;
742     krb5_kdc_flags  flags;
743     krb5_data       out_data;
744     krb5_principal  principal;
745 
746     ret = krb5_cc_default (context, &ccache);
747     if (ret) {
748 	if (auth_debug_mode)
749 	    print_krb5_error(context, ret, "KerberosV5: could not get default ccache: %s\r\n");
750 	return;
751     }
752 
753     ret = krb5_cc_get_principal (context, ccache, &principal);
754     if (ret) {
755 	if (auth_debug_mode)
756 	    print_krb5_error(context, ret, "KerberosV5: could not get principal: %s\r\n");
757 	return;
758     }
759 
760     memset (&creds, 0, sizeof(creds));
761 
762     creds.client = principal;
763 
764     ret = krb5_build_principal (context,
765 				&creds.server,
766 				strlen(principal->realm),
767 				principal->realm,
768 				"krbtgt",
769 				principal->realm,
770 				NULL);
771 
772     if (ret) {
773 	if (auth_debug_mode)
774 	    print_krb5_error(context, ret, "KerberosV5: could not get principal: %s\r\n");
775 	return;
776     }
777 
778     creds.times.endtime = 0;
779 
780     flags.i = 0;
781     flags.b.forwarded = 1;
782     if (forward_flags & OPTS_FORWARDABLE_CREDS)
783 	flags.b.forwardable = 1;
784 
785     ret = krb5_get_forwarded_creds (context,
786 				    auth_context,
787 				    ccache,
788 				    flags.i,
789 				    RemoteHostName,
790 				    &creds,
791 				    &out_data);
792     if (ret) {
793 	if (auth_debug_mode)
794 	    print_krb5_error(context, ret, "Kerberos V5: error getting forwarded creds: %s\r\n");
795 	return;
796     }
797 
798     if(!Data(ap, KRB_FORWARD, out_data.data, out_data.length)) {
799 	if (auth_debug_mode)
800 	    printf("Not enough room for authentication data\r\n");
801     } else {
802 	if (auth_debug_mode)
803 	    printf("Forwarded local Kerberos V5 credentials to server\r\n");
804     }
805 }
806 
807 #if defined(DCE)
808 /* if this was a K5 authentication try and join a PAG for the user. */
809 void
810 kerberos5_dfspag(void)
811 {
812     if (dfsk5ok) {
813 	dfspag = krb5_dfs_pag(context, dfsfwd, ticket->client,
814 			      UserNameRequested);
815     }
816 }
817 #endif
818 
819 #endif /* KRB5 */
820