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
40mit_krb5_error_code KRB5_CALLCONV
41krb5_cc_default(mit_krb5_context context, mit_krb5_ccache *cache)
42{
43    LOG_ENTRY();
44    return heim_krb5_cc_default(HC(context), (krb5_ccache *)cache);
45}
46
47mit_krb5_error_code KRB5_CALLCONV
48krb5_cc_resolve(mit_krb5_context context, const char *str, mit_krb5_ccache *cache)
49{
50    LOG_ENTRY();
51    return heim_krb5_cc_resolve(HC(context), str, (krb5_ccache *)cache);
52}
53
54mit_krb5_error_code KRB5_CALLCONV
55krb5_cc_initialize(mit_krb5_context context,
56		   mit_krb5_ccache cache,
57		   mit_krb5_principal principal)
58{
59    struct comb_principal *p = (struct comb_principal *)principal;
60    LOG_ENTRY();
61    return heim_krb5_cc_initialize(HC(context), (krb5_ccache)cache, p->heim);
62}
63
64mit_krb5_error_code KRB5_CALLCONV
65krb5_cc_store_cred(mit_krb5_context context,
66		   mit_krb5_ccache cache,
67		   mit_krb5_creds *creds)
68{
69    krb5_error_code ret;
70    krb5_creds hcred;
71    LOG_ENTRY();
72    mshim_mcred2hcred(HC(context), creds, &hcred);
73    ret = heim_krb5_cc_store_cred(HC(context), (krb5_ccache)cache, &hcred);
74    heim_krb5_free_cred_contents(HC(context), &hcred);
75    return ret;
76}
77
78mit_krb5_error_code KRB5_CALLCONV
79krb5_cc_get_principal (mit_krb5_context context,
80		       mit_krb5_ccache cache,
81		       mit_krb5_principal *principal)
82{
83    krb5_principal p;
84    krb5_error_code ret;
85
86    LOG_ENTRY();
87
88    ret = heim_krb5_cc_get_principal(HC(context), (krb5_ccache)cache, &p);
89    if (ret)
90	return ret;
91    *principal = mshim_hprinc2mprinc(HC(context), p);
92    heim_krb5_free_principal(HC(context), p);
93    if (*principal == NULL) {
94	krb5_set_error_message(context, ENOMEM, "out of memory");
95	return ENOMEM;
96    }
97    return 0;
98}
99
100mit_krb5_error_code KRB5_CALLCONV
101krb5_cc_close(mit_krb5_context context,
102	      mit_krb5_ccache cache)
103{
104    return heim_krb5_cc_close(HC(context), (krb5_ccache)cache);
105}
106
107const char * KRB5_CALLCONV
108krb5_cc_get_name (mit_krb5_context context, mit_krb5_ccache cache)
109{
110    return heim_krb5_cc_get_name(HC(context), (krb5_ccache)cache);
111}
112
113const char * KRB5_CALLCONV
114krb5_cc_get_type (mit_krb5_context context, mit_krb5_ccache cache)
115{
116    return heim_krb5_cc_get_type(HC(context), (krb5_ccache)cache);
117}
118
119mit_krb5_error_code KRB5_CALLCONV
120krb5_cc_get_config(mit_krb5_context context, mit_krb5_ccache id,
121		   mit_krb5_const_principal principal,
122		   const char *key, mit_krb5_data *data)
123{
124    struct comb_principal *p = (struct comb_principal *)principal;
125    krb5_principal hc = NULL;
126    krb5_error_code ret;
127    krb5_data hdata;
128
129    if (p)
130	hc = p->heim;
131
132    ret = heim_krb5_cc_get_config(HC(context), (krb5_ccache)id, hc, key, &hdata);
133    if (ret)
134	return ret;
135    ret = mshim_hdata2mdata(&hdata, data);
136    heim_krb5_data_free(&hdata);
137    return ret;
138}
139
140mit_krb5_error_code KRB5_CALLCONV
141krb5_cc_new_unique(mit_krb5_context context,
142		   const char *type,
143		   const char *hint,
144		   mit_krb5_ccache *id)
145{
146    LOG_ENTRY();
147    return heim_krb5_cc_new_unique(HC(context), type, hint, (krb5_ccache *)id);
148}
149
150mit_krb5_error_code KRB5_CALLCONV
151krb5_cc_gen_new (mit_krb5_context context, mit_krb5_ccache *id)
152{
153    LOG_ENTRY();
154    return heim_krb5_cc_new_unique(HC(context), NULL, NULL, (krb5_ccache *)id);
155}
156
157mit_krb5_error_code KRB5_CALLCONV
158krb5_cc_cache_match (mit_krb5_context context,
159		     mit_krb5_principal client,
160		     mit_krb5_ccache *id)
161{
162    struct comb_principal *p = (struct comb_principal *)client;
163    return heim_krb5_cc_cache_match(HC(context), p->heim, (krb5_ccache *)id);
164}
165
166static const struct mshim_map_flags whichfields_flags[] = {
167    { MIT_KRB5_TC_MATCH_TIMES,		KRB5_TC_MATCH_TIMES },
168    { MIT_KRB5_TC_MATCH_IS_SKEY,	KRB5_TC_MATCH_IS_SKEY },
169    { MIT_KRB5_TC_MATCH_FLAGS,		KRB5_TC_MATCH_FLAGS },
170    { MIT_KRB5_TC_MATCH_TIMES_EXACT,	KRB5_TC_MATCH_TIMES_EXACT },
171    { MIT_KRB5_TC_MATCH_FLAGS_EXACT,	KRB5_TC_MATCH_FLAGS_EXACT },
172    { MIT_KRB5_TC_MATCH_AUTHDATA,	KRB5_TC_MATCH_AUTHDATA },
173    { MIT_KRB5_TC_MATCH_SRV_NAMEONLY,	KRB5_TC_MATCH_SRV_NAMEONLY },
174    { MIT_KRB5_TC_MATCH_2ND_TKT,	KRB5_TC_MATCH_2ND_TKT },
175    { MIT_KRB5_TC_MATCH_KTYPE,		KRB5_TC_MATCH_KEYTYPE },
176    { MIT_KRB5_TC_SUPPORTED_KTYPES,	0 },
177    { 0 }
178};
179
180mit_krb5_error_code KRB5_CALLCONV
181krb5_cc_retrieve_cred(mit_krb5_context context,
182		      mit_krb5_ccache cache,
183		      mit_krb5_flags flags,
184		      mit_krb5_creds *mcreds,
185		      mit_krb5_creds *creds)
186{
187    krb5_error_code ret;
188    krb5_creds hcreds, hmcreds;
189    krb5_flags whichfields;
190
191    LOG_ENTRY();
192
193    memset(creds, 0, sizeof(*creds));
194    memset(&hcreds, 0, sizeof(hcreds));
195
196    whichfields = mshim_remap_flags(flags, whichfields_flags);
197
198    mshim_mcred2hcred(HC(context), mcreds, &hmcreds);
199    ret = heim_krb5_cc_retrieve_cred(HC(context), (krb5_ccache)cache, whichfields,
200				     &hmcreds, &hcreds);
201    heim_krb5_free_cred_contents(HC(context), &hmcreds);
202    if (ret == 0) {
203	mshim_hcred2mcred(HC(context), &hcreds, creds);
204	heim_krb5_free_cred_contents(HC(context), &hcreds);
205    }
206    return ret;
207
208}
209
210mit_krb5_error_code KRB5_CALLCONV
211krb5_cc_next_cred(mit_krb5_context context,
212		  mit_krb5_ccache cache,
213		  mit_krb5_cc_cursor *cursor,
214		  mit_krb5_creds *creds)
215{
216    krb5_error_code ret;
217    krb5_creds c;
218
219    LOG_ENTRY();
220
221    ret = heim_krb5_cc_next_cred(HC(context), (krb5_ccache)cache, (krb5_cc_cursor *)cursor, &c);
222    if (ret == 0) {
223	mshim_hcred2mcred(HC(context), &c, creds);
224	heim_krb5_free_cred_contents(HC(context), &c);
225    }
226    return ret;
227}
228
229/* <rdar://problem/7381784> */
230
231mit_krb5_error_code KRB5_CALLCONV
232krb5_cc_end_seq_get (mit_krb5_context context, mit_krb5_ccache cache,
233		     mit_krb5_cc_cursor *cursor)
234{
235    LOG_ENTRY();
236    if (context == NULL || cache == NULL || cursor == NULL || *cursor == NULL) {
237	/*
238	 * We have to return a non failure code to make AppleConnect
239	 * happy, when testing this, make sure you don't have any
240	 * credentails at all since AC will pick up both API and FILE
241	 * based credentials.
242	 */
243	return 0;
244    }
245    return heim_krb5_cc_end_seq_get(HC(context), (krb5_ccache)cache, (krb5_cc_cursor)cursor);
246}
247