]> git.cameronkatri.com Git - apple_cmds.git/blob - lib/libtelnet/kerberos5.c
libtelnet-13
[apple_cmds.git] / lib / libtelnet / kerberos5.c
1 /*
2 * appl/telnet/libtelnet/kerberos5.c
3 */
4
5 /*-
6 * Copyright (c) 1991, 1993
7 * The Regents of the University of California. All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by the University of
20 * California, Berkeley and its contributors.
21 * 4. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 */
37
38 /* based on @(#)kerberos5.c 8.1 (Berkeley) 6/4/93 */
39
40 /*
41 * Copyright (C) 1990 by the Massachusetts Institute of Technology
42 *
43 * Export of this software from the United States of America may
44 * require a specific license from the United States Government.
45 * It is the responsibility of any person or organization contemplating
46 * export to obtain such a license before exporting.
47 *
48 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
49 * distribute this software and its documentation for any purpose and
50 * without fee is hereby granted, provided that the above copyright
51 * notice appear in all copies and that both that copyright notice and
52 * this permission notice appear in supporting documentation, and that
53 * the name of M.I.T. not be used in advertising or publicity pertaining
54 * to distribution of the software without specific, written prior
55 * permission. Furthermore if you modify this software you must label
56 * your software as modified software and not distribute it in such a
57 * fashion that it might be confused with the original M.I.T. software.
58 * M.I.T. makes no representations about the suitability of
59 * this software for any purpose. It is provided "as is" without express
60 * or implied warranty.
61 */
62
63
64 #ifdef KRB5
65 #include <arpa/telnet.h>
66 #include <stdio.h>
67 #define KRB5_DEPRECATED 1 /* krb5_auth_con_getremotesubkey */
68 #include <krb5.h>
69 #include "com_err.h"
70 #include <netdb.h>
71 #include <ctype.h>
72 #include <syslog.h>
73 #include <sys/errno.h>
74
75 #ifdef HAVE_STDLIB_H
76 #include <stdlib.h>
77 #else
78 extern char *malloc();
79 #endif
80 #ifdef HAVE_STRING_H
81 #include <string.h>
82 #else
83 #include <strings.h>
84 #endif
85
86 #include "encrypt.h"
87 #include "auth.h"
88 #include "misc.h"
89
90 extern int auth_debug_mode;
91 extern int net;
92
93 #ifdef FORWARD
94 int forward_flags = 0; /* Flags get set in telnet/main.c on -f and -F */
95
96 void kerberos5_forward();
97 krb5_error_code
98 rd_and_store_for_creds(krb5_context context, krb5_auth_context auth_context, krb5_data *inbuf, krb5_ticket *ticket);
99
100 #endif /* FORWARD */
101
102 static unsigned char str_data[8192] = {IAC, SB, TELOPT_AUTHENTICATION, 0,
103 AUTHTYPE_KERBEROS_V5, };
104 /*static unsigned char str_name[1024] = { IAC, SB, TELOPT_AUTHENTICATION,
105 TELQUAL_NAME, };*/
106
107 #define AUTH_ENCRYPT_OFF 0
108 #define AUTH_ENCRYPT_ON 4
109 #define AUTH_ENCRYPT_MASK 4
110
111 #define KRB_AUTH 0 /* Authentication data follows */
112 #define KRB_REJECT 1 /* Rejected (reason might follow) */
113 #define KRB_ACCEPT 2 /* Accepted */
114 #define KRB_RESPONSE 3 /* Response for mutual auth. */
115
116 #ifdef FORWARD
117 #define KRB_FORWARD 4 /* Forwarded credentials follow */
118 #define KRB_FORWARD_ACCEPT 5 /* Forwarded credentials accepted */
119 #define KRB_FORWARD_REJECT 6 /* Forwarded credentials rejected */
120 #endif /* FORWARD */
121
122 krb5_auth_context auth_context = 0;
123
124 static krb5_data auth;
125 /* telnetd gets session key from here */
126 static krb5_ticket * ticket = NULL;
127 /* telnet matches the AP_REQ and AP_REP with this */
128
129 /* some compilers can't hack void *, so we use the Kerberos krb5_pointer,
130 which is either void * or char *, depending on the compiler. */
131
132 #define Voidptr krb5_pointer
133
134 krb5_keyblock *session_key = 0;
135 char * telnet_srvtab = NULL;
136 char * telnet_krb5_realm = NULL;
137
138 static int
139 Data(ap, type, d, c)
140 Authenticator *ap;
141 int type;
142 Voidptr d;
143 int c;
144 {
145 unsigned char *p = str_data + 4;
146 unsigned char *cd = (unsigned char *)d;
147 size_t spaceleft = sizeof(str_data) - 4;
148
149 if (c == -1)
150 c = strlen((char *)cd);
151
152 if (auth_debug_mode) {
153 printf("%s:%d: [%d] (%d)",
154 str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY",
155 str_data[3],
156 type, c);
157 printd(d, c);
158 printf("\r\n");
159 }
160 *p++ = ap->type;
161 *p++ = ap->way;
162 *p++ = type;
163 spaceleft -= 3;
164 while (c-- > 0) {
165 if ((*p++ = *cd++) == IAC) {
166 *p++ = IAC;
167 spaceleft--;
168 }
169 if ((--spaceleft < 4) && c) {
170 errno = ENOMEM;
171 return -1;
172 }
173 }
174 *p++ = IAC;
175 *p++ = SE;
176 if (str_data[3] == TELQUAL_IS)
177 printsub('>', &str_data[2], p - &str_data[2]);
178 return(net_write(str_data, p - str_data));
179 }
180
181 krb5_context telnet_context = 0;
182 int
183 kerberos5_init(ap, server)
184 Authenticator *ap;
185 int server;
186 {
187 krb5_error_code retval;
188
189 if (server)
190 str_data[3] = TELQUAL_REPLY;
191 else
192 str_data[3] = TELQUAL_IS;
193 if (telnet_context == 0) {
194 retval = krb5_init_context(&telnet_context);
195 if (retval)
196 return 0;
197 }
198 return(1);
199 }
200
201 void
202 kerberos5_cleanup()
203 {
204 krb5_error_code retval;
205 krb5_ccache ccache;
206 char *ccname;
207
208 if (telnet_context == 0)
209 return;
210
211 ccname = getenv("KRB5CCNAME");
212 if (ccname) {
213 retval = krb5_cc_resolve(telnet_context, ccname, &ccache);
214 if (!retval)
215 retval = krb5_cc_destroy(telnet_context, ccache);
216 }
217
218 krb5_free_context(telnet_context);
219 telnet_context = 0;
220 }
221
222
223 int
224 kerberos5_send(ap)
225 Authenticator *ap;
226 {
227 krb5_error_code r;
228 krb5_ccache ccache;
229 krb5_creds creds; /* telnet gets session key from here */
230 krb5_creds * new_creds = 0;
231 int ap_opts;
232 char type_check[2];
233 krb5_data check_data;
234
235 #ifdef ENCRYPTION
236 krb5_keyblock *newkey = 0;
237 #endif /* ENCRYPTION */
238
239 if (!UserNameRequested) {
240 if (auth_debug_mode) {
241 printf(
242 "telnet: Kerberos V5: no user name supplied\r\n");
243 }
244 return(0);
245 }
246
247 if ((r = krb5_cc_default(telnet_context, &ccache))) {
248 if (auth_debug_mode) {
249 printf(
250 "telnet: Kerberos V5: could not get default ccache\r\n");
251 }
252 return(0);
253 }
254
255 memset((char *)&creds, 0, sizeof(creds));
256 if ((r = krb5_sname_to_principal(telnet_context, RemoteHostName,
257 "host", KRB5_NT_SRV_HST,
258 &creds.server))) {
259 if (auth_debug_mode)
260 printf("telnet: Kerberos V5: error while constructing service name: %s\r\n", error_message(r));
261 return(0);
262 }
263
264 if (telnet_krb5_realm != NULL) {
265 krb5_data rdata;
266
267 rdata.length = strlen(telnet_krb5_realm);
268 rdata.data = (char *) malloc(rdata.length + 1);
269 if (rdata.data == NULL) {
270 fprintf(stderr, "malloc failed\n");
271 return(0);
272 }
273 strcpy(rdata.data, telnet_krb5_realm);
274 krb5_princ_set_realm(telnet_context, creds.server, &rdata);
275 }
276
277 if ((r = krb5_cc_get_principal(telnet_context, ccache,
278 &creds.client))) {
279 if (auth_debug_mode) {
280 printf(
281 "telnet: Kerberos V5: failure on principal (%s)\r\n",
282 error_message(r));
283 }
284 krb5_free_cred_contents(telnet_context, &creds);
285 return(0);
286 }
287
288 creds.keyblock.enctype=ENCTYPE_DES_CBC_CRC;
289 if ((r = krb5_get_credentials(telnet_context, 0,
290 ccache, &creds, &new_creds))) {
291 if (auth_debug_mode) {
292 printf(
293 "telnet: Kerberos V5: failure on credentials(%s)\r\n",
294 error_message(r));
295 }
296 krb5_free_cred_contents(telnet_context, &creds);
297 return(0);
298 }
299
300 if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL)
301 ap_opts = AP_OPTS_MUTUAL_REQUIRED;
302 else
303 ap_opts = 0;
304
305 #ifdef ENCRYPTION
306 ap_opts |= AP_OPTS_USE_SUBKEY;
307 #endif /* ENCRYPTION */
308
309 if (auth_context) {
310 krb5_auth_con_free(telnet_context, auth_context);
311 auth_context = 0;
312 }
313 if ((r = krb5_auth_con_init(telnet_context, &auth_context))) {
314 if (auth_debug_mode) {
315 printf("Kerberos V5: failed to init auth_context (%s)\r\n",
316 error_message(r));
317 }
318 return(0);
319 }
320
321 krb5_auth_con_setflags(telnet_context, auth_context,
322 KRB5_AUTH_CONTEXT_RET_TIME);
323
324 type_check[0] = ap->type;
325 type_check[1] = ap->way;
326 check_data.magic = KV5M_DATA;
327 check_data.length = 2;
328 check_data.data = (char *) &type_check;
329
330 r = krb5_mk_req_extended(telnet_context, &auth_context, ap_opts,
331 &check_data, new_creds, &auth);
332
333 #ifdef ENCRYPTION
334 krb5_auth_con_getlocalsubkey(telnet_context, auth_context, &newkey);
335 if (session_key) {
336 krb5_free_keyblock(telnet_context, session_key);
337 session_key = 0;
338 }
339
340 if (newkey) {
341 /* keep the key in our private storage, but don't use it
342 yet---see kerberos5_reply() below */
343 if ((newkey->enctype != ENCTYPE_DES_CBC_CRC) &&
344 (newkey-> enctype != ENCTYPE_DES_CBC_MD5)) {
345 if ((new_creds->keyblock.enctype == ENCTYPE_DES_CBC_CRC) ||
346 (new_creds->keyblock.enctype == ENCTYPE_DES_CBC_MD5))
347 /* use the session key in credentials instead */
348 krb5_copy_keyblock(telnet_context,&new_creds->keyblock,
349 &session_key);
350 else
351 /* XXX ? */;
352 } else {
353 krb5_copy_keyblock(telnet_context, newkey, &session_key);
354 }
355 krb5_free_keyblock(telnet_context, newkey);
356 }
357 #endif /* ENCRYPTION */
358 krb5_free_cred_contents(telnet_context, &creds);
359 krb5_free_creds(telnet_context, new_creds);
360 if (r) {
361 if (auth_debug_mode) {
362 printf("telnet: Kerberos V5: mk_req failed (%s)\r\n",
363 error_message(r));
364 }
365 return(0);
366 }
367
368 if (!auth_sendname(UserNameRequested, strlen(UserNameRequested))) {
369 if (auth_debug_mode)
370 printf("telnet: Not enough room for user name\r\n");
371 return(0);
372 }
373 if (!Data(ap, KRB_AUTH, auth.data, auth.length)) {
374 if (auth_debug_mode)
375 printf(
376 "telnet: Not enough room for authentication data\r\n");
377 return(0);
378 }
379 if (auth_debug_mode) {
380 printf("telnet: Sent Kerberos V5 credentials to server\r\n");
381 }
382 return(1);
383 }
384
385 void
386 kerberos5_is(ap, data, cnt)
387 Authenticator *ap;
388 unsigned char *data;
389 int cnt;
390 {
391 int r = 0;
392 krb5_principal server;
393 krb5_keyblock *newkey = NULL;
394 krb5_keytab keytabid = 0;
395 krb5_data outbuf;
396 #ifdef ENCRYPTION
397 Session_Key skey;
398 #endif
399 char errbuf[320];
400 char *name;
401 char *getenv();
402 krb5_data inbuf;
403 krb5_authenticator *authenticator;
404
405 if (cnt-- < 1)
406 return;
407 switch (*data++) {
408 case KRB_AUTH:
409 auth.data = (char *)data;
410 auth.length = cnt;
411
412 if (!r && !auth_context)
413 r = krb5_auth_con_init(telnet_context, &auth_context);
414 if (!r) {
415 krb5_rcache rcache;
416
417 r = krb5_auth_con_getrcache(telnet_context, auth_context,
418 &rcache);
419 if (!r && !rcache) {
420 r = krb5_sname_to_principal(telnet_context, 0, 0,
421 KRB5_NT_SRV_HST, &server);
422 if (!r) {
423 r = krb5_get_server_rcache(telnet_context,
424 krb5_princ_component(telnet_context,
425 server, 0),
426 &rcache);
427 krb5_free_principal(telnet_context, server);
428 }
429 }
430 if (!r)
431 r = krb5_auth_con_setrcache(telnet_context,
432 auth_context, rcache);
433 }
434 if (!r && telnet_srvtab)
435 r = krb5_kt_resolve(telnet_context,
436 telnet_srvtab, &keytabid);
437 if (!r)
438 r = krb5_rd_req(telnet_context, &auth_context, &auth,
439 NULL, keytabid, NULL, &ticket);
440 if (r) {
441 (void) strcpy(errbuf, "krb5_rd_req failed: ");
442 errbuf[sizeof(errbuf) - 1] = '\0';
443 (void) strncat(errbuf, error_message(r), sizeof(errbuf) - 1 - strlen(errbuf));
444 goto errout;
445 }
446
447 /*
448 * 256 bytes should be much larger than any reasonable
449 * first component of a service name especially since
450 * the default is of length 4.
451 */
452 if (krb5_princ_component(telnet_context,ticket->server,0)->length < 256) {
453 char princ[256];
454 strncpy(princ,
455 krb5_princ_component(telnet_context, ticket->server,0)->data,
456 krb5_princ_component(telnet_context, ticket->server,0)->length);
457 princ[krb5_princ_component(telnet_context,
458 ticket->server,0)->length] = '\0';
459 if (strcmp("host", princ)) {
460 if(strlen(princ) < sizeof(errbuf) - 39) {
461 (void) sprintf(errbuf, "incorrect service name: \"%s\" != \"host\"",
462 princ);
463 } else {
464 (void) sprintf(errbuf, "incorrect service name: principal != \"host\"");
465 }
466 goto errout;
467 }
468 } else {
469 (void) strcpy(errbuf, "service name too long");
470 goto errout;
471 }
472
473 r = krb5_auth_con_getauthenticator(telnet_context,
474 auth_context,
475 &authenticator);
476 if (r) {
477 (void) strcpy(errbuf,
478 "krb5_auth_con_getauthenticator failed: ");
479 errbuf[sizeof(errbuf) - 1] = '\0';
480 (void) strncat(errbuf, error_message(r), sizeof(errbuf) - 1 - strlen(errbuf));
481 goto errout;
482 }
483 if ((ap->way & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_ON &&
484 !authenticator->checksum) {
485 (void) strcpy(errbuf,
486 "authenticator is missing required checksum");
487 goto errout;
488 }
489 if (authenticator->checksum) {
490 char type_check[2];
491 krb5_checksum *cksum = authenticator->checksum;
492 krb5_keyblock *key;
493
494 type_check[0] = ap->type;
495 type_check[1] = ap->way;
496
497 r = krb5_auth_con_getkey(telnet_context, auth_context,
498 &key);
499 if (r) {
500 (void) strcpy(errbuf, "krb5_auth_con_getkey failed: ");
501 errbuf[sizeof(errbuf) - 1] = '\0';
502 (void) strncat(errbuf, error_message(r), sizeof(errbuf) - 1 - strlen(errbuf));
503 goto errout;
504 }
505 r = krb5_verify_checksum(telnet_context,
506 cksum->checksum_type, cksum,
507 &type_check, 2, key->contents,
508 key->length);
509 /*
510 * Note that krb5_verify_checksum() will fail if a pre-
511 * MIT Kerberos Beta 5 client is attempting to connect
512 * to this server (Beta 6 or later). There is not way to
513 * fix this without compromising encryption. It would be
514 * reasonable to add a -i option to telnetd to ignore
515 * checksums (like in klogind). Such an option is not
516 * present at this time.
517 */
518 if (r) {
519 (void) strcpy(errbuf,
520 "checksum verification failed: ");
521 errbuf[sizeof(errbuf) - 1] = '\0';
522 (void) strncat(errbuf, error_message(r), sizeof(errbuf) - 1 - strlen(errbuf));
523 goto errout;
524 }
525 krb5_free_keyblock(telnet_context, key);
526 }
527 krb5_free_authenticator(telnet_context, authenticator);
528 if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
529 /* do ap_rep stuff here */
530 if ((r = krb5_mk_rep(telnet_context, auth_context,
531 &outbuf))) {
532 (void) strcpy(errbuf, "Make reply failed: ");
533 errbuf[sizeof(errbuf) - 1] = '\0';
534 (void) strncat(errbuf, error_message(r), sizeof(errbuf) - 1 - strlen(errbuf));
535 goto errout;
536 }
537
538 Data(ap, KRB_RESPONSE, outbuf.data, outbuf.length);
539 }
540 if (krb5_unparse_name(telnet_context,
541 ticket->enc_part2 ->client,
542 &name))
543 name = 0;
544 Data(ap, KRB_ACCEPT, name, name ? -1 : 0);
545 if (auth_debug_mode) {
546 printf(
547 "telnetd: Kerberos5 identifies him as ``%s''\r\n",
548 name ? name : "");
549 }
550 auth_finished(ap, AUTH_USER);
551
552 if (name)
553 free(name);
554 krb5_auth_con_getremotesubkey(telnet_context, auth_context,
555 &newkey);
556 if (session_key) {
557 krb5_free_keyblock(telnet_context, session_key);
558 session_key = 0;
559 }
560 if (newkey) {
561 krb5_copy_keyblock(telnet_context, newkey, &session_key);
562 krb5_free_keyblock(telnet_context, newkey);
563 } else {
564 krb5_copy_keyblock(telnet_context,
565 ticket->enc_part2->session,
566 &session_key);
567 }
568
569 #ifdef ENCRYPTION
570 skey.type = SK_DES;
571 skey.length = 8;
572 skey.data = session_key->contents;
573 encrypt_session_key(&skey, 1);
574 #endif
575 break;
576 #ifdef FORWARD
577 case KRB_FORWARD:
578 inbuf.length = cnt;
579 inbuf.data = (char *)data;
580 if ((r = krb5_auth_con_genaddrs(telnet_context, auth_context,
581 net, KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR)) ||
582 (r = rd_and_store_for_creds(telnet_context, auth_context,
583 &inbuf, ticket))) {
584
585 char errbuf[128];
586
587 (void) strcpy(errbuf, "Read forwarded creds failed: ");
588 errbuf[sizeof(errbuf) - 1] = '\0';
589 (void) strncat(errbuf, error_message(r), sizeof(errbuf) - 1 - strlen(errbuf));
590 Data(ap, KRB_FORWARD_REJECT, errbuf, -1);
591 if (auth_debug_mode)
592 printf(
593 "telnetd: Could not read forwarded credentials\r\n");
594 }
595 else
596 Data(ap, KRB_FORWARD_ACCEPT, 0, 0);
597 if (auth_debug_mode)
598 printf("telnetd: Forwarded credentials obtained\r\n");
599 break;
600 #endif /* FORWARD */
601 default:
602 if (auth_debug_mode)
603 printf("telnetd: Unknown Kerberos option %d\r\n",
604 data[-1]);
605 Data(ap, KRB_REJECT, 0, 0);
606 break;
607 }
608 return;
609
610 errout:
611 {
612 char eerrbuf[329];
613
614 strcpy(eerrbuf, "telnetd: ");
615 eerrbuf[sizeof(eerrbuf) - 1] = '\0';
616 strncat(eerrbuf, errbuf, sizeof(eerrbuf) - 1 - strlen(eerrbuf));
617 Data(ap, KRB_REJECT, eerrbuf, -1);
618 }
619 if (auth_debug_mode)
620 printf("telnetd: %s\r\n", errbuf);
621 syslog(LOG_ERR, "%s", errbuf);
622 if (auth_context) {
623 krb5_auth_con_free(telnet_context, auth_context);
624 auth_context = 0;
625 }
626 return;
627 }
628
629 void
630 kerberos5_reply(ap, data, cnt)
631 Authenticator *ap;
632 unsigned char *data;
633 int cnt;
634 {
635 #ifdef ENCRYPTION
636 Session_Key skey;
637 #endif
638 static int mutual_complete = 0;
639
640 if (cnt-- < 1)
641 return;
642 switch (*data++) {
643 case KRB_REJECT:
644 if (cnt > 0) {
645 printf("[ Kerberos V5 refuses authentication because %.*s ]\r\n",
646 cnt, data);
647 } else
648 printf("[ Kerberos V5 refuses authentication ]\r\n");
649 auth_send_retry();
650 return;
651 case KRB_ACCEPT:
652 if (!mutual_complete) {
653 if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
654 printf("[ Kerberos V5 accepted you, but didn't provide mutual authentication! ]\r\n");
655 auth_send_retry();
656 return;
657 }
658 #ifdef ENCRYPTION
659 if (session_key) {
660 skey.type = SK_DES;
661 skey.length = 8;
662 skey.data = session_key->contents;
663 encrypt_session_key(&skey, 0);
664 }
665 #endif /* ENCRYPTION */
666 }
667 if (cnt)
668 printf("[ Kerberos V5 accepts you as ``%.*s'' ]\r\n", cnt, data);
669 else
670 printf("[ Kerberos V5 accepts you ]\r\n");
671 auth_finished(ap, AUTH_USER);
672 #ifdef FORWARD
673 if (forward_flags & OPTS_FORWARD_CREDS)
674 kerberos5_forward(ap);
675 #endif /* FORWARD */
676 break;
677 case KRB_RESPONSE:
678 if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
679 /* the rest of the reply should contain a krb_ap_rep */
680 krb5_ap_rep_enc_part *reply;
681 krb5_data inbuf;
682 krb5_error_code r;
683
684 inbuf.length = cnt;
685 inbuf.data = (char *)data;
686
687 if ((r = krb5_rd_rep(telnet_context, auth_context, &inbuf,
688 &reply))) {
689 printf("[ Mutual authentication failed: %s ]\r\n",
690 error_message(r));
691 auth_send_retry();
692 return;
693 }
694 krb5_free_ap_rep_enc_part(telnet_context, reply);
695 #ifdef ENCRYPTION
696 if (session_key) {
697 skey.type = SK_DES;
698 skey.length = 8;
699 skey.data = session_key->contents;
700 encrypt_session_key(&skey, 0);
701 }
702 #endif /* ENCRYPTION */
703 mutual_complete = 1;
704 }
705 return;
706 #ifdef FORWARD
707 case KRB_FORWARD_ACCEPT:
708 printf("[ Kerberos V5 accepted forwarded credentials ]\r\n");
709 return;
710 case KRB_FORWARD_REJECT:
711 printf("[ Kerberos V5 refuses forwarded credentials because %.*s ]\r\n",
712 cnt, data);
713 return;
714 #endif /* FORWARD */
715 default:
716 if (auth_debug_mode)
717 printf("Unknown Kerberos option %d\r\n", data[-1]);
718 return;
719 }
720 return;
721 }
722
723 int
724 kerberos5_status(ap, name, level)
725 Authenticator *ap;
726 char *name;
727 int level;
728 {
729 if (level < AUTH_USER)
730 return(level);
731
732 if (UserNameRequested &&
733 krb5_kuserok(telnet_context, ticket->enc_part2->client,
734 UserNameRequested))
735 {
736 /* the name buffer comes from telnetd/telnetd{-ktd}.c */
737 strncpy(name, UserNameRequested, 255);
738 name[255] = '\0';
739 return(AUTH_VALID);
740 } else
741 return(AUTH_USER);
742 }
743
744 #define BUMP(buf, len) while (*(buf)) {++(buf), --(len);}
745 #define ADDC(buf, len, c) if ((len) > 0) {*(buf)++ = (c); --(len);}
746
747 void
748 kerberos5_printsub(data, cnt, buf, buflen)
749 unsigned char *data, *buf;
750 int cnt, buflen;
751 {
752 char lbuf[32];
753 register int i;
754
755 buf[buflen-1] = '\0'; /* make sure its NULL terminated */
756 buflen -= 1;
757
758 switch(data[3]) {
759 case KRB_REJECT: /* Rejected (reason might follow) */
760 strncpy((char *)buf, " REJECT ", buflen);
761 goto common;
762
763 case KRB_ACCEPT: /* Accepted (name might follow) */
764 strncpy((char *)buf, " ACCEPT ", buflen);
765 common:
766 BUMP(buf, buflen);
767 if (cnt <= 4)
768 break;
769 ADDC(buf, buflen, '"');
770 for (i = 4; i < cnt; i++)
771 ADDC(buf, buflen, data[i]);
772 ADDC(buf, buflen, '"');
773 ADDC(buf, buflen, '\0');
774 break;
775
776
777 case KRB_AUTH: /* Authentication data follows */
778 strncpy((char *)buf, " AUTH", buflen);
779 goto common2;
780
781 case KRB_RESPONSE:
782 strncpy((char *)buf, " RESPONSE", buflen);
783 goto common2;
784
785 #ifdef FORWARD
786 case KRB_FORWARD: /* Forwarded credentials follow */
787 strncpy((char *)buf, " FORWARD", buflen);
788 goto common2;
789
790 case KRB_FORWARD_ACCEPT: /* Forwarded credentials accepted */
791 strncpy((char *)buf, " FORWARD_ACCEPT", buflen);
792 goto common2;
793
794 case KRB_FORWARD_REJECT: /* Forwarded credentials rejected */
795 /* (reason might follow) */
796 strncpy((char *)buf, " FORWARD_REJECT", buflen);
797 goto common2;
798 #endif /* FORWARD */
799
800 default:
801 sprintf(lbuf, " %d (unknown)", data[3]);
802 strncpy((char *)buf, lbuf, buflen);
803 common2:
804 BUMP(buf, buflen);
805 for (i = 4; i < cnt; i++) {
806 sprintf(lbuf, " %d", data[i]);
807 strncpy((char *)buf, lbuf, buflen);
808 BUMP(buf, buflen);
809 }
810 break;
811 }
812 }
813
814 #ifdef FORWARD
815
816 void
817 kerberos5_forward(ap)
818 Authenticator *ap;
819 {
820 krb5_error_code r;
821 krb5_ccache ccache;
822 krb5_principal client = 0;
823 krb5_principal server = 0;
824 krb5_data forw_creds;
825
826 forw_creds.data = 0;
827
828 if ((r = krb5_cc_default(telnet_context, &ccache))) {
829 if (auth_debug_mode)
830 printf("Kerberos V5: could not get default ccache - %s\r\n",
831 error_message(r));
832 return;
833 }
834
835 if ((r = krb5_cc_get_principal(telnet_context, ccache, &client))) {
836 if (auth_debug_mode)
837 printf("Kerberos V5: could not get default principal - %s\r\n",
838 error_message(r));
839 goto cleanup;
840 }
841
842 if ((r = krb5_sname_to_principal(telnet_context, RemoteHostName, "host",
843 KRB5_NT_SRV_HST, &server))) {
844 if (auth_debug_mode)
845 printf("Kerberos V5: could not make server principal - %s\r\n",
846 error_message(r));
847 goto cleanup;
848 }
849
850 if ((r = krb5_auth_con_genaddrs(telnet_context, auth_context, net,
851 KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR))) {
852 if (auth_debug_mode)
853 printf("Kerberos V5: could not gen local full address - %s\r\n",
854 error_message(r));
855 goto cleanup;
856 }
857
858 if ((r = krb5_fwd_tgt_creds(telnet_context, auth_context, 0, client,
859 server, ccache,
860 forward_flags & OPTS_FORWARDABLE_CREDS,
861 &forw_creds))) {
862 if (auth_debug_mode)
863 printf("Kerberos V5: error getting forwarded creds - %s\r\n",
864 error_message(r));
865 goto cleanup;
866 }
867
868 /* Send forwarded credentials */
869 if (!Data(ap, KRB_FORWARD, forw_creds.data, forw_creds.length)) {
870 if (auth_debug_mode)
871 printf("Not enough room for authentication data\r\n");
872 } else {
873 if (auth_debug_mode)
874 printf("Forwarded local Kerberos V5 credentials to server\r\n");
875 }
876
877 cleanup:
878 if (client)
879 krb5_free_principal(telnet_context, client);
880 if (server)
881 krb5_free_principal(telnet_context, server);
882 if (forw_creds.data)
883 free(forw_creds.data);
884 krb5_cc_close(telnet_context, ccache);
885 }
886 #endif /* FORWARD */
887
888 #endif /* KRB5 */