Annotation of src/usr.bin/telnet/kerberos5.c, Revision 1.2
1.2 ! ajacouto 1: /* $OpenBSD: kerberos5.c,v 1.1 2005/05/24 03:43:56 deraadt Exp $ */
1.1 deraadt 2:
3: /*-
4: * Copyright (c) 1991, 1993
5: * The Regents of the University of California. All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: * 3. Neither the name of the University nor the names of its contributors
16: * may be used to endorse or promote products derived from this software
17: * without specific prior written permission.
18: *
19: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29: * SUCH DAMAGE.
30: */
31:
32: /*
33: * This source code is no longer held under any constraint of USA
34: * `cryptographic laws' since it was exported legally. The cryptographic
35: * functions were removed from the code and a "Bones" distribution was
36: * made. A Commodity Jurisdiction Request #012-94 was filed with the
37: * USA State Department, who handed it to the Commerce department. The
38: * code was determined to fall under General License GTDA under ECCN 5D96G,
39: * and hence exportable. The cryptographic interfaces were re-added by Eric
40: * Young, and then KTH proceeded to maintain the code in the free world.
41: *
42: */
43:
44: /*
45: * Copyright (C) 1990 by the Massachusetts Institute of Technology
46: *
47: * Export of this software from the United States of America may
48: * require a specific license from the United States Government.
49: * It is the responsibility of any person or organization contemplating
50: * export to obtain such a license before exporting.
51: *
52: * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
53: * distribute this software and its documentation for any purpose and
54: * without fee is hereby granted, provided that the above copyright
55: * notice appear in all copies and that both that copyright notice and
56: * this permission notice appear in supporting documentation, and that
57: * the name of M.I.T. not be used in advertising or publicity pertaining
58: * to distribution of the software without specific, written prior
59: * permission. M.I.T. makes no representations about the suitability of
60: * this software for any purpose. It is provided "as is" without express
61: * or implied warranty.
62: */
63:
64: /* $KTH: kerberos5.c,v 1.47 2001/01/09 18:45:33 assar Exp $ */
65:
66: #ifdef KRB5
67:
68: #include <arpa/telnet.h>
69: #include <stdio.h>
70: #include <stdlib.h>
71: #include <string.h>
72: #include <unistd.h>
73: #include <netdb.h>
74: #include <ctype.h>
75: #include <pwd.h>
76: #include <errno.h>
77: #define Authenticator k5_Authenticator
78: #include <kerberosV/krb5.h>
79: #undef Authenticator
80: #include <err.h>
81:
82: #include "encrypt.h"
83: #include "auth.h"
84: #include "misc.h"
85:
86: #if defined(DCE)
87: int dfsk5ok = 0;
88: int dfspag = 0;
89: int dfsfwd = 0;
90: #endif
91:
92: int forward_flags = 0; /* Flags get set in telnet/main.c on -f and -F */
93:
94: int forward(int);
95: int forwardable(int);
96:
97: /* These values need to be the same as those defined in telnet/main.c. */
98: /* Either define them in both places, or put in some common header file. */
99: #define OPTS_FORWARD_CREDS 0x00000002
100: #define OPTS_FORWARDABLE_CREDS 0x00000001
101:
102:
103: void kerberos5_forward (Authenticator *);
104:
105: static unsigned char str_data[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 0,
106: AUTHTYPE_KERBEROS_V5, };
107:
108: #define KRB_AUTH 0 /* Authentication data follows */
109: #define KRB_REJECT 1 /* Rejected (reason might follow) */
110: #define KRB_ACCEPT 2 /* Accepted */
111: #define KRB_RESPONSE 3 /* Response for mutual auth. */
112:
113: #define KRB_FORWARD 4 /* Forwarded credentials follow */
114: #define KRB_FORWARD_ACCEPT 5 /* Forwarded credentials accepted */
115: #define KRB_FORWARD_REJECT 6 /* Forwarded credentials rejected */
116:
117: static krb5_data auth;
118: static krb5_ticket *ticket;
119:
120: static krb5_context context;
121: static krb5_auth_context auth_context;
122:
123: int
124: check_krb5_tickets()
125: {
126: krb5_error_code ret;
127: krb5_context context;
128: krb5_ccache ccache;
129: krb5_principal principal;
130: int retval = 1;
131:
132: ret = krb5_init_context(&context);
133: if(ret)
134: errx(1, "krb5_init_context failt: %d", ret);
135:
136: ret = krb5_cc_default(context, &ccache);
137: if(ret)
138: errx(1, "krb5_cc_default: %d", ret);
139:
140: ret = krb5_cc_get_principal (context, ccache, &principal);
141: switch(ret) {
142: case ENOENT:
143: retval = 0;
144: goto done;
145: case 0:
146: retval = 1;
147: goto done;
148: default:
149: errx(1, "krb5_cc_get_principal: %d", ret);
150: break;
151: }
152:
153: done:
154: krb5_free_context(context);
155: return retval;
156: }
157:
158: static int
159: Data(Authenticator *ap, int type, void *d, int c)
160: {
161: unsigned char *p = str_data + 4;
162: unsigned char *cd = (unsigned char *)d;
163:
164: if (c == -1)
165: c = strlen(cd);
166:
167: if (auth_debug_mode) {
168: printf("%s:%d: [%d] (%d)",
169: str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY",
170: str_data[3],
171: type, c);
172: printd(d, c);
173: printf("\r\n");
174: }
175: *p++ = ap->type;
176: *p++ = ap->way;
177: *p++ = type;
178: while (c-- > 0) {
179: if ((*p++ = *cd++) == IAC)
180: *p++ = IAC;
181: }
182: *p++ = IAC;
183: *p++ = SE;
184: if (str_data[3] == TELQUAL_IS)
185: printsub('>', &str_data[2], p - &str_data[2]);
186: return(telnet_net_write(str_data, p - str_data));
187: }
188:
189: int
190: kerberos5_init(Authenticator *ap, int server)
191: {
192: krb5_error_code ret;
193:
194: ret = krb5_init_context(&context);
195: if (ret)
196: return 0;
197: if (server) {
198: krb5_keytab kt;
199: krb5_kt_cursor cursor;
200:
201: ret = krb5_kt_default(context, &kt);
202: if (ret)
203: return 0;
204:
205: ret = krb5_kt_start_seq_get (context, kt, &cursor);
206: if (ret) {
207: krb5_kt_close (context, kt);
208: return 0;
209: }
210: krb5_kt_end_seq_get (context, kt, &cursor);
211: krb5_kt_close (context, kt);
212:
213: str_data[3] = TELQUAL_REPLY;
214: } else
215: str_data[3] = TELQUAL_IS;
216: return(1);
217: }
218:
219: extern int net;
220: static int
221: kerberos5_send(char *name, Authenticator *ap)
222: {
223: krb5_error_code ret;
224: krb5_ccache ccache;
225: int ap_opts;
226: krb5_data cksum_data;
227: char foo[2];
1.2 ! ajacouto 228: const char *s;
1.1 deraadt 229:
230: if(check_krb5_tickets() != 1)
231: return 0;
232:
233: if (!UserNameRequested) {
234: if (auth_debug_mode) {
235: printf("Kerberos V5: no user name supplied\r\n");
236: }
237: return(0);
238: }
239:
240: ret = krb5_cc_default(context, &ccache);
241: if (ret) {
242: if (auth_debug_mode) {
1.2 ! ajacouto 243: s = krb5_get_error_message(context, ret);
! 244: printf("Kerberos V5: could not get default ccache: %s\r\n", s);
! 245: krb5_free_error_message(context, s);
1.1 deraadt 246: }
247: return 0;
248: }
249:
250: if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL)
251: ap_opts = AP_OPTS_MUTUAL_REQUIRED;
252: else
253: ap_opts = 0;
254:
255: ap_opts |= AP_OPTS_USE_SUBKEY;
256:
257: ret = krb5_auth_con_init (context, &auth_context);
258: if (ret) {
259: if (auth_debug_mode) {
1.2 ! ajacouto 260: s = krb5_get_error_message(context, ret);
! 261: printf("Kerberos V5: krb5_auth_con_init failed (%s)\r\n", s);
! 262: krb5_free_error_message(context, s);
1.1 deraadt 263: }
264: return(0);
265: }
266:
267: ret = krb5_auth_con_setaddrs_from_fd (context,
268: auth_context,
269: &net);
270: if (ret) {
271: if (auth_debug_mode) {
1.2 ! ajacouto 272: s = krb5_get_error_message(context, ret);
1.1 deraadt 273: printf ("Kerberos V5:"
1.2 ! ajacouto 274: " krb5_auth_con_setaddrs_from_fd failed (%s)\r\n", s);
! 275: krb5_free_error_message(context, s);
1.1 deraadt 276: }
277: return(0);
278: }
279:
280: krb5_auth_con_setkeytype (context, auth_context, KEYTYPE_DES);
281:
282: foo[0] = ap->type;
283: foo[1] = ap->way;
284:
285: cksum_data.length = sizeof(foo);
286: cksum_data.data = foo;
287:
288:
289: {
290: krb5_principal service;
291: char sname[128];
292:
293:
294: ret = krb5_sname_to_principal (context,
295: RemoteHostName,
296: NULL,
297: KRB5_NT_SRV_HST,
298: &service);
299: if(ret) {
300: if (auth_debug_mode) {
1.2 ! ajacouto 301: s = krb5_get_error_message(context, ret);
1.1 deraadt 302: printf ("Kerberos V5:"
1.2 ! ajacouto 303: " krb5_sname_to_principal(%s) failed (%s)\r\n", RemoteHostName, s);
! 304: krb5_free_error_message(context, s);
1.1 deraadt 305: }
306: return 0;
307: }
308: ret = krb5_unparse_name_fixed(context, service, sname, sizeof(sname));
309: if(ret) {
310: if (auth_debug_mode) {
1.2 ! ajacouto 311: s = krb5_get_error_message(context, ret);
1.1 deraadt 312: printf ("Kerberos V5:"
1.2 ! ajacouto 313: " krb5_unparse_name_fixed failed (%s)\r\n", s);
! 314: krb5_free_error_message(context, s);
1.1 deraadt 315: }
316: return 0;
317: }
318: printf("[ Trying %s (%s)... ]\r\n", name, sname);
319: ret = krb5_mk_req_exact(context, &auth_context, ap_opts,
320: service,
321: &cksum_data, ccache, &auth);
322: krb5_free_principal (context, service);
323:
324: }
325: if (ret) {
326: if (1 || auth_debug_mode) {
1.2 ! ajacouto 327: s = krb5_get_error_message(context, ret);
! 328: printf("Kerberos V5: mk_req failed (%s)\r\n", s);
! 329: krb5_free_error_message(context, s);
1.1 deraadt 330: }
331: return(0);
332: }
333:
334: if (!auth_sendname((unsigned char *)UserNameRequested,
335: strlen(UserNameRequested))) {
336: if (auth_debug_mode)
337: printf("Not enough room for user name\r\n");
338: return(0);
339: }
340: if (!Data(ap, KRB_AUTH, auth.data, auth.length)) {
341: if (auth_debug_mode)
342: printf("Not enough room for authentication data\r\n");
343: return(0);
344: }
345: if (auth_debug_mode) {
346: printf("Sent Kerberos V5 credentials to server\r\n");
347: }
348: return(1);
349: }
350:
351: int
352: kerberos5_send_mutual(Authenticator *ap)
353: {
354: return kerberos5_send("mutual KERBEROS5", ap);
355: }
356:
357: int
358: kerberos5_send_oneway(Authenticator *ap)
359: {
360: return kerberos5_send("KERBEROS5", ap);
361: }
362:
363: void
364: kerberos5_is(Authenticator *ap, unsigned char *data, int cnt)
365: {
366: krb5_error_code ret;
367: krb5_data outbuf;
368: krb5_keyblock *key_block;
369: char *name;
370: krb5_principal server;
371: int zero = 0;
1.2 ! ajacouto 372: const char *s;
1.1 deraadt 373:
374: if (cnt-- < 1)
375: return;
376: switch (*data++) {
377: case KRB_AUTH:
378: auth.data = (char *)data;
379: auth.length = cnt;
380:
381: auth_context = NULL;
382:
383: ret = krb5_auth_con_init (context, &auth_context);
384: if (ret) {
385: Data(ap, KRB_REJECT, "krb5_auth_con_init failed", -1);
386: auth_finished(ap, AUTH_REJECT);
1.2 ! ajacouto 387: if (auth_debug_mode) {
! 388: s = krb5_get_error_message(context, ret);
! 389: printf("Kerberos V5: krb5_auth_con_init failed (%s)\r\n", s);
! 390: krb5_free_error_message(context, s);
! 391: }
1.1 deraadt 392: return;
393: }
394:
395: ret = krb5_auth_con_setaddrs_from_fd (context,
396: auth_context,
397: &zero);
398: if (ret) {
399: Data(ap, KRB_REJECT, "krb5_auth_con_setaddrs_from_fd failed", -1);
400: auth_finished(ap, AUTH_REJECT);
1.2 ! ajacouto 401: if (auth_debug_mode) {
! 402: s = krb5_get_error_message(context, ret);
1.1 deraadt 403: printf("Kerberos V5: "
1.2 ! ajacouto 404: "krb5_auth_con_setaddrs_from_fd failed (%s)\r\n", s);
! 405: krb5_free_error_message(context, s);
! 406: }
1.1 deraadt 407: return;
408: }
409:
410: ret = krb5_sock_to_principal (context,
411: 0,
412: "host",
413: KRB5_NT_SRV_HST,
414: &server);
415: if (ret) {
416: Data(ap, KRB_REJECT, "krb5_sock_to_principal failed", -1);
417: auth_finished(ap, AUTH_REJECT);
1.2 ! ajacouto 418: if (auth_debug_mode) {
! 419: s = krb5_get_error_message(context, ret);
1.1 deraadt 420: printf("Kerberos V5: "
1.2 ! ajacouto 421: "krb5_sock_to_principal failed (%s)\r\n", s);
! 422: krb5_free_error_message(context, s);
! 423: }
1.1 deraadt 424: return;
425: }
426:
427: ret = krb5_rd_req(context,
428: &auth_context,
429: &auth,
430: server,
431: NULL,
432: NULL,
433: &ticket);
434:
435: krb5_free_principal (context, server);
436: if (ret) {
437: char *errbuf;
1.2 ! ajacouto 438: s = krb5_get_error_message(context, ret);
1.1 deraadt 439:
440: asprintf(&errbuf,
1.2 ! ajacouto 441: "Read req failed: %s", s);
! 442: krb5_free_error_message(context, s);
1.1 deraadt 443: Data(ap, KRB_REJECT, errbuf, -1);
444: if (auth_debug_mode)
445: printf("%s\r\n", errbuf);
446: free (errbuf);
447: return;
448: }
449:
450: {
451: char foo[2];
452:
453: foo[0] = ap->type;
454: foo[1] = ap->way;
455:
456: ret = krb5_verify_authenticator_checksum(context,
457: auth_context,
458: foo,
459: sizeof(foo));
460:
461: if (ret) {
462: char *errbuf;
1.2 ! ajacouto 463: s = krb5_get_error_message(context, ret);
! 464: asprintf(&errbuf, "Bad checksum: %s", s);
! 465: krb5_free_error_message(context, s);
1.1 deraadt 466: Data(ap, KRB_REJECT, errbuf, -1);
467: if (auth_debug_mode)
468: printf ("%s\r\n", errbuf);
469: free(errbuf);
470: return;
471: }
472: }
473: ret = krb5_auth_con_getremotesubkey (context,
474: auth_context,
475: &key_block);
476:
477: if (ret) {
478: Data(ap, KRB_REJECT, "krb5_auth_con_getremotesubkey failed", -1);
479: auth_finished(ap, AUTH_REJECT);
1.2 ! ajacouto 480: if (auth_debug_mode) {
! 481: s = krb5_get_error_message(context, ret);
1.1 deraadt 482: printf("Kerberos V5: "
1.2 ! ajacouto 483: "krb5_auth_con_getremotesubkey failed (%s)\r\n", s);
! 484: krb5_free_error_message(context, s);
! 485: }
1.1 deraadt 486: return;
487: }
488:
489: if (key_block == NULL) {
490: ret = krb5_auth_con_getkey(context,
491: auth_context,
492: &key_block);
493: }
494: if (ret) {
495: Data(ap, KRB_REJECT, "krb5_auth_con_getkey failed", -1);
496: auth_finished(ap, AUTH_REJECT);
1.2 ! ajacouto 497: if (auth_debug_mode) {
! 498: s = krb5_get_error_message(context, ret);
1.1 deraadt 499: printf("Kerberos V5: "
1.2 ! ajacouto 500: "krb5_auth_con_getkey failed (%s)\r\n", s);
! 501: krb5_free_error_message(context, s);
! 502: }
1.1 deraadt 503: return;
504: }
505: if (key_block == NULL) {
506: Data(ap, KRB_REJECT, "no subkey received", -1);
507: auth_finished(ap, AUTH_REJECT);
508: if (auth_debug_mode)
509: printf("Kerberos V5: "
510: "krb5_auth_con_getremotesubkey returned NULL key\r\n");
511: return;
512: }
513:
514: if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
515: ret = krb5_mk_rep(context, auth_context, &outbuf);
516: if (ret) {
517: Data(ap, KRB_REJECT,
518: "krb5_mk_rep failed", -1);
519: auth_finished(ap, AUTH_REJECT);
1.2 ! ajacouto 520: if (auth_debug_mode) {
! 521: s = krb5_get_error_message(context, ret);
1.1 deraadt 522: printf("Kerberos V5: "
1.2 ! ajacouto 523: "krb5_mk_rep failed (%s)\r\n", s);
! 524: krb5_free_error_message(context, s);
! 525: }
1.1 deraadt 526: return;
527: }
528: Data(ap, KRB_RESPONSE, outbuf.data, outbuf.length);
529: }
530: if (krb5_unparse_name(context, ticket->client, &name))
531: name = 0;
532:
533: if(UserNameRequested && krb5_kuserok(context,
534: ticket->client,
535: UserNameRequested)) {
536: Data(ap, KRB_ACCEPT, name, name ? -1 : 0);
537: if (auth_debug_mode) {
538: printf("Kerberos5 identifies him as ``%s''\r\n",
539: name ? name : "");
540: }
541:
542: if(key_block->keytype == ETYPE_DES_CBC_MD5 ||
543: key_block->keytype == ETYPE_DES_CBC_MD4 ||
544: key_block->keytype == ETYPE_DES_CBC_CRC) {
545: Session_Key skey;
546:
547: skey.type = SK_DES;
548: skey.length = 8;
549: skey.data = key_block->keyvalue.data;
550: encrypt_session_key(&skey, 0);
551: }
552:
553: } else {
554: char *msg;
555:
556: asprintf (&msg, "user `%s' is not authorized to "
557: "login as `%s'",
558: name ? name : "<unknown>",
559: UserNameRequested ? UserNameRequested : "<nobody>");
560: if (msg == NULL)
561: Data(ap, KRB_REJECT, NULL, 0);
562: else {
563: Data(ap, KRB_REJECT, (void *)msg, -1);
564: free(msg);
565: }
566: auth_finished (ap, AUTH_REJECT);
567: krb5_free_keyblock_contents(context, key_block);
568: break;
569: }
570: auth_finished(ap, AUTH_USER);
571: krb5_free_keyblock_contents(context, key_block);
572:
573: break;
574: case KRB_FORWARD: {
575: struct passwd *pwd;
576: char ccname[1024]; /* XXX */
577: krb5_data inbuf;
578: krb5_ccache ccache;
579: inbuf.data = (char *)data;
580: inbuf.length = cnt;
581:
582: pwd = getpwnam (UserNameRequested);
583: if (pwd == NULL)
584: break;
585:
586: snprintf (ccname, sizeof(ccname),
587: "FILE:/tmp/krb5cc_%u", pwd->pw_uid);
588:
589: ret = krb5_cc_resolve (context, ccname, &ccache);
590: if (ret) {
1.2 ! ajacouto 591: if (auth_debug_mode) {
! 592: s = krb5_get_error_message(context, ret);
! 593: printf ("Kerberos V5: could not get ccache: %s\r\n", s);
! 594: krb5_free_error_message(context, s);
! 595: }
1.1 deraadt 596: break;
597: }
598:
599: ret = krb5_cc_initialize (context,
600: ccache,
601: ticket->client);
602: if (ret) {
1.2 ! ajacouto 603: if (auth_debug_mode) {
! 604: s = krb5_get_error_message(context, ret);
! 605: printf ("Kerberos V5: could not init ccache: %s\r\n", s);
! 606: krb5_free_error_message(context, s);
! 607: }
1.1 deraadt 608: break;
609: }
610:
611: #if defined(DCE)
612: esetenv("KRB5CCNAME", ccname, 1);
613: #endif
614: ret = krb5_rd_cred2 (context,
615: auth_context,
616: ccache,
617: &inbuf);
618: if(ret) {
619: char *errbuf;
1.2 ! ajacouto 620: s = krb5_get_error_message(context, ret);
1.1 deraadt 621:
622: asprintf (&errbuf,
1.2 ! ajacouto 623: "Read forwarded creds failed: %s", s);
! 624: krb5_free_error_message(context, s);
1.1 deraadt 625: if(errbuf == NULL)
626: Data(ap, KRB_FORWARD_REJECT, NULL, 0);
627: else
628: Data(ap, KRB_FORWARD_REJECT, errbuf, -1);
629: if (auth_debug_mode)
630: printf("Could not read forwarded credentials: %s\r\n",
631: errbuf);
632: free (errbuf);
633: } else {
634: Data(ap, KRB_FORWARD_ACCEPT, 0, 0);
635: #if defined(DCE)
636: dfsfwd = 1;
637: #endif
638: }
639: chown (ccname + 5, pwd->pw_uid, -1);
640: if (auth_debug_mode)
641: printf("Forwarded credentials obtained\r\n");
642: break;
643: }
644: default:
645: if (auth_debug_mode)
646: printf("Unknown Kerberos option %d\r\n", data[-1]);
647: Data(ap, KRB_REJECT, 0, 0);
648: break;
649: }
650: }
651:
652: void
653: kerberos5_reply(Authenticator *ap, unsigned char *data, int cnt)
654: {
655: static int mutual_complete = 0;
1.2 ! ajacouto 656: const char *s;
1.1 deraadt 657:
658: if (cnt-- < 1)
659: return;
660: switch (*data++) {
661: case KRB_REJECT:
662: if (cnt > 0) {
663: printf("[ Kerberos V5 refuses authentication because %.*s ]\r\n",
664: cnt, data);
665: } else
666: printf("[ Kerberos V5 refuses authentication ]\r\n");
667: auth_send_retry();
668: return;
669: case KRB_ACCEPT: {
670: krb5_error_code ret;
671: Session_Key skey;
672: krb5_keyblock *keyblock;
673:
674: if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL &&
675: !mutual_complete) {
676: printf("[ Kerberos V5 accepted you, but didn't provide mutual authentication! ]\r\n");
677: auth_send_retry();
678: return;
679: }
680: if (cnt)
681: printf("[ Kerberos V5 accepts you as ``%.*s'' ]\r\n", cnt, data);
682: else
683: printf("[ Kerberos V5 accepts you ]\r\n");
684:
685: ret = krb5_auth_con_getlocalsubkey (context,
686: auth_context,
687: &keyblock);
688: if (ret)
689: ret = krb5_auth_con_getkey (context,
690: auth_context,
691: &keyblock);
692: if(ret) {
1.2 ! ajacouto 693: s = krb5_get_error_message(context, ret);
! 694: printf("[ krb5_auth_con_getkey: %s ]\r\n", s);
! 695: krb5_free_error_message(context, s);
1.1 deraadt 696: auth_send_retry();
697: return;
698: }
699:
700: skey.type = SK_DES;
701: skey.length = 8;
702: skey.data = keyblock->keyvalue.data;
703: encrypt_session_key(&skey, 0);
704: krb5_free_keyblock_contents (context, keyblock);
705: auth_finished(ap, AUTH_USER);
706: if (forward_flags & OPTS_FORWARD_CREDS)
707: kerberos5_forward(ap);
708: break;
709: }
710: case KRB_RESPONSE:
711: if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
712: /* the rest of the reply should contain a krb_ap_rep */
713: krb5_ap_rep_enc_part *reply;
714: krb5_data inbuf;
715: krb5_error_code ret;
716:
717: inbuf.length = cnt;
718: inbuf.data = (char *)data;
719:
720: ret = krb5_rd_rep(context, auth_context, &inbuf, &reply);
721: if (ret) {
1.2 ! ajacouto 722: s = krb5_get_error_message(context, ret);
! 723: printf("[ Mutual authentication failed: %s ]\r\n", s);
! 724: krb5_free_error_message(context, s);
1.1 deraadt 725: auth_send_retry();
726: return;
727: }
728: krb5_free_ap_rep_enc_part(context, reply);
729: mutual_complete = 1;
730: }
731: return;
732: case KRB_FORWARD_ACCEPT:
733: printf("[ Kerberos V5 accepted forwarded credentials ]\r\n");
734: return;
735: case KRB_FORWARD_REJECT:
736: printf("[ Kerberos V5 refuses forwarded credentials because %.*s ]\r\n",
737: cnt, data);
738: return;
739: default:
740: if (auth_debug_mode)
741: printf("Unknown Kerberos option %d\r\n", data[-1]);
742: return;
743: }
744: }
745:
746: int
747: kerberos5_status(Authenticator *ap, char *name, size_t name_sz, int level)
748: {
749: if (level < AUTH_USER)
750: return(level);
751:
752: if (UserNameRequested &&
753: krb5_kuserok(context,
754: ticket->client,
755: UserNameRequested))
756: {
757: strlcpy(name, UserNameRequested, name_sz);
758: #if defined(DCE)
759: dfsk5ok = 1;
760: #endif
761: return(AUTH_VALID);
762: } else
763: return(AUTH_USER);
764: }
765:
766: #define BUMP(buf, len) while (*(buf)) {++(buf), --(len);}
767: #define ADDC(buf, len, c) if ((len) > 0) {*(buf)++ = (c); --(len);}
768:
769: void
770: kerberos5_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen)
771: {
772: int i;
773:
774: buf[buflen-1] = '\0'; /* make sure its NULL terminated */
775: buflen -= 1;
776:
777: switch(data[3]) {
778: case KRB_REJECT: /* Rejected (reason might follow) */
779: strlcpy((char *)buf, " REJECT ", buflen);
780: goto common;
781:
782: case KRB_ACCEPT: /* Accepted (name might follow) */
783: strlcpy((char *)buf, " ACCEPT ", buflen);
784: common:
785: BUMP(buf, buflen);
786: if (cnt <= 4)
787: break;
788: ADDC(buf, buflen, '"');
789: for (i = 4; i < cnt; i++)
790: ADDC(buf, buflen, data[i]);
791: ADDC(buf, buflen, '"');
792: ADDC(buf, buflen, '\0');
793: break;
794:
795:
796: case KRB_AUTH: /* Authentication data follows */
797: strlcpy((char *)buf, " AUTH", buflen);
798: goto common2;
799:
800: case KRB_RESPONSE:
801: strlcpy((char *)buf, " RESPONSE", buflen);
802: goto common2;
803:
804: case KRB_FORWARD: /* Forwarded credentials follow */
805: strlcpy((char *)buf, " FORWARD", buflen);
806: goto common2;
807:
808: case KRB_FORWARD_ACCEPT: /* Forwarded credentials accepted */
809: strlcpy((char *)buf, " FORWARD_ACCEPT", buflen);
810: goto common2;
811:
812: case KRB_FORWARD_REJECT: /* Forwarded credentials rejected */
813: /* (reason might follow) */
814: strlcpy((char *)buf, " FORWARD_REJECT", buflen);
815: goto common2;
816:
817: default:
818: snprintf(buf, buflen, " %d (unknown)", data[3]);
819: common2:
820: BUMP(buf, buflen);
821: for (i = 4; i < cnt; i++) {
822: snprintf(buf, buflen, " %d", data[i]);
823: BUMP(buf, buflen);
824: }
825: break;
826: }
827: }
828:
829: void
830: kerberos5_forward(Authenticator *ap)
831: {
832: krb5_error_code ret;
833: krb5_ccache ccache;
834: krb5_creds creds;
835: krb5_kdc_flags flags;
836: krb5_data out_data;
837: krb5_principal principal;
1.2 ! ajacouto 838: const char *s;
1.1 deraadt 839:
840: ret = krb5_cc_default (context, &ccache);
841: if (ret) {
1.2 ! ajacouto 842: if (auth_debug_mode) {
! 843: s = krb5_get_error_message(context, ret);
! 844: printf ("KerberosV5: could not get default ccache: %s\r\n", s);
! 845: krb5_free_error_message(context, s);
! 846: }
1.1 deraadt 847: return;
848: }
849:
850: ret = krb5_cc_get_principal (context, ccache, &principal);
851: if (ret) {
1.2 ! ajacouto 852: if (auth_debug_mode) {
! 853: s = krb5_get_error_message(context, ret);
! 854: printf ("KerberosV5: could not get principal: %s\r\n", s);
! 855: krb5_free_error_message(context, s);
! 856: }
1.1 deraadt 857: return;
858: }
859:
860: memset (&creds, 0, sizeof(creds));
861:
862: creds.client = principal;
863:
864: ret = krb5_build_principal (context,
865: &creds.server,
866: strlen(principal->realm),
867: principal->realm,
868: "krbtgt",
869: principal->realm,
870: NULL);
871:
872: if (ret) {
1.2 ! ajacouto 873: if (auth_debug_mode) {
! 874: s = krb5_get_error_message(context, ret);
! 875: printf ("KerberosV5: could not get principal: %s\r\n", s);
! 876: krb5_free_error_message(context, s);
! 877: }
1.1 deraadt 878: return;
879: }
880:
881: creds.times.endtime = 0;
882:
883: flags.i = 0;
884: flags.b.forwarded = 1;
885: if (forward_flags & OPTS_FORWARDABLE_CREDS)
886: flags.b.forwardable = 1;
887:
888: ret = krb5_get_forwarded_creds (context,
889: auth_context,
890: ccache,
891: flags.i,
892: RemoteHostName,
893: &creds,
894: &out_data);
895: if (ret) {
1.2 ! ajacouto 896: if (auth_debug_mode) {
! 897: s = krb5_get_error_message(context, ret);
! 898: printf ("Kerberos V5: error getting forwarded creds: %s\r\n", s);
! 899: krb5_free_error_message(context, s);
! 900: }
1.1 deraadt 901: return;
902: }
903:
904: if(!Data(ap, KRB_FORWARD, out_data.data, out_data.length)) {
905: if (auth_debug_mode)
906: printf("Not enough room for authentication data\r\n");
907: } else {
908: if (auth_debug_mode)
909: printf("Forwarded local Kerberos V5 credentials to server\r\n");
910: }
911: }
912:
913: #if defined(DCE)
914: /* if this was a K5 authentication try and join a PAG for the user. */
915: void
916: kerberos5_dfspag(void)
917: {
918: if (dfsk5ok) {
919: dfspag = krb5_dfs_pag(context, dfsfwd, ticket->client,
920: UserNameRequested);
921: }
922: }
923: #endif
924:
925: int
926: kerberos5_set_forward(int on)
927: {
928: if(on == 0)
929: forward_flags &= ~OPTS_FORWARD_CREDS;
930: if(on == 1)
931: forward_flags |= OPTS_FORWARD_CREDS;
932: if(on == -1)
933: forward_flags ^= OPTS_FORWARD_CREDS;
934: return 0;
935: }
936:
937: int
938: kerberos5_set_forwardable(int on)
939: {
940: if(on == 0)
941: forward_flags &= ~OPTS_FORWARDABLE_CREDS;
942: if(on == 1)
943: forward_flags |= OPTS_FORWARDABLE_CREDS;
944: if(on == -1)
945: forward_flags ^= OPTS_FORWARDABLE_CREDS;
946: return 0;
947: }
948:
949: #endif /* KRB5 */