Line data Source code
1 : /*
2 : * Copyright (c) 2004 - 2007 Kungliga Tekniska Högskolan
3 : * (Royal Institute of Technology, Stockholm, Sweden).
4 : * All rights reserved.
5 : *
6 : * Portions Copyright (c) 2009 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 "krb5_locl.h"
37 : #include <krb5_ccapi.h>
38 :
39 : #ifndef KCM_IS_API_CACHE
40 :
41 : static HEIMDAL_MUTEX acc_mutex = HEIMDAL_MUTEX_INITIALIZER;
42 : static cc_initialize_func init_func;
43 : static void (KRB5_CALLCONV *set_target_uid)(uid_t);
44 : static void (KRB5_CALLCONV *clear_target)(void);
45 :
46 : #ifdef HAVE_DLOPEN
47 : static void *cc_handle;
48 : #endif
49 :
50 : typedef struct krb5_acc {
51 : char *cache_name;
52 : char *cache_subsidiary;
53 : cc_context_t context;
54 : cc_ccache_t ccache;
55 : } krb5_acc;
56 :
57 : static krb5_error_code KRB5_CALLCONV acc_close(krb5_context, krb5_ccache);
58 :
59 : #define ACACHE(X) ((krb5_acc *)(X)->data.data)
60 :
61 : static const struct {
62 : cc_int32 error;
63 : krb5_error_code ret;
64 : } cc_errors[] = {
65 : { ccErrBadName, KRB5_CC_BADNAME },
66 : { ccErrCredentialsNotFound, KRB5_CC_NOTFOUND },
67 : { ccErrCCacheNotFound, KRB5_FCC_NOFILE },
68 : { ccErrContextNotFound, KRB5_CC_NOTFOUND },
69 : { ccIteratorEnd, KRB5_CC_END },
70 : { ccErrNoMem, KRB5_CC_NOMEM },
71 : { ccErrServerUnavailable, KRB5_CC_NOSUPP },
72 : { ccErrInvalidCCache, KRB5_CC_BADNAME },
73 : { ccNoError, 0 }
74 : };
75 :
76 : static krb5_error_code
77 0 : translate_cc_error(krb5_context context, cc_int32 error)
78 : {
79 0 : size_t i;
80 0 : krb5_clear_error_message(context);
81 0 : for(i = 0; i < sizeof(cc_errors)/sizeof(cc_errors[0]); i++)
82 0 : if (cc_errors[i].error == error)
83 0 : return cc_errors[i].ret;
84 0 : return KRB5_FCC_INTERNAL;
85 : }
86 :
87 : static krb5_error_code
88 52 : init_ccapi(krb5_context context)
89 : {
90 52 : const char *lib = NULL;
91 : #ifdef HAVE_DLOPEN
92 : char *explib = NULL;
93 : #endif
94 :
95 0 : HEIMDAL_MUTEX_lock(&acc_mutex);
96 52 : if (init_func) {
97 0 : HEIMDAL_MUTEX_unlock(&acc_mutex);
98 0 : if (context)
99 0 : krb5_clear_error_message(context);
100 0 : return 0;
101 : }
102 :
103 52 : if (context)
104 52 : lib = krb5_config_get_string(context, NULL,
105 : "libdefaults", "ccapi_library",
106 : NULL);
107 52 : if (lib == NULL) {
108 : #ifdef __APPLE__
109 : lib = "/System/Library/Frameworks/Kerberos.framework/Kerberos";
110 : #elif defined(_WIN32)
111 : lib = "%{LIBDIR}/libkrb5_cc.dll";
112 : #else
113 52 : lib = "%{LIBDIR}/libkrb5_cc.so";
114 : #endif
115 : }
116 :
117 : #ifdef HAVE_DLOPEN
118 :
119 : if (_krb5_expand_path_tokens(context, lib, 0, &explib) == 0) {
120 : cc_handle = dlopen(explib, RTLD_LAZY|RTLD_LOCAL|RTLD_GROUP);
121 : free(explib);
122 : }
123 :
124 : if (cc_handle == NULL) {
125 : HEIMDAL_MUTEX_unlock(&acc_mutex);
126 : krb5_set_error_message(context, KRB5_CC_NOSUPP,
127 : N_("Failed to load API cache module %s", "file"),
128 : lib);
129 : return KRB5_CC_NOSUPP;
130 : }
131 :
132 : init_func = (cc_initialize_func)dlsym(cc_handle, "cc_initialize");
133 : set_target_uid = (void (KRB5_CALLCONV *)(uid_t))
134 : dlsym(cc_handle, "krb5_ipc_client_set_target_uid");
135 : clear_target = (void (KRB5_CALLCONV *)(void))
136 : dlsym(cc_handle, "krb5_ipc_client_clear_target");
137 : HEIMDAL_MUTEX_unlock(&acc_mutex);
138 : if (init_func == NULL) {
139 : krb5_set_error_message(context, KRB5_CC_NOSUPP,
140 : N_("Failed to find cc_initialize"
141 : "in %s: %s", "file, error"), lib, dlerror());
142 : dlclose(cc_handle);
143 : return KRB5_CC_NOSUPP;
144 : }
145 :
146 : return 0;
147 : #else
148 0 : HEIMDAL_MUTEX_unlock(&acc_mutex);
149 52 : krb5_set_error_message(context, KRB5_CC_NOSUPP,
150 52 : N_("no support for shared object", ""));
151 52 : return KRB5_CC_NOSUPP;
152 : #endif
153 : }
154 :
155 : KRB5_LIB_FUNCTION void KRB5_LIB_CALL
156 0 : _heim_krb5_ipc_client_set_target_uid(uid_t uid)
157 : {
158 0 : init_ccapi(NULL);
159 0 : if (set_target_uid != NULL)
160 0 : (*set_target_uid)(uid);
161 0 : }
162 :
163 : KRB5_LIB_FUNCTION void KRB5_LIB_CALL
164 0 : _heim_krb5_ipc_client_clear_target(void)
165 : {
166 0 : init_ccapi(NULL);
167 0 : if (clear_target != NULL)
168 0 : (*clear_target)();
169 0 : }
170 :
171 : static krb5_error_code
172 0 : make_cred_from_ccred(krb5_context context,
173 : const cc_credentials_v5_t *incred,
174 : krb5_creds *cred)
175 : {
176 0 : krb5_error_code ret;
177 0 : unsigned int i;
178 :
179 0 : memset(cred, 0, sizeof(*cred));
180 :
181 0 : ret = krb5_parse_name(context, incred->client, &cred->client);
182 0 : if (ret)
183 0 : goto fail;
184 :
185 0 : ret = krb5_parse_name(context, incred->server, &cred->server);
186 0 : if (ret)
187 0 : goto fail;
188 :
189 0 : cred->session.keytype = incred->keyblock.type;
190 0 : cred->session.keyvalue.length = incred->keyblock.length;
191 0 : cred->session.keyvalue.data = malloc(incred->keyblock.length);
192 0 : if (cred->session.keyvalue.data == NULL)
193 0 : goto nomem;
194 0 : memcpy(cred->session.keyvalue.data, incred->keyblock.data,
195 0 : incred->keyblock.length);
196 :
197 0 : cred->times.authtime = incred->authtime;
198 0 : cred->times.starttime = incred->starttime;
199 0 : cred->times.endtime = incred->endtime;
200 0 : cred->times.renew_till = incred->renew_till;
201 :
202 0 : ret = krb5_data_copy(&cred->ticket,
203 0 : incred->ticket.data,
204 0 : incred->ticket.length);
205 0 : if (ret)
206 0 : goto nomem;
207 :
208 0 : ret = krb5_data_copy(&cred->second_ticket,
209 0 : incred->second_ticket.data,
210 0 : incred->second_ticket.length);
211 0 : if (ret)
212 0 : goto nomem;
213 :
214 0 : cred->authdata.val = NULL;
215 0 : cred->authdata.len = 0;
216 :
217 0 : cred->addresses.val = NULL;
218 0 : cred->addresses.len = 0;
219 :
220 0 : for (i = 0; incred->authdata && incred->authdata[i]; i++)
221 : ;
222 :
223 0 : if (i) {
224 0 : cred->authdata.val = calloc(i, sizeof(cred->authdata.val[0]));
225 0 : if (cred->authdata.val == NULL)
226 0 : goto nomem;
227 0 : cred->authdata.len = i;
228 0 : for (i = 0; i < cred->authdata.len; i++) {
229 0 : cred->authdata.val[i].ad_type = incred->authdata[i]->type;
230 0 : ret = krb5_data_copy(&cred->authdata.val[i].ad_data,
231 0 : incred->authdata[i]->data,
232 0 : incred->authdata[i]->length);
233 0 : if (ret)
234 0 : goto nomem;
235 : }
236 : }
237 :
238 0 : for (i = 0; incred->addresses && incred->addresses[i]; i++)
239 : ;
240 :
241 0 : if (i) {
242 0 : cred->addresses.val = calloc(i, sizeof(cred->addresses.val[0]));
243 0 : if (cred->addresses.val == NULL)
244 0 : goto nomem;
245 0 : cred->addresses.len = i;
246 :
247 0 : for (i = 0; i < cred->addresses.len; i++) {
248 0 : cred->addresses.val[i].addr_type = incred->addresses[i]->type;
249 0 : ret = krb5_data_copy(&cred->addresses.val[i].address,
250 0 : incred->addresses[i]->data,
251 0 : incred->addresses[i]->length);
252 0 : if (ret)
253 0 : goto nomem;
254 : }
255 : }
256 :
257 0 : cred->flags.i = 0;
258 0 : if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_FORWARDABLE)
259 0 : cred->flags.b.forwardable = 1;
260 0 : if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_FORWARDED)
261 0 : cred->flags.b.forwarded = 1;
262 0 : if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_PROXIABLE)
263 0 : cred->flags.b.proxiable = 1;
264 0 : if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_PROXY)
265 0 : cred->flags.b.proxy = 1;
266 0 : if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_MAY_POSTDATE)
267 0 : cred->flags.b.may_postdate = 1;
268 0 : if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_POSTDATED)
269 0 : cred->flags.b.postdated = 1;
270 0 : if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_INVALID)
271 0 : cred->flags.b.invalid = 1;
272 0 : if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_RENEWABLE)
273 0 : cred->flags.b.renewable = 1;
274 0 : if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_INITIAL)
275 0 : cred->flags.b.initial = 1;
276 0 : if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_PRE_AUTH)
277 0 : cred->flags.b.pre_authent = 1;
278 0 : if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_HW_AUTH)
279 0 : cred->flags.b.hw_authent = 1;
280 0 : if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_TRANSIT_POLICY_CHECKED)
281 0 : cred->flags.b.transited_policy_checked = 1;
282 0 : if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_OK_AS_DELEGATE)
283 0 : cred->flags.b.ok_as_delegate = 1;
284 0 : if (incred->ticket_flags & KRB5_CCAPI_TKT_FLG_ANONYMOUS)
285 0 : cred->flags.b.anonymous = 1;
286 :
287 0 : return 0;
288 :
289 0 : nomem:
290 0 : ret = krb5_enomem(context);
291 :
292 0 : fail:
293 0 : krb5_free_cred_contents(context, cred);
294 0 : return ret;
295 : }
296 :
297 : static void
298 0 : free_ccred(cc_credentials_v5_t *cred)
299 : {
300 0 : int i;
301 :
302 0 : if (cred->addresses) {
303 0 : for (i = 0; cred->addresses[i] != 0; i++) {
304 0 : if (cred->addresses[i]->data)
305 0 : free(cred->addresses[i]->data);
306 0 : free(cred->addresses[i]);
307 : }
308 0 : free(cred->addresses);
309 : }
310 0 : if (cred->server)
311 0 : free(cred->server);
312 0 : if (cred->client)
313 0 : free(cred->client);
314 0 : memset(cred, 0, sizeof(*cred));
315 0 : }
316 :
317 : static krb5_error_code
318 0 : make_ccred_from_cred(krb5_context context,
319 : const krb5_creds *incred,
320 : cc_credentials_v5_t *cred)
321 : {
322 0 : krb5_error_code ret;
323 0 : size_t i;
324 :
325 0 : memset(cred, 0, sizeof(*cred));
326 :
327 0 : ret = krb5_unparse_name(context, incred->client, &cred->client);
328 0 : if (ret)
329 0 : goto fail;
330 :
331 0 : ret = krb5_unparse_name(context, incred->server, &cred->server);
332 0 : if (ret)
333 0 : goto fail;
334 :
335 0 : cred->keyblock.type = incred->session.keytype;
336 0 : cred->keyblock.length = incred->session.keyvalue.length;
337 0 : cred->keyblock.data = incred->session.keyvalue.data;
338 :
339 0 : cred->authtime = incred->times.authtime;
340 0 : cred->starttime = incred->times.starttime;
341 0 : cred->endtime = incred->times.endtime;
342 0 : cred->renew_till = incred->times.renew_till;
343 :
344 0 : cred->ticket.length = incred->ticket.length;
345 0 : cred->ticket.data = incred->ticket.data;
346 :
347 0 : cred->second_ticket.length = incred->second_ticket.length;
348 0 : cred->second_ticket.data = incred->second_ticket.data;
349 :
350 : /* XXX this one should also be filled in */
351 0 : cred->authdata = NULL;
352 :
353 0 : cred->addresses = calloc(incred->addresses.len + 1,
354 : sizeof(cred->addresses[0]));
355 0 : if (cred->addresses == NULL) {
356 :
357 0 : ret = ENOMEM;
358 0 : goto fail;
359 : }
360 :
361 0 : for (i = 0; i < incred->addresses.len; i++) {
362 0 : cc_data *addr;
363 0 : addr = malloc(sizeof(*addr));
364 0 : if (addr == NULL) {
365 0 : ret = ENOMEM;
366 0 : goto fail;
367 : }
368 0 : addr->type = incred->addresses.val[i].addr_type;
369 0 : addr->length = incred->addresses.val[i].address.length;
370 0 : addr->data = malloc(addr->length);
371 0 : if (addr->data == NULL) {
372 0 : free(addr);
373 0 : ret = ENOMEM;
374 0 : goto fail;
375 : }
376 0 : memcpy(addr->data, incred->addresses.val[i].address.data,
377 0 : addr->length);
378 0 : cred->addresses[i] = addr;
379 : }
380 0 : cred->addresses[i] = NULL;
381 :
382 0 : cred->ticket_flags = 0;
383 0 : if (incred->flags.b.forwardable)
384 0 : cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_FORWARDABLE;
385 0 : if (incred->flags.b.forwarded)
386 0 : cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_FORWARDED;
387 0 : if (incred->flags.b.proxiable)
388 0 : cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_PROXIABLE;
389 0 : if (incred->flags.b.proxy)
390 0 : cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_PROXY;
391 0 : if (incred->flags.b.may_postdate)
392 0 : cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_MAY_POSTDATE;
393 0 : if (incred->flags.b.postdated)
394 0 : cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_POSTDATED;
395 0 : if (incred->flags.b.invalid)
396 0 : cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_INVALID;
397 0 : if (incred->flags.b.renewable)
398 0 : cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_RENEWABLE;
399 0 : if (incred->flags.b.initial)
400 0 : cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_INITIAL;
401 0 : if (incred->flags.b.pre_authent)
402 0 : cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_PRE_AUTH;
403 0 : if (incred->flags.b.hw_authent)
404 0 : cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_HW_AUTH;
405 0 : if (incred->flags.b.transited_policy_checked)
406 0 : cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_TRANSIT_POLICY_CHECKED;
407 0 : if (incred->flags.b.ok_as_delegate)
408 0 : cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_OK_AS_DELEGATE;
409 0 : if (incred->flags.b.anonymous)
410 0 : cred->ticket_flags |= KRB5_CCAPI_TKT_FLG_ANONYMOUS;
411 :
412 0 : return 0;
413 :
414 0 : fail:
415 0 : free_ccred(cred);
416 :
417 0 : krb5_clear_error_message(context);
418 0 : return ret;
419 : }
420 :
421 : static cc_int32
422 0 : get_cc_name(krb5_acc *a)
423 : {
424 0 : cc_string_t name;
425 0 : cc_int32 error;
426 :
427 0 : error = (*a->ccache->func->get_name)(a->ccache, &name);
428 0 : if (error)
429 0 : return error;
430 :
431 0 : a->cache_name = strdup(name->data);
432 0 : (*name->func->release)(name);
433 0 : if (a->cache_name == NULL)
434 0 : return ccErrNoMem;
435 0 : return ccNoError;
436 : }
437 :
438 :
439 : static krb5_error_code KRB5_CALLCONV
440 0 : acc_get_name_2(krb5_context context,
441 : krb5_ccache id,
442 : const char **name,
443 : const char **colname,
444 : const char **subsidiary)
445 : {
446 0 : krb5_error_code ret = 0;
447 0 : krb5_acc *a = ACACHE(id);
448 0 : int32_t error;
449 :
450 0 : if (name)
451 0 : *name = NULL;
452 0 : if (colname)
453 0 : *colname = NULL;
454 0 : if (subsidiary)
455 0 : *subsidiary = NULL;
456 0 : if (a->cache_subsidiary == NULL) {
457 0 : krb5_principal principal = NULL;
458 :
459 0 : ret = _krb5_get_default_principal_local(context, &principal);
460 0 : if (ret == 0)
461 0 : ret = krb5_unparse_name(context, principal, &a->cache_subsidiary);
462 0 : krb5_free_principal(context, principal);
463 0 : if (ret)
464 0 : return ret;
465 : }
466 :
467 0 : if (a->cache_name == NULL) {
468 0 : error = (*a->context->func->create_new_ccache)(a->context,
469 : cc_credentials_v5,
470 0 : a->cache_subsidiary,
471 : &a->ccache);
472 0 : if (error == ccNoError)
473 0 : error = get_cc_name(a);
474 0 : if (error != ccNoError)
475 0 : ret = translate_cc_error(context, error);
476 : }
477 0 : if (name)
478 0 : *name = a->cache_name;
479 0 : if (colname)
480 0 : *colname = "";
481 0 : if (subsidiary)
482 0 : *subsidiary = a->cache_subsidiary;
483 0 : return ret;
484 : }
485 :
486 : static krb5_error_code KRB5_CALLCONV
487 0 : acc_alloc(krb5_context context, krb5_ccache *id)
488 : {
489 0 : krb5_error_code ret;
490 0 : cc_int32 error;
491 0 : krb5_acc *a;
492 :
493 0 : ret = init_ccapi(context);
494 0 : if (ret)
495 0 : return ret;
496 :
497 0 : ret = krb5_data_alloc(&(*id)->data, sizeof(*a));
498 0 : if (ret) {
499 0 : krb5_clear_error_message(context);
500 0 : return ret;
501 : }
502 :
503 0 : a = ACACHE(*id);
504 0 : a->cache_subsidiary = NULL;
505 0 : a->cache_name = NULL;
506 0 : a->context = NULL;
507 0 : a->ccache = NULL;
508 :
509 0 : error = (*init_func)(&a->context, ccapi_version_3, NULL, NULL);
510 0 : if (error) {
511 0 : krb5_data_free(&(*id)->data);
512 0 : return translate_cc_error(context, error);
513 : }
514 :
515 0 : return 0;
516 : }
517 :
518 : static krb5_error_code KRB5_CALLCONV
519 0 : acc_resolve_2(krb5_context context, krb5_ccache *id, const char *res, const char *sub)
520 : {
521 0 : krb5_error_code ret;
522 0 : cc_time_t offset;
523 0 : cc_int32 error;
524 0 : krb5_acc *a;
525 0 : char *s = NULL;
526 :
527 0 : ret = acc_alloc(context, id);
528 0 : if (ret)
529 0 : return ret;
530 :
531 0 : a = ACACHE(*id);
532 :
533 0 : if (sub) {
534 : /*
535 : * For API there's no such thing as a collection name, there's only the
536 : * default collection. Though we could perhaps put a CCAPI shared
537 : * object path in the collection name.
538 : *
539 : * So we'll treat (res && !sub) and (!res && sub) as the same cases.
540 : *
541 : * See also the KCM ccache type, where we have similar considerations.
542 : */
543 0 : if (asprintf(&s, "%s%s%s", res && *res ? res : "",
544 0 : res && *res ? ":" : "", sub) == -1 || s == NULL ||
545 0 : (a->cache_subsidiary = strdup(sub)) == NULL) {
546 0 : acc_close(context, *id);
547 0 : free(s);
548 0 : return krb5_enomem(context);
549 : }
550 0 : res = s;
551 : /*
552 : * XXX With a bit of extra refactoring we could use the collection name
553 : * as the path to the shared object implementing CCAPI... For now we
554 : * ignore the collection name.
555 : */
556 : }
557 :
558 0 : error = (*a->context->func->open_ccache)(a->context, res, &a->ccache);
559 0 : if (error == ccErrCCacheNotFound) {
560 0 : a->ccache = NULL;
561 0 : a->cache_name = NULL;
562 0 : free(s);
563 0 : return 0;
564 : }
565 0 : if (error == ccNoError)
566 0 : error = get_cc_name(a);
567 0 : if (error != ccNoError) {
568 0 : acc_close(context, *id);
569 0 : *id = NULL;
570 0 : free(s);
571 0 : return translate_cc_error(context, error);
572 : }
573 :
574 0 : error = (*a->ccache->func->get_kdc_time_offset)(a->ccache,
575 : cc_credentials_v5,
576 : &offset);
577 0 : if (error == 0)
578 0 : context->kdc_sec_offset = offset;
579 0 : free(s);
580 0 : return 0;
581 : }
582 :
583 : static krb5_error_code KRB5_CALLCONV
584 0 : acc_gen_new(krb5_context context, krb5_ccache *id)
585 : {
586 0 : return acc_alloc(context, id);
587 : }
588 :
589 : static krb5_error_code KRB5_CALLCONV
590 0 : acc_initialize(krb5_context context,
591 : krb5_ccache id,
592 : krb5_principal primary_principal)
593 : {
594 0 : krb5_acc *a = ACACHE(id);
595 0 : krb5_error_code ret;
596 0 : int32_t error;
597 0 : char *name;
598 :
599 0 : ret = krb5_unparse_name(context, primary_principal, &name);
600 0 : if (ret)
601 0 : return ret;
602 :
603 0 : if (a->cache_name == NULL) {
604 0 : error = (*a->context->func->create_new_ccache)(a->context,
605 : cc_credentials_v5,
606 : name,
607 : &a->ccache);
608 0 : free(name);
609 0 : if (error == ccNoError)
610 0 : error = get_cc_name(a);
611 : } else {
612 0 : cc_credentials_iterator_t iter;
613 0 : cc_credentials_t ccred;
614 :
615 0 : error = (*a->ccache->func->new_credentials_iterator)(a->ccache, &iter);
616 0 : if (error) {
617 0 : free(name);
618 0 : return translate_cc_error(context, error);
619 : }
620 :
621 0 : while (1) {
622 0 : error = (*iter->func->next)(iter, &ccred);
623 0 : if (error)
624 0 : break;
625 0 : (*a->ccache->func->remove_credentials)(a->ccache, ccred);
626 0 : (*ccred->func->release)(ccred);
627 : }
628 0 : (*iter->func->release)(iter);
629 :
630 0 : error = (*a->ccache->func->set_principal)(a->ccache,
631 : cc_credentials_v5,
632 : name);
633 : }
634 :
635 0 : if (error == 0 && context->kdc_sec_offset)
636 0 : error = (*a->ccache->func->set_kdc_time_offset)(a->ccache,
637 : cc_credentials_v5,
638 0 : context->kdc_sec_offset);
639 :
640 0 : return translate_cc_error(context, error);
641 : }
642 :
643 : static krb5_error_code KRB5_CALLCONV
644 0 : acc_close(krb5_context context,
645 : krb5_ccache id)
646 : {
647 0 : krb5_acc *a = ACACHE(id);
648 :
649 0 : if (a->ccache) {
650 0 : (*a->ccache->func->release)(a->ccache);
651 0 : a->ccache = NULL;
652 : }
653 0 : if (a->cache_name) {
654 0 : free(a->cache_name);
655 0 : a->cache_name = NULL;
656 : }
657 0 : if (a->context) {
658 0 : (*a->context->func->release)(a->context);
659 0 : a->context = NULL;
660 : }
661 0 : krb5_data_free(&id->data);
662 0 : return 0;
663 : }
664 :
665 : static krb5_error_code KRB5_CALLCONV
666 0 : acc_destroy(krb5_context context,
667 : krb5_ccache id)
668 : {
669 0 : krb5_acc *a = ACACHE(id);
670 0 : cc_int32 error = 0;
671 :
672 0 : if (a->ccache) {
673 0 : error = (*a->ccache->func->destroy)(a->ccache);
674 0 : a->ccache = NULL;
675 : }
676 0 : if (a->context) {
677 0 : error = (a->context->func->release)(a->context);
678 0 : a->context = NULL;
679 : }
680 0 : return translate_cc_error(context, error);
681 : }
682 :
683 : static krb5_error_code KRB5_CALLCONV
684 0 : acc_store_cred(krb5_context context,
685 : krb5_ccache id,
686 : krb5_creds *creds)
687 : {
688 0 : krb5_acc *a = ACACHE(id);
689 0 : cc_credentials_union cred;
690 0 : cc_credentials_v5_t v5cred;
691 0 : krb5_error_code ret;
692 0 : cc_int32 error;
693 :
694 0 : if (a->ccache == NULL) {
695 0 : krb5_set_error_message(context, KRB5_CC_NOTFOUND,
696 0 : N_("No API credential found", ""));
697 0 : return KRB5_CC_NOTFOUND;
698 : }
699 :
700 0 : cred.version = cc_credentials_v5;
701 0 : cred.credentials.credentials_v5 = &v5cred;
702 :
703 0 : ret = make_ccred_from_cred(context,
704 : creds,
705 : &v5cred);
706 0 : if (ret)
707 0 : return ret;
708 :
709 0 : error = (*a->ccache->func->store_credentials)(a->ccache, &cred);
710 0 : if (error)
711 0 : ret = translate_cc_error(context, error);
712 :
713 0 : free_ccred(&v5cred);
714 :
715 0 : return ret;
716 : }
717 :
718 : static krb5_error_code KRB5_CALLCONV
719 0 : acc_get_principal(krb5_context context,
720 : krb5_ccache id,
721 : krb5_principal *principal)
722 : {
723 0 : krb5_acc *a = ACACHE(id);
724 0 : krb5_error_code ret;
725 0 : int32_t error;
726 0 : cc_string_t name;
727 :
728 0 : if (a->ccache == NULL) {
729 0 : krb5_set_error_message(context, KRB5_CC_NOTFOUND,
730 0 : N_("No API credential found", ""));
731 0 : return KRB5_CC_NOTFOUND;
732 : }
733 :
734 0 : error = (*a->ccache->func->get_principal)(a->ccache,
735 : cc_credentials_v5,
736 : &name);
737 0 : if (error)
738 0 : return translate_cc_error(context, error);
739 :
740 0 : ret = krb5_parse_name(context, name->data, principal);
741 :
742 0 : (*name->func->release)(name);
743 0 : return ret;
744 : }
745 :
746 : static krb5_error_code KRB5_CALLCONV
747 0 : acc_get_first (krb5_context context,
748 : krb5_ccache id,
749 : krb5_cc_cursor *cursor)
750 : {
751 0 : cc_credentials_iterator_t iter;
752 0 : krb5_acc *a = ACACHE(id);
753 0 : int32_t error;
754 :
755 0 : if (a->ccache == NULL) {
756 0 : krb5_set_error_message(context, KRB5_CC_NOTFOUND,
757 0 : N_("No API credential found", ""));
758 0 : return KRB5_CC_NOTFOUND;
759 : }
760 :
761 0 : error = (*a->ccache->func->new_credentials_iterator)(a->ccache, &iter);
762 0 : if (error) {
763 0 : krb5_clear_error_message(context);
764 0 : return ENOENT;
765 : }
766 0 : *cursor = iter;
767 0 : return 0;
768 : }
769 :
770 :
771 : static krb5_error_code KRB5_CALLCONV
772 0 : acc_get_next (krb5_context context,
773 : krb5_ccache id,
774 : krb5_cc_cursor *cursor,
775 : krb5_creds *creds)
776 : {
777 0 : cc_credentials_iterator_t iter = *cursor;
778 0 : cc_credentials_t cred;
779 0 : krb5_error_code ret;
780 0 : int32_t error;
781 :
782 0 : while (1) {
783 0 : error = (*iter->func->next)(iter, &cred);
784 0 : if (error)
785 0 : return translate_cc_error(context, error);
786 0 : if (cred->data->version == cc_credentials_v5)
787 0 : break;
788 0 : (*cred->func->release)(cred);
789 : }
790 :
791 0 : ret = make_cred_from_ccred(context,
792 0 : cred->data->credentials.credentials_v5,
793 : creds);
794 0 : (*cred->func->release)(cred);
795 0 : return ret;
796 : }
797 :
798 : static krb5_error_code KRB5_CALLCONV
799 0 : acc_end_get (krb5_context context,
800 : krb5_ccache id,
801 : krb5_cc_cursor *cursor)
802 : {
803 0 : cc_credentials_iterator_t iter = *cursor;
804 0 : (*iter->func->release)(iter);
805 0 : return 0;
806 : }
807 :
808 : static krb5_error_code KRB5_CALLCONV
809 0 : acc_remove_cred(krb5_context context,
810 : krb5_ccache id,
811 : krb5_flags which,
812 : krb5_creds *cred)
813 : {
814 0 : cc_credentials_iterator_t iter;
815 0 : krb5_acc *a = ACACHE(id);
816 0 : cc_credentials_t ccred;
817 0 : krb5_error_code ret;
818 0 : cc_int32 error;
819 0 : char *client, *server;
820 :
821 0 : if (a->ccache == NULL) {
822 0 : krb5_set_error_message(context, KRB5_CC_NOTFOUND,
823 0 : N_("No API credential found", ""));
824 0 : return KRB5_CC_NOTFOUND;
825 : }
826 :
827 0 : if (cred->client) {
828 0 : ret = krb5_unparse_name(context, cred->client, &client);
829 0 : if (ret)
830 0 : return ret;
831 : } else
832 0 : client = NULL;
833 :
834 0 : ret = krb5_unparse_name(context, cred->server, &server);
835 0 : if (ret) {
836 0 : free(client);
837 0 : return ret;
838 : }
839 :
840 0 : error = (*a->ccache->func->new_credentials_iterator)(a->ccache, &iter);
841 0 : if (error) {
842 0 : free(server);
843 0 : free(client);
844 0 : return translate_cc_error(context, error);
845 : }
846 :
847 0 : ret = KRB5_CC_NOTFOUND;
848 0 : while (1) {
849 0 : cc_credentials_v5_t *v5cred;
850 :
851 0 : error = (*iter->func->next)(iter, &ccred);
852 0 : if (error)
853 0 : break;
854 :
855 0 : if (ccred->data->version != cc_credentials_v5)
856 0 : goto next;
857 :
858 0 : v5cred = ccred->data->credentials.credentials_v5;
859 :
860 0 : if (client && strcmp(v5cred->client, client) != 0)
861 0 : goto next;
862 :
863 0 : if (strcmp(v5cred->server, server) != 0)
864 0 : goto next;
865 :
866 0 : (*a->ccache->func->remove_credentials)(a->ccache, ccred);
867 0 : ret = 0;
868 0 : next:
869 0 : (*ccred->func->release)(ccred);
870 : }
871 :
872 0 : (*iter->func->release)(iter);
873 :
874 0 : if (ret)
875 0 : krb5_set_error_message(context, ret,
876 0 : N_("Can't find credential %s in cache",
877 : "principal"), server);
878 0 : free(server);
879 0 : free(client);
880 :
881 0 : return ret;
882 : }
883 :
884 : static krb5_error_code KRB5_CALLCONV
885 0 : acc_set_flags(krb5_context context,
886 : krb5_ccache id,
887 : krb5_flags flags)
888 : {
889 0 : return 0;
890 : }
891 :
892 : static int KRB5_CALLCONV
893 0 : acc_get_version(krb5_context context,
894 : krb5_ccache id)
895 : {
896 0 : return 0;
897 : }
898 :
899 : struct cache_iter {
900 : cc_context_t context;
901 : cc_ccache_iterator_t iter;
902 : };
903 :
904 : static krb5_error_code KRB5_CALLCONV
905 52 : acc_get_cache_first(krb5_context context, krb5_cc_cursor *cursor)
906 : {
907 0 : struct cache_iter *iter;
908 0 : krb5_error_code ret;
909 0 : cc_int32 error;
910 :
911 52 : ret = init_ccapi(context);
912 52 : if (ret)
913 52 : return ret;
914 :
915 0 : iter = calloc(1, sizeof(*iter));
916 0 : if (iter == NULL)
917 0 : return krb5_enomem(context);
918 :
919 0 : error = (*init_func)(&iter->context, ccapi_version_3, NULL, NULL);
920 0 : if (error) {
921 0 : free(iter);
922 0 : return translate_cc_error(context, error);
923 : }
924 :
925 0 : error = (*iter->context->func->new_ccache_iterator)(iter->context,
926 : &iter->iter);
927 0 : if (error) {
928 0 : free(iter);
929 0 : krb5_clear_error_message(context);
930 0 : return ENOENT;
931 : }
932 0 : *cursor = iter;
933 0 : return 0;
934 : }
935 :
936 : static krb5_error_code KRB5_CALLCONV
937 0 : acc_get_cache_next(krb5_context context, krb5_cc_cursor cursor, krb5_ccache *id)
938 : {
939 0 : struct cache_iter *iter = cursor;
940 0 : cc_ccache_t cache;
941 0 : krb5_acc *a;
942 0 : krb5_error_code ret;
943 0 : int32_t error;
944 :
945 0 : error = (*iter->iter->func->next)(iter->iter, &cache);
946 0 : if (error)
947 0 : return translate_cc_error(context, error);
948 :
949 0 : ret = _krb5_cc_allocate(context, &krb5_acc_ops, id);
950 0 : if (ret) {
951 0 : (*cache->func->release)(cache);
952 0 : return ret;
953 : }
954 :
955 0 : ret = acc_alloc(context, id);
956 0 : if (ret) {
957 0 : (*cache->func->release)(cache);
958 0 : free(*id);
959 0 : return ret;
960 : }
961 :
962 0 : a = ACACHE(*id);
963 0 : a->ccache = cache;
964 :
965 0 : error = get_cc_name(a);
966 0 : if (error) {
967 0 : acc_close(context, *id);
968 0 : *id = NULL;
969 0 : return translate_cc_error(context, error);
970 : }
971 0 : return 0;
972 : }
973 :
974 : static krb5_error_code KRB5_CALLCONV
975 0 : acc_end_cache_get(krb5_context context, krb5_cc_cursor cursor)
976 : {
977 0 : struct cache_iter *iter = cursor;
978 :
979 0 : (*iter->iter->func->release)(iter->iter);
980 0 : iter->iter = NULL;
981 0 : (*iter->context->func->release)(iter->context);
982 0 : iter->context = NULL;
983 0 : free(iter);
984 0 : return 0;
985 : }
986 :
987 : static krb5_error_code KRB5_CALLCONV
988 0 : acc_move(krb5_context context, krb5_ccache from, krb5_ccache to)
989 : {
990 0 : krb5_error_code ret;
991 0 : krb5_acc *afrom = ACACHE(from);
992 0 : krb5_acc *ato = ACACHE(to);
993 0 : int32_t error;
994 :
995 0 : if (ato->ccache == NULL) {
996 0 : cc_string_t name;
997 :
998 0 : error = (*afrom->ccache->func->get_principal)(afrom->ccache,
999 : cc_credentials_v5,
1000 : &name);
1001 0 : if (error)
1002 0 : return translate_cc_error(context, error);
1003 :
1004 0 : error = (*ato->context->func->create_new_ccache)(ato->context,
1005 : cc_credentials_v5,
1006 0 : name->data,
1007 : &ato->ccache);
1008 0 : (*name->func->release)(name);
1009 0 : if (error)
1010 0 : return translate_cc_error(context, error);
1011 : }
1012 :
1013 0 : error = (*ato->ccache->func->move)(afrom->ccache, ato->ccache);
1014 0 : ret = translate_cc_error(context, error);
1015 0 : if (ret == 0)
1016 0 : krb5_cc_destroy(context, from);
1017 0 : return ret;
1018 : }
1019 :
1020 : static krb5_error_code KRB5_CALLCONV
1021 0 : acc_get_default_name(krb5_context context, char **str)
1022 : {
1023 0 : krb5_error_code ret;
1024 0 : cc_context_t cc;
1025 0 : cc_string_t name;
1026 0 : int32_t error;
1027 :
1028 0 : ret = init_ccapi(context);
1029 0 : if (ret)
1030 0 : return ret;
1031 :
1032 0 : error = (*init_func)(&cc, ccapi_version_3, NULL, NULL);
1033 0 : if (error)
1034 0 : return translate_cc_error(context, error);
1035 :
1036 0 : error = (*cc->func->get_default_ccache_name)(cc, &name);
1037 0 : if (error) {
1038 0 : (*cc->func->release)(cc);
1039 0 : return translate_cc_error(context, error);
1040 : }
1041 :
1042 0 : error = asprintf(str, "API:%s", name->data);
1043 0 : (*name->func->release)(name);
1044 0 : (*cc->func->release)(cc);
1045 :
1046 0 : if (error < 0 || *str == NULL)
1047 0 : return krb5_enomem(context);
1048 0 : return 0;
1049 : }
1050 :
1051 : static krb5_error_code KRB5_CALLCONV
1052 0 : acc_set_default(krb5_context context, krb5_ccache id)
1053 : {
1054 0 : krb5_acc *a = ACACHE(id);
1055 0 : cc_int32 error;
1056 :
1057 0 : if (a->ccache == NULL) {
1058 0 : krb5_set_error_message(context, KRB5_CC_NOTFOUND,
1059 0 : N_("No API credential found", ""));
1060 0 : return KRB5_CC_NOTFOUND;
1061 : }
1062 :
1063 0 : error = (*a->ccache->func->set_default)(a->ccache);
1064 0 : if (error)
1065 0 : return translate_cc_error(context, error);
1066 :
1067 0 : return 0;
1068 : }
1069 :
1070 : static krb5_error_code KRB5_CALLCONV
1071 0 : acc_lastchange(krb5_context context, krb5_ccache id, krb5_timestamp *mtime)
1072 : {
1073 0 : krb5_acc *a = ACACHE(id);
1074 0 : cc_int32 error;
1075 0 : cc_time_t t;
1076 :
1077 0 : if (a->ccache == NULL) {
1078 0 : krb5_set_error_message(context, KRB5_CC_NOTFOUND,
1079 0 : N_("No API credential found", ""));
1080 0 : return KRB5_CC_NOTFOUND;
1081 : }
1082 :
1083 0 : error = (*a->ccache->func->get_change_time)(a->ccache, &t);
1084 0 : if (error)
1085 0 : return translate_cc_error(context, error);
1086 :
1087 0 : *mtime = t;
1088 :
1089 0 : return 0;
1090 : }
1091 :
1092 : /**
1093 : * Variable containing the API based credential cache implemention.
1094 : *
1095 : * @ingroup krb5_ccache
1096 : */
1097 :
1098 : KRB5_LIB_VARIABLE const krb5_cc_ops krb5_acc_ops = {
1099 : KRB5_CC_OPS_VERSION_5,
1100 : "API",
1101 : NULL,
1102 : NULL,
1103 : acc_gen_new,
1104 : acc_initialize,
1105 : acc_destroy,
1106 : acc_close,
1107 : acc_store_cred,
1108 : NULL, /* acc_retrieve */
1109 : acc_get_principal,
1110 : acc_get_first,
1111 : acc_get_next,
1112 : acc_end_get,
1113 : acc_remove_cred,
1114 : acc_set_flags,
1115 : acc_get_version,
1116 : acc_get_cache_first,
1117 : acc_get_cache_next,
1118 : acc_end_cache_get,
1119 : acc_move,
1120 : acc_get_default_name,
1121 : acc_set_default,
1122 : acc_lastchange,
1123 : NULL,
1124 : NULL,
1125 : acc_get_name_2,
1126 : acc_resolve_2
1127 : };
1128 :
1129 : #endif
|