1/*
2 * Copyright (c) 2008-2010 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Portions Copyright (c) 2008-2010 Apple Inc. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * 3. Neither the name of the Institute nor the names of its contributors
20 *    may be used to endorse or promote products derived from this software
21 *    without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36#include "heim.h"
37#include <string.h>
38#include <errno.h>
39#include <stdio.h>
40#include <stdarg.h>
41#include <stdlib.h>
42#include <pthread.h>
43
44#include <dispatch/dispatch.h>
45
46#include <CommonCrypto/CommonDigest.h>
47#include <CoreFoundation/CoreFoundation.h>
48#include <Heimdal/gkrb5_err.h>
49#include <Heimdal/wind_err.h>
50#include <Heimdal/krb_err.h>
51#include <Heimdal/hx509_err.h>
52
53const char *__KerberosInternal_krb5_defkeyname = "FILE:/etc/krb5.keytab";
54
55int krb5_use_broken_arcfour_string2key = 0;
56
57static int do_log = 0;
58
59static CFTypeRef
60CopyKeyFromFile(CFStringRef domain, CFStringRef key)
61{
62    CFReadStreamRef s;
63    CFDictionaryRef d;
64    CFStringRef file;
65    CFErrorRef e;
66    CFURLRef url;
67    CFTypeRef val;
68
69    file = CFStringCreateWithFormat(NULL, 0, CFSTR("/Library/Preferences/%@.plist"), domain);
70    if (file == NULL)
71	return NULL;
72
73    url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, domain, kCFURLPOSIXPathStyle, false);
74    CFRelease(file);
75    if (url == NULL)
76	return NULL;
77
78    s = CFReadStreamCreateWithFile(kCFAllocatorDefault, url);
79    CFRelease(url);
80    if (s == NULL)
81	return NULL;
82
83    if (!CFReadStreamOpen(s)) {
84	CFRelease(s);
85	return NULL;
86    }
87
88    d = (CFDictionaryRef)CFPropertyListCreateWithStream (kCFAllocatorDefault, s, 0, kCFPropertyListImmutable, NULL, &e);
89    CFRelease(s);
90    if (d == NULL)
91	return NULL;
92
93    if (CFGetTypeID(d) != CFDictionaryGetTypeID()) {
94	CFRelease(d);
95	return NULL;
96    }
97
98    val = CFDictionaryGetValue(d, key);
99    if (val)
100	CFRetain(val);
101    CFRelease(d);
102    return val;
103}
104
105static void
106init_log(void)
107{
108    static dispatch_once_t once = 0;
109    dispatch_once(&once, ^{
110	    CFBooleanRef b;
111	    b = CopyKeyFromFile(CFSTR("com.apple.MITKerberosShim"),
112			       CFSTR("EnableDebugging"));
113	    if (b && CFGetTypeID(b) == CFBooleanGetTypeID())
114		do_log = CFBooleanGetValue(b);
115	    if (b)
116		CFRelease(b);
117    });
118}
119
120void
121mshim_log_entry(const char *msg, ...)
122{
123    init_log();
124
125    if (do_log) {
126	va_list ap;
127	va_start(ap, msg);
128	vsyslog(LOG_DEBUG, msg, ap);
129	va_end(ap);
130    }
131}
132
133int
134mshim_failure(const char *func, int error, const char *subsystem)
135{
136    init_log();
137
138    if (do_log && error)
139	syslog(LOG_DEBUG, "%s failed with %d for '%s'", func, error, subsystem);
140    return error;
141}
142
143static void
144destroy_ctx(void *ptr)
145{
146    heim_krb5_free_context(ptr);
147}
148
149krb5_context
150mshim_ctx(void)
151{
152    static dispatch_once_t once;
153    static pthread_key_t key;
154    krb5_context ctx = NULL;
155
156    dispatch_once(&once, ^{
157	if (pthread_key_create(&key, destroy_ctx) != 0)
158	    abort();
159	});
160
161    ctx = pthread_getspecific(key);
162    if (ctx == NULL) {
163	krb5_error_code ret;
164
165	ret = heim_krb5_init_context(&ctx);
166	if (ret)
167	    ret = heim_krb5_init_context_flags(KRB5_CONTEXT_FLAG_NO_CONFIG, &ctx);
168
169	if (ret) {
170	    syslog(LOG_ERR, "Failed to create kerberos context for thread (milcontext): %d", ret);
171	    abort();
172	}
173
174	pthread_setspecific(key, ctx);
175    }
176    return ctx;
177}
178
179
180void *
181mshim_malloc(size_t size)
182{
183    void *ptr = malloc(size);
184    if (ptr == NULL) {
185	syslog(LOG_DEBUG, "mshim_malloc: can't allocate %d", (int)size);
186	abort();
187    }
188    memset(ptr, 0, size);
189    return ptr;
190}
191
192krb5_error_code
193mshim_hdata2mdata(const krb5_data *h, mit_krb5_data *m)
194{
195    m->magic = MIT_KV5M_DATA;
196    m->length = h->length;
197    m->data = mshim_malloc(h->length);
198    memcpy(m->data, h->data, h->length);
199    return 0;
200}
201
202
203krb5_error_code
204mshim_mdata2hdata(const mit_krb5_data *m, krb5_data *h)
205{
206    h->length = m->length;
207    h->data = mshim_malloc(m->length);
208    memcpy(h->data, m->data, m->length);
209    return 0;
210}
211
212void
213mshim_hkeyblock2mkeyblock(const krb5_keyblock *h, mit_krb5_keyblock *m)
214{
215    m->magic = MIT_KV5M_KEYBLOCK;
216    m->enctype = h->keytype;
217    m->length = h->keyvalue.length;
218    m->contents = mshim_malloc(h->keyvalue.length);
219    memcpy(m->contents, h->keyvalue.data, h->keyvalue.length);
220}
221
222void
223mshim_mkeyblock2hkeyblock(const mit_krb5_keyblock *m, krb5_keyblock *h)
224{
225    h->keytype = m->enctype;
226    h->keyvalue.length = m->length;
227    h->keyvalue.data = mshim_malloc(h->keyvalue.length);
228    memcpy(h->keyvalue.data, m->contents, h->keyvalue.length);
229}
230
231
232mit_krb5_error_code KRB5_CALLCONV
233krb5_copy_keyblock_contents(mit_krb5_context context,
234			    const mit_krb5_keyblock *from,
235			    mit_krb5_keyblock *to)
236{
237    LOG_ENTRY();
238    to->magic = MIT_KV5M_KEYBLOCK;
239    to->enctype = from->enctype;
240    to->length = from->length;
241    to->contents = mshim_malloc(from->length);
242    memcpy(to->contents, from->contents, from->length);
243    return 0;
244}
245
246mit_krb5_error_code KRB5_CALLCONV
247krb5_copy_keyblock(mit_krb5_context context,
248		   const mit_krb5_keyblock *from,
249		   mit_krb5_keyblock **to)
250{
251    LOG_ENTRY();
252    *to = mshim_malloc(sizeof(**to));
253    return krb5_copy_keyblock_contents(context, from, *to);
254}
255
256
257
258void
259mshim_mcred2hcred(krb5_context context, mit_krb5_creds *m, krb5_creds *h)
260{
261    struct comb_principal *p;
262    memset(h, 0, sizeof(*h));
263
264    p = (struct comb_principal *)m->client;
265    if (p)
266        heim_krb5_copy_principal(context, p->heim, &h->client);
267    p = (struct comb_principal *)m->server;
268    if (p)
269        heim_krb5_copy_principal(context, p->heim, &h->server);
270
271    h->session.keytype = m->keyblock.enctype;
272    heim_krb5_data_copy(&h->session.keyvalue, m->keyblock.contents, m->keyblock.length);
273
274    heim_krb5_data_copy(&h->ticket, m->ticket.data, m->ticket.length);
275
276    h->times.authtime = m->times.authtime;
277    h->times.starttime = m->times.starttime;
278    h->times.endtime = m->times.endtime;
279    h->times.renew_till = m->times.renew_till;
280
281    h->flags.i = 0;
282    if (m->ticket_flags & MIT_TKT_FLG_FORWARDABLE)
283	h->flags.b.forwardable = 1;
284    if (m->ticket_flags & MIT_TKT_FLG_FORWARDED)
285	h->flags.b.forwarded = 1;
286    if (m->ticket_flags & MIT_TKT_FLG_PROXIABLE)
287	h->flags.b.proxiable = 1;
288    if (m->ticket_flags & MIT_TKT_FLG_PROXY)
289	h->flags.b.proxy = 1;
290    if (m->ticket_flags & MIT_TKT_FLG_MAY_POSTDATE)
291	h->flags.b.may_postdate = 1;
292    if (m->ticket_flags & MIT_TKT_FLG_POSTDATED)
293	h->flags.b.postdated = 1;
294    if (m->ticket_flags & MIT_TKT_FLG_INVALID)
295	h->flags.b.invalid = 1;
296    if (m->ticket_flags & MIT_TKT_FLG_RENEWABLE)
297	h->flags.b.renewable = 1;
298    if (m->ticket_flags & MIT_TKT_FLG_INITIAL)
299	h->flags.b.initial = 1;
300    if (m->ticket_flags & MIT_TKT_FLG_PRE_AUTH)
301	h->flags.b.pre_authent = 1;
302    if (m->ticket_flags & MIT_TKT_FLG_HW_AUTH)
303	h->flags.b.hw_authent = 1;
304    if (m->ticket_flags & MIT_TKT_FLG_TRANSIT_POLICY_CHECKED)
305	h->flags.b.transited_policy_checked = 1;
306    if (m->ticket_flags & MIT_TKT_FLG_OK_AS_DELEGATE)
307	h->flags.b.ok_as_delegate = 1;
308    if (m->ticket_flags & MIT_TKT_FLG_ANONYMOUS)
309	h->flags.b.anonymous = 1;
310
311}
312
313void
314mshim_hcred2mcred(krb5_context context, krb5_creds *h, mit_krb5_creds *m)
315{
316    memset(m, 0, sizeof(*m));
317
318    m->magic = MIT_KV5M_CREDS;
319    if (h->client)
320        m->client = mshim_hprinc2mprinc(context, h->client);
321    if (h->server)
322        m->server = mshim_hprinc2mprinc(context, h->server);
323
324    mshim_hkeyblock2mkeyblock(&h->session, &m->keyblock);
325
326    mshim_hdata2mdata(&h->ticket, &m->ticket);
327
328    m->times.authtime = h->times.authtime;
329    m->times.starttime = h->times.starttime;
330    m->times.endtime = h->times.endtime;
331    m->times.renew_till = h->times.renew_till;
332
333    m->ticket_flags = 0;
334    if (h->flags.b.forwardable)
335	m->ticket_flags |= MIT_TKT_FLG_FORWARDABLE;
336    if (h->flags.b.forwarded)
337	m->ticket_flags |= MIT_TKT_FLG_FORWARDED;
338    if (h->flags.b.proxiable)
339	m->ticket_flags |= MIT_TKT_FLG_PROXIABLE;
340    if (h->flags.b.proxy)
341	m->ticket_flags |= MIT_TKT_FLG_PROXY;
342    if (h->flags.b.may_postdate)
343	m->ticket_flags |= MIT_TKT_FLG_MAY_POSTDATE;
344    if (h->flags.b.postdated)
345	m->ticket_flags |= MIT_TKT_FLG_POSTDATED;
346    if (h->flags.b.invalid)
347	m->ticket_flags |= MIT_TKT_FLG_INVALID;
348    if (h->flags.b.renewable)
349	m->ticket_flags |= MIT_TKT_FLG_RENEWABLE;
350    if (h->flags.b.initial)
351	m->ticket_flags |= MIT_TKT_FLG_INITIAL;
352    if (h->flags.b.pre_authent)
353	m->ticket_flags |= MIT_TKT_FLG_PRE_AUTH;
354    if (h->flags.b.hw_authent)
355	m->ticket_flags |= MIT_TKT_FLG_HW_AUTH;
356    if (h->flags.b.transited_policy_checked)
357	m->ticket_flags |= MIT_TKT_FLG_TRANSIT_POLICY_CHECKED;
358    if (h->flags.b.ok_as_delegate)
359	m->ticket_flags |= MIT_TKT_FLG_OK_AS_DELEGATE;
360    if (h->flags.b.anonymous)
361	m->ticket_flags |= MIT_TKT_FLG_ANONYMOUS;
362}
363
364void
365mshim_haprepencpart2maprepencpart(const krb5_ap_rep_enc_part *h,
366				  mit_krb5_ap_rep_enc_part *m)
367{
368    m->magic = MIT_KV5M_AP_REP_ENC_PART;
369    m->ctime = h->ctime;
370    m->cusec = h->cusec;
371
372    if (h->subkey) {
373	m->subkey = mshim_malloc(sizeof(*m->subkey));
374	mshim_hkeyblock2mkeyblock(h->subkey, m->subkey);
375    } else
376	m->subkey = NULL;
377
378    if (h->seq_number) {
379	m->seq_number = *h->seq_number;
380    } else
381	m->seq_number = 0;
382}
383
384void
385mshim_hreplay2mreplay(const krb5_replay_data *h, mit_krb5_replay_data *m)
386{
387    m->timestamp = h->timestamp;
388    m->usec = h->usec;
389    m->seq = h->seq;
390}
391
392
393void KRB5_CALLCONV
394krb5_free_ap_rep_enc_part(mit_krb5_context context,
395			  mit_krb5_ap_rep_enc_part *enc_part)
396{
397    LOG_ENTRY();
398    if (enc_part->subkey)
399	krb5_free_keyblock(context, enc_part->subkey);
400    free(enc_part);
401}
402
403void KRB5_CALLCONV
404krb5_free_error(mit_krb5_context context, mit_krb5_error *error)
405{
406    LOG_ENTRY();
407    krb5_free_principal(context, error->client);
408    krb5_free_principal(context, error->server);
409    krb5_free_data_contents(context, &error->text);
410    krb5_free_data_contents(context, &error->e_data);
411    free(error);
412}
413
414void
415mshim_herror2merror(krb5_context context, const krb5_error *h, mit_krb5_error *m)
416{
417    LOG_ENTRY();
418    memset(m, 0, sizeof(*m));
419
420    m->magic = MIT_KV5M_ERROR;
421    if (h->ctime)
422	m->ctime = *h->ctime;
423    if (h->cusec)
424	m->cusec = *h->cusec;
425    m->stime = h->stime;
426    m->susec = h->susec;
427#if 0
428    m->client = mshim_hprinc2mprinc(context, h->client);
429    m->server = mshim_hprinc2mprinc(context, h->server);
430#endif
431    m->error = h->error_code;
432    if (h->e_text) {
433	m->text.magic = MIT_KV5M_DATA;
434	m->text.data = strdup(*(h->e_text));
435	m->text.length = strlen(*(h->e_text));
436    }
437    if (h->e_data)
438	mshim_hdata2mdata(h->e_data, &m->e_data);
439#if 0
440    krb5_principal client;		/* client's principal identifier;
441					   optional */
442    krb5_principal server;		/* server's principal identifier */
443#endif
444}
445
446unsigned long
447mshim_remap_flags(unsigned long in, const struct mshim_map_flags *table)
448{
449    unsigned long out = 0;
450    while(table->in) {
451	if (table->in & in)
452	    out |= table->out;
453	table++;
454    }
455    return out;
456}
457
458
459mit_krb5_error_code
460krb5_init_context(mit_krb5_context *context)
461{
462    LOG_ENTRY();
463    return heim_krb5_init_context((krb5_context *)context);
464}
465
466mit_krb5_error_code
467krb5_init_secure_context(mit_krb5_context *context)
468{
469    LOG_ENTRY();
470    return heim_krb5_init_context((krb5_context *)context);
471}
472
473void
474krb5_free_context(mit_krb5_context context)
475{
476    LOG_ENTRY();
477    heim_krb5_free_context(HC(context));
478}
479
480const char *
481error_message(errcode_t code)
482{
483    static dispatch_once_t once = 0;
484    static struct et_list *et_list = NULL;
485    static char buffer[1024];
486    const char *str;
487
488    dispatch_once(&once, ^{
489	initialize_asn1_error_table_r(&et_list);
490	initialize_gk5_error_table_r(&et_list);
491	initialize_wind_error_table_r(&et_list);
492	initialize_krb5_error_table_r(&et_list);
493	initialize_krb_error_table_r(&et_list);
494	initialize_k524_error_table_r(&et_list);
495	initialize_heim_error_table_r(&et_list);
496	initialize_hx_error_table_r(&et_list);
497    });
498
499    str = heim_com_right_r(et_list, code, buffer, sizeof(buffer));
500    if (str == NULL) {
501	snprintf(buffer, sizeof(buffer), "Unknown error %d", (int)code);
502	str = buffer;
503    }
504    return str;
505}
506
507void KRB5_CALLCONV
508krb5_free_keyblock(mit_krb5_context context, mit_krb5_keyblock *keyblock)
509{
510    LOG_ENTRY();
511    krb5_free_keyblock_contents(context, keyblock);
512    free(keyblock);
513}
514
515void KRB5_CALLCONV
516krb5_free_keyblock_contents(mit_krb5_context context, mit_krb5_keyblock *keyblock)
517{
518    LOG_ENTRY();
519    memset(keyblock->contents, 0, keyblock->length);
520    free(keyblock->contents);
521    memset(keyblock, 0, sizeof(*keyblock));
522}
523
524void KRB5_CALLCONV
525krb5_free_data(mit_krb5_context context, mit_krb5_data *data)
526{
527    LOG_ENTRY();
528    krb5_free_data_contents(context, data);
529    free(data);
530}
531
532void KRB5_CALLCONV
533krb5_free_data_contents(mit_krb5_context context, mit_krb5_data *data)
534{
535    LOG_ENTRY();
536    free(data->data);
537    memset(data, 0, sizeof(*data));
538}
539
540mit_krb5_error_code KRB5_CALLCONV
541krb5_copy_data(mit_krb5_context context,
542		const mit_krb5_data *from,
543		mit_krb5_data **to)
544{
545    *to = mshim_malloc(sizeof(**to));
546    (*to)->magic = MIT_KV5M_DATA;
547    (*to)->length = from->length;
548    (*to)->data = mshim_malloc(from->length);
549    memcpy((*to)->data, from->data, from->length);
550    return 0;
551}
552
553void KRB5_CALLCONV
554krb5_free_cred_contents(mit_krb5_context context, mit_krb5_creds *cred)
555{
556    LOG_ENTRY();
557    if (cred == NULL)
558	return;
559    krb5_free_principal(context, cred->client);
560    krb5_free_principal(context, cred->server);
561    krb5_free_keyblock_contents(context, &cred->keyblock);
562    krb5_free_data_contents(context, &cred->ticket);
563    krb5_free_data_contents(context, &cred->second_ticket);
564    /*
565    mit_krb5_address **addresses;
566    mit_krb5_authdata **authdata;
567    */
568    memset(cred, 0, sizeof(*cred));
569}
570
571void KRB5_CALLCONV
572krb5_free_creds(mit_krb5_context context, mit_krb5_creds *cred)
573{
574    LOG_ENTRY();
575    krb5_free_cred_contents(context, cred);
576    free(cred);
577}
578
579void KRB5_CALLCONV
580krb5_free_enc_tkt_part(mit_krb5_context context, krb5_enc_tkt_part *enc_part2)
581{
582    if (enc_part2->session)
583	krb5_free_keyblock(context, enc_part2->session);
584    if (enc_part2->client)
585	krb5_free_principal(context, enc_part2->client);
586    memset(enc_part2, 0, sizeof(*enc_part2));
587    free(enc_part2);
588}
589
590void KRB5_CALLCONV
591krb5_free_ticket(mit_krb5_context context, mit_krb5_ticket *ticket)
592{
593    LOG_ENTRY();
594    if (ticket == NULL)
595	return;
596    if (ticket->server)
597	krb5_free_principal(context, ticket->server);
598    if (ticket->enc_part.ciphertext.data)
599	krb5_free_data_contents(context, &ticket->enc_part.ciphertext);
600    if (ticket->enc_part2)
601	krb5_free_enc_tkt_part(context, ticket->enc_part2);
602    memset(ticket, 0, sizeof(*ticket));
603    free(ticket);
604}
605
606void KRB5_CALLCONV
607krb5_free_authdata(mit_krb5_context context,
608		   mit_krb5_authdata **val)
609{
610    mit_krb5_authdata **ptr;
611
612    for (ptr = val; ptr && *ptr; ptr++) {
613	free((*ptr)->contents);
614	free(*ptr);
615    }
616    free(val);
617}
618
619mit_krb5_error_code KRB5_CALLCONV
620krb5_us_timeofday(mit_krb5_context context,
621		  mit_krb5_timestamp *outsec,
622		  mit_krb5_int32 *outusec)
623{
624    krb5_timestamp sec;
625    int32_t usec;
626    LOG_ENTRY();
627    heim_krb5_us_timeofday((krb5_context)context, &sec, &usec);
628    *outsec = sec;
629    *outusec = usec;
630    return 0;
631}
632
633mit_krb5_error_code KRB5_CALLCONV
634krb5_timeofday(mit_krb5_context context,
635	       mit_krb5_timestamp *out)
636{
637    krb5_timestamp ts;
638    LOG_ENTRY();
639    heim_krb5_timeofday((krb5_context)context, &ts);
640    *out = ts;
641    return 0;
642}
643
644char *
645krb5_pkinit_cert_hash_str(const mit_krb5_data *cert)
646{
647    CC_SHA1_CTX ctx;
648    char *outstr, *cpOut;
649    unsigned char digest[CC_SHA1_DIGEST_LENGTH];
650    unsigned i;
651
652    LOG_ENTRY();
653
654    CC_SHA1_Init(&ctx);
655    CC_SHA1_Update(&ctx, cert->data, cert->length);
656    CC_SHA1_Final(digest, &ctx);
657
658    cpOut = outstr = (char *)malloc((2 * CC_SHA1_DIGEST_LENGTH) + 1);
659    if(outstr == NULL)
660	return NULL;
661
662    for(i = 0; i < CC_SHA1_DIGEST_LENGTH; i++, cpOut += 2)
663	sprintf(cpOut, "%02X", (unsigned)digest[i]);
664    *cpOut = '\0';
665    return outstr;
666}
667
668mit_krb5_error_code KRB5_CALLCONV
669krb5_enctype_to_string(mit_krb5_enctype enctype,
670		       char *str,
671		       size_t size)
672{
673    snprintf(str, size, "enctype-%d", enctype);
674    return 0;
675}
676
677void KRB5_CALLCONV
678krb5_free_addresses(mit_krb5_context context, mit_krb5_address **addrs)
679{
680    unsigned int i;
681    for (i = 0; addrs && addrs[i] ; i++) {
682	free(addrs[i]->contents);
683	free(addrs[i]);
684    }
685    memset(addrs, 0, sizeof(*addrs));
686    free(addrs);
687}
688
689mit_krb5_error_code KRB5_CALLCONV
690krb5_get_server_rcache(mit_krb5_context context,
691		       const mit_krb5_data *foo,
692		       mit_krb5_rcache *rcache)
693{
694    *rcache = NULL;
695    return 0;
696}
697
698mit_krb5_error_code KRB5_CALLCONV
699krb5_os_localaddr(mit_krb5_context context, mit_krb5_address ***addresses)
700{
701    mit_krb5_address **a;
702    krb5_addresses addrs;
703    krb5_error_code ret;
704    unsigned i;
705
706    *addresses = NULL;
707
708    addrs.len = 0;
709    addrs.val = NULL;
710
711    ret = heim_krb5_get_all_client_addrs(HC(context), &addrs);
712    if (ret)
713	return ret;
714
715    a = calloc(addrs.len + 1, sizeof(a[0]));
716    for (i = 0; i < addrs.len; i++) {
717	a[i] = calloc(1, sizeof(mit_krb5_address));
718	a[i]->addrtype = addrs.val[i].addr_type;
719	a[i]->length = addrs.val[i].address.length;
720	a[i]->contents = mshim_malloc(addrs.val[i].address.length);
721	memcpy(a[i]->contents, addrs.val[i].address.data, addrs.val[i].address.length);
722    }
723    a[i] = NULL;
724
725    *addresses = a;
726
727    return 0;
728}
729
730mit_krb5_error_code KRB5_CALLCONV
731krb5_string_to_deltat(char *str, mit_krb5_deltat *t)
732{
733    krb5_error_code ret;
734    krb5_deltat ht;
735
736    ret = heim_krb5_string_to_deltat(str, &ht);
737    if (ret)
738	return ret;
739    *t = ht;
740    return 0;
741}
742
743mit_krb5_error_code KRB5_CALLCONV
744krb5_prompter_posix(mit_krb5_context context,
745		    void *data,
746		    const char *name,
747		    const char *banner,
748		    int num_prompts,
749		    mit_krb5_prompt prompts[])
750{
751    return EINVAL;
752}
753
754mit_krb5_error_code KRB5_CALLCONV
755krb5_get_validated_creds(mit_krb5_context context,
756			 mit_krb5_creds *creds,
757			 mit_krb5_principal client,
758			 mit_krb5_ccache ccache,
759			 char *in_tkt_service)
760{
761    struct comb_principal *p = (struct comb_principal *)client;
762    krb5_error_code ret;
763    krb5_creds hcreds;
764
765    mshim_mcred2hcred(HC(context), creds, &hcreds);
766
767    ret = heim_krb5_get_validated_creds(HC(context), &hcreds, p->heim, (krb5_ccache)ccache, in_tkt_service);
768    heim_krb5_free_cred_contents(HC(context), &hcreds);
769    return ret;
770}
771
772mit_krb5_error_code KRB5_CALLCONV
773krb5_get_renewed_creds (mit_krb5_context context,
774			mit_krb5_creds *creds,
775			mit_krb5_principal client,
776			mit_krb5_ccache ccache,
777			char *in_tkt_service)
778{
779    struct comb_principal *p = (struct comb_principal *)client;
780    krb5_error_code ret;
781    krb5_creds hcreds;
782
783    mshim_mcred2hcred(HC(context), creds, &hcreds);
784
785    ret = heim_krb5_get_renewed_creds(HC(context), &hcreds, p->heim, (krb5_ccache)ccache, in_tkt_service);
786    heim_krb5_free_cred_contents(HC(context), &hcreds);
787    return ret;
788}
789
790mit_krb5_error_code KRB5_CALLCONV
791krb5_set_real_time(mit_krb5_context context,
792		   mit_krb5_timestamp ts,
793		   mit_krb5_int32 usec)
794{
795    LOG_ENTRY();
796    return heim_krb5_set_real_time(HC(context), ts, usec);
797}
798
799#include "Kerberos/kim_library.h"
800
801kim_error
802kim_library_set_ui_environment(kim_ui_environment in_ui_environment)
803{
804    LOG_ENTRY();
805    return 0;
806}
807
808mit_krb5_boolean KRB5_CALLCONV
809krb5_kuserok(mit_krb5_context context,
810	     mit_krb5_principal client,
811	     const char *luser)
812{
813    struct comb_principal *p = (struct comb_principal *)client;
814    LOG_ENTRY();
815    return heim_krb5_kuserok(HC(context), p->heim, luser);
816}
817
818void KRB5_CALLCONV
819krb5_appdefault_string(mit_krb5_context context,
820		       const char *appname,
821		       const mit_krb5_data *realm,
822		       const char *option,
823		       const char *default_value,
824		       char ** ret_value)
825{
826    char *hrealm;
827
828    *ret_value = (char *)default_value;
829
830    if (realm->length > 5000)
831	return;
832
833    hrealm = mshim_malloc(realm->length + 1);
834    memcpy(hrealm, realm->data, realm->length);
835    hrealm[realm->length] = '\0';
836
837    (void)heim_krb5_appdefault_string(HC(context),
838				      appname,
839				      hrealm,
840				      option,
841				      default_value,
842				      ret_value);
843    free(hrealm);
844}
845
846void KRB5_CALLCONV
847krb5_appdefault_boolean(mit_krb5_context context,
848			const char *appname,
849			const mit_krb5_data *realm,
850			const char *option,
851			int default_value,
852			int *ret_value)
853{
854    char *hrealm;
855
856    *ret_value = default_value;
857
858    if (realm->length > 5000)
859	return;
860
861    hrealm = mshim_malloc(realm->length + 1);
862    memcpy(hrealm, realm->data, realm->length);
863    hrealm[realm->length] = '\0';
864
865    (void)heim_krb5_appdefault_boolean(HC(context),
866				       appname,
867				       hrealm,
868				       option,
869				       default_value,
870				       ret_value);
871    free(hrealm);
872}
873
874/*
875 * Debug macros
876 */
877
878#define ddebuglevel       __KerberosDebugLogLevel
879#define dprintf           __KerberosDebugPrint
880#define dvprintf          __KerberosDebugVAPrint
881#define dprintmem         __KerberosDebugPrintMemory
882#define dprintsession     __KerberosDebugPrintSession
883
884int ddebuglevel (void);
885void dprintf (const char *in_format, ...) __attribute__ ((format (printf, 1, 2)));
886void dvprintf (const char *in_format, va_list in_args);
887void dprintmem (const void *in_data, size_t in_length);
888void dprintsession (void);
889
890
891int ddebuglevel (void)
892{
893    return 0;
894}
895
896void dprintf (const char *in_format, ...)
897{
898}
899
900void dvprintf (const char *in_format, va_list in_args)
901{
902}
903
904void dprintmem (const void *in_data, size_t in_length)
905{
906}
907
908void dprintsession (void)
909{
910}
911
912const char * KRB5_CALLCONV
913krb5_get_error_message(mit_krb5_context context, mit_krb5_error_code code)
914{
915    LOG_ENTRY();
916    return heim_krb5_get_error_message(HC(context), code);
917}
918