📄 kcm.c
字号:
/* * 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 <sys/un.h>#endif#include "kcm.h"RCSID("$Id: kcm.c 22108 2007-12-03 17:23:53Z lha $");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) (*(uint32_t *)(C))static krb5_error_codetry_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_codetry_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_codekcm_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_codekcm_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_codekcm_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_codekcm_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; int32_t 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 voidkcm_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_codekcm_resolve(krb5_context context, krb5_ccache *id, const char *res){ return kcm_alloc(context, res, id);}/* * Request: * * Response: * NameZ */static krb5_error_codekcm_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_codekcm_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_codekcm_close(krb5_context context, krb5_ccache id){ kcm_free(context, &id); return 0;}/* * Request: * NameZ * * Response: * */static krb5_error_codekcm_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_codekcm_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_codekcm_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_codekcm_get_principal(krb5_context context, krb5_ccache id, krb5_principal *principal){ krb5_error_code ret; krb5_kcmcache *k = KCMCACHE(id); krb5_storage *request, *response;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -