From 954c01728e0c7485b72c9a5d5737e5f6bd0cf0b9 Mon Sep 17 00:00:00 2001 From: Heimdal Import User Date: Mon, 11 Jul 2005 01:16:55 +0000 Subject: r8302: import mini HEIMDAL into the tree (This used to be commit 118be28a7aef233799956615a99d1a2a74dac175) --- source4/heimdal/lib/krb5/kcm.c | 1095 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1095 insertions(+) create mode 100644 source4/heimdal/lib/krb5/kcm.c (limited to 'source4/heimdal/lib/krb5/kcm.c') diff --git a/source4/heimdal/lib/krb5/kcm.c b/source4/heimdal/lib/krb5/kcm.c new file mode 100644 index 0000000000..b7873f33d5 --- /dev/null +++ b/source4/heimdal/lib/krb5/kcm.c @@ -0,0 +1,1095 @@ +/* + * Copyright (c) 2005, PADL Software Pty Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of PADL Software nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +#ifdef HAVE_KCM +/* + * Client library for Kerberos Credentials Manager (KCM) daemon + */ + +#ifdef HAVE_SYS_UN_H +#include +#endif + +#include "kcm.h" + +RCSID("$Id: kcm.c,v 1.7 2005/06/17 04:20:11 lha Exp $"); + +typedef struct krb5_kcmcache { + char *name; + struct sockaddr_un path; + char *door_path; +} krb5_kcmcache; + +#define KCMCACHE(X) ((krb5_kcmcache *)(X)->data.data) +#define CACHENAME(X) (KCMCACHE(X)->name) +#define KCMCURSOR(C) (*(u_int32_t *)(C)) + +static krb5_error_code +try_door(krb5_context context, const krb5_kcmcache *k, + krb5_data *request_data, + krb5_data *response_data) +{ +#ifdef HAVE_DOOR_CREATE + door_arg_t arg; + int fd; + int ret; + + memset(&arg, 0, sizeof(arg)); + + fd = open(k->door_path, O_RDWR); + if (fd < 0) + return KRB5_CC_IO; + + arg.data_ptr = request_data->data; + arg.data_size = request_data->length; + arg.desc_ptr = NULL; + arg.desc_num = 0; + arg.rbuf = NULL; + arg.rsize = 0; + + ret = door_call(fd, &arg); + close(fd); + if (ret != 0) + return KRB5_CC_IO; + + ret = krb5_data_copy(response_data, arg.rbuf, arg.rsize); + munmap(arg.rbuf, arg.rsize); + if (ret) + return ret; + + return 0; +#else + return KRB5_CC_IO; +#endif +} + +static krb5_error_code +try_unix_socket(krb5_context context, const krb5_kcmcache *k, + krb5_data *request_data, + krb5_data *response_data) +{ + krb5_error_code ret; + int fd; + + fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd < 0) + return KRB5_CC_IO; + + if (connect(fd, rk_UNCONST(&k->path), sizeof(k->path)) != 0) { + close(fd); + return KRB5_CC_IO; + } + + ret = _krb5_send_and_recv_tcp(fd, context->kdc_timeout, + request_data, response_data); + close(fd); + return ret; +} + +static krb5_error_code +kcm_send_request(krb5_context context, + krb5_kcmcache *k, + krb5_storage *request, + krb5_data *response_data) +{ + krb5_error_code ret; + krb5_data request_data; + int i; + + response_data->data = NULL; + response_data->length = 0; + + ret = krb5_storage_to_data(request, &request_data); + if (ret) { + krb5_clear_error_string(context); + return KRB5_CC_NOMEM; + } + + ret = KRB5_CC_IO; + + for (i = 0; i < context->max_retries; i++) { + ret = try_door(context, k, &request_data, response_data); + if (ret == 0 && response_data->length != 0) + break; + ret = try_unix_socket(context, k, &request_data, response_data); + if (ret == 0 && response_data->length != 0) + break; + } + + krb5_data_free(&request_data); + + if (ret) { + krb5_clear_error_string(context); + ret = KRB5_CC_IO; + } + + return ret; +} + +static krb5_error_code +kcm_storage_request(krb5_context context, + kcm_operation opcode, + krb5_storage **storage_p) +{ + krb5_storage *sp; + krb5_error_code ret; + + *storage_p = NULL; + + sp = krb5_storage_emem(); + if (sp == NULL) { + krb5_set_error_string(context, "malloc: out of memory"); + return KRB5_CC_NOMEM; + } + + /* Send MAJOR | VERSION | OPCODE */ + ret = krb5_store_int8(sp, KCM_PROTOCOL_VERSION_MAJOR); + if (ret) + goto fail; + ret = krb5_store_int8(sp, KCM_PROTOCOL_VERSION_MINOR); + if (ret) + goto fail; + ret = krb5_store_int16(sp, opcode); + if (ret) + goto fail; + + *storage_p = sp; + fail: + if (ret) { + krb5_set_error_string(context, "Failed to encode request"); + krb5_storage_free(sp); + } + + return ret; +} + +static krb5_error_code +kcm_alloc(krb5_context context, const char *name, krb5_ccache *id) +{ + krb5_kcmcache *k; + const char *path; + + k = malloc(sizeof(*k)); + if (k == NULL) { + krb5_set_error_string(context, "malloc: out of memory"); + return KRB5_CC_NOMEM; + } + + if (name != NULL) { + k->name = strdup(name); + if (k->name == NULL) { + free(k); + krb5_set_error_string(context, "malloc: out of memory"); + return KRB5_CC_NOMEM; + } + } else + k->name = NULL; + + path = krb5_config_get_string_default(context, NULL, + _PATH_KCM_SOCKET, + "libdefaults", + "kcm_socket", + NULL); + + k->path.sun_family = AF_UNIX; + strlcpy(k->path.sun_path, path, sizeof(k->path.sun_path)); + + path = krb5_config_get_string_default(context, NULL, + _PATH_KCM_DOOR, + "libdefaults", + "kcm_door", + NULL); + k->door_path = strdup(path); + + (*id)->data.data = k; + (*id)->data.length = sizeof(*k); + + return 0; +} + +static krb5_error_code +kcm_call(krb5_context context, + krb5_kcmcache *k, + krb5_storage *request, + krb5_storage **response_p, + krb5_data *response_data_p) +{ + krb5_data response_data; + krb5_error_code ret, status; + krb5_storage *response; + + if (response_p != NULL) + *response_p = NULL; + + ret = kcm_send_request(context, k, request, &response_data); + if (ret) { + return ret; + } + + response = krb5_storage_from_data(&response_data); + if (response == NULL) { + krb5_data_free(&response_data); + return KRB5_CC_IO; + } + + ret = krb5_ret_int32(response, &status); + if (ret) { + krb5_storage_free(response); + krb5_data_free(&response_data); + return KRB5_CC_FORMAT; + } + + if (status) { + krb5_storage_free(response); + krb5_data_free(&response_data); + return status; + } + + if (response_p != NULL) { + *response_data_p = response_data; + *response_p = response; + + return 0; + } + + krb5_storage_free(response); + krb5_data_free(&response_data); + + return 0; +} + +static void +kcm_free(krb5_context context, krb5_ccache *id) +{ + krb5_kcmcache *k = KCMCACHE(*id); + + if (k != NULL) { + if (k->name != NULL) + free(k->name); + if (k->door_path) + free(k->door_path); + memset(k, 0, sizeof(*k)); + krb5_data_free(&(*id)->data); + } + + *id = NULL; +} + +static const char * +kcm_get_name(krb5_context context, + krb5_ccache id) +{ + return CACHENAME(id); +} + +static krb5_error_code +kcm_resolve(krb5_context context, krb5_ccache *id, const char *res) +{ + return kcm_alloc(context, res, id); +} + +/* + * Request: + * + * Response: + * NameZ + */ +static krb5_error_code +kcm_gen_new(krb5_context context, krb5_ccache *id) +{ + krb5_kcmcache *k; + krb5_error_code ret; + krb5_storage *request, *response; + krb5_data response_data; + + ret = kcm_alloc(context, NULL, id); + if (ret) + return ret; + + k = KCMCACHE(*id); + + ret = kcm_storage_request(context, KCM_OP_GEN_NEW, &request); + if (ret) { + kcm_free(context, id); + return ret; + } + + ret = kcm_call(context, k, request, &response, &response_data); + if (ret) { + krb5_storage_free(request); + kcm_free(context, id); + return ret; + } + + ret = krb5_ret_stringz(response, &k->name); + if (ret) + ret = KRB5_CC_IO; + + krb5_storage_free(request); + krb5_storage_free(response); + krb5_data_free(&response_data); + + if (ret) + kcm_free(context, id); + + return ret; +} + +/* + * Request: + * NameZ + * Principal + * + * Response: + * + */ +static krb5_error_code +kcm_initialize(krb5_context context, + krb5_ccache id, + krb5_principal primary_principal) +{ + krb5_error_code ret; + krb5_kcmcache *k = KCMCACHE(id); + krb5_storage *request; + + ret = kcm_storage_request(context, KCM_OP_INITIALIZE, &request); + if (ret) + return ret; + + ret = krb5_store_stringz(request, k->name); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = krb5_store_principal(request, primary_principal); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = kcm_call(context, k, request, NULL, NULL); + + krb5_storage_free(request); + return ret; +} + +static krb5_error_code +kcm_close(krb5_context context, + krb5_ccache id) +{ + kcm_free(context, &id); + return 0; +} + +/* + * Request: + * NameZ + * + * Response: + * + */ +static krb5_error_code +kcm_destroy(krb5_context context, + krb5_ccache id) +{ + krb5_error_code ret; + krb5_kcmcache *k = KCMCACHE(id); + krb5_storage *request; + + ret = kcm_storage_request(context, KCM_OP_DESTROY, &request); + if (ret) + return ret; + + ret = krb5_store_stringz(request, k->name); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = kcm_call(context, k, request, NULL, NULL); + + krb5_storage_free(request); + return ret; +} + +/* + * Request: + * NameZ + * Creds + * + * Response: + * + */ +static krb5_error_code +kcm_store_cred(krb5_context context, + krb5_ccache id, + krb5_creds *creds) +{ + krb5_error_code ret; + krb5_kcmcache *k = KCMCACHE(id); + krb5_storage *request; + + ret = kcm_storage_request(context, KCM_OP_STORE, &request); + if (ret) + return ret; + + ret = krb5_store_stringz(request, k->name); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = krb5_store_creds(request, creds); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = kcm_call(context, k, request, NULL, NULL); + + krb5_storage_free(request); + return ret; +} + +/* + * Request: + * NameZ + * WhichFields + * MatchCreds + * + * Response: + * Creds + * + */ +static krb5_error_code +kcm_retrieve(krb5_context context, + krb5_ccache id, + krb5_flags which, + const krb5_creds *mcred, + krb5_creds *creds) +{ + krb5_error_code ret; + krb5_kcmcache *k = KCMCACHE(id); + krb5_storage *request, *response; + krb5_data response_data; + + ret = kcm_storage_request(context, KCM_OP_RETRIEVE, &request); + if (ret) + return ret; + + ret = krb5_store_stringz(request, k->name); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = krb5_store_int32(request, which); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = krb5_store_creds_tag(request, rk_UNCONST(mcred)); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = kcm_call(context, k, request, &response, &response_data); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = krb5_ret_creds(response, creds); + if (ret) + ret = KRB5_CC_IO; + + krb5_storage_free(request); + krb5_storage_free(response); + krb5_data_free(&response_data); + + return ret; +} + +/* + * Request: + * NameZ + * + * Response: + * Principal + */ +static krb5_error_code +kcm_get_principal(krb5_context context, + krb5_ccache id, + krb5_principal *principal) +{ + krb5_error_code ret; + krb5_kcmcache *k = KCMCACHE(id); + krb5_storage *request, *response; + krb5_data response_data; + + ret = kcm_storage_request(context, KCM_OP_GET_PRINCIPAL, &request); + if (ret) + return ret; + + ret = krb5_store_stringz(request, k->name); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = kcm_call(context, k, request, &response, &response_data); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = krb5_ret_principal(response, principal); + if (ret) + ret = KRB5_CC_IO; + + krb5_storage_free(request); + krb5_storage_free(response); + krb5_data_free(&response_data); + + return ret; +} + +/* + * Request: + * NameZ + * + * Response: + * Cursor + * + */ +static krb5_error_code +kcm_get_first (krb5_context context, + krb5_ccache id, + krb5_cc_cursor *cursor) +{ + krb5_error_code ret; + krb5_kcmcache *k = KCMCACHE(id); + krb5_storage *request, *response; + krb5_data response_data; + u_int32_t tmp; + + ret = kcm_storage_request(context, KCM_OP_GET_FIRST, &request); + if (ret) + return ret; + + ret = krb5_store_stringz(request, k->name); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = kcm_call(context, k, request, &response, &response_data); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = krb5_ret_int32(response, &tmp); + if (ret) + ret = KRB5_CC_IO; + + krb5_storage_free(request); + krb5_storage_free(response); + krb5_data_free(&response_data); + + if (ret) + return ret; + + *cursor = malloc(sizeof(tmp)); + if (*cursor == NULL) + return KRB5_CC_NOMEM; + + KCMCURSOR(*cursor) = tmp; + + return 0; +} + +/* + * Request: + * NameZ + * Cursor + * + * Response: + * Creds + */ +static krb5_error_code +kcm_get_next (krb5_context context, + krb5_ccache id, + krb5_cc_cursor *cursor, + krb5_creds *creds) +{ + krb5_error_code ret; + krb5_kcmcache *k = KCMCACHE(id); + krb5_storage *request, *response; + krb5_data response_data; + + ret = kcm_storage_request(context, KCM_OP_GET_NEXT, &request); + if (ret) + return ret; + + ret = krb5_store_stringz(request, k->name); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = krb5_store_int32(request, KCMCURSOR(*cursor)); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = kcm_call(context, k, request, &response, &response_data); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = krb5_ret_creds(response, creds); + if (ret) + ret = KRB5_CC_IO; + + krb5_storage_free(request); + krb5_storage_free(response); + krb5_data_free(&response_data); + + return ret; +} + +/* + * Request: + * NameZ + * Cursor + * + * Response: + * + */ +static krb5_error_code +kcm_end_get (krb5_context context, + krb5_ccache id, + krb5_cc_cursor *cursor) +{ + krb5_error_code ret; + krb5_kcmcache *k = KCMCACHE(id); + krb5_storage *request; + + ret = kcm_storage_request(context, KCM_OP_END_GET, &request); + if (ret) + return ret; + + ret = krb5_store_stringz(request, k->name); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = krb5_store_int32(request, KCMCURSOR(*cursor)); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = kcm_call(context, k, request, NULL, NULL); + if (ret) { + krb5_storage_free(request); + return ret; + } + + krb5_storage_free(request); + + KCMCURSOR(*cursor) = 0; + free(*cursor); + *cursor = NULL; + + return ret; +} + +/* + * Request: + * NameZ + * WhichFields + * MatchCreds + * + * Response: + * + */ +static krb5_error_code +kcm_remove_cred(krb5_context context, + krb5_ccache id, + krb5_flags which, + krb5_creds *cred) +{ + krb5_error_code ret; + krb5_kcmcache *k = KCMCACHE(id); + krb5_storage *request; + + ret = kcm_storage_request(context, KCM_OP_REMOVE_CRED, &request); + if (ret) + return ret; + + ret = krb5_store_stringz(request, k->name); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = krb5_store_int32(request, which); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = krb5_store_creds_tag(request, cred); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = kcm_call(context, k, request, NULL, NULL); + + krb5_storage_free(request); + return ret; +} + +static krb5_error_code +kcm_set_flags(krb5_context context, + krb5_ccache id, + krb5_flags flags) +{ + krb5_error_code ret; + krb5_kcmcache *k = KCMCACHE(id); + krb5_storage *request; + + ret = kcm_storage_request(context, KCM_OP_SET_FLAGS, &request); + if (ret) + return ret; + + ret = krb5_store_stringz(request, k->name); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = krb5_store_int32(request, flags); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = kcm_call(context, k, request, NULL, NULL); + + krb5_storage_free(request); + return ret; +} + +static krb5_error_code +kcm_get_version(krb5_context context, + krb5_ccache id) +{ + return 0; +} + +const krb5_cc_ops krb5_kcm_ops = { + "KCM", + kcm_get_name, + kcm_resolve, + kcm_gen_new, + kcm_initialize, + kcm_destroy, + kcm_close, + kcm_store_cred, + kcm_retrieve, + kcm_get_principal, + kcm_get_first, + kcm_get_next, + kcm_end_get, + kcm_remove_cred, + kcm_set_flags, + kcm_get_version +}; + +krb5_boolean +_krb5_kcm_is_running(krb5_context context) +{ + krb5_error_code ret; + krb5_ccache_data ccdata; + krb5_ccache id = &ccdata; + krb5_boolean running; + + ret = kcm_alloc(context, NULL, &id); + if (ret) + return 0; + + running = (_krb5_kcm_noop(context, id) == 0); + + kcm_free(context, &id); + + return running; +} + +/* + * Request: + * + * Response: + * + */ +krb5_error_code +_krb5_kcm_noop(krb5_context context, + krb5_ccache id) +{ + krb5_error_code ret; + krb5_kcmcache *k = KCMCACHE(id); + krb5_storage *request; + + ret = kcm_storage_request(context, KCM_OP_NOOP, &request); + if (ret) + return ret; + + ret = kcm_call(context, k, request, NULL, NULL); + + krb5_storage_free(request); + return ret; +} + + +/* + * Request: + * NameZ + * Mode + * + * Response: + * + */ +krb5_error_code +_krb5_kcm_chmod(krb5_context context, + krb5_ccache id, + u_int16_t mode) +{ + krb5_error_code ret; + krb5_kcmcache *k = KCMCACHE(id); + krb5_storage *request; + + ret = kcm_storage_request(context, KCM_OP_CHMOD, &request); + if (ret) + return ret; + + ret = krb5_store_stringz(request, k->name); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = krb5_store_int16(request, mode); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = kcm_call(context, k, request, NULL, NULL); + + krb5_storage_free(request); + return ret; +} + + +/* + * Request: + * NameZ + * UID + * GID + * + * Response: + * + */ +krb5_error_code +_krb5_kcm_chown(krb5_context context, + krb5_ccache id, + u_int32_t uid, + u_int32_t gid) +{ + krb5_error_code ret; + krb5_kcmcache *k = KCMCACHE(id); + krb5_storage *request; + + ret = kcm_storage_request(context, KCM_OP_CHOWN, &request); + if (ret) + return ret; + + ret = krb5_store_stringz(request, k->name); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = krb5_store_int32(request, uid); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = krb5_store_int32(request, gid); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = kcm_call(context, k, request, NULL, NULL); + + krb5_storage_free(request); + return ret; +} + + +/* + * Request: + * NameZ + * ServerPrincipalPresent + * ServerPrincipal OPTIONAL + * Key + * + * Repsonse: + * + */ +krb5_error_code +_krb5_kcm_get_initial_ticket(krb5_context context, + krb5_ccache id, + krb5_principal server, + krb5_keyblock *key) +{ + krb5_error_code ret; + krb5_kcmcache *k = KCMCACHE(id); + krb5_storage *request; + + ret = kcm_storage_request(context, KCM_OP_GET_INITIAL_TICKET, &request); + if (ret) + return ret; + + ret = krb5_store_stringz(request, k->name); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = krb5_store_int8(request, (server == NULL) ? 0 : 1); + if (ret) { + krb5_storage_free(request); + return ret; + } + + if (server != NULL) { + ret = krb5_store_principal(request, server); + if (ret) { + krb5_storage_free(request); + return ret; + } + } + + ret = krb5_store_keyblock(request, *key); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = kcm_call(context, k, request, NULL, NULL); + + krb5_storage_free(request); + return ret; +} + + +/* + * Request: + * NameZ + * KDCFlags + * EncryptionType + * ServerPrincipal + * + * Repsonse: + * + */ +krb5_error_code +_krb5_kcm_get_ticket(krb5_context context, + krb5_ccache id, + krb5_kdc_flags flags, + krb5_enctype enctype, + krb5_principal server) +{ + krb5_error_code ret; + krb5_kcmcache *k = KCMCACHE(id); + krb5_storage *request; + + ret = kcm_storage_request(context, KCM_OP_GET_TICKET, &request); + if (ret) + return ret; + + ret = krb5_store_stringz(request, k->name); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = krb5_store_int32(request, flags.i); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = krb5_store_int32(request, enctype); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = krb5_store_principal(request, server); + if (ret) { + krb5_storage_free(request); + return ret; + } + + ret = kcm_call(context, k, request, NULL, NULL); + + krb5_storage_free(request); + return ret; +} + + +#endif /* HAVE_KCM */ -- cgit