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