kcm.c revision 178825
1178825Sdfr/* 2178825Sdfr * Copyright (c) 2005, PADL Software Pty Ltd. 3178825Sdfr * All rights reserved. 4178825Sdfr * 5178825Sdfr * Redistribution and use in source and binary forms, with or without 6178825Sdfr * modification, are permitted provided that the following conditions 7178825Sdfr * are met: 8178825Sdfr * 9178825Sdfr * 1. Redistributions of source code must retain the above copyright 10178825Sdfr * notice, this list of conditions and the following disclaimer. 11178825Sdfr * 12178825Sdfr * 2. Redistributions in binary form must reproduce the above copyright 13178825Sdfr * notice, this list of conditions and the following disclaimer in the 14178825Sdfr * documentation and/or other materials provided with the distribution. 15178825Sdfr * 16178825Sdfr * 3. Neither the name of PADL Software nor the names of its contributors 17178825Sdfr * may be used to endorse or promote products derived from this software 18178825Sdfr * without specific prior written permission. 19178825Sdfr * 20178825Sdfr * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND 21178825Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22178825Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23178825Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE 24178825Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25178825Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26178825Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27178825Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28178825Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29178825Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30178825Sdfr * SUCH DAMAGE. 31178825Sdfr */ 32178825Sdfr 33178825Sdfr#include "krb5_locl.h" 34178825Sdfr 35178825Sdfr#ifdef HAVE_KCM 36178825Sdfr/* 37178825Sdfr * Client library for Kerberos Credentials Manager (KCM) daemon 38178825Sdfr */ 39178825Sdfr 40178825Sdfr#ifdef HAVE_SYS_UN_H 41178825Sdfr#include <sys/un.h> 42178825Sdfr#endif 43178825Sdfr 44178825Sdfr#include "kcm.h" 45178825Sdfr 46178825SdfrRCSID("$Id: kcm.c 22108 2007-12-03 17:23:53Z lha $"); 47178825Sdfr 48178825Sdfrtypedef struct krb5_kcmcache { 49178825Sdfr char *name; 50178825Sdfr struct sockaddr_un path; 51178825Sdfr char *door_path; 52178825Sdfr} krb5_kcmcache; 53178825Sdfr 54178825Sdfr#define KCMCACHE(X) ((krb5_kcmcache *)(X)->data.data) 55178825Sdfr#define CACHENAME(X) (KCMCACHE(X)->name) 56178825Sdfr#define KCMCURSOR(C) (*(uint32_t *)(C)) 57178825Sdfr 58178825Sdfrstatic krb5_error_code 59178825Sdfrtry_door(krb5_context context, const krb5_kcmcache *k, 60178825Sdfr krb5_data *request_data, 61178825Sdfr krb5_data *response_data) 62178825Sdfr{ 63178825Sdfr#ifdef HAVE_DOOR_CREATE 64178825Sdfr door_arg_t arg; 65178825Sdfr int fd; 66178825Sdfr int ret; 67178825Sdfr 68178825Sdfr memset(&arg, 0, sizeof(arg)); 69178825Sdfr 70178825Sdfr fd = open(k->door_path, O_RDWR); 71178825Sdfr if (fd < 0) 72178825Sdfr return KRB5_CC_IO; 73178825Sdfr 74178825Sdfr arg.data_ptr = request_data->data; 75178825Sdfr arg.data_size = request_data->length; 76178825Sdfr arg.desc_ptr = NULL; 77178825Sdfr arg.desc_num = 0; 78178825Sdfr arg.rbuf = NULL; 79178825Sdfr arg.rsize = 0; 80178825Sdfr 81178825Sdfr ret = door_call(fd, &arg); 82178825Sdfr close(fd); 83178825Sdfr if (ret != 0) 84178825Sdfr return KRB5_CC_IO; 85178825Sdfr 86178825Sdfr ret = krb5_data_copy(response_data, arg.rbuf, arg.rsize); 87178825Sdfr munmap(arg.rbuf, arg.rsize); 88178825Sdfr if (ret) 89178825Sdfr return ret; 90178825Sdfr 91178825Sdfr return 0; 92178825Sdfr#else 93178825Sdfr return KRB5_CC_IO; 94178825Sdfr#endif 95178825Sdfr} 96178825Sdfr 97178825Sdfrstatic krb5_error_code 98178825Sdfrtry_unix_socket(krb5_context context, const krb5_kcmcache *k, 99178825Sdfr krb5_data *request_data, 100178825Sdfr krb5_data *response_data) 101178825Sdfr{ 102178825Sdfr krb5_error_code ret; 103178825Sdfr int fd; 104178825Sdfr 105178825Sdfr fd = socket(AF_UNIX, SOCK_STREAM, 0); 106178825Sdfr if (fd < 0) 107178825Sdfr return KRB5_CC_IO; 108178825Sdfr 109178825Sdfr if (connect(fd, rk_UNCONST(&k->path), sizeof(k->path)) != 0) { 110178825Sdfr close(fd); 111178825Sdfr return KRB5_CC_IO; 112178825Sdfr } 113178825Sdfr 114178825Sdfr ret = _krb5_send_and_recv_tcp(fd, context->kdc_timeout, 115178825Sdfr request_data, response_data); 116178825Sdfr close(fd); 117178825Sdfr return ret; 118178825Sdfr} 119178825Sdfr 120178825Sdfrstatic krb5_error_code 121178825Sdfrkcm_send_request(krb5_context context, 122178825Sdfr krb5_kcmcache *k, 123178825Sdfr krb5_storage *request, 124178825Sdfr krb5_data *response_data) 125178825Sdfr{ 126178825Sdfr krb5_error_code ret; 127178825Sdfr krb5_data request_data; 128178825Sdfr int i; 129178825Sdfr 130178825Sdfr response_data->data = NULL; 131178825Sdfr response_data->length = 0; 132178825Sdfr 133178825Sdfr ret = krb5_storage_to_data(request, &request_data); 134178825Sdfr if (ret) { 135178825Sdfr krb5_clear_error_string(context); 136178825Sdfr return KRB5_CC_NOMEM; 137178825Sdfr } 138178825Sdfr 139178825Sdfr ret = KRB5_CC_IO; 140178825Sdfr 141178825Sdfr for (i = 0; i < context->max_retries; i++) { 142178825Sdfr ret = try_door(context, k, &request_data, response_data); 143178825Sdfr if (ret == 0 && response_data->length != 0) 144178825Sdfr break; 145178825Sdfr ret = try_unix_socket(context, k, &request_data, response_data); 146178825Sdfr if (ret == 0 && response_data->length != 0) 147178825Sdfr break; 148178825Sdfr } 149178825Sdfr 150178825Sdfr krb5_data_free(&request_data); 151178825Sdfr 152178825Sdfr if (ret) { 153178825Sdfr krb5_clear_error_string(context); 154178825Sdfr ret = KRB5_CC_IO; 155178825Sdfr } 156178825Sdfr 157178825Sdfr return ret; 158178825Sdfr} 159178825Sdfr 160178825Sdfrstatic krb5_error_code 161178825Sdfrkcm_storage_request(krb5_context context, 162178825Sdfr kcm_operation opcode, 163178825Sdfr krb5_storage **storage_p) 164178825Sdfr{ 165178825Sdfr krb5_storage *sp; 166178825Sdfr krb5_error_code ret; 167178825Sdfr 168178825Sdfr *storage_p = NULL; 169178825Sdfr 170178825Sdfr sp = krb5_storage_emem(); 171178825Sdfr if (sp == NULL) { 172178825Sdfr krb5_set_error_string(context, "malloc: out of memory"); 173178825Sdfr return KRB5_CC_NOMEM; 174178825Sdfr } 175178825Sdfr 176178825Sdfr /* Send MAJOR | VERSION | OPCODE */ 177178825Sdfr ret = krb5_store_int8(sp, KCM_PROTOCOL_VERSION_MAJOR); 178178825Sdfr if (ret) 179178825Sdfr goto fail; 180178825Sdfr ret = krb5_store_int8(sp, KCM_PROTOCOL_VERSION_MINOR); 181178825Sdfr if (ret) 182178825Sdfr goto fail; 183178825Sdfr ret = krb5_store_int16(sp, opcode); 184178825Sdfr if (ret) 185178825Sdfr goto fail; 186178825Sdfr 187178825Sdfr *storage_p = sp; 188178825Sdfr fail: 189178825Sdfr if (ret) { 190178825Sdfr krb5_set_error_string(context, "Failed to encode request"); 191178825Sdfr krb5_storage_free(sp); 192178825Sdfr } 193178825Sdfr 194178825Sdfr return ret; 195178825Sdfr} 196178825Sdfr 197178825Sdfrstatic krb5_error_code 198178825Sdfrkcm_alloc(krb5_context context, const char *name, krb5_ccache *id) 199178825Sdfr{ 200178825Sdfr krb5_kcmcache *k; 201178825Sdfr const char *path; 202178825Sdfr 203178825Sdfr k = malloc(sizeof(*k)); 204178825Sdfr if (k == NULL) { 205178825Sdfr krb5_set_error_string(context, "malloc: out of memory"); 206178825Sdfr return KRB5_CC_NOMEM; 207178825Sdfr } 208178825Sdfr 209178825Sdfr if (name != NULL) { 210178825Sdfr k->name = strdup(name); 211178825Sdfr if (k->name == NULL) { 212178825Sdfr free(k); 213178825Sdfr krb5_set_error_string(context, "malloc: out of memory"); 214178825Sdfr return KRB5_CC_NOMEM; 215178825Sdfr } 216178825Sdfr } else 217178825Sdfr k->name = NULL; 218178825Sdfr 219178825Sdfr path = krb5_config_get_string_default(context, NULL, 220178825Sdfr _PATH_KCM_SOCKET, 221178825Sdfr "libdefaults", 222178825Sdfr "kcm_socket", 223178825Sdfr NULL); 224178825Sdfr 225178825Sdfr k->path.sun_family = AF_UNIX; 226178825Sdfr strlcpy(k->path.sun_path, path, sizeof(k->path.sun_path)); 227178825Sdfr 228178825Sdfr path = krb5_config_get_string_default(context, NULL, 229178825Sdfr _PATH_KCM_DOOR, 230178825Sdfr "libdefaults", 231178825Sdfr "kcm_door", 232178825Sdfr NULL); 233178825Sdfr k->door_path = strdup(path); 234178825Sdfr 235178825Sdfr (*id)->data.data = k; 236178825Sdfr (*id)->data.length = sizeof(*k); 237178825Sdfr 238178825Sdfr return 0; 239178825Sdfr} 240178825Sdfr 241178825Sdfrstatic krb5_error_code 242178825Sdfrkcm_call(krb5_context context, 243178825Sdfr krb5_kcmcache *k, 244178825Sdfr krb5_storage *request, 245178825Sdfr krb5_storage **response_p, 246178825Sdfr krb5_data *response_data_p) 247178825Sdfr{ 248178825Sdfr krb5_data response_data; 249178825Sdfr krb5_error_code ret; 250178825Sdfr int32_t status; 251178825Sdfr krb5_storage *response; 252178825Sdfr 253178825Sdfr if (response_p != NULL) 254178825Sdfr *response_p = NULL; 255178825Sdfr 256178825Sdfr ret = kcm_send_request(context, k, request, &response_data); 257178825Sdfr if (ret) { 258178825Sdfr return ret; 259178825Sdfr } 260178825Sdfr 261178825Sdfr response = krb5_storage_from_data(&response_data); 262178825Sdfr if (response == NULL) { 263178825Sdfr krb5_data_free(&response_data); 264178825Sdfr return KRB5_CC_IO; 265178825Sdfr } 266178825Sdfr 267178825Sdfr ret = krb5_ret_int32(response, &status); 268178825Sdfr if (ret) { 269178825Sdfr krb5_storage_free(response); 270178825Sdfr krb5_data_free(&response_data); 271178825Sdfr return KRB5_CC_FORMAT; 272178825Sdfr } 273178825Sdfr 274178825Sdfr if (status) { 275178825Sdfr krb5_storage_free(response); 276178825Sdfr krb5_data_free(&response_data); 277178825Sdfr return status; 278178825Sdfr } 279178825Sdfr 280178825Sdfr if (response_p != NULL) { 281178825Sdfr *response_data_p = response_data; 282178825Sdfr *response_p = response; 283178825Sdfr 284178825Sdfr return 0; 285178825Sdfr } 286178825Sdfr 287178825Sdfr krb5_storage_free(response); 288178825Sdfr krb5_data_free(&response_data); 289178825Sdfr 290178825Sdfr return 0; 291178825Sdfr} 292178825Sdfr 293178825Sdfrstatic void 294178825Sdfrkcm_free(krb5_context context, krb5_ccache *id) 295178825Sdfr{ 296178825Sdfr krb5_kcmcache *k = KCMCACHE(*id); 297178825Sdfr 298178825Sdfr if (k != NULL) { 299178825Sdfr if (k->name != NULL) 300178825Sdfr free(k->name); 301178825Sdfr if (k->door_path) 302178825Sdfr free(k->door_path); 303178825Sdfr memset(k, 0, sizeof(*k)); 304178825Sdfr krb5_data_free(&(*id)->data); 305178825Sdfr } 306178825Sdfr 307178825Sdfr *id = NULL; 308178825Sdfr} 309178825Sdfr 310178825Sdfrstatic const char * 311178825Sdfrkcm_get_name(krb5_context context, 312178825Sdfr krb5_ccache id) 313178825Sdfr{ 314178825Sdfr return CACHENAME(id); 315178825Sdfr} 316178825Sdfr 317178825Sdfrstatic krb5_error_code 318178825Sdfrkcm_resolve(krb5_context context, krb5_ccache *id, const char *res) 319178825Sdfr{ 320178825Sdfr return kcm_alloc(context, res, id); 321178825Sdfr} 322178825Sdfr 323178825Sdfr/* 324178825Sdfr * Request: 325178825Sdfr * 326178825Sdfr * Response: 327178825Sdfr * NameZ 328178825Sdfr */ 329178825Sdfrstatic krb5_error_code 330178825Sdfrkcm_gen_new(krb5_context context, krb5_ccache *id) 331178825Sdfr{ 332178825Sdfr krb5_kcmcache *k; 333178825Sdfr krb5_error_code ret; 334178825Sdfr krb5_storage *request, *response; 335178825Sdfr krb5_data response_data; 336178825Sdfr 337178825Sdfr ret = kcm_alloc(context, NULL, id); 338178825Sdfr if (ret) 339178825Sdfr return ret; 340178825Sdfr 341178825Sdfr k = KCMCACHE(*id); 342178825Sdfr 343178825Sdfr ret = kcm_storage_request(context, KCM_OP_GEN_NEW, &request); 344178825Sdfr if (ret) { 345178825Sdfr kcm_free(context, id); 346178825Sdfr return ret; 347178825Sdfr } 348178825Sdfr 349178825Sdfr ret = kcm_call(context, k, request, &response, &response_data); 350178825Sdfr if (ret) { 351178825Sdfr krb5_storage_free(request); 352178825Sdfr kcm_free(context, id); 353178825Sdfr return ret; 354178825Sdfr } 355178825Sdfr 356178825Sdfr ret = krb5_ret_stringz(response, &k->name); 357178825Sdfr if (ret) 358178825Sdfr ret = KRB5_CC_IO; 359178825Sdfr 360178825Sdfr krb5_storage_free(request); 361178825Sdfr krb5_storage_free(response); 362178825Sdfr krb5_data_free(&response_data); 363178825Sdfr 364178825Sdfr if (ret) 365178825Sdfr kcm_free(context, id); 366178825Sdfr 367178825Sdfr return ret; 368178825Sdfr} 369178825Sdfr 370178825Sdfr/* 371178825Sdfr * Request: 372178825Sdfr * NameZ 373178825Sdfr * Principal 374178825Sdfr * 375178825Sdfr * Response: 376178825Sdfr * 377178825Sdfr */ 378178825Sdfrstatic krb5_error_code 379178825Sdfrkcm_initialize(krb5_context context, 380178825Sdfr krb5_ccache id, 381178825Sdfr krb5_principal primary_principal) 382178825Sdfr{ 383178825Sdfr krb5_error_code ret; 384178825Sdfr krb5_kcmcache *k = KCMCACHE(id); 385178825Sdfr krb5_storage *request; 386178825Sdfr 387178825Sdfr ret = kcm_storage_request(context, KCM_OP_INITIALIZE, &request); 388178825Sdfr if (ret) 389178825Sdfr return ret; 390178825Sdfr 391178825Sdfr ret = krb5_store_stringz(request, k->name); 392178825Sdfr if (ret) { 393178825Sdfr krb5_storage_free(request); 394178825Sdfr return ret; 395178825Sdfr } 396178825Sdfr 397178825Sdfr ret = krb5_store_principal(request, primary_principal); 398178825Sdfr if (ret) { 399178825Sdfr krb5_storage_free(request); 400178825Sdfr return ret; 401178825Sdfr } 402178825Sdfr 403178825Sdfr ret = kcm_call(context, k, request, NULL, NULL); 404178825Sdfr 405178825Sdfr krb5_storage_free(request); 406178825Sdfr return ret; 407178825Sdfr} 408178825Sdfr 409178825Sdfrstatic krb5_error_code 410178825Sdfrkcm_close(krb5_context context, 411178825Sdfr krb5_ccache id) 412178825Sdfr{ 413178825Sdfr kcm_free(context, &id); 414178825Sdfr return 0; 415178825Sdfr} 416178825Sdfr 417178825Sdfr/* 418178825Sdfr * Request: 419178825Sdfr * NameZ 420178825Sdfr * 421178825Sdfr * Response: 422178825Sdfr * 423178825Sdfr */ 424178825Sdfrstatic krb5_error_code 425178825Sdfrkcm_destroy(krb5_context context, 426178825Sdfr krb5_ccache id) 427178825Sdfr{ 428178825Sdfr krb5_error_code ret; 429178825Sdfr krb5_kcmcache *k = KCMCACHE(id); 430178825Sdfr krb5_storage *request; 431178825Sdfr 432178825Sdfr ret = kcm_storage_request(context, KCM_OP_DESTROY, &request); 433178825Sdfr if (ret) 434178825Sdfr return ret; 435178825Sdfr 436178825Sdfr ret = krb5_store_stringz(request, k->name); 437178825Sdfr if (ret) { 438178825Sdfr krb5_storage_free(request); 439178825Sdfr return ret; 440178825Sdfr } 441178825Sdfr 442178825Sdfr ret = kcm_call(context, k, request, NULL, NULL); 443178825Sdfr 444178825Sdfr krb5_storage_free(request); 445178825Sdfr return ret; 446178825Sdfr} 447178825Sdfr 448178825Sdfr/* 449178825Sdfr * Request: 450178825Sdfr * NameZ 451178825Sdfr * Creds 452178825Sdfr * 453178825Sdfr * Response: 454178825Sdfr * 455178825Sdfr */ 456178825Sdfrstatic krb5_error_code 457178825Sdfrkcm_store_cred(krb5_context context, 458178825Sdfr krb5_ccache id, 459178825Sdfr krb5_creds *creds) 460178825Sdfr{ 461178825Sdfr krb5_error_code ret; 462178825Sdfr krb5_kcmcache *k = KCMCACHE(id); 463178825Sdfr krb5_storage *request; 464178825Sdfr 465178825Sdfr ret = kcm_storage_request(context, KCM_OP_STORE, &request); 466178825Sdfr if (ret) 467178825Sdfr return ret; 468178825Sdfr 469178825Sdfr ret = krb5_store_stringz(request, k->name); 470178825Sdfr if (ret) { 471178825Sdfr krb5_storage_free(request); 472178825Sdfr return ret; 473178825Sdfr } 474178825Sdfr 475178825Sdfr ret = krb5_store_creds(request, creds); 476178825Sdfr if (ret) { 477178825Sdfr krb5_storage_free(request); 478178825Sdfr return ret; 479178825Sdfr } 480178825Sdfr 481178825Sdfr ret = kcm_call(context, k, request, NULL, NULL); 482178825Sdfr 483178825Sdfr krb5_storage_free(request); 484178825Sdfr return ret; 485178825Sdfr} 486178825Sdfr 487178825Sdfr/* 488178825Sdfr * Request: 489178825Sdfr * NameZ 490178825Sdfr * WhichFields 491178825Sdfr * MatchCreds 492178825Sdfr * 493178825Sdfr * Response: 494178825Sdfr * Creds 495178825Sdfr * 496178825Sdfr */ 497178825Sdfrstatic krb5_error_code 498178825Sdfrkcm_retrieve(krb5_context context, 499178825Sdfr krb5_ccache id, 500178825Sdfr krb5_flags which, 501178825Sdfr const krb5_creds *mcred, 502178825Sdfr krb5_creds *creds) 503178825Sdfr{ 504178825Sdfr krb5_error_code ret; 505178825Sdfr krb5_kcmcache *k = KCMCACHE(id); 506178825Sdfr krb5_storage *request, *response; 507178825Sdfr krb5_data response_data; 508178825Sdfr 509178825Sdfr ret = kcm_storage_request(context, KCM_OP_RETRIEVE, &request); 510178825Sdfr if (ret) 511178825Sdfr return ret; 512178825Sdfr 513178825Sdfr ret = krb5_store_stringz(request, k->name); 514178825Sdfr if (ret) { 515178825Sdfr krb5_storage_free(request); 516178825Sdfr return ret; 517178825Sdfr } 518178825Sdfr 519178825Sdfr ret = krb5_store_int32(request, which); 520178825Sdfr if (ret) { 521178825Sdfr krb5_storage_free(request); 522178825Sdfr return ret; 523178825Sdfr } 524178825Sdfr 525178825Sdfr ret = krb5_store_creds_tag(request, rk_UNCONST(mcred)); 526178825Sdfr if (ret) { 527178825Sdfr krb5_storage_free(request); 528178825Sdfr return ret; 529178825Sdfr } 530178825Sdfr 531178825Sdfr ret = kcm_call(context, k, request, &response, &response_data); 532178825Sdfr if (ret) { 533178825Sdfr krb5_storage_free(request); 534178825Sdfr return ret; 535178825Sdfr } 536178825Sdfr 537178825Sdfr ret = krb5_ret_creds(response, creds); 538178825Sdfr if (ret) 539178825Sdfr ret = KRB5_CC_IO; 540178825Sdfr 541178825Sdfr krb5_storage_free(request); 542178825Sdfr krb5_storage_free(response); 543178825Sdfr krb5_data_free(&response_data); 544178825Sdfr 545178825Sdfr return ret; 546178825Sdfr} 547178825Sdfr 548178825Sdfr/* 549178825Sdfr * Request: 550178825Sdfr * NameZ 551178825Sdfr * 552178825Sdfr * Response: 553178825Sdfr * Principal 554178825Sdfr */ 555178825Sdfrstatic krb5_error_code 556178825Sdfrkcm_get_principal(krb5_context context, 557178825Sdfr krb5_ccache id, 558178825Sdfr krb5_principal *principal) 559178825Sdfr{ 560178825Sdfr krb5_error_code ret; 561178825Sdfr krb5_kcmcache *k = KCMCACHE(id); 562178825Sdfr krb5_storage *request, *response; 563178825Sdfr krb5_data response_data; 564178825Sdfr 565178825Sdfr ret = kcm_storage_request(context, KCM_OP_GET_PRINCIPAL, &request); 566178825Sdfr if (ret) 567178825Sdfr return ret; 568178825Sdfr 569178825Sdfr ret = krb5_store_stringz(request, k->name); 570178825Sdfr if (ret) { 571178825Sdfr krb5_storage_free(request); 572178825Sdfr return ret; 573178825Sdfr } 574178825Sdfr 575178825Sdfr ret = kcm_call(context, k, request, &response, &response_data); 576178825Sdfr if (ret) { 577178825Sdfr krb5_storage_free(request); 578178825Sdfr return ret; 579178825Sdfr } 580178825Sdfr 581178825Sdfr ret = krb5_ret_principal(response, principal); 582178825Sdfr if (ret) 583178825Sdfr ret = KRB5_CC_IO; 584178825Sdfr 585178825Sdfr krb5_storage_free(request); 586178825Sdfr krb5_storage_free(response); 587178825Sdfr krb5_data_free(&response_data); 588178825Sdfr 589178825Sdfr return ret; 590178825Sdfr} 591178825Sdfr 592178825Sdfr/* 593178825Sdfr * Request: 594178825Sdfr * NameZ 595178825Sdfr * 596178825Sdfr * Response: 597178825Sdfr * Cursor 598178825Sdfr * 599178825Sdfr */ 600178825Sdfrstatic krb5_error_code 601178825Sdfrkcm_get_first (krb5_context context, 602178825Sdfr krb5_ccache id, 603178825Sdfr krb5_cc_cursor *cursor) 604178825Sdfr{ 605178825Sdfr krb5_error_code ret; 606178825Sdfr krb5_kcmcache *k = KCMCACHE(id); 607178825Sdfr krb5_storage *request, *response; 608178825Sdfr krb5_data response_data; 609178825Sdfr int32_t tmp; 610178825Sdfr 611178825Sdfr ret = kcm_storage_request(context, KCM_OP_GET_FIRST, &request); 612178825Sdfr if (ret) 613178825Sdfr return ret; 614178825Sdfr 615178825Sdfr ret = krb5_store_stringz(request, k->name); 616178825Sdfr if (ret) { 617178825Sdfr krb5_storage_free(request); 618178825Sdfr return ret; 619178825Sdfr } 620178825Sdfr 621178825Sdfr ret = kcm_call(context, k, request, &response, &response_data); 622178825Sdfr if (ret) { 623178825Sdfr krb5_storage_free(request); 624178825Sdfr return ret; 625178825Sdfr } 626178825Sdfr 627178825Sdfr ret = krb5_ret_int32(response, &tmp); 628178825Sdfr if (ret || tmp < 0) 629178825Sdfr ret = KRB5_CC_IO; 630178825Sdfr 631178825Sdfr krb5_storage_free(request); 632178825Sdfr krb5_storage_free(response); 633178825Sdfr krb5_data_free(&response_data); 634178825Sdfr 635178825Sdfr if (ret) 636178825Sdfr return ret; 637178825Sdfr 638178825Sdfr *cursor = malloc(sizeof(tmp)); 639178825Sdfr if (*cursor == NULL) 640178825Sdfr return KRB5_CC_NOMEM; 641178825Sdfr 642178825Sdfr KCMCURSOR(*cursor) = tmp; 643178825Sdfr 644178825Sdfr return 0; 645178825Sdfr} 646178825Sdfr 647178825Sdfr/* 648178825Sdfr * Request: 649178825Sdfr * NameZ 650178825Sdfr * Cursor 651178825Sdfr * 652178825Sdfr * Response: 653178825Sdfr * Creds 654178825Sdfr */ 655178825Sdfrstatic krb5_error_code 656178825Sdfrkcm_get_next (krb5_context context, 657178825Sdfr krb5_ccache id, 658178825Sdfr krb5_cc_cursor *cursor, 659178825Sdfr krb5_creds *creds) 660178825Sdfr{ 661178825Sdfr krb5_error_code ret; 662178825Sdfr krb5_kcmcache *k = KCMCACHE(id); 663178825Sdfr krb5_storage *request, *response; 664178825Sdfr krb5_data response_data; 665178825Sdfr 666178825Sdfr ret = kcm_storage_request(context, KCM_OP_GET_NEXT, &request); 667178825Sdfr if (ret) 668178825Sdfr return ret; 669178825Sdfr 670178825Sdfr ret = krb5_store_stringz(request, k->name); 671178825Sdfr if (ret) { 672178825Sdfr krb5_storage_free(request); 673178825Sdfr return ret; 674178825Sdfr } 675178825Sdfr 676178825Sdfr ret = krb5_store_int32(request, KCMCURSOR(*cursor)); 677178825Sdfr if (ret) { 678178825Sdfr krb5_storage_free(request); 679178825Sdfr return ret; 680178825Sdfr } 681178825Sdfr 682178825Sdfr ret = kcm_call(context, k, request, &response, &response_data); 683178825Sdfr if (ret) { 684178825Sdfr krb5_storage_free(request); 685178825Sdfr return ret; 686178825Sdfr } 687178825Sdfr 688178825Sdfr ret = krb5_ret_creds(response, creds); 689178825Sdfr if (ret) 690178825Sdfr ret = KRB5_CC_IO; 691178825Sdfr 692178825Sdfr krb5_storage_free(request); 693178825Sdfr krb5_storage_free(response); 694178825Sdfr krb5_data_free(&response_data); 695178825Sdfr 696178825Sdfr return ret; 697178825Sdfr} 698178825Sdfr 699178825Sdfr/* 700178825Sdfr * Request: 701178825Sdfr * NameZ 702178825Sdfr * Cursor 703178825Sdfr * 704178825Sdfr * Response: 705178825Sdfr * 706178825Sdfr */ 707178825Sdfrstatic krb5_error_code 708178825Sdfrkcm_end_get (krb5_context context, 709178825Sdfr krb5_ccache id, 710178825Sdfr krb5_cc_cursor *cursor) 711178825Sdfr{ 712178825Sdfr krb5_error_code ret; 713178825Sdfr krb5_kcmcache *k = KCMCACHE(id); 714178825Sdfr krb5_storage *request; 715178825Sdfr 716178825Sdfr ret = kcm_storage_request(context, KCM_OP_END_GET, &request); 717178825Sdfr if (ret) 718178825Sdfr return ret; 719178825Sdfr 720178825Sdfr ret = krb5_store_stringz(request, k->name); 721178825Sdfr if (ret) { 722178825Sdfr krb5_storage_free(request); 723178825Sdfr return ret; 724178825Sdfr } 725178825Sdfr 726178825Sdfr ret = krb5_store_int32(request, KCMCURSOR(*cursor)); 727178825Sdfr if (ret) { 728178825Sdfr krb5_storage_free(request); 729178825Sdfr return ret; 730178825Sdfr } 731178825Sdfr 732178825Sdfr ret = kcm_call(context, k, request, NULL, NULL); 733178825Sdfr if (ret) { 734178825Sdfr krb5_storage_free(request); 735178825Sdfr return ret; 736178825Sdfr } 737178825Sdfr 738178825Sdfr krb5_storage_free(request); 739178825Sdfr 740178825Sdfr KCMCURSOR(*cursor) = 0; 741178825Sdfr free(*cursor); 742178825Sdfr *cursor = NULL; 743178825Sdfr 744178825Sdfr return ret; 745178825Sdfr} 746178825Sdfr 747178825Sdfr/* 748178825Sdfr * Request: 749178825Sdfr * NameZ 750178825Sdfr * WhichFields 751178825Sdfr * MatchCreds 752178825Sdfr * 753178825Sdfr * Response: 754178825Sdfr * 755178825Sdfr */ 756178825Sdfrstatic krb5_error_code 757178825Sdfrkcm_remove_cred(krb5_context context, 758178825Sdfr krb5_ccache id, 759178825Sdfr krb5_flags which, 760178825Sdfr krb5_creds *cred) 761178825Sdfr{ 762178825Sdfr krb5_error_code ret; 763178825Sdfr krb5_kcmcache *k = KCMCACHE(id); 764178825Sdfr krb5_storage *request; 765178825Sdfr 766178825Sdfr ret = kcm_storage_request(context, KCM_OP_REMOVE_CRED, &request); 767178825Sdfr if (ret) 768178825Sdfr return ret; 769178825Sdfr 770178825Sdfr ret = krb5_store_stringz(request, k->name); 771178825Sdfr if (ret) { 772178825Sdfr krb5_storage_free(request); 773178825Sdfr return ret; 774178825Sdfr } 775178825Sdfr 776178825Sdfr ret = krb5_store_int32(request, which); 777178825Sdfr if (ret) { 778178825Sdfr krb5_storage_free(request); 779178825Sdfr return ret; 780178825Sdfr } 781178825Sdfr 782178825Sdfr ret = krb5_store_creds_tag(request, cred); 783178825Sdfr if (ret) { 784178825Sdfr krb5_storage_free(request); 785178825Sdfr return ret; 786178825Sdfr } 787178825Sdfr 788178825Sdfr ret = kcm_call(context, k, request, NULL, NULL); 789178825Sdfr 790178825Sdfr krb5_storage_free(request); 791178825Sdfr return ret; 792178825Sdfr} 793178825Sdfr 794178825Sdfrstatic krb5_error_code 795178825Sdfrkcm_set_flags(krb5_context context, 796178825Sdfr krb5_ccache id, 797178825Sdfr krb5_flags flags) 798178825Sdfr{ 799178825Sdfr krb5_error_code ret; 800178825Sdfr krb5_kcmcache *k = KCMCACHE(id); 801178825Sdfr krb5_storage *request; 802178825Sdfr 803178825Sdfr ret = kcm_storage_request(context, KCM_OP_SET_FLAGS, &request); 804178825Sdfr if (ret) 805178825Sdfr return ret; 806178825Sdfr 807178825Sdfr ret = krb5_store_stringz(request, k->name); 808178825Sdfr if (ret) { 809178825Sdfr krb5_storage_free(request); 810178825Sdfr return ret; 811178825Sdfr } 812178825Sdfr 813178825Sdfr ret = krb5_store_int32(request, flags); 814178825Sdfr if (ret) { 815178825Sdfr krb5_storage_free(request); 816178825Sdfr return ret; 817178825Sdfr } 818178825Sdfr 819178825Sdfr ret = kcm_call(context, k, request, NULL, NULL); 820178825Sdfr 821178825Sdfr krb5_storage_free(request); 822178825Sdfr return ret; 823178825Sdfr} 824178825Sdfr 825178825Sdfrstatic krb5_error_code 826178825Sdfrkcm_get_version(krb5_context context, 827178825Sdfr krb5_ccache id) 828178825Sdfr{ 829178825Sdfr return 0; 830178825Sdfr} 831178825Sdfr 832178825Sdfrstatic krb5_error_code 833178825Sdfrkcm_move(krb5_context context, krb5_ccache from, krb5_ccache to) 834178825Sdfr{ 835178825Sdfr krb5_set_error_string(context, "kcm_move not implemented"); 836178825Sdfr return EINVAL; 837178825Sdfr} 838178825Sdfr 839178825Sdfrstatic krb5_error_code 840178825Sdfrkcm_default_name(krb5_context context, char **str) 841178825Sdfr{ 842178825Sdfr return _krb5_expand_default_cc_name(context, 843178825Sdfr KRB5_DEFAULT_CCNAME_KCM, 844178825Sdfr str); 845178825Sdfr} 846178825Sdfr 847178825Sdfr/** 848178825Sdfr * Variable containing the KCM based credential cache implemention. 849178825Sdfr * 850178825Sdfr * @ingroup krb5_ccache 851178825Sdfr */ 852178825Sdfr 853178825Sdfrconst krb5_cc_ops krb5_kcm_ops = { 854178825Sdfr "KCM", 855178825Sdfr kcm_get_name, 856178825Sdfr kcm_resolve, 857178825Sdfr kcm_gen_new, 858178825Sdfr kcm_initialize, 859178825Sdfr kcm_destroy, 860178825Sdfr kcm_close, 861178825Sdfr kcm_store_cred, 862178825Sdfr kcm_retrieve, 863178825Sdfr kcm_get_principal, 864178825Sdfr kcm_get_first, 865178825Sdfr kcm_get_next, 866178825Sdfr kcm_end_get, 867178825Sdfr kcm_remove_cred, 868178825Sdfr kcm_set_flags, 869178825Sdfr kcm_get_version, 870178825Sdfr NULL, 871178825Sdfr NULL, 872178825Sdfr NULL, 873178825Sdfr kcm_move, 874178825Sdfr kcm_default_name 875178825Sdfr}; 876178825Sdfr 877178825Sdfrkrb5_boolean 878178825Sdfr_krb5_kcm_is_running(krb5_context context) 879178825Sdfr{ 880178825Sdfr krb5_error_code ret; 881178825Sdfr krb5_ccache_data ccdata; 882178825Sdfr krb5_ccache id = &ccdata; 883178825Sdfr krb5_boolean running; 884178825Sdfr 885178825Sdfr ret = kcm_alloc(context, NULL, &id); 886178825Sdfr if (ret) 887178825Sdfr return 0; 888178825Sdfr 889178825Sdfr running = (_krb5_kcm_noop(context, id) == 0); 890178825Sdfr 891178825Sdfr kcm_free(context, &id); 892178825Sdfr 893178825Sdfr return running; 894178825Sdfr} 895178825Sdfr 896178825Sdfr/* 897178825Sdfr * Request: 898178825Sdfr * 899178825Sdfr * Response: 900178825Sdfr * 901178825Sdfr */ 902178825Sdfrkrb5_error_code 903178825Sdfr_krb5_kcm_noop(krb5_context context, 904178825Sdfr krb5_ccache id) 905178825Sdfr{ 906178825Sdfr krb5_error_code ret; 907178825Sdfr krb5_kcmcache *k = KCMCACHE(id); 908178825Sdfr krb5_storage *request; 909178825Sdfr 910178825Sdfr ret = kcm_storage_request(context, KCM_OP_NOOP, &request); 911178825Sdfr if (ret) 912178825Sdfr return ret; 913178825Sdfr 914178825Sdfr ret = kcm_call(context, k, request, NULL, NULL); 915178825Sdfr 916178825Sdfr krb5_storage_free(request); 917178825Sdfr return ret; 918178825Sdfr} 919178825Sdfr 920178825Sdfr 921178825Sdfr/* 922178825Sdfr * Request: 923178825Sdfr * NameZ 924178825Sdfr * Mode 925178825Sdfr * 926178825Sdfr * Response: 927178825Sdfr * 928178825Sdfr */ 929178825Sdfrkrb5_error_code 930178825Sdfr_krb5_kcm_chmod(krb5_context context, 931178825Sdfr krb5_ccache id, 932178825Sdfr uint16_t mode) 933178825Sdfr{ 934178825Sdfr krb5_error_code ret; 935178825Sdfr krb5_kcmcache *k = KCMCACHE(id); 936178825Sdfr krb5_storage *request; 937178825Sdfr 938178825Sdfr ret = kcm_storage_request(context, KCM_OP_CHMOD, &request); 939178825Sdfr if (ret) 940178825Sdfr return ret; 941178825Sdfr 942178825Sdfr ret = krb5_store_stringz(request, k->name); 943178825Sdfr if (ret) { 944178825Sdfr krb5_storage_free(request); 945178825Sdfr return ret; 946178825Sdfr } 947178825Sdfr 948178825Sdfr ret = krb5_store_int16(request, mode); 949178825Sdfr if (ret) { 950178825Sdfr krb5_storage_free(request); 951178825Sdfr return ret; 952178825Sdfr } 953178825Sdfr 954178825Sdfr ret = kcm_call(context, k, request, NULL, NULL); 955178825Sdfr 956178825Sdfr krb5_storage_free(request); 957178825Sdfr return ret; 958178825Sdfr} 959178825Sdfr 960178825Sdfr 961178825Sdfr/* 962178825Sdfr * Request: 963178825Sdfr * NameZ 964178825Sdfr * UID 965178825Sdfr * GID 966178825Sdfr * 967178825Sdfr * Response: 968178825Sdfr * 969178825Sdfr */ 970178825Sdfrkrb5_error_code 971178825Sdfr_krb5_kcm_chown(krb5_context context, 972178825Sdfr krb5_ccache id, 973178825Sdfr uint32_t uid, 974178825Sdfr uint32_t gid) 975178825Sdfr{ 976178825Sdfr krb5_error_code ret; 977178825Sdfr krb5_kcmcache *k = KCMCACHE(id); 978178825Sdfr krb5_storage *request; 979178825Sdfr 980178825Sdfr ret = kcm_storage_request(context, KCM_OP_CHOWN, &request); 981178825Sdfr if (ret) 982178825Sdfr return ret; 983178825Sdfr 984178825Sdfr ret = krb5_store_stringz(request, k->name); 985178825Sdfr if (ret) { 986178825Sdfr krb5_storage_free(request); 987178825Sdfr return ret; 988178825Sdfr } 989178825Sdfr 990178825Sdfr ret = krb5_store_int32(request, uid); 991178825Sdfr if (ret) { 992178825Sdfr krb5_storage_free(request); 993178825Sdfr return ret; 994178825Sdfr } 995178825Sdfr 996178825Sdfr ret = krb5_store_int32(request, gid); 997178825Sdfr if (ret) { 998178825Sdfr krb5_storage_free(request); 999178825Sdfr return ret; 1000178825Sdfr } 1001178825Sdfr 1002178825Sdfr ret = kcm_call(context, k, request, NULL, NULL); 1003178825Sdfr 1004178825Sdfr krb5_storage_free(request); 1005178825Sdfr return ret; 1006178825Sdfr} 1007178825Sdfr 1008178825Sdfr 1009178825Sdfr/* 1010178825Sdfr * Request: 1011178825Sdfr * NameZ 1012178825Sdfr * ServerPrincipalPresent 1013178825Sdfr * ServerPrincipal OPTIONAL 1014178825Sdfr * Key 1015178825Sdfr * 1016178825Sdfr * Repsonse: 1017178825Sdfr * 1018178825Sdfr */ 1019178825Sdfrkrb5_error_code 1020178825Sdfr_krb5_kcm_get_initial_ticket(krb5_context context, 1021178825Sdfr krb5_ccache id, 1022178825Sdfr krb5_principal server, 1023178825Sdfr krb5_keyblock *key) 1024178825Sdfr{ 1025178825Sdfr krb5_error_code ret; 1026178825Sdfr krb5_kcmcache *k = KCMCACHE(id); 1027178825Sdfr krb5_storage *request; 1028178825Sdfr 1029178825Sdfr ret = kcm_storage_request(context, KCM_OP_GET_INITIAL_TICKET, &request); 1030178825Sdfr if (ret) 1031178825Sdfr return ret; 1032178825Sdfr 1033178825Sdfr ret = krb5_store_stringz(request, k->name); 1034178825Sdfr if (ret) { 1035178825Sdfr krb5_storage_free(request); 1036178825Sdfr return ret; 1037178825Sdfr } 1038178825Sdfr 1039178825Sdfr ret = krb5_store_int8(request, (server == NULL) ? 0 : 1); 1040178825Sdfr if (ret) { 1041178825Sdfr krb5_storage_free(request); 1042178825Sdfr return ret; 1043178825Sdfr } 1044178825Sdfr 1045178825Sdfr if (server != NULL) { 1046178825Sdfr ret = krb5_store_principal(request, server); 1047178825Sdfr if (ret) { 1048178825Sdfr krb5_storage_free(request); 1049178825Sdfr return ret; 1050178825Sdfr } 1051178825Sdfr } 1052178825Sdfr 1053178825Sdfr ret = krb5_store_keyblock(request, *key); 1054178825Sdfr if (ret) { 1055178825Sdfr krb5_storage_free(request); 1056178825Sdfr return ret; 1057178825Sdfr } 1058178825Sdfr 1059178825Sdfr ret = kcm_call(context, k, request, NULL, NULL); 1060178825Sdfr 1061178825Sdfr krb5_storage_free(request); 1062178825Sdfr return ret; 1063178825Sdfr} 1064178825Sdfr 1065178825Sdfr 1066178825Sdfr/* 1067178825Sdfr * Request: 1068178825Sdfr * NameZ 1069178825Sdfr * KDCFlags 1070178825Sdfr * EncryptionType 1071178825Sdfr * ServerPrincipal 1072178825Sdfr * 1073178825Sdfr * Repsonse: 1074178825Sdfr * 1075178825Sdfr */ 1076178825Sdfrkrb5_error_code 1077178825Sdfr_krb5_kcm_get_ticket(krb5_context context, 1078178825Sdfr krb5_ccache id, 1079178825Sdfr krb5_kdc_flags flags, 1080178825Sdfr krb5_enctype enctype, 1081178825Sdfr krb5_principal server) 1082178825Sdfr{ 1083178825Sdfr krb5_error_code ret; 1084178825Sdfr krb5_kcmcache *k = KCMCACHE(id); 1085178825Sdfr krb5_storage *request; 1086178825Sdfr 1087178825Sdfr ret = kcm_storage_request(context, KCM_OP_GET_TICKET, &request); 1088178825Sdfr if (ret) 1089178825Sdfr return ret; 1090178825Sdfr 1091178825Sdfr ret = krb5_store_stringz(request, k->name); 1092178825Sdfr if (ret) { 1093178825Sdfr krb5_storage_free(request); 1094178825Sdfr return ret; 1095178825Sdfr } 1096178825Sdfr 1097178825Sdfr ret = krb5_store_int32(request, flags.i); 1098178825Sdfr if (ret) { 1099178825Sdfr krb5_storage_free(request); 1100178825Sdfr return ret; 1101178825Sdfr } 1102178825Sdfr 1103178825Sdfr ret = krb5_store_int32(request, enctype); 1104178825Sdfr if (ret) { 1105178825Sdfr krb5_storage_free(request); 1106178825Sdfr return ret; 1107178825Sdfr } 1108178825Sdfr 1109178825Sdfr ret = krb5_store_principal(request, server); 1110178825Sdfr if (ret) { 1111178825Sdfr krb5_storage_free(request); 1112178825Sdfr return ret; 1113178825Sdfr } 1114178825Sdfr 1115178825Sdfr ret = kcm_call(context, k, request, NULL, NULL); 1116178825Sdfr 1117178825Sdfr krb5_storage_free(request); 1118178825Sdfr return ret; 1119178825Sdfr} 1120178825Sdfr 1121178825Sdfr 1122178825Sdfr#endif /* HAVE_KCM */ 1123