2 * Copyright (c) 2004 - 2007 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
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.
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.
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
36 #include "krb5_locl.h"
37 #include <krb5_ccapi.h>
39 #ifndef KCM_IS_API_CACHE
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);
47 static void *cc_handle
;
50 typedef struct krb5_acc
{
52 char *cache_subsidiary
;
57 static krb5_error_code KRB5_CALLCONV
acc_close(krb5_context
, krb5_ccache
);
59 #define ACACHE(X) ((krb5_acc *)(X)->data.data)
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
},
76 static krb5_error_code
77 translate_cc_error(krb5_context context
, cc_int32 error
)
80 krb5_clear_error_message(context
);
81 for(i
= 0; i
< sizeof(cc_errors
)/sizeof(cc_errors
[0]); i
++)
82 if (cc_errors
[i
].error
== error
)
83 return cc_errors
[i
].ret
;
84 return KRB5_FCC_INTERNAL
;
87 static krb5_error_code
88 init_ccapi(krb5_context context
)
90 const char *lib
= NULL
;
95 HEIMDAL_MUTEX_lock(&acc_mutex
);
97 HEIMDAL_MUTEX_unlock(&acc_mutex
);
99 krb5_clear_error_message(context
);
104 lib
= krb5_config_get_string(context
, NULL
,
105 "libdefaults", "ccapi_library",
109 lib
= "/System/Library/Frameworks/Kerberos.framework/Kerberos";
110 #elif defined(_WIN32)
111 lib
= "%{LIBDIR}/libkrb5_cc.dll";
113 lib
= "%{LIBDIR}/libkrb5_cc.so";
119 if (_krb5_expand_path_tokens(context
, lib
, 0, &explib
) == 0) {
120 cc_handle
= dlopen(explib
, RTLD_LAZY
|RTLD_LOCAL
|RTLD_GROUP
);
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"),
129 return KRB5_CC_NOSUPP
;
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());
143 return KRB5_CC_NOSUPP
;
148 HEIMDAL_MUTEX_unlock(&acc_mutex
);
149 krb5_set_error_message(context
, KRB5_CC_NOSUPP
,
150 N_("no support for shared object", ""));
151 return KRB5_CC_NOSUPP
;
155 KRB5_LIB_FUNCTION
void KRB5_LIB_CALL
156 _heim_krb5_ipc_client_set_target_uid(uid_t uid
)
159 if (set_target_uid
!= NULL
)
160 (*set_target_uid
)(uid
);
163 KRB5_LIB_FUNCTION
void KRB5_LIB_CALL
164 _heim_krb5_ipc_client_clear_target(void)
167 if (clear_target
!= NULL
)
171 static krb5_error_code
172 make_cred_from_ccred(krb5_context context
,
173 const cc_credentials_v5_t
*incred
,
179 memset(cred
, 0, sizeof(*cred
));
181 ret
= krb5_parse_name(context
, incred
->client
, &cred
->client
);
185 ret
= krb5_parse_name(context
, incred
->server
, &cred
->server
);
189 cred
->session
.keytype
= incred
->keyblock
.type
;
190 cred
->session
.keyvalue
.length
= incred
->keyblock
.length
;
191 cred
->session
.keyvalue
.data
= malloc(incred
->keyblock
.length
);
192 if (cred
->session
.keyvalue
.data
== NULL
)
194 memcpy(cred
->session
.keyvalue
.data
, incred
->keyblock
.data
,
195 incred
->keyblock
.length
);
197 cred
->times
.authtime
= incred
->authtime
;
198 cred
->times
.starttime
= incred
->starttime
;
199 cred
->times
.endtime
= incred
->endtime
;
200 cred
->times
.renew_till
= incred
->renew_till
;
202 ret
= krb5_data_copy(&cred
->ticket
,
204 incred
->ticket
.length
);
208 ret
= krb5_data_copy(&cred
->second_ticket
,
209 incred
->second_ticket
.data
,
210 incred
->second_ticket
.length
);
214 cred
->authdata
.val
= NULL
;
215 cred
->authdata
.len
= 0;
217 cred
->addresses
.val
= NULL
;
218 cred
->addresses
.len
= 0;
220 for (i
= 0; incred
->authdata
&& incred
->authdata
[i
]; i
++)
224 cred
->authdata
.val
= calloc(i
, sizeof(cred
->authdata
.val
[0]));
225 if (cred
->authdata
.val
== NULL
)
227 cred
->authdata
.len
= i
;
228 for (i
= 0; i
< cred
->authdata
.len
; i
++) {
229 cred
->authdata
.val
[i
].ad_type
= incred
->authdata
[i
]->type
;
230 ret
= krb5_data_copy(&cred
->authdata
.val
[i
].ad_data
,
231 incred
->authdata
[i
]->data
,
232 incred
->authdata
[i
]->length
);
238 for (i
= 0; incred
->addresses
&& incred
->addresses
[i
]; i
++)
242 cred
->addresses
.val
= calloc(i
, sizeof(cred
->addresses
.val
[0]));
243 if (cred
->addresses
.val
== NULL
)
245 cred
->addresses
.len
= i
;
247 for (i
= 0; i
< cred
->addresses
.len
; i
++) {
248 cred
->addresses
.val
[i
].addr_type
= incred
->addresses
[i
]->type
;
249 ret
= krb5_data_copy(&cred
->addresses
.val
[i
].address
,
250 incred
->addresses
[i
]->data
,
251 incred
->addresses
[i
]->length
);
258 if (incred
->ticket_flags
& KRB5_CCAPI_TKT_FLG_FORWARDABLE
)
259 cred
->flags
.b
.forwardable
= 1;
260 if (incred
->ticket_flags
& KRB5_CCAPI_TKT_FLG_FORWARDED
)
261 cred
->flags
.b
.forwarded
= 1;
262 if (incred
->ticket_flags
& KRB5_CCAPI_TKT_FLG_PROXIABLE
)
263 cred
->flags
.b
.proxiable
= 1;
264 if (incred
->ticket_flags
& KRB5_CCAPI_TKT_FLG_PROXY
)
265 cred
->flags
.b
.proxy
= 1;
266 if (incred
->ticket_flags
& KRB5_CCAPI_TKT_FLG_MAY_POSTDATE
)
267 cred
->flags
.b
.may_postdate
= 1;
268 if (incred
->ticket_flags
& KRB5_CCAPI_TKT_FLG_POSTDATED
)
269 cred
->flags
.b
.postdated
= 1;
270 if (incred
->ticket_flags
& KRB5_CCAPI_TKT_FLG_INVALID
)
271 cred
->flags
.b
.invalid
= 1;
272 if (incred
->ticket_flags
& KRB5_CCAPI_TKT_FLG_RENEWABLE
)
273 cred
->flags
.b
.renewable
= 1;
274 if (incred
->ticket_flags
& KRB5_CCAPI_TKT_FLG_INITIAL
)
275 cred
->flags
.b
.initial
= 1;
276 if (incred
->ticket_flags
& KRB5_CCAPI_TKT_FLG_PRE_AUTH
)
277 cred
->flags
.b
.pre_authent
= 1;
278 if (incred
->ticket_flags
& KRB5_CCAPI_TKT_FLG_HW_AUTH
)
279 cred
->flags
.b
.hw_authent
= 1;
280 if (incred
->ticket_flags
& KRB5_CCAPI_TKT_FLG_TRANSIT_POLICY_CHECKED
)
281 cred
->flags
.b
.transited_policy_checked
= 1;
282 if (incred
->ticket_flags
& KRB5_CCAPI_TKT_FLG_OK_AS_DELEGATE
)
283 cred
->flags
.b
.ok_as_delegate
= 1;
284 if (incred
->ticket_flags
& KRB5_CCAPI_TKT_FLG_ANONYMOUS
)
285 cred
->flags
.b
.anonymous
= 1;
290 ret
= krb5_enomem(context
);
293 krb5_free_cred_contents(context
, cred
);
298 free_ccred(cc_credentials_v5_t
*cred
)
302 if (cred
->addresses
) {
303 for (i
= 0; cred
->addresses
[i
] != 0; i
++) {
304 if (cred
->addresses
[i
]->data
)
305 free(cred
->addresses
[i
]->data
);
306 free(cred
->addresses
[i
]);
308 free(cred
->addresses
);
314 memset(cred
, 0, sizeof(*cred
));
317 static krb5_error_code
318 make_ccred_from_cred(krb5_context context
,
319 const krb5_creds
*incred
,
320 cc_credentials_v5_t
*cred
)
325 memset(cred
, 0, sizeof(*cred
));
327 ret
= krb5_unparse_name(context
, incred
->client
, &cred
->client
);
331 ret
= krb5_unparse_name(context
, incred
->server
, &cred
->server
);
335 cred
->keyblock
.type
= incred
->session
.keytype
;
336 cred
->keyblock
.length
= incred
->session
.keyvalue
.length
;
337 cred
->keyblock
.data
= incred
->session
.keyvalue
.data
;
339 cred
->authtime
= incred
->times
.authtime
;
340 cred
->starttime
= incred
->times
.starttime
;
341 cred
->endtime
= incred
->times
.endtime
;
342 cred
->renew_till
= incred
->times
.renew_till
;
344 cred
->ticket
.length
= incred
->ticket
.length
;
345 cred
->ticket
.data
= incred
->ticket
.data
;
347 cred
->second_ticket
.length
= incred
->second_ticket
.length
;
348 cred
->second_ticket
.data
= incred
->second_ticket
.data
;
350 /* XXX this one should also be filled in */
351 cred
->authdata
= NULL
;
353 cred
->addresses
= calloc(incred
->addresses
.len
+ 1,
354 sizeof(cred
->addresses
[0]));
355 if (cred
->addresses
== NULL
) {
361 for (i
= 0; i
< incred
->addresses
.len
; i
++) {
363 addr
= malloc(sizeof(*addr
));
368 addr
->type
= incred
->addresses
.val
[i
].addr_type
;
369 addr
->length
= incred
->addresses
.val
[i
].address
.length
;
370 addr
->data
= malloc(addr
->length
);
371 if (addr
->data
== NULL
) {
376 memcpy(addr
->data
, incred
->addresses
.val
[i
].address
.data
,
378 cred
->addresses
[i
] = addr
;
380 cred
->addresses
[i
] = NULL
;
382 cred
->ticket_flags
= 0;
383 if (incred
->flags
.b
.forwardable
)
384 cred
->ticket_flags
|= KRB5_CCAPI_TKT_FLG_FORWARDABLE
;
385 if (incred
->flags
.b
.forwarded
)
386 cred
->ticket_flags
|= KRB5_CCAPI_TKT_FLG_FORWARDED
;
387 if (incred
->flags
.b
.proxiable
)
388 cred
->ticket_flags
|= KRB5_CCAPI_TKT_FLG_PROXIABLE
;
389 if (incred
->flags
.b
.proxy
)
390 cred
->ticket_flags
|= KRB5_CCAPI_TKT_FLG_PROXY
;
391 if (incred
->flags
.b
.may_postdate
)
392 cred
->ticket_flags
|= KRB5_CCAPI_TKT_FLG_MAY_POSTDATE
;
393 if (incred
->flags
.b
.postdated
)
394 cred
->ticket_flags
|= KRB5_CCAPI_TKT_FLG_POSTDATED
;
395 if (incred
->flags
.b
.invalid
)
396 cred
->ticket_flags
|= KRB5_CCAPI_TKT_FLG_INVALID
;
397 if (incred
->flags
.b
.renewable
)
398 cred
->ticket_flags
|= KRB5_CCAPI_TKT_FLG_RENEWABLE
;
399 if (incred
->flags
.b
.initial
)
400 cred
->ticket_flags
|= KRB5_CCAPI_TKT_FLG_INITIAL
;
401 if (incred
->flags
.b
.pre_authent
)
402 cred
->ticket_flags
|= KRB5_CCAPI_TKT_FLG_PRE_AUTH
;
403 if (incred
->flags
.b
.hw_authent
)
404 cred
->ticket_flags
|= KRB5_CCAPI_TKT_FLG_HW_AUTH
;
405 if (incred
->flags
.b
.transited_policy_checked
)
406 cred
->ticket_flags
|= KRB5_CCAPI_TKT_FLG_TRANSIT_POLICY_CHECKED
;
407 if (incred
->flags
.b
.ok_as_delegate
)
408 cred
->ticket_flags
|= KRB5_CCAPI_TKT_FLG_OK_AS_DELEGATE
;
409 if (incred
->flags
.b
.anonymous
)
410 cred
->ticket_flags
|= KRB5_CCAPI_TKT_FLG_ANONYMOUS
;
417 krb5_clear_error_message(context
);
422 get_cc_name(krb5_acc
*a
)
427 error
= (*a
->ccache
->func
->get_name
)(a
->ccache
, &name
);
431 a
->cache_name
= strdup(name
->data
);
432 (*name
->func
->release
)(name
);
433 if (a
->cache_name
== NULL
)
439 static krb5_error_code KRB5_CALLCONV
440 acc_get_name_2(krb5_context context
,
443 const char **colname
,
444 const char **subsidiary
)
446 krb5_error_code ret
= 0;
447 krb5_acc
*a
= ACACHE(id
);
456 if (a
->cache_subsidiary
== NULL
) {
457 krb5_principal principal
= NULL
;
459 ret
= _krb5_get_default_principal_local(context
, &principal
);
461 ret
= krb5_unparse_name(context
, principal
, &a
->cache_subsidiary
);
462 krb5_free_principal(context
, principal
);
467 if (a
->cache_name
== NULL
) {
468 error
= (*a
->context
->func
->create_new_ccache
)(a
->context
,
472 if (error
== ccNoError
)
473 error
= get_cc_name(a
);
474 if (error
!= ccNoError
)
475 ret
= translate_cc_error(context
, error
);
478 *name
= a
->cache_name
;
482 *subsidiary
= a
->cache_subsidiary
;
486 static krb5_error_code KRB5_CALLCONV
487 acc_alloc(krb5_context context
, krb5_ccache
*id
)
493 ret
= init_ccapi(context
);
497 ret
= krb5_data_alloc(&(*id
)->data
, sizeof(*a
));
499 krb5_clear_error_message(context
);
504 a
->cache_subsidiary
= NULL
;
505 a
->cache_name
= NULL
;
509 error
= (*init_func
)(&a
->context
, ccapi_version_3
, NULL
, NULL
);
511 krb5_data_free(&(*id
)->data
);
512 return translate_cc_error(context
, error
);
518 static krb5_error_code KRB5_CALLCONV
519 acc_resolve_2(krb5_context context
, krb5_ccache
*id
, const char *res
, const char *sub
)
527 ret
= acc_alloc(context
, id
);
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.
539 * So we'll treat (res && !sub) and (!res && sub) as the same cases.
541 * See also the KCM ccache type, where we have similar considerations.
543 if (asprintf(&s
, "%s%s%s", res
&& *res
? res
: "",
544 res
&& *res
? ":" : "", sub
) == -1 || s
== NULL
||
545 (a
->cache_subsidiary
= strdup(sub
)) == NULL
) {
546 acc_close(context
, *id
);
548 return krb5_enomem(context
);
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.
558 error
= (*a
->context
->func
->open_ccache
)(a
->context
, res
, &a
->ccache
);
559 if (error
== ccErrCCacheNotFound
) {
561 a
->cache_name
= NULL
;
565 if (error
== ccNoError
)
566 error
= get_cc_name(a
);
567 if (error
!= ccNoError
) {
568 acc_close(context
, *id
);
571 return translate_cc_error(context
, error
);
574 error
= (*a
->ccache
->func
->get_kdc_time_offset
)(a
->ccache
,
578 context
->kdc_sec_offset
= offset
;
583 static krb5_error_code KRB5_CALLCONV
584 acc_gen_new(krb5_context context
, krb5_ccache
*id
)
586 return acc_alloc(context
, id
);
589 static krb5_error_code KRB5_CALLCONV
590 acc_initialize(krb5_context context
,
592 krb5_principal primary_principal
)
594 krb5_acc
*a
= ACACHE(id
);
599 ret
= krb5_unparse_name(context
, primary_principal
, &name
);
603 if (a
->cache_name
== NULL
) {
604 error
= (*a
->context
->func
->create_new_ccache
)(a
->context
,
609 if (error
== ccNoError
)
610 error
= get_cc_name(a
);
612 cc_credentials_iterator_t iter
;
613 cc_credentials_t ccred
;
615 error
= (*a
->ccache
->func
->new_credentials_iterator
)(a
->ccache
, &iter
);
618 return translate_cc_error(context
, error
);
622 error
= (*iter
->func
->next
)(iter
, &ccred
);
625 (*a
->ccache
->func
->remove_credentials
)(a
->ccache
, ccred
);
626 (*ccred
->func
->release
)(ccred
);
628 (*iter
->func
->release
)(iter
);
630 error
= (*a
->ccache
->func
->set_principal
)(a
->ccache
,
635 if (error
== 0 && context
->kdc_sec_offset
)
636 error
= (*a
->ccache
->func
->set_kdc_time_offset
)(a
->ccache
,
638 context
->kdc_sec_offset
);
640 return translate_cc_error(context
, error
);
643 static krb5_error_code KRB5_CALLCONV
644 acc_close(krb5_context context
,
647 krb5_acc
*a
= ACACHE(id
);
650 (*a
->ccache
->func
->release
)(a
->ccache
);
655 a
->cache_name
= NULL
;
658 (*a
->context
->func
->release
)(a
->context
);
661 krb5_data_free(&id
->data
);
665 static krb5_error_code KRB5_CALLCONV
666 acc_destroy(krb5_context context
,
669 krb5_acc
*a
= ACACHE(id
);
673 error
= (*a
->ccache
->func
->destroy
)(a
->ccache
);
677 error
= (a
->context
->func
->release
)(a
->context
);
680 return translate_cc_error(context
, error
);
683 static krb5_error_code KRB5_CALLCONV
684 acc_store_cred(krb5_context context
,
688 krb5_acc
*a
= ACACHE(id
);
689 cc_credentials_union cred
;
690 cc_credentials_v5_t v5cred
;
694 if (a
->ccache
== NULL
) {
695 krb5_set_error_message(context
, KRB5_CC_NOTFOUND
,
696 N_("No API credential found", ""));
697 return KRB5_CC_NOTFOUND
;
700 cred
.version
= cc_credentials_v5
;
701 cred
.credentials
.credentials_v5
= &v5cred
;
703 ret
= make_ccred_from_cred(context
,
709 error
= (*a
->ccache
->func
->store_credentials
)(a
->ccache
, &cred
);
711 ret
= translate_cc_error(context
, error
);
718 static krb5_error_code KRB5_CALLCONV
719 acc_get_principal(krb5_context context
,
721 krb5_principal
*principal
)
723 krb5_acc
*a
= ACACHE(id
);
728 if (a
->ccache
== NULL
) {
729 krb5_set_error_message(context
, KRB5_CC_NOTFOUND
,
730 N_("No API credential found", ""));
731 return KRB5_CC_NOTFOUND
;
734 error
= (*a
->ccache
->func
->get_principal
)(a
->ccache
,
738 return translate_cc_error(context
, error
);
740 ret
= krb5_parse_name(context
, name
->data
, principal
);
742 (*name
->func
->release
)(name
);
746 static krb5_error_code KRB5_CALLCONV
747 acc_get_first (krb5_context context
,
749 krb5_cc_cursor
*cursor
)
751 cc_credentials_iterator_t iter
;
752 krb5_acc
*a
= ACACHE(id
);
755 if (a
->ccache
== NULL
) {
756 krb5_set_error_message(context
, KRB5_CC_NOTFOUND
,
757 N_("No API credential found", ""));
758 return KRB5_CC_NOTFOUND
;
761 error
= (*a
->ccache
->func
->new_credentials_iterator
)(a
->ccache
, &iter
);
763 krb5_clear_error_message(context
);
771 static krb5_error_code KRB5_CALLCONV
772 acc_get_next (krb5_context context
,
774 krb5_cc_cursor
*cursor
,
777 cc_credentials_iterator_t iter
= *cursor
;
778 cc_credentials_t cred
;
783 error
= (*iter
->func
->next
)(iter
, &cred
);
785 return translate_cc_error(context
, error
);
786 if (cred
->data
->version
== cc_credentials_v5
)
788 (*cred
->func
->release
)(cred
);
791 ret
= make_cred_from_ccred(context
,
792 cred
->data
->credentials
.credentials_v5
,
794 (*cred
->func
->release
)(cred
);
798 static krb5_error_code KRB5_CALLCONV
799 acc_end_get (krb5_context context
,
801 krb5_cc_cursor
*cursor
)
803 cc_credentials_iterator_t iter
= *cursor
;
804 (*iter
->func
->release
)(iter
);
808 static krb5_error_code KRB5_CALLCONV
809 acc_remove_cred(krb5_context context
,
814 cc_credentials_iterator_t iter
;
815 krb5_acc
*a
= ACACHE(id
);
816 cc_credentials_t ccred
;
819 char *client
, *server
;
821 if (a
->ccache
== NULL
) {
822 krb5_set_error_message(context
, KRB5_CC_NOTFOUND
,
823 N_("No API credential found", ""));
824 return KRB5_CC_NOTFOUND
;
828 ret
= krb5_unparse_name(context
, cred
->client
, &client
);
834 ret
= krb5_unparse_name(context
, cred
->server
, &server
);
840 error
= (*a
->ccache
->func
->new_credentials_iterator
)(a
->ccache
, &iter
);
844 return translate_cc_error(context
, error
);
847 ret
= KRB5_CC_NOTFOUND
;
849 cc_credentials_v5_t
*v5cred
;
851 error
= (*iter
->func
->next
)(iter
, &ccred
);
855 if (ccred
->data
->version
!= cc_credentials_v5
)
858 v5cred
= ccred
->data
->credentials
.credentials_v5
;
860 if (client
&& strcmp(v5cred
->client
, client
) != 0)
863 if (strcmp(v5cred
->server
, server
) != 0)
866 (*a
->ccache
->func
->remove_credentials
)(a
->ccache
, ccred
);
869 (*ccred
->func
->release
)(ccred
);
872 (*iter
->func
->release
)(iter
);
875 krb5_set_error_message(context
, ret
,
876 N_("Can't find credential %s in cache",
877 "principal"), server
);
884 static krb5_error_code KRB5_CALLCONV
885 acc_set_flags(krb5_context context
,
892 static int KRB5_CALLCONV
893 acc_get_version(krb5_context context
,
900 cc_context_t context
;
901 cc_ccache_iterator_t iter
;
904 static krb5_error_code KRB5_CALLCONV
905 acc_get_cache_first(krb5_context context
, krb5_cc_cursor
*cursor
)
907 struct cache_iter
*iter
;
911 ret
= init_ccapi(context
);
915 iter
= calloc(1, sizeof(*iter
));
917 return krb5_enomem(context
);
919 error
= (*init_func
)(&iter
->context
, ccapi_version_3
, NULL
, NULL
);
922 return translate_cc_error(context
, error
);
925 error
= (*iter
->context
->func
->new_ccache_iterator
)(iter
->context
,
929 krb5_clear_error_message(context
);
936 static krb5_error_code KRB5_CALLCONV
937 acc_get_cache_next(krb5_context context
, krb5_cc_cursor cursor
, krb5_ccache
*id
)
939 struct cache_iter
*iter
= cursor
;
945 error
= (*iter
->iter
->func
->next
)(iter
->iter
, &cache
);
947 return translate_cc_error(context
, error
);
949 ret
= _krb5_cc_allocate(context
, &krb5_acc_ops
, id
);
951 (*cache
->func
->release
)(cache
);
955 ret
= acc_alloc(context
, id
);
957 (*cache
->func
->release
)(cache
);
965 error
= get_cc_name(a
);
967 acc_close(context
, *id
);
969 return translate_cc_error(context
, error
);
974 static krb5_error_code KRB5_CALLCONV
975 acc_end_cache_get(krb5_context context
, krb5_cc_cursor cursor
)
977 struct cache_iter
*iter
= cursor
;
979 (*iter
->iter
->func
->release
)(iter
->iter
);
981 (*iter
->context
->func
->release
)(iter
->context
);
982 iter
->context
= NULL
;
987 static krb5_error_code KRB5_CALLCONV
988 acc_move(krb5_context context
, krb5_ccache from
, krb5_ccache to
)
991 krb5_acc
*afrom
= ACACHE(from
);
992 krb5_acc
*ato
= ACACHE(to
);
995 if (ato
->ccache
== NULL
) {
998 error
= (*afrom
->ccache
->func
->get_principal
)(afrom
->ccache
,
1002 return translate_cc_error(context
, error
);
1004 error
= (*ato
->context
->func
->create_new_ccache
)(ato
->context
,
1008 (*name
->func
->release
)(name
);
1010 return translate_cc_error(context
, error
);
1013 error
= (*ato
->ccache
->func
->move
)(afrom
->ccache
, ato
->ccache
);
1014 ret
= translate_cc_error(context
, error
);
1016 krb5_cc_destroy(context
, from
);
1020 static krb5_error_code KRB5_CALLCONV
1021 acc_get_default_name(krb5_context context
, char **str
)
1023 krb5_error_code ret
;
1028 ret
= init_ccapi(context
);
1032 error
= (*init_func
)(&cc
, ccapi_version_3
, NULL
, NULL
);
1034 return translate_cc_error(context
, error
);
1036 error
= (*cc
->func
->get_default_ccache_name
)(cc
, &name
);
1038 (*cc
->func
->release
)(cc
);
1039 return translate_cc_error(context
, error
);
1042 error
= asprintf(str
, "API:%s", name
->data
);
1043 (*name
->func
->release
)(name
);
1044 (*cc
->func
->release
)(cc
);
1046 if (error
< 0 || *str
== NULL
)
1047 return krb5_enomem(context
);
1051 static krb5_error_code KRB5_CALLCONV
1052 acc_set_default(krb5_context context
, krb5_ccache id
)
1054 krb5_acc
*a
= ACACHE(id
);
1057 if (a
->ccache
== NULL
) {
1058 krb5_set_error_message(context
, KRB5_CC_NOTFOUND
,
1059 N_("No API credential found", ""));
1060 return KRB5_CC_NOTFOUND
;
1063 error
= (*a
->ccache
->func
->set_default
)(a
->ccache
);
1065 return translate_cc_error(context
, error
);
1070 static krb5_error_code KRB5_CALLCONV
1071 acc_lastchange(krb5_context context
, krb5_ccache id
, krb5_timestamp
*mtime
)
1073 krb5_acc
*a
= ACACHE(id
);
1077 if (a
->ccache
== NULL
) {
1078 krb5_set_error_message(context
, KRB5_CC_NOTFOUND
,
1079 N_("No API credential found", ""));
1080 return KRB5_CC_NOTFOUND
;
1083 error
= (*a
->ccache
->func
->get_change_time
)(a
->ccache
, &t
);
1085 return translate_cc_error(context
, error
);
1093 * Variable containing the API based credential cache implementation.
1095 * @ingroup krb5_ccache
1098 KRB5_LIB_VARIABLE
const krb5_cc_ops krb5_acc_ops
= {
1099 KRB5_CC_OPS_VERSION_5
,
1108 NULL
, /* acc_retrieve */
1116 acc_get_cache_first
,
1120 acc_get_default_name
,