source: branches/samba-3.0/source/libsmb/clikrb5.c@ 134

Last change on this file since 134 was 124, checked in by Paul Smedley, 17 years ago

Update source to 3.0.28a

File size: 40.3 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3 simple kerberos5 routines for active directory
4 Copyright (C) Andrew Tridgell 2001
5 Copyright (C) Luke Howard 2002-2003
6 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
7 Copyright (C) Guenther Deschner 2005
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22*/
23
24#define KRB5_PRIVATE 1 /* this file uses PRIVATE interfaces! */
25#define KRB5_DEPRECATED 1 /* this file uses DEPRECATED interfaces! */
26
27#include "includes.h"
28
29#ifdef HAVE_KRB5
30
31#ifdef HAVE_KRB5_KEYBLOCK_KEYVALUE
32#define KRB5_KEY_TYPE(k) ((k)->keytype)
33#define KRB5_KEY_LENGTH(k) ((k)->keyvalue.length)
34#define KRB5_KEY_DATA(k) ((k)->keyvalue.data)
35#else
36#define KRB5_KEY_TYPE(k) ((k)->enctype)
37#define KRB5_KEY_LENGTH(k) ((k)->length)
38#define KRB5_KEY_DATA(k) ((k)->contents)
39#endif /* HAVE_KRB5_KEYBLOCK_KEYVALUE */
40
41/**************************************************************
42 Wrappers around kerberos string functions that convert from
43 utf8 -> unix charset and vica versa.
44**************************************************************/
45
46/**************************************************************
47 krb5_parse_name that takes a UNIX charset.
48**************************************************************/
49
50 krb5_error_code smb_krb5_parse_name(krb5_context context,
51 const char *name, /* in unix charset */
52 krb5_principal *principal)
53{
54 krb5_error_code ret;
55 char *utf8_name;
56
57 if (push_utf8_allocate(&utf8_name, name) == (size_t)-1) {
58 return ENOMEM;
59 }
60
61 ret = krb5_parse_name(context, utf8_name, principal);
62 SAFE_FREE(utf8_name);
63 return ret;
64}
65
66#ifdef HAVE_KRB5_PARSE_NAME_NOREALM
67/**************************************************************
68 krb5_parse_name_norealm that takes a UNIX charset.
69**************************************************************/
70
71static krb5_error_code smb_krb5_parse_name_norealm_conv(krb5_context context,
72 const char *name, /* in unix charset */
73 krb5_principal *principal)
74{
75 krb5_error_code ret;
76 char *utf8_name;
77
78 *principal = NULL;
79 if (push_utf8_allocate(&utf8_name, name) == (size_t)-1) {
80 return ENOMEM;
81 }
82
83 ret = krb5_parse_name_norealm(context, utf8_name, principal);
84 SAFE_FREE(utf8_name);
85 return ret;
86}
87#endif
88
89/**************************************************************
90 krb5_parse_name that returns a UNIX charset name. Must
91 be freed with normal free() call.
92**************************************************************/
93
94 krb5_error_code smb_krb5_unparse_name(krb5_context context,
95 krb5_const_principal principal,
96 char **unix_name)
97{
98 krb5_error_code ret;
99 char *utf8_name;
100
101 *unix_name = NULL;
102 ret = krb5_unparse_name(context, principal, &utf8_name);
103 if (ret) {
104 return ret;
105 }
106
107 if (pull_utf8_allocate(unix_name, utf8_name)==-1) {
108 krb5_free_unparsed_name(context, utf8_name);
109 return ENOMEM;
110 }
111 krb5_free_unparsed_name(context, utf8_name);
112 return 0;
113}
114
115#ifndef HAVE_KRB5_SET_REAL_TIME
116/*
117 * This function is not in the Heimdal mainline.
118 */
119 krb5_error_code krb5_set_real_time(krb5_context context, int32_t seconds, int32_t microseconds)
120{
121 krb5_error_code ret;
122 int32_t sec, usec;
123
124 ret = krb5_us_timeofday(context, &sec, &usec);
125 if (ret)
126 return ret;
127
128 context->kdc_sec_offset = seconds - sec;
129 context->kdc_usec_offset = microseconds - usec;
130
131 return 0;
132}
133#endif
134
135#if !defined(HAVE_KRB5_SET_DEFAULT_TGS_KTYPES)
136
137#if defined(HAVE_KRB5_SET_DEFAULT_TGS_ENCTYPES)
138
139/* With MIT kerberos, we should use krb5_set_default_tgs_enctypes in preference
140 * to krb5_set_default_tgs_ktypes. See
141 * http://lists.samba.org/archive/samba-technical/2006-July/048271.html
142 *
143 * If the MIT libraries are not exporting internal symbols, we will end up in
144 * this branch, which is correct. Otherwise we will continue to use the
145 * internal symbol
146 */
147 krb5_error_code krb5_set_default_tgs_ktypes(krb5_context ctx, const krb5_enctype *enc)
148{
149 return krb5_set_default_tgs_enctypes(ctx, enc);
150}
151
152#elif defined(HAVE_KRB5_SET_DEFAULT_IN_TKT_ETYPES)
153
154/* Heimdal */
155 krb5_error_code krb5_set_default_tgs_ktypes(krb5_context ctx, const krb5_enctype *enc)
156{
157 return krb5_set_default_in_tkt_etypes(ctx, enc);
158}
159
160#endif /* HAVE_KRB5_SET_DEFAULT_TGS_ENCTYPES */
161
162#endif /* HAVE_KRB5_SET_DEFAULT_TGS_KTYPES */
163
164#if defined(HAVE_ADDR_TYPE_IN_KRB5_ADDRESS)
165/* HEIMDAL */
166 void setup_kaddr( krb5_address *pkaddr, struct sockaddr *paddr)
167{
168 pkaddr->addr_type = KRB5_ADDRESS_INET;
169 pkaddr->address.length = sizeof(((struct sockaddr_in *)paddr)->sin_addr);
170 pkaddr->address.data = (char *)&(((struct sockaddr_in *)paddr)->sin_addr);
171}
172#elif defined(HAVE_ADDRTYPE_IN_KRB5_ADDRESS)
173/* MIT */
174 void setup_kaddr( krb5_address *pkaddr, struct sockaddr *paddr)
175{
176 pkaddr->addrtype = ADDRTYPE_INET;
177 pkaddr->length = sizeof(((struct sockaddr_in *)paddr)->sin_addr);
178 pkaddr->contents = (krb5_octet *)&(((struct sockaddr_in *)paddr)->sin_addr);
179}
180#else
181#error UNKNOWN_ADDRTYPE
182#endif
183
184#if defined(HAVE_KRB5_PRINCIPAL2SALT) && defined(HAVE_KRB5_USE_ENCTYPE) && defined(HAVE_KRB5_STRING_TO_KEY) && defined(HAVE_KRB5_ENCRYPT_BLOCK)
185 int create_kerberos_key_from_string_direct(krb5_context context,
186 krb5_principal host_princ,
187 krb5_data *password,
188 krb5_keyblock *key,
189 krb5_enctype enctype)
190{
191 int ret;
192 krb5_data salt;
193 krb5_encrypt_block eblock;
194
195 ret = krb5_principal2salt(context, host_princ, &salt);
196 if (ret) {
197 DEBUG(1,("krb5_principal2salt failed (%s)\n", error_message(ret)));
198 return ret;
199 }
200 krb5_use_enctype(context, &eblock, enctype);
201 ret = krb5_string_to_key(context, &eblock, key, password, &salt);
202 SAFE_FREE(salt.data);
203 return ret;
204}
205#elif defined(HAVE_KRB5_GET_PW_SALT) && defined(HAVE_KRB5_STRING_TO_KEY_SALT)
206 int create_kerberos_key_from_string_direct(krb5_context context,
207 krb5_principal host_princ,
208 krb5_data *password,
209 krb5_keyblock *key,
210 krb5_enctype enctype)
211{
212 int ret;
213 krb5_salt salt;
214
215 ret = krb5_get_pw_salt(context, host_princ, &salt);
216 if (ret) {
217 DEBUG(1,("krb5_get_pw_salt failed (%s)\n", error_message(ret)));
218 return ret;
219 }
220
221 ret = krb5_string_to_key_salt(context, enctype, (const char *)password->data, salt, key);
222 krb5_free_salt(context, salt);
223 return ret;
224}
225#else
226#error UNKNOWN_CREATE_KEY_FUNCTIONS
227#endif
228
229 int create_kerberos_key_from_string(krb5_context context,
230 krb5_principal host_princ,
231 krb5_data *password,
232 krb5_keyblock *key,
233 krb5_enctype enctype)
234{
235 krb5_principal salt_princ = NULL;
236 int ret;
237 /*
238 * Check if we've determined that the KDC is salting keys for this
239 * principal/enctype in a non-obvious way. If it is, try to match
240 * its behavior.
241 */
242 salt_princ = kerberos_fetch_salt_princ_for_host_princ(context, host_princ, enctype);
243 ret = create_kerberos_key_from_string_direct(context, salt_princ ? salt_princ : host_princ, password, key, enctype);
244 if (salt_princ) {
245 krb5_free_principal(context, salt_princ);
246 }
247 return ret;
248}
249
250#if defined(HAVE_KRB5_GET_PERMITTED_ENCTYPES)
251 krb5_error_code get_kerberos_allowed_etypes(krb5_context context,
252 krb5_enctype **enctypes)
253{
254 return krb5_get_permitted_enctypes(context, enctypes);
255}
256#elif defined(HAVE_KRB5_GET_DEFAULT_IN_TKT_ETYPES)
257 krb5_error_code get_kerberos_allowed_etypes(krb5_context context,
258 krb5_enctype **enctypes)
259{
260 return krb5_get_default_in_tkt_etypes(context, enctypes);
261}
262#else
263#error UNKNOWN_GET_ENCTYPES_FUNCTIONS
264#endif
265
266#if defined(HAVE_KRB5_AUTH_CON_SETKEY) && !defined(HAVE_KRB5_AUTH_CON_SETUSERUSERKEY)
267 krb5_error_code krb5_auth_con_setuseruserkey(krb5_context context,
268 krb5_auth_context auth_context,
269 krb5_keyblock *keyblock)
270{
271 return krb5_auth_con_setkey(context, auth_context, keyblock);
272}
273#endif
274
275BOOL unwrap_pac(TALLOC_CTX *mem_ctx, DATA_BLOB *auth_data, DATA_BLOB *unwrapped_pac_data)
276{
277 DATA_BLOB pac_contents;
278 ASN1_DATA data;
279 int data_type;
280
281 if (!auth_data->length) {
282 return False;
283 }
284
285 asn1_load(&data, *auth_data);
286 asn1_start_tag(&data, ASN1_SEQUENCE(0));
287 asn1_start_tag(&data, ASN1_SEQUENCE(0));
288 asn1_start_tag(&data, ASN1_CONTEXT(0));
289 asn1_read_Integer(&data, &data_type);
290
291 if (data_type != KRB5_AUTHDATA_WIN2K_PAC ) {
292 DEBUG(10,("authorization data is not a Windows PAC (type: %d)\n", data_type));
293 asn1_free(&data);
294 return False;
295 }
296
297 asn1_end_tag(&data);
298 asn1_start_tag(&data, ASN1_CONTEXT(1));
299 asn1_read_OctetString(&data, &pac_contents);
300 asn1_end_tag(&data);
301 asn1_end_tag(&data);
302 asn1_end_tag(&data);
303 asn1_free(&data);
304
305 *unwrapped_pac_data = data_blob_talloc(mem_ctx, pac_contents.data, pac_contents.length);
306
307 data_blob_free(&pac_contents);
308
309 return True;
310}
311
312 BOOL get_auth_data_from_tkt(TALLOC_CTX *mem_ctx, DATA_BLOB *auth_data, krb5_ticket *tkt)
313{
314 DATA_BLOB auth_data_wrapped;
315 BOOL got_auth_data_pac = False;
316 int i;
317
318#if defined(HAVE_KRB5_TKT_ENC_PART2)
319 if (tkt->enc_part2 && tkt->enc_part2->authorization_data &&
320 tkt->enc_part2->authorization_data[0] &&
321 tkt->enc_part2->authorization_data[0]->length)
322 {
323 for (i = 0; tkt->enc_part2->authorization_data[i] != NULL; i++) {
324
325 if (tkt->enc_part2->authorization_data[i]->ad_type !=
326 KRB5_AUTHDATA_IF_RELEVANT) {
327 DEBUG(10,("get_auth_data_from_tkt: ad_type is %d\n",
328 tkt->enc_part2->authorization_data[i]->ad_type));
329 continue;
330 }
331
332 auth_data_wrapped = data_blob(tkt->enc_part2->authorization_data[i]->contents,
333 tkt->enc_part2->authorization_data[i]->length);
334
335 /* check if it is a PAC */
336 got_auth_data_pac = unwrap_pac(mem_ctx, &auth_data_wrapped, auth_data);
337 data_blob_free(&auth_data_wrapped);
338
339 if (got_auth_data_pac) {
340 return true;
341 }
342 }
343
344 return got_auth_data_pac;
345 }
346
347#else
348 if (tkt->ticket.authorization_data &&
349 tkt->ticket.authorization_data->len)
350 {
351 for (i = 0; i < tkt->ticket.authorization_data->len; i++) {
352
353 if (tkt->ticket.authorization_data->val[i].ad_type !=
354 KRB5_AUTHDATA_IF_RELEVANT) {
355 DEBUG(10,("get_auth_data_from_tkt: ad_type is %d\n",
356 tkt->ticket.authorization_data->val[i].ad_type));
357 continue;
358 }
359
360 auth_data_wrapped = data_blob(tkt->ticket.authorization_data->val[i].ad_data.data,
361 tkt->ticket.authorization_data->val[i].ad_data.length);
362
363 /* check if it is a PAC */
364 got_auth_data_pac = unwrap_pac(mem_ctx, &auth_data_wrapped, auth_data);
365 data_blob_free(&auth_data_wrapped);
366
367 if (got_auth_data_pac) {
368 return true;
369 }
370 }
371
372 return got_auth_data_pac;
373 }
374#endif
375 return False;
376}
377
378 krb5_const_principal get_principal_from_tkt(krb5_ticket *tkt)
379{
380#if defined(HAVE_KRB5_TKT_ENC_PART2)
381 return tkt->enc_part2->client;
382#else
383 return tkt->client;
384#endif
385}
386
387#if !defined(HAVE_KRB5_LOCATE_KDC)
388
389/* krb5_locate_kdc is an internal MIT symbol. MIT are not yet willing to commit
390 * to a public interface for this functionality, so we have to be able to live
391 * without it if the MIT libraries are hiding their internal symbols.
392 */
393
394#if defined(KRB5_KRBHST_INIT)
395/* Heimdal */
396 krb5_error_code smb_krb5_locate_kdc(krb5_context ctx, const krb5_data *realm, struct sockaddr **addr_pp, int *naddrs, int get_masters)
397{
398 krb5_krbhst_handle hnd;
399 krb5_krbhst_info *hinfo;
400 krb5_error_code rc;
401 int num_kdcs, i;
402 struct sockaddr *sa;
403 struct addrinfo *ai;
404
405 *addr_pp = NULL;
406 *naddrs = 0;
407
408 rc = krb5_krbhst_init(ctx, realm->data, KRB5_KRBHST_KDC, &hnd);
409 if (rc) {
410 DEBUG(0, ("smb_krb5_locate_kdc: krb5_krbhst_init failed (%s)\n", error_message(rc)));
411 return rc;
412 }
413
414 for ( num_kdcs = 0; (rc = krb5_krbhst_next(ctx, hnd, &hinfo) == 0); num_kdcs++)
415 ;
416
417 krb5_krbhst_reset(ctx, hnd);
418
419 if (!num_kdcs) {
420 DEBUG(0, ("smb_krb5_locate_kdc: zero kdcs found !\n"));
421 krb5_krbhst_free(ctx, hnd);
422 return -1;
423 }
424
425 sa = SMB_MALLOC_ARRAY( struct sockaddr, num_kdcs );
426 if (!sa) {
427 DEBUG(0, ("smb_krb5_locate_kdc: malloc failed\n"));
428 krb5_krbhst_free(ctx, hnd);
429 naddrs = 0;
430 return -1;
431 }
432
433 memset(sa, '\0', sizeof(struct sockaddr) * num_kdcs );
434
435 for (i = 0; i < num_kdcs && (rc = krb5_krbhst_next(ctx, hnd, &hinfo) == 0); i++) {
436
437#if defined(HAVE_KRB5_KRBHST_GET_ADDRINFO)
438 rc = krb5_krbhst_get_addrinfo(ctx, hinfo, &ai);
439 if (rc) {
440 DEBUG(0,("krb5_krbhst_get_addrinfo failed: %s\n", error_message(rc)));
441 continue;
442 }
443#endif
444 if (hinfo->ai && hinfo->ai->ai_family == AF_INET)
445 memcpy(&sa[i], hinfo->ai->ai_addr, sizeof(struct sockaddr));
446 }
447
448 krb5_krbhst_free(ctx, hnd);
449
450 *naddrs = num_kdcs;
451 *addr_pp = sa;
452 return 0;
453}
454
455#else /* ! defined(KRB5_KRBHST_INIT) */
456
457 krb5_error_code smb_krb5_locate_kdc(krb5_context ctx, const krb5_data *realm,
458 struct sockaddr **addr_pp, int *naddrs, int get_masters)
459{
460 DEBUG(0, ("unable to explicitly locate the KDC on this platform\n"));
461 return KRB5_KDC_UNREACH;
462}
463
464#endif /* KRB5_KRBHST_INIT */
465
466#else /* ! HAVE_KRB5_LOCATE_KDC */
467
468 krb5_error_code smb_krb5_locate_kdc(krb5_context ctx, const krb5_data *realm,
469 struct sockaddr **addr_pp, int *naddrs, int get_masters)
470{
471 return krb5_locate_kdc(ctx, realm, addr_pp, naddrs, get_masters);
472}
473
474#endif /* HAVE_KRB5_LOCATE_KDC */
475
476#if !defined(HAVE_KRB5_FREE_UNPARSED_NAME)
477 void krb5_free_unparsed_name(krb5_context context, char *val)
478{
479 SAFE_FREE(val);
480}
481#endif
482
483 void kerberos_free_data_contents(krb5_context context, krb5_data *pdata)
484{
485#if defined(HAVE_KRB5_FREE_DATA_CONTENTS)
486 if (pdata->data) {
487 krb5_free_data_contents(context, pdata);
488 }
489#else
490 SAFE_FREE(pdata->data);
491#endif
492}
493
494 void kerberos_set_creds_enctype(krb5_creds *pcreds, int enctype)
495{
496#if defined(HAVE_KRB5_KEYBLOCK_IN_CREDS)
497 KRB5_KEY_TYPE((&pcreds->keyblock)) = enctype;
498#elif defined(HAVE_KRB5_SESSION_IN_CREDS)
499 KRB5_KEY_TYPE((&pcreds->session)) = enctype;
500#else
501#error UNKNOWN_KEYBLOCK_MEMBER_IN_KRB5_CREDS_STRUCT
502#endif
503}
504
505 BOOL kerberos_compatible_enctypes(krb5_context context,
506 krb5_enctype enctype1,
507 krb5_enctype enctype2)
508{
509#if defined(HAVE_KRB5_C_ENCTYPE_COMPARE)
510 krb5_boolean similar = 0;
511
512 krb5_c_enctype_compare(context, enctype1, enctype2, &similar);
513 return similar ? True : False;
514#elif defined(HAVE_KRB5_ENCTYPES_COMPATIBLE_KEYS)
515 return krb5_enctypes_compatible_keys(context, enctype1, enctype2) ? True : False;
516#endif
517}
518
519static BOOL ads_cleanup_expired_creds(krb5_context context,
520 krb5_ccache ccache,
521 krb5_creds *credsp)
522{
523 krb5_error_code retval;
524 const char *cc_type = krb5_cc_get_type(context, ccache);
525
526 DEBUG(3, ("ads_cleanup_expired_creds: Ticket in ccache[%s:%s] expiration %s\n",
527 cc_type, krb5_cc_get_name(context, ccache),
528 http_timestring(credsp->times.endtime)));
529
530 /* we will probably need new tickets if the current ones
531 will expire within 10 seconds.
532 */
533 if (credsp->times.endtime >= (time(NULL) + 10))
534 return False;
535
536 /* heimdal won't remove creds from a file ccache, and
537 perhaps we shouldn't anyway, since internally we
538 use memory ccaches, and a FILE one probably means that
539 we're using creds obtained outside of our exectuable
540 */
541 if (strequal(cc_type, "FILE")) {
542 DEBUG(5, ("ads_cleanup_expired_creds: We do not remove creds from a %s ccache\n", cc_type));
543 return False;
544 }
545
546 retval = krb5_cc_remove_cred(context, ccache, 0, credsp);
547 if (retval) {
548 DEBUG(1, ("ads_cleanup_expired_creds: krb5_cc_remove_cred failed, err %s\n",
549 error_message(retval)));
550 /* If we have an error in this, we want to display it,
551 but continue as though we deleted it */
552 }
553 return True;
554}
555
556/*
557 we can't use krb5_mk_req because w2k wants the service to be in a particular format
558*/
559static krb5_error_code ads_krb5_mk_req(krb5_context context,
560 krb5_auth_context *auth_context,
561 const krb5_flags ap_req_options,
562 const char *principal,
563 krb5_ccache ccache,
564 krb5_data *outbuf,
565 time_t *expire_time)
566{
567 krb5_error_code retval;
568 krb5_principal server;
569 krb5_creds * credsp;
570 krb5_creds creds;
571 krb5_data in_data;
572 BOOL creds_ready = False;
573 int i = 0, maxtries = 3;
574
575 retval = smb_krb5_parse_name(context, principal, &server);
576 if (retval) {
577 DEBUG(1,("ads_krb5_mk_req: Failed to parse principal %s\n", principal));
578 return retval;
579 }
580
581 /* obtain ticket & session key */
582 ZERO_STRUCT(creds);
583 if ((retval = krb5_copy_principal(context, server, &creds.server))) {
584 DEBUG(1,("ads_krb5_mk_req: krb5_copy_principal failed (%s)\n",
585 error_message(retval)));
586 goto cleanup_princ;
587 }
588
589 if ((retval = krb5_cc_get_principal(context, ccache, &creds.client))) {
590 /* This can commonly fail on smbd startup with no ticket in the cache.
591 * Report at higher level than 1. */
592 DEBUG(3,("ads_krb5_mk_req: krb5_cc_get_principal failed (%s)\n",
593 error_message(retval)));
594 goto cleanup_creds;
595 }
596
597 while (!creds_ready && (i < maxtries)) {
598
599 if ((retval = krb5_get_credentials(context, 0, ccache,
600 &creds, &credsp))) {
601 DEBUG(1,("ads_krb5_mk_req: krb5_get_credentials failed for %s (%s)\n",
602 principal, error_message(retval)));
603 goto cleanup_creds;
604 }
605
606 /* cope with ticket being in the future due to clock skew */
607 if ((unsigned)credsp->times.starttime > time(NULL)) {
608 time_t t = time(NULL);
609 int time_offset =(int)((unsigned)credsp->times.starttime-t);
610 DEBUG(4,("ads_krb5_mk_req: Advancing clock by %d seconds to cope with clock skew\n", time_offset));
611 krb5_set_real_time(context, t + time_offset + 1, 0);
612 }
613
614 if (!ads_cleanup_expired_creds(context, ccache, credsp)) {
615 creds_ready = True;
616 }
617
618 i++;
619 }
620
621 DEBUG(10,("ads_krb5_mk_req: Ticket (%s) in ccache (%s:%s) is valid until: (%s - %u)\n",
622 principal, krb5_cc_get_type(context, ccache), krb5_cc_get_name(context, ccache),
623 http_timestring((unsigned)credsp->times.endtime),
624 (unsigned)credsp->times.endtime));
625
626 if (expire_time) {
627 *expire_time = (time_t)credsp->times.endtime;
628 }
629
630 in_data.length = 0;
631 retval = krb5_mk_req_extended(context, auth_context, ap_req_options,
632 &in_data, credsp, outbuf);
633 if (retval) {
634 DEBUG(1,("ads_krb5_mk_req: krb5_mk_req_extended failed (%s)\n",
635 error_message(retval)));
636 }
637
638 krb5_free_creds(context, credsp);
639
640cleanup_creds:
641 krb5_free_cred_contents(context, &creds);
642
643cleanup_princ:
644 krb5_free_principal(context, server);
645
646 return retval;
647}
648
649/*
650 get a kerberos5 ticket for the given service
651*/
652int cli_krb5_get_ticket(const char *principal, time_t time_offset,
653 DATA_BLOB *ticket, DATA_BLOB *session_key_krb5,
654 uint32 extra_ap_opts, const char *ccname,
655 time_t *tgs_expire)
656
657{
658 krb5_error_code retval;
659 krb5_data packet;
660 krb5_context context = NULL;
661 krb5_ccache ccdef = NULL;
662 krb5_auth_context auth_context = NULL;
663 krb5_enctype enc_types[] = {
664#ifdef ENCTYPE_ARCFOUR_HMAC
665 ENCTYPE_ARCFOUR_HMAC,
666#endif
667 ENCTYPE_DES_CBC_MD5,
668 ENCTYPE_DES_CBC_CRC,
669 ENCTYPE_NULL};
670
671 initialize_krb5_error_table();
672 retval = krb5_init_context(&context);
673 if (retval) {
674 DEBUG(1,("cli_krb5_get_ticket: krb5_init_context failed (%s)\n",
675 error_message(retval)));
676 goto failed;
677 }
678
679 if (time_offset != 0) {
680 krb5_set_real_time(context, time(NULL) + time_offset, 0);
681 }
682
683 if ((retval = krb5_cc_resolve(context, ccname ?
684 ccname : krb5_cc_default_name(context), &ccdef))) {
685 DEBUG(1,("cli_krb5_get_ticket: krb5_cc_default failed (%s)\n",
686 error_message(retval)));
687 goto failed;
688 }
689
690 if ((retval = krb5_set_default_tgs_ktypes(context, enc_types))) {
691 DEBUG(1,("cli_krb5_get_ticket: krb5_set_default_tgs_ktypes failed (%s)\n",
692 error_message(retval)));
693 goto failed;
694 }
695
696 if ((retval = ads_krb5_mk_req(context,
697 &auth_context,
698 AP_OPTS_USE_SUBKEY | (krb5_flags)extra_ap_opts,
699 principal,
700 ccdef, &packet,
701 tgs_expire))) {
702 goto failed;
703 }
704
705 get_krb5_smb_session_key(context, auth_context, session_key_krb5, False);
706
707 *ticket = data_blob(packet.data, packet.length);
708
709 kerberos_free_data_contents(context, &packet);
710
711failed:
712
713 if ( context ) {
714 if (ccdef)
715 krb5_cc_close(context, ccdef);
716 if (auth_context)
717 krb5_auth_con_free(context, auth_context);
718 krb5_free_context(context);
719 }
720
721 return retval;
722}
723
724 BOOL get_krb5_smb_session_key(krb5_context context, krb5_auth_context auth_context, DATA_BLOB *session_key, BOOL remote)
725 {
726 krb5_keyblock *skey;
727 krb5_error_code err;
728 BOOL ret = False;
729
730 if (remote)
731 err = krb5_auth_con_getremotesubkey(context, auth_context, &skey);
732 else
733 err = krb5_auth_con_getlocalsubkey(context, auth_context, &skey);
734 if (err == 0 && skey != NULL) {
735 DEBUG(10, ("Got KRB5 session key of length %d\n", (int)KRB5_KEY_LENGTH(skey)));
736 *session_key = data_blob(KRB5_KEY_DATA(skey), KRB5_KEY_LENGTH(skey));
737 dump_data_pw("KRB5 Session Key:\n", session_key->data, session_key->length);
738
739 ret = True;
740
741 krb5_free_keyblock(context, skey);
742 } else {
743 DEBUG(10, ("KRB5 error getting session key %d\n", err));
744 }
745
746 return ret;
747 }
748
749
750#if defined(HAVE_KRB5_PRINCIPAL_GET_COMP_STRING) && !defined(HAVE_KRB5_PRINC_COMPONENT)
751 const krb5_data *krb5_princ_component(krb5_context context, krb5_principal principal, int i );
752
753 const krb5_data *krb5_princ_component(krb5_context context, krb5_principal principal, int i )
754{
755 static krb5_data kdata;
756
757 kdata.data = (char *)krb5_principal_get_comp_string(context, principal, i);
758 kdata.length = strlen((const char *)kdata.data);
759 return &kdata;
760}
761#endif
762
763 krb5_error_code smb_krb5_kt_free_entry(krb5_context context, krb5_keytab_entry *kt_entry)
764{
765#if defined(HAVE_KRB5_KT_FREE_ENTRY)
766 return krb5_kt_free_entry(context, kt_entry);
767#elif defined(HAVE_KRB5_FREE_KEYTAB_ENTRY_CONTENTS)
768 return krb5_free_keytab_entry_contents(context, kt_entry);
769#else
770#error UNKNOWN_KT_FREE_FUNCTION
771#endif
772}
773
774 void smb_krb5_checksum_from_pac_sig(krb5_checksum *cksum,
775 PAC_SIGNATURE_DATA *sig)
776{
777#ifdef HAVE_CHECKSUM_IN_KRB5_CHECKSUM
778 cksum->cksumtype = (krb5_cksumtype)sig->type;
779 cksum->checksum.length = sig->signature.buf_len;
780 cksum->checksum.data = sig->signature.buffer;
781#else
782 cksum->checksum_type = (krb5_cksumtype)sig->type;
783 cksum->length = sig->signature.buf_len;
784 cksum->contents = sig->signature.buffer;
785#endif
786}
787
788 krb5_error_code smb_krb5_verify_checksum(krb5_context context,
789 krb5_keyblock *keyblock,
790 krb5_keyusage usage,
791 krb5_checksum *cksum,
792 uint8 *data,
793 size_t length)
794{
795 krb5_error_code ret;
796
797 /* verify the checksum */
798
799 /* welcome to the wonderful world of samba's kerberos abstraction layer:
800 *
801 * function heimdal 0.6.1rc3 heimdal 0.7 MIT krb 1.4.2
802 * -----------------------------------------------------------------------------
803 * krb5_c_verify_checksum - works works
804 * krb5_verify_checksum works (6 args) works (6 args) broken (7 args)
805 */
806
807#if defined(HAVE_KRB5_C_VERIFY_CHECKSUM)
808 {
809 krb5_boolean checksum_valid = False;
810 krb5_data input;
811
812 input.data = (char *)data;
813 input.length = length;
814
815 ret = krb5_c_verify_checksum(context,
816 keyblock,
817 usage,
818 &input,
819 cksum,
820 &checksum_valid);
821 if (ret) {
822 DEBUG(3,("smb_krb5_verify_checksum: krb5_c_verify_checksum() failed: %s\n",
823 error_message(ret)));
824 return ret;
825 }
826
827 if (!checksum_valid)
828 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
829 }
830
831#elif KRB5_VERIFY_CHECKSUM_ARGS == 6 && defined(HAVE_KRB5_CRYPTO_INIT) && defined(HAVE_KRB5_CRYPTO) && defined(HAVE_KRB5_CRYPTO_DESTROY)
832
833 /* Warning: MIT's krb5_verify_checksum cannot be used as it will use a key
834 * without enctype and it ignores any key_usage types - Guenther */
835
836 {
837
838 krb5_crypto crypto;
839 ret = krb5_crypto_init(context,
840 keyblock,
841 0,
842 &crypto);
843 if (ret) {
844 DEBUG(0,("smb_krb5_verify_checksum: krb5_crypto_init() failed: %s\n",
845 error_message(ret)));
846 return ret;
847 }
848
849 ret = krb5_verify_checksum(context,
850 crypto,
851 usage,
852 data,
853 length,
854 cksum);
855
856 krb5_crypto_destroy(context, crypto);
857 }
858
859#else
860#error UNKNOWN_KRB5_VERIFY_CHECKSUM_FUNCTION
861#endif
862
863 return ret;
864}
865
866 time_t get_authtime_from_tkt(krb5_ticket *tkt)
867{
868#if defined(HAVE_KRB5_TKT_ENC_PART2)
869 return tkt->enc_part2->times.authtime;
870#else
871 return tkt->ticket.authtime;
872#endif
873}
874
875#ifdef HAVE_KRB5_DECODE_AP_REQ /* Heimdal */
876static int get_kvno_from_ap_req(krb5_ap_req *ap_req)
877{
878#ifdef HAVE_TICKET_POINTER_IN_KRB5_AP_REQ /* MIT */
879 if (ap_req->ticket->enc_part.kvno)
880 return ap_req->ticket->enc_part.kvno;
881#else /* Heimdal */
882 if (ap_req->ticket.enc_part.kvno)
883 return *ap_req->ticket.enc_part.kvno;
884#endif
885 return 0;
886}
887
888static krb5_enctype get_enctype_from_ap_req(krb5_ap_req *ap_req)
889{
890#ifdef HAVE_ETYPE_IN_ENCRYPTEDDATA /* Heimdal */
891 return ap_req->ticket.enc_part.etype;
892#else /* MIT */
893 return ap_req->ticket->enc_part.enctype;
894#endif
895}
896#endif /* HAVE_KRB5_DECODE_AP_REQ */
897
898static krb5_error_code
899get_key_from_keytab(krb5_context context,
900 krb5_const_principal server,
901 krb5_enctype enctype,
902 krb5_kvno kvno,
903 krb5_keyblock **out_key)
904{
905 krb5_keytab_entry entry;
906 krb5_error_code ret;
907 krb5_keytab keytab;
908 char *name = NULL;
909
910 /* We have to open a new keytab handle here, as MIT does
911 an implicit open/getnext/close on krb5_kt_get_entry. We
912 may be in the middle of a keytab enumeration when this is
913 called. JRA. */
914
915 ret = krb5_kt_default(context, &keytab);
916 if (ret) {
917 DEBUG(0,("get_key_from_keytab: failed to open keytab: %s\n", error_message(ret)));
918 return ret;
919 }
920
921 if ( DEBUGLEVEL >= 10 ) {
922 if (smb_krb5_unparse_name(context, server, &name) == 0) {
923 DEBUG(10,("get_key_from_keytab: will look for kvno %d, enctype %d and name: %s\n",
924 kvno, enctype, name));
925 SAFE_FREE(name);
926 }
927 }
928
929 ret = krb5_kt_get_entry(context,
930 keytab,
931 server,
932 kvno,
933 enctype,
934 &entry);
935
936 if (ret) {
937 DEBUG(0,("get_key_from_keytab: failed to retrieve key: %s\n", error_message(ret)));
938 goto out;
939 }
940
941#ifdef HAVE_KRB5_KEYTAB_ENTRY_KEYBLOCK /* Heimdal */
942 ret = krb5_copy_keyblock(context, &entry.keyblock, out_key);
943#elif defined(HAVE_KRB5_KEYTAB_ENTRY_KEY) /* MIT */
944 ret = krb5_copy_keyblock(context, &entry.key, out_key);
945#else
946#error UNKNOWN_KRB5_KEYTAB_ENTRY_FORMAT
947#endif
948
949 if (ret) {
950 DEBUG(0,("get_key_from_keytab: failed to copy key: %s\n", error_message(ret)));
951 goto out;
952 }
953
954 smb_krb5_kt_free_entry(context, &entry);
955
956out:
957 krb5_kt_close(context, keytab);
958 return ret;
959}
960
961/* Prototypes */
962
963 krb5_error_code smb_krb5_get_keyinfo_from_ap_req(krb5_context context,
964 const krb5_data *inbuf,
965 krb5_kvno *kvno,
966 krb5_enctype *enctype)
967{
968#ifdef HAVE_KRB5_DECODE_AP_REQ /* Heimdal */
969 {
970 krb5_error_code ret;
971 krb5_ap_req ap_req;
972
973 ret = krb5_decode_ap_req(context, inbuf, &ap_req);
974 if (ret)
975 return ret;
976
977 *kvno = get_kvno_from_ap_req(&ap_req);
978 *enctype = get_enctype_from_ap_req(&ap_req);
979
980 free_AP_REQ(&ap_req);
981 return 0;
982 }
983#endif
984
985 /* Possibly not an appropriate error code. */
986 return KRB5KDC_ERR_BADOPTION;
987}
988
989 krb5_error_code krb5_rd_req_return_keyblock_from_keytab(krb5_context context,
990 krb5_auth_context *auth_context,
991 const krb5_data *inbuf,
992 krb5_const_principal server,
993 krb5_keytab keytab,
994 krb5_flags *ap_req_options,
995 krb5_ticket **ticket,
996 krb5_keyblock **keyblock)
997{
998 krb5_error_code ret;
999 krb5_kvno kvno;
1000 krb5_enctype enctype;
1001 krb5_keyblock *local_keyblock;
1002
1003 ret = krb5_rd_req(context,
1004 auth_context,
1005 inbuf,
1006 server,
1007 keytab,
1008 ap_req_options,
1009 ticket);
1010 if (ret) {
1011 return ret;
1012 }
1013
1014#ifdef KRB5_TICKET_HAS_KEYINFO
1015 enctype = (*ticket)->enc_part.enctype;
1016 kvno = (*ticket)->enc_part.kvno;
1017#else
1018 ret = smb_krb5_get_keyinfo_from_ap_req(context, inbuf, &kvno, &enctype);
1019 if (ret) {
1020 return ret;
1021 }
1022#endif
1023
1024 ret = get_key_from_keytab(context,
1025 server,
1026 enctype,
1027 kvno,
1028 &local_keyblock);
1029 if (ret) {
1030 DEBUG(0,("krb5_rd_req_return_keyblock_from_keytab: failed to call get_key_from_keytab\n"));
1031 goto out;
1032 }
1033
1034out:
1035 if (ret && local_keyblock != NULL) {
1036 krb5_free_keyblock(context, local_keyblock);
1037 } else {
1038 *keyblock = local_keyblock;
1039 }
1040
1041 return ret;
1042}
1043
1044 krb5_error_code smb_krb5_parse_name_norealm(krb5_context context,
1045 const char *name,
1046 krb5_principal *principal)
1047{
1048#ifdef HAVE_KRB5_PARSE_NAME_NOREALM
1049 return smb_krb5_parse_name_norealm_conv(context, name, principal);
1050#endif
1051
1052 /* we are cheating here because parse_name will in fact set the realm.
1053 * We don't care as the only caller of smb_krb5_parse_name_norealm
1054 * ignores the realm anyway when calling
1055 * smb_krb5_principal_compare_any_realm later - Guenther */
1056
1057 return smb_krb5_parse_name(context, name, principal);
1058}
1059
1060 BOOL smb_krb5_principal_compare_any_realm(krb5_context context,
1061 krb5_const_principal princ1,
1062 krb5_const_principal princ2)
1063{
1064#ifdef HAVE_KRB5_PRINCIPAL_COMPARE_ANY_REALM
1065
1066 return krb5_principal_compare_any_realm(context, princ1, princ2);
1067
1068/* krb5_princ_size is a macro in MIT */
1069#elif defined(HAVE_KRB5_PRINC_SIZE) || defined(krb5_princ_size)
1070
1071 int i, len1, len2;
1072 const krb5_data *p1, *p2;
1073
1074 len1 = krb5_princ_size(context, princ1);
1075 len2 = krb5_princ_size(context, princ2);
1076
1077 if (len1 != len2)
1078 return False;
1079
1080 for (i = 0; i < len1; i++) {
1081
1082 p1 = krb5_princ_component(context, CONST_DISCARD(krb5_principal, princ1), i);
1083 p2 = krb5_princ_component(context, CONST_DISCARD(krb5_principal, princ2), i);
1084
1085 if (p1->length != p2->length || memcmp(p1->data, p2->data, p1->length))
1086 return False;
1087 }
1088
1089 return True;
1090#else
1091#error NO_SUITABLE_PRINCIPAL_COMPARE_FUNCTION
1092#endif
1093}
1094
1095 krb5_error_code smb_krb5_renew_ticket(const char *ccache_string, /* FILE:/tmp/krb5cc_0 */
1096 const char *client_string, /* gd@BER.SUSE.DE */
1097 const char *service_string, /* krbtgt/BER.SUSE.DE@BER.SUSE.DE */
1098 time_t *expire_time)
1099{
1100 krb5_error_code ret;
1101 krb5_context context = NULL;
1102 krb5_ccache ccache = NULL;
1103 krb5_principal client = NULL;
1104
1105 initialize_krb5_error_table();
1106 ret = krb5_init_context(&context);
1107 if (ret) {
1108 goto done;
1109 }
1110
1111 if (!ccache_string) {
1112 ccache_string = krb5_cc_default_name(context);
1113 }
1114
1115 DEBUG(10,("smb_krb5_renew_ticket: using %s as ccache\n", ccache_string));
1116
1117 /* FIXME: we should not fall back to defaults */
1118 ret = krb5_cc_resolve(context, CONST_DISCARD(char *, ccache_string), &ccache);
1119 if (ret) {
1120 goto done;
1121 }
1122
1123#ifdef HAVE_KRB5_GET_RENEWED_CREDS /* MIT */
1124 {
1125 krb5_creds creds;
1126
1127 if (client_string) {
1128 ret = smb_krb5_parse_name(context, client_string, &client);
1129 if (ret) {
1130 goto done;
1131 }
1132 } else {
1133 ret = krb5_cc_get_principal(context, ccache, &client);
1134 if (ret) {
1135 goto done;
1136 }
1137 }
1138
1139 ret = krb5_get_renewed_creds(context, &creds, client, ccache, CONST_DISCARD(char *, service_string));
1140 if (ret) {
1141 DEBUG(10,("smb_krb5_renew_ticket: krb5_get_kdc_cred failed: %s\n", error_message(ret)));
1142 goto done;
1143 }
1144
1145 /* hm, doesn't that create a new one if the old one wasn't there? - Guenther */
1146 ret = krb5_cc_initialize(context, ccache, client);
1147 if (ret) {
1148 goto done;
1149 }
1150
1151 ret = krb5_cc_store_cred(context, ccache, &creds);
1152
1153 if (expire_time) {
1154 *expire_time = (time_t) creds.times.endtime;
1155 }
1156
1157 krb5_free_cred_contents(context, &creds);
1158 }
1159#elif defined(HAVE_KRB5_GET_KDC_CRED) /* Heimdal */
1160 {
1161 krb5_kdc_flags flags;
1162 krb5_creds creds_in;
1163 krb5_realm *client_realm;
1164 krb5_creds *creds;
1165
1166 memset(&creds_in, 0, sizeof(creds_in));
1167
1168 if (client_string) {
1169 ret = smb_krb5_parse_name(context, client_string, &creds_in.client);
1170 if (ret) {
1171 goto done;
1172 }
1173 } else {
1174 ret = krb5_cc_get_principal(context, ccache, &creds_in.client);
1175 if (ret) {
1176 goto done;
1177 }
1178 }
1179
1180 if (service_string) {
1181 ret = smb_krb5_parse_name(context, service_string, &creds_in.server);
1182 if (ret) {
1183 goto done;
1184 }
1185 } else {
1186 /* build tgt service by default */
1187 client_realm = krb5_princ_realm(context, creds_in.client);
1188 if (!client_realm) {
1189 ret = ENOMEM;
1190 goto done;
1191 }
1192 ret = krb5_make_principal(context, &creds_in.server, *client_realm, KRB5_TGS_NAME, *client_realm, NULL);
1193 if (ret) {
1194 goto done;
1195 }
1196 }
1197
1198 flags.i = 0;
1199 flags.b.renewable = flags.b.renew = True;
1200
1201 ret = krb5_get_kdc_cred(context, ccache, flags, NULL, NULL, &creds_in, &creds);
1202 if (ret) {
1203 DEBUG(10,("smb_krb5_renew_ticket: krb5_get_kdc_cred failed: %s\n", error_message(ret)));
1204 goto done;
1205 }
1206
1207 /* hm, doesn't that create a new one if the old one wasn't there? - Guenther */
1208 ret = krb5_cc_initialize(context, ccache, creds_in.client);
1209 if (ret) {
1210 goto done;
1211 }
1212
1213 ret = krb5_cc_store_cred(context, ccache, creds);
1214
1215 if (expire_time) {
1216 *expire_time = (time_t) creds->times.endtime;
1217 }
1218
1219 krb5_free_cred_contents(context, &creds_in);
1220 krb5_free_creds(context, creds);
1221 }
1222#else
1223#error No suitable krb5 ticket renew function available
1224#endif
1225
1226
1227done:
1228 if (client) {
1229 krb5_free_principal(context, client);
1230 }
1231 if (context) {
1232 krb5_free_context(context);
1233 }
1234 if (ccache) {
1235 krb5_cc_close(context, ccache);
1236 }
1237
1238 return ret;
1239
1240}
1241
1242 krb5_error_code smb_krb5_free_addresses(krb5_context context, smb_krb5_addresses *addr)
1243{
1244 krb5_error_code ret = 0;
1245 if (addr == NULL) {
1246 return ret;
1247 }
1248#if defined(HAVE_MAGIC_IN_KRB5_ADDRESS) && defined(HAVE_ADDRTYPE_IN_KRB5_ADDRESS) /* MIT */
1249 krb5_free_addresses(context, addr->addrs);
1250#elif defined(HAVE_ADDR_TYPE_IN_KRB5_ADDRESS) /* Heimdal */
1251 ret = krb5_free_addresses(context, addr->addrs);
1252 SAFE_FREE(addr->addrs);
1253#endif
1254 SAFE_FREE(addr);
1255 addr = NULL;
1256 return ret;
1257}
1258
1259 krb5_error_code smb_krb5_gen_netbios_krb5_address(smb_krb5_addresses **kerb_addr)
1260{
1261 krb5_error_code ret = 0;
1262 nstring buf;
1263#if defined(HAVE_MAGIC_IN_KRB5_ADDRESS) && defined(HAVE_ADDRTYPE_IN_KRB5_ADDRESS) /* MIT */
1264 krb5_address **addrs = NULL;
1265#elif defined(HAVE_ADDR_TYPE_IN_KRB5_ADDRESS) /* Heimdal */
1266 krb5_addresses *addrs = NULL;
1267#endif
1268
1269 *kerb_addr = (smb_krb5_addresses *)SMB_MALLOC(sizeof(smb_krb5_addresses));
1270 if (*kerb_addr == NULL) {
1271 return ENOMEM;
1272 }
1273
1274 put_name(buf, global_myname(), ' ', 0x20);
1275
1276#if defined(HAVE_MAGIC_IN_KRB5_ADDRESS) && defined(HAVE_ADDRTYPE_IN_KRB5_ADDRESS) /* MIT */
1277 {
1278 int num_addr = 2;
1279
1280 addrs = (krb5_address **)SMB_MALLOC(sizeof(krb5_address *) * num_addr);
1281 if (addrs == NULL) {
1282 SAFE_FREE(kerb_addr);
1283 return ENOMEM;
1284 }
1285
1286 memset(addrs, 0, sizeof(krb5_address *) * num_addr);
1287
1288 addrs[0] = (krb5_address *)SMB_MALLOC(sizeof(krb5_address));
1289 if (addrs[0] == NULL) {
1290 SAFE_FREE(addrs);
1291 SAFE_FREE(kerb_addr);
1292 return ENOMEM;
1293 }
1294
1295 addrs[0]->magic = KV5M_ADDRESS;
1296 addrs[0]->addrtype = KRB5_ADDR_NETBIOS;
1297 addrs[0]->length = MAX_NETBIOSNAME_LEN;
1298 addrs[0]->contents = (unsigned char *)SMB_MALLOC(addrs[0]->length);
1299 if (addrs[0]->contents == NULL) {
1300 SAFE_FREE(addrs[0]);
1301 SAFE_FREE(addrs);
1302 SAFE_FREE(kerb_addr);
1303 return ENOMEM;
1304 }
1305
1306 memcpy(addrs[0]->contents, buf, addrs[0]->length);
1307
1308 addrs[1] = NULL;
1309 }
1310#elif defined(HAVE_ADDR_TYPE_IN_KRB5_ADDRESS) /* Heimdal */
1311 {
1312 addrs = (krb5_addresses *)SMB_MALLOC(sizeof(krb5_addresses));
1313 if (addrs == NULL) {
1314 SAFE_FREE(kerb_addr);
1315 return ENOMEM;
1316 }
1317
1318 memset(addrs, 0, sizeof(krb5_addresses));
1319
1320 addrs->len = 1;
1321 addrs->val = (krb5_address *)SMB_MALLOC(sizeof(krb5_address));
1322 if (addrs->val == NULL) {
1323 SAFE_FREE(addrs);
1324 SAFE_FREE(kerb_addr);
1325 return ENOMEM;
1326 }
1327
1328 addrs->val[0].addr_type = KRB5_ADDR_NETBIOS;
1329 addrs->val[0].address.length = MAX_NETBIOSNAME_LEN;
1330 addrs->val[0].address.data = (unsigned char *)SMB_MALLOC(addrs->val[0].address.length);
1331 if (addrs->val[0].address.data == NULL) {
1332 SAFE_FREE(addrs->val);
1333 SAFE_FREE(addrs);
1334 SAFE_FREE(kerb_addr);
1335 return ENOMEM;
1336 }
1337
1338 memcpy(addrs->val[0].address.data, buf, addrs->val[0].address.length);
1339 }
1340#else
1341#error UNKNOWN_KRB5_ADDRESS_FORMAT
1342#endif
1343 (*kerb_addr)->addrs = addrs;
1344
1345 return ret;
1346}
1347
1348 void smb_krb5_free_error(krb5_context context, krb5_error *krberror)
1349{
1350#ifdef HAVE_KRB5_FREE_ERROR_CONTENTS /* Heimdal */
1351 krb5_free_error_contents(context, krberror);
1352#else /* MIT */
1353 krb5_free_error(context, krberror);
1354#endif
1355}
1356
1357 krb5_error_code handle_krberror_packet(krb5_context context,
1358 krb5_data *packet)
1359{
1360 krb5_error_code ret;
1361 BOOL got_error_code = False;
1362
1363 DEBUG(10,("handle_krberror_packet: got error packet\n"));
1364
1365#ifdef HAVE_E_DATA_POINTER_IN_KRB5_ERROR /* Heimdal */
1366 {
1367 krb5_error krberror;
1368
1369 if ((ret = krb5_rd_error(context, packet, &krberror))) {
1370 DEBUG(10,("handle_krberror_packet: krb5_rd_error failed with: %s\n",
1371 error_message(ret)));
1372 return ret;
1373 }
1374
1375 if (krberror.e_data == NULL || krberror.e_data->data == NULL) {
1376 ret = (krb5_error_code) krberror.error_code;
1377 got_error_code = True;
1378 }
1379
1380 smb_krb5_free_error(context, &krberror);
1381 }
1382#else /* MIT */
1383 {
1384 krb5_error *krberror;
1385
1386 if ((ret = krb5_rd_error(context, packet, &krberror))) {
1387 DEBUG(10,("handle_krberror_packet: krb5_rd_error failed with: %s\n",
1388 error_message(ret)));
1389 return ret;
1390 }
1391
1392 if (krberror->e_data.data == NULL) {
1393 ret = ERROR_TABLE_BASE_krb5 + (krb5_error_code) krberror->error;
1394 got_error_code = True;
1395 }
1396 smb_krb5_free_error(context, krberror);
1397 }
1398#endif
1399 if (got_error_code) {
1400 DEBUG(5,("handle_krberror_packet: got KERBERR from kpasswd: %s (%d)\n",
1401 error_message(ret), ret));
1402 }
1403 return ret;
1404}
1405
1406 krb5_error_code smb_krb5_get_init_creds_opt_alloc(krb5_context context,
1407 krb5_get_init_creds_opt **opt)
1408{
1409#ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_ALLOC
1410 /* Heimdal or modern MIT version */
1411 return krb5_get_init_creds_opt_alloc(context, opt);
1412#else
1413 /* Historical MIT version */
1414 krb5_get_init_creds_opt *my_opt;
1415
1416 *opt = NULL;
1417
1418 if ((my_opt = SMB_MALLOC(sizeof(krb5_get_init_creds_opt))) == NULL) {
1419 return ENOMEM;
1420 }
1421
1422 krb5_get_init_creds_opt_init(my_opt);
1423
1424 *opt = my_opt;
1425 return 0;
1426#endif /* HAVE_KRB5_GET_INIT_CREDS_OPT_ALLOC */
1427}
1428
1429 void smb_krb5_get_init_creds_opt_free(krb5_context context,
1430 krb5_get_init_creds_opt *opt)
1431{
1432#ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_FREE
1433
1434#ifdef KRB5_CREDS_OPT_FREE_REQUIRES_CONTEXT
1435 /* Modern MIT version */
1436 krb5_get_init_creds_opt_free(context, opt);
1437#else
1438 /* Heimdal version */
1439 krb5_get_init_creds_opt_free(opt);
1440#endif
1441
1442#else /* HAVE_KRB5_GET_INIT_CREDS_OPT_FREE */
1443 /* Historical MIT version */
1444 SAFE_FREE(opt);
1445 opt = NULL;
1446#endif /* HAVE_KRB5_GET_INIT_CREDS_OPT_FREE */
1447}
1448
1449 krb5_error_code smb_krb5_mk_error(krb5_context context,
1450 krb5_error_code error_code,
1451 const krb5_principal server,
1452 krb5_data *reply)
1453{
1454#ifdef HAVE_SHORT_KRB5_MK_ERROR_INTERFACE /* MIT */
1455 /*
1456 * The MIT interface is *terrible*.
1457 * We have to construct this ourselves...
1458 */
1459 krb5_error e;
1460
1461 memset(&e, 0, sizeof(e));
1462 krb5_us_timeofday(context, &e.stime, &e.susec);
1463 e.server = server;
1464#if defined(krb5_err_base)
1465 e.error = error_code - krb5_err_base;
1466#elif defined(ERROR_TABLE_BASE_krb5)
1467 e.error = error_code - ERROR_TABLE_BASE_krb5;
1468#else
1469 e.error = error_code; /* Almost certainly wrong, but what can we do... ? */
1470#endif
1471
1472 return krb5_mk_error(context, &e, reply);
1473#else /* Heimdal. */
1474 return krb5_mk_error(context,
1475 error_code,
1476 NULL,
1477 NULL, /* e_data */
1478 NULL,
1479 server,
1480 NULL,
1481 NULL,
1482 reply);
1483#endif
1484}
1485
1486#else /* HAVE_KRB5 */
1487 /* this saves a few linking headaches */
1488 int cli_krb5_get_ticket(const char *principal, time_t time_offset,
1489 DATA_BLOB *ticket, DATA_BLOB *session_key_krb5, uint32 extra_ap_opts,
1490 const char *ccname, time_t *tgs_expire)
1491{
1492 DEBUG(0,("NO KERBEROS SUPPORT\n"));
1493 return 1;
1494}
1495
1496#endif
Note: See TracBrowser for help on using the repository browser.