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