155682Smarkm/* 2233294Sstas * Copyright (c) 1997 - 2006 Kungliga Tekniska H��gskolan 3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden). 4233294Sstas * All rights reserved. 555682Smarkm * 6233294Sstas * Redistribution and use in source and binary forms, with or without 7233294Sstas * modification, are permitted provided that the following conditions 8233294Sstas * are met: 955682Smarkm * 10233294Sstas * 1. Redistributions of source code must retain the above copyright 11233294Sstas * notice, this list of conditions and the following disclaimer. 1255682Smarkm * 13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright 14233294Sstas * notice, this list of conditions and the following disclaimer in the 15233294Sstas * documentation and/or other materials provided with the distribution. 1655682Smarkm * 17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors 18233294Sstas * may be used to endorse or promote products derived from this software 19233294Sstas * without specific prior written permission. 2055682Smarkm * 21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24233294Sstas * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31233294Sstas * SUCH DAMAGE. 3255682Smarkm */ 3355682Smarkm 3455682Smarkm#include "kadm5_locl.h" 3555682Smarkm#include <sys/types.h> 36233294Sstas#ifdef HAVE_SYS_SOCKET_H 3755682Smarkm#include <sys/socket.h> 38233294Sstas#endif 39233294Sstas#ifdef HAVE_NETINET_IN_H 4055682Smarkm#include <netinet/in.h> 41233294Sstas#endif 42233294Sstas#ifdef HAVE_NETDB_H 4355682Smarkm#include <netdb.h> 44233294Sstas#endif 4555682Smarkm 46233294SstasRCSID("$Id$"); 4755682Smarkm 4855682Smarkmstatic void 4955682Smarkmset_funcs(kadm5_client_context *c) 5055682Smarkm{ 5155682Smarkm#define SET(C, F) (C)->funcs.F = kadm5 ## _c_ ## F 5255682Smarkm SET(c, chpass_principal); 5372445Sassar SET(c, chpass_principal_with_key); 5455682Smarkm SET(c, create_principal); 5555682Smarkm SET(c, delete_principal); 5655682Smarkm SET(c, destroy); 5755682Smarkm SET(c, flush); 5855682Smarkm SET(c, get_principal); 5955682Smarkm SET(c, get_principals); 6055682Smarkm SET(c, get_privs); 6155682Smarkm SET(c, modify_principal); 6255682Smarkm SET(c, randkey_principal); 6355682Smarkm SET(c, rename_principal); 6455682Smarkm} 6555682Smarkm 6655682Smarkmkadm5_ret_t 67233294Sstas_kadm5_c_init_context(kadm5_client_context **ctx, 6855682Smarkm kadm5_config_params *params, 6955682Smarkm krb5_context context) 7055682Smarkm{ 7155682Smarkm krb5_error_code ret; 7255682Smarkm char *colon; 7355682Smarkm 7455682Smarkm *ctx = malloc(sizeof(**ctx)); 7555682Smarkm if(*ctx == NULL) 7655682Smarkm return ENOMEM; 7755682Smarkm memset(*ctx, 0, sizeof(**ctx)); 7855682Smarkm krb5_add_et_list (context, initialize_kadm5_error_table_r); 7955682Smarkm set_funcs(*ctx); 8055682Smarkm (*ctx)->context = context; 81127808Snectar if(params->mask & KADM5_CONFIG_REALM) { 82127808Snectar ret = 0; 8355682Smarkm (*ctx)->realm = strdup(params->realm); 84127808Snectar if ((*ctx)->realm == NULL) 85127808Snectar ret = ENOMEM; 86127808Snectar } else 87127808Snectar ret = krb5_get_default_realm((*ctx)->context, &(*ctx)->realm); 88127808Snectar if (ret) { 89127808Snectar free(*ctx); 90127808Snectar return ret; 91127808Snectar } 9255682Smarkm if(params->mask & KADM5_CONFIG_ADMIN_SERVER) 9355682Smarkm (*ctx)->admin_server = strdup(params->admin_server); 9455682Smarkm else { 9555682Smarkm char **hostlist; 9655682Smarkm 9755682Smarkm ret = krb5_get_krb_admin_hst (context, &(*ctx)->realm, &hostlist); 98127808Snectar if (ret) { 99127808Snectar free((*ctx)->realm); 100127808Snectar free(*ctx); 10155682Smarkm return ret; 102127808Snectar } 10355682Smarkm (*ctx)->admin_server = strdup(*hostlist); 10455682Smarkm krb5_free_krbhst (context, hostlist); 10555682Smarkm } 10655682Smarkm 107127808Snectar if ((*ctx)->admin_server == NULL) { 108127808Snectar free((*ctx)->realm); 109127808Snectar free(*ctx); 110178825Sdfr return ENOMEM; 111127808Snectar } 11255682Smarkm colon = strchr ((*ctx)->admin_server, ':'); 11355682Smarkm if (colon != NULL) 11455682Smarkm *colon++ = '\0'; 11555682Smarkm 11655682Smarkm (*ctx)->kadmind_port = 0; 11755682Smarkm 11855682Smarkm if(params->mask & KADM5_CONFIG_KADMIND_PORT) 11955682Smarkm (*ctx)->kadmind_port = params->kadmind_port; 12055682Smarkm else if (colon != NULL) { 12155682Smarkm char *end; 12255682Smarkm 12355682Smarkm (*ctx)->kadmind_port = htons(strtol (colon, &end, 0)); 12455682Smarkm } 12555682Smarkm if ((*ctx)->kadmind_port == 0) 126233294Sstas (*ctx)->kadmind_port = krb5_getportbyname (context, "kerberos-adm", 12755682Smarkm "tcp", 749); 12855682Smarkm return 0; 12955682Smarkm} 13055682Smarkm 13155682Smarkmstatic krb5_error_code 13255682Smarkmget_kadm_ticket(krb5_context context, 13355682Smarkm krb5_ccache id, 13455682Smarkm krb5_principal client, 13555682Smarkm const char *server_name) 13655682Smarkm{ 13755682Smarkm krb5_error_code ret; 13855682Smarkm krb5_creds in, *out; 139233294Sstas 14055682Smarkm memset(&in, 0, sizeof(in)); 14155682Smarkm in.client = client; 14255682Smarkm ret = krb5_parse_name(context, server_name, &in.server); 143233294Sstas if(ret) 14455682Smarkm return ret; 14555682Smarkm ret = krb5_get_credentials(context, 0, id, &in, &out); 14655682Smarkm if(ret == 0) 14755682Smarkm krb5_free_creds(context, out); 14855682Smarkm krb5_free_principal(context, in.server); 14955682Smarkm return ret; 15055682Smarkm} 15155682Smarkm 15255682Smarkmstatic krb5_error_code 15355682Smarkmget_new_cache(krb5_context context, 15455682Smarkm krb5_principal client, 15555682Smarkm const char *password, 15655682Smarkm krb5_prompter_fct prompter, 15755682Smarkm const char *keytab, 15855682Smarkm const char *server_name, 15955682Smarkm krb5_ccache *ret_cache) 16055682Smarkm{ 16155682Smarkm krb5_error_code ret; 16255682Smarkm krb5_creds cred; 163178825Sdfr krb5_get_init_creds_opt *opt; 16455682Smarkm krb5_ccache id; 165233294Sstas 166178825Sdfr ret = krb5_get_init_creds_opt_alloc (context, &opt); 167178825Sdfr if (ret) 168178825Sdfr return ret; 16990926Snectar 170233294Sstas krb5_get_init_creds_opt_set_default_flags(context, "kadmin", 171233294Sstas krb5_principal_get_realm(context, 172233294Sstas client), 173178825Sdfr opt); 17490926Snectar 17590926Snectar 176178825Sdfr krb5_get_init_creds_opt_set_forwardable (opt, FALSE); 177178825Sdfr krb5_get_init_creds_opt_set_proxiable (opt, FALSE); 17857416Smarkm 17955682Smarkm if(password == NULL && prompter == NULL) { 18055682Smarkm krb5_keytab kt; 18155682Smarkm if(keytab == NULL) 18255682Smarkm ret = krb5_kt_default(context, &kt); 18355682Smarkm else 18455682Smarkm ret = krb5_kt_resolve(context, keytab, &kt); 185178825Sdfr if(ret) { 186178825Sdfr krb5_get_init_creds_opt_free(context, opt); 18755682Smarkm return ret; 188178825Sdfr } 18955682Smarkm ret = krb5_get_init_creds_keytab (context, 19055682Smarkm &cred, 19155682Smarkm client, 19255682Smarkm kt, 19355682Smarkm 0, 19455682Smarkm server_name, 195178825Sdfr opt); 19655682Smarkm krb5_kt_close(context, kt); 19755682Smarkm } else { 19855682Smarkm ret = krb5_get_init_creds_password (context, 19955682Smarkm &cred, 20055682Smarkm client, 20155682Smarkm password, 20255682Smarkm prompter, 20355682Smarkm NULL, 20455682Smarkm 0, 20555682Smarkm server_name, 206178825Sdfr opt); 20755682Smarkm } 208178825Sdfr krb5_get_init_creds_opt_free(context, opt); 20955682Smarkm switch(ret){ 21055682Smarkm case 0: 21155682Smarkm break; 21255682Smarkm case KRB5_LIBOS_PWDINTR: /* don't print anything if it was just C-c:ed */ 21355682Smarkm case KRB5KRB_AP_ERR_BAD_INTEGRITY: 21455682Smarkm case KRB5KRB_AP_ERR_MODIFIED: 21555682Smarkm return KADM5_BAD_PASSWORD; 21655682Smarkm default: 21755682Smarkm return ret; 21855682Smarkm } 219233294Sstas ret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &id); 22055682Smarkm if(ret) 22155682Smarkm return ret; 22255682Smarkm ret = krb5_cc_initialize (context, id, cred.client); 22355682Smarkm if (ret) 22455682Smarkm return ret; 22555682Smarkm ret = krb5_cc_store_cred (context, id, &cred); 22655682Smarkm if (ret) 22755682Smarkm return ret; 228178825Sdfr krb5_free_cred_contents (context, &cred); 22955682Smarkm *ret_cache = id; 23055682Smarkm return 0; 23155682Smarkm} 23255682Smarkm 233178825Sdfr/* 234233294Sstas * Check the credential cache `id�� to figure out what principal to use 235178825Sdfr * when talking to the kadmind. If there is a initial kadmin/admin@ 236178825Sdfr * credential in the cache, use that client principal. Otherwise, use 237178825Sdfr * the client principals first component and add /admin to the 238178825Sdfr * principal. 239178825Sdfr */ 240178825Sdfr 24155682Smarkmstatic krb5_error_code 242178825Sdfrget_cache_principal(krb5_context context, 243178825Sdfr krb5_ccache *id, 244178825Sdfr krb5_principal *client) 24555682Smarkm{ 24655682Smarkm krb5_error_code ret; 247178825Sdfr const char *name, *inst; 248178825Sdfr krb5_principal p1, p2; 249178825Sdfr 250178825Sdfr ret = krb5_cc_default(context, id); 251178825Sdfr if(ret) { 252178825Sdfr *id = NULL; 253178825Sdfr return ret; 254178825Sdfr } 255233294Sstas 256178825Sdfr ret = krb5_cc_get_principal(context, *id, &p1); 257178825Sdfr if(ret) { 258178825Sdfr krb5_cc_close(context, *id); 259178825Sdfr *id = NULL; 260178825Sdfr return ret; 261178825Sdfr } 262178825Sdfr 263233294Sstas ret = krb5_make_principal(context, &p2, NULL, 264178825Sdfr "kadmin", "admin", NULL); 265178825Sdfr if (ret) { 266178825Sdfr krb5_cc_close(context, *id); 267178825Sdfr *id = NULL; 268178825Sdfr krb5_free_principal(context, p1); 269178825Sdfr return ret; 270178825Sdfr } 271178825Sdfr 272178825Sdfr { 273178825Sdfr krb5_creds in, *out; 274178825Sdfr krb5_kdc_flags flags; 275178825Sdfr 276178825Sdfr flags.i = 0; 277178825Sdfr memset(&in, 0, sizeof(in)); 278178825Sdfr 279178825Sdfr in.client = p1; 280178825Sdfr in.server = p2; 281178825Sdfr 282178825Sdfr /* check for initial ticket kadmin/admin */ 283178825Sdfr ret = krb5_get_credentials_with_flags(context, KRB5_GC_CACHED, flags, 284178825Sdfr *id, &in, &out); 285178825Sdfr krb5_free_principal(context, p2); 286178825Sdfr if (ret == 0) { 287178825Sdfr if (out->flags.b.initial) { 288178825Sdfr *client = p1; 289178825Sdfr krb5_free_creds(context, out); 290178825Sdfr return 0; 291178825Sdfr } 292178825Sdfr krb5_free_creds(context, out); 293178825Sdfr } 294178825Sdfr } 295178825Sdfr krb5_cc_close(context, *id); 296178825Sdfr *id = NULL; 297178825Sdfr 298178825Sdfr name = krb5_principal_get_comp_string(context, p1, 0); 299178825Sdfr inst = krb5_principal_get_comp_string(context, p1, 1); 300178825Sdfr if(inst == NULL || strcmp(inst, "admin") != 0) { 301178825Sdfr ret = krb5_make_principal(context, &p2, NULL, name, "admin", NULL); 302178825Sdfr krb5_free_principal(context, p1); 303178825Sdfr if(ret != 0) 304178825Sdfr return ret; 305178825Sdfr 306178825Sdfr *client = p2; 307178825Sdfr return 0; 308178825Sdfr } 309178825Sdfr 310178825Sdfr *client = p1; 311178825Sdfr 312178825Sdfr return 0; 313178825Sdfr} 314178825Sdfr 315178825Sdfrkrb5_error_code 316178825Sdfr_kadm5_c_get_cred_cache(krb5_context context, 317178825Sdfr const char *client_name, 318178825Sdfr const char *server_name, 319178825Sdfr const char *password, 320178825Sdfr krb5_prompter_fct prompter, 321178825Sdfr const char *keytab, 322178825Sdfr krb5_ccache ccache, 323178825Sdfr krb5_ccache *ret_cache) 324178825Sdfr{ 325178825Sdfr krb5_error_code ret; 32655682Smarkm krb5_ccache id = NULL; 32755682Smarkm krb5_principal default_client = NULL, client = NULL; 328233294Sstas 32955682Smarkm /* treat empty password as NULL */ 33055682Smarkm if(password && *password == '\0') 33155682Smarkm password = NULL; 33255682Smarkm if(server_name == NULL) 33355682Smarkm server_name = KADM5_ADMIN_SERVICE; 334233294Sstas 33555682Smarkm if(client_name != NULL) { 33655682Smarkm ret = krb5_parse_name(context, client_name, &client); 337233294Sstas if(ret) 33855682Smarkm return ret; 33955682Smarkm } 34055682Smarkm 341178825Sdfr if(ccache != NULL) { 342178825Sdfr id = ccache; 343178825Sdfr ret = krb5_cc_get_principal(context, id, &client); 344178825Sdfr if(ret) 345178825Sdfr return ret; 346178825Sdfr } else { 34755682Smarkm /* get principal from default cache, ok if this doesn't work */ 348102644Snectar 349178825Sdfr ret = get_cache_principal(context, &id, &default_client); 350178825Sdfr if (ret) { 351233294Sstas /* 352178825Sdfr * No client was specified by the caller and we cannot 353178825Sdfr * determine the client from a credentials cache. 354102644Snectar */ 35555682Smarkm const char *user; 35655682Smarkm 35755682Smarkm user = get_default_username (); 35855682Smarkm 359178825Sdfr if(user == NULL) { 360233294Sstas krb5_set_error_message(context, KADM5_FAILURE, "Unable to find local user name"); 36155682Smarkm return KADM5_FAILURE; 362178825Sdfr } 363233294Sstas ret = krb5_make_principal(context, &default_client, 36455682Smarkm NULL, user, "admin", NULL); 36555682Smarkm if(ret) 36655682Smarkm return ret; 36755682Smarkm } 368178825Sdfr } 369178825Sdfr 370178825Sdfr 371178825Sdfr /* 372178825Sdfr * No client was specified by the caller, but we have a client 373178825Sdfr * from the default credentials cache. 374178825Sdfr */ 375178825Sdfr if (client == NULL && default_client != NULL) 376178825Sdfr client = default_client; 377178825Sdfr 378233294Sstas 379233294Sstas if(id && client && (default_client == NULL || 380233294Sstas krb5_principal_compare(context, client, default_client) != 0)) { 38155682Smarkm ret = get_kadm_ticket(context, id, client, server_name); 38255682Smarkm if(ret == 0) { 38355682Smarkm *ret_cache = id; 38455682Smarkm krb5_free_principal(context, default_client); 38555682Smarkm if (default_client != client) 38655682Smarkm krb5_free_principal(context, client); 38755682Smarkm return 0; 38855682Smarkm } 38955682Smarkm if(ccache != NULL) 39055682Smarkm /* couldn't get ticket from cache */ 39155682Smarkm return -1; 39255682Smarkm } 39355682Smarkm /* get creds via AS request */ 394178825Sdfr if(id && (id != ccache)) 39555682Smarkm krb5_cc_close(context, id); 39655682Smarkm if (client != default_client) 39755682Smarkm krb5_free_principal(context, default_client); 39855682Smarkm 399233294Sstas ret = get_new_cache(context, client, password, prompter, keytab, 40055682Smarkm server_name, ret_cache); 40155682Smarkm krb5_free_principal(context, client); 40255682Smarkm return ret; 40355682Smarkm} 40455682Smarkm 40572445Sassarstatic kadm5_ret_t 40672445Sassarkadm_connect(kadm5_client_context *ctx) 40755682Smarkm{ 40855682Smarkm kadm5_ret_t ret; 40955682Smarkm krb5_principal server; 41055682Smarkm krb5_ccache cc; 411233294Sstas rk_socket_t s = rk_INVALID_SOCKET; 41255682Smarkm struct addrinfo *ai, *a; 41355682Smarkm struct addrinfo hints; 41455682Smarkm int error; 41555682Smarkm char portstr[NI_MAXSERV]; 41655682Smarkm char *hostname, *slash; 417120945Snectar char *service_name; 41872445Sassar krb5_context context = ctx->context; 41955682Smarkm 42055682Smarkm memset (&hints, 0, sizeof(hints)); 42155682Smarkm hints.ai_socktype = SOCK_STREAM; 42255682Smarkm hints.ai_protocol = IPPROTO_TCP; 423233294Sstas 42455682Smarkm snprintf (portstr, sizeof(portstr), "%u", ntohs(ctx->kadmind_port)); 42555682Smarkm 42655682Smarkm hostname = ctx->admin_server; 42755682Smarkm slash = strchr (hostname, '/'); 42855682Smarkm if (slash != NULL) 42955682Smarkm hostname = slash + 1; 43055682Smarkm 43155682Smarkm error = getaddrinfo (hostname, portstr, &hints, &ai); 432178825Sdfr if (error) { 433233294Sstas krb5_clear_error_message(context); 43455682Smarkm return KADM5_BAD_SERVER_NAME; 435178825Sdfr } 436233294Sstas 43755682Smarkm for (a = ai; a != NULL; a = a->ai_next) { 43855682Smarkm s = socket (a->ai_family, a->ai_socktype, a->ai_protocol); 43955682Smarkm if (s < 0) 44055682Smarkm continue; 44155682Smarkm if (connect (s, a->ai_addr, a->ai_addrlen) < 0) { 442233294Sstas krb5_clear_error_message(context); 44355682Smarkm krb5_warn (context, errno, "connect(%s)", hostname); 444233294Sstas rk_closesocket (s); 44555682Smarkm continue; 44655682Smarkm } 44755682Smarkm break; 44855682Smarkm } 44955682Smarkm if (a == NULL) { 45055682Smarkm freeaddrinfo (ai); 451233294Sstas krb5_clear_error_message(context); 45255682Smarkm krb5_warnx (context, "failed to contact %s", hostname); 45355682Smarkm return KADM5_FAILURE; 45455682Smarkm } 455178825Sdfr ret = _kadm5_c_get_cred_cache(context, 456233294Sstas ctx->client_name, 457233294Sstas ctx->service_name, 458233294Sstas NULL, ctx->prompter, ctx->keytab, 459178825Sdfr ctx->ccache, &cc); 460233294Sstas 46155682Smarkm if(ret) { 46255682Smarkm freeaddrinfo (ai); 463233294Sstas rk_closesocket(s); 46455682Smarkm return ret; 46555682Smarkm } 466120945Snectar 467120945Snectar if (ctx->realm) 468120945Snectar asprintf(&service_name, "%s@%s", KADM5_ADMIN_SERVICE, ctx->realm); 469120945Snectar else 470120945Snectar asprintf(&service_name, "%s", KADM5_ADMIN_SERVICE); 471120945Snectar 472120945Snectar if (service_name == NULL) { 473120945Snectar freeaddrinfo (ai); 474233294Sstas rk_closesocket(s); 475233294Sstas krb5_clear_error_message(context); 476120945Snectar return ENOMEM; 477120945Snectar } 478120945Snectar 479120945Snectar ret = krb5_parse_name(context, service_name, &server); 480120945Snectar free(service_name); 48155682Smarkm if(ret) { 48255682Smarkm freeaddrinfo (ai); 48372445Sassar if(ctx->ccache == NULL) 48455682Smarkm krb5_cc_close(context, cc); 485233294Sstas rk_closesocket(s); 48655682Smarkm return ret; 48755682Smarkm } 48855682Smarkm ctx->ac = NULL; 48955682Smarkm 490233294Sstas ret = krb5_sendauth(context, &ctx->ac, &s, 491233294Sstas KADMIN_APPL_VERSION, NULL, 492233294Sstas server, AP_OPTS_MUTUAL_REQUIRED, 49355682Smarkm NULL, NULL, cc, NULL, NULL, NULL); 49455682Smarkm if(ret == 0) { 49572445Sassar krb5_data params; 49690926Snectar kadm5_config_params p; 49790926Snectar memset(&p, 0, sizeof(p)); 49890926Snectar if(ctx->realm) { 49990926Snectar p.mask |= KADM5_CONFIG_REALM; 50090926Snectar p.realm = ctx->realm; 50190926Snectar } 50290926Snectar ret = _kadm5_marshal_params(context, &p, ¶ms); 503233294Sstas 50472445Sassar ret = krb5_write_priv_message(context, ctx->ac, &s, ¶ms); 50555682Smarkm krb5_data_free(¶ms); 50672445Sassar if(ret) { 50772445Sassar freeaddrinfo (ai); 508233294Sstas rk_closesocket(s); 50972445Sassar if(ctx->ccache == NULL) 51072445Sassar krb5_cc_close(context, cc); 51172445Sassar return ret; 51272445Sassar } 51355682Smarkm } else if(ret == KRB5_SENDAUTH_BADAPPLVERS) { 514233294Sstas rk_closesocket(s); 51555682Smarkm 51655682Smarkm s = socket (a->ai_family, a->ai_socktype, a->ai_protocol); 51755682Smarkm if (s < 0) { 51855682Smarkm freeaddrinfo (ai); 519233294Sstas krb5_clear_error_message(context); 52055682Smarkm return errno; 52155682Smarkm } 52255682Smarkm if (connect (s, a->ai_addr, a->ai_addrlen) < 0) { 523233294Sstas rk_closesocket (s); 52455682Smarkm freeaddrinfo (ai); 525233294Sstas krb5_clear_error_message(context); 52655682Smarkm return errno; 52755682Smarkm } 528233294Sstas ret = krb5_sendauth(context, &ctx->ac, &s, 529233294Sstas KADMIN_OLD_APPL_VERSION, NULL, 530233294Sstas server, AP_OPTS_MUTUAL_REQUIRED, 53155682Smarkm NULL, NULL, cc, NULL, NULL, NULL); 53255682Smarkm } 53355682Smarkm freeaddrinfo (ai); 53455682Smarkm if(ret) { 535233294Sstas rk_closesocket(s); 53655682Smarkm return ret; 53755682Smarkm } 538233294Sstas 53955682Smarkm krb5_free_principal(context, server); 54072445Sassar if(ctx->ccache == NULL) 54155682Smarkm krb5_cc_close(context, cc); 54255682Smarkm ctx->sock = s; 543233294Sstas 54472445Sassar return 0; 54572445Sassar} 54672445Sassar 54772445Sassarkadm5_ret_t 54872445Sassar_kadm5_connect(void *handle) 54972445Sassar{ 55072445Sassar kadm5_client_context *ctx = handle; 55172445Sassar if(ctx->sock == -1) 55272445Sassar return kadm_connect(ctx); 55372445Sassar return 0; 55472445Sassar} 55572445Sassar 556233294Sstasstatic kadm5_ret_t 55772445Sassarkadm5_c_init_with_context(krb5_context context, 558233294Sstas const char *client_name, 55972445Sassar const char *password, 56072445Sassar krb5_prompter_fct prompter, 56172445Sassar const char *keytab, 56272445Sassar krb5_ccache ccache, 56372445Sassar const char *service_name, 56472445Sassar kadm5_config_params *realm_params, 56572445Sassar unsigned long struct_version, 56672445Sassar unsigned long api_version, 56772445Sassar void **server_handle) 56872445Sassar{ 56972445Sassar kadm5_ret_t ret; 57072445Sassar kadm5_client_context *ctx; 57172445Sassar krb5_ccache cc; 57272445Sassar 57372445Sassar ret = _kadm5_c_init_context(&ctx, realm_params, context); 57472445Sassar if(ret) 57572445Sassar return ret; 57672445Sassar 57772445Sassar if(password != NULL && *password != '\0') { 578233294Sstas ret = _kadm5_c_get_cred_cache(context, 579178825Sdfr client_name, 580233294Sstas service_name, 581178825Sdfr password, prompter, keytab, ccache, &cc); 58272445Sassar if(ret) 58372445Sassar return ret; /* XXX */ 58472445Sassar ccache = cc; 58572445Sassar } 58672445Sassar 587233294Sstas 58872445Sassar if (client_name != NULL) 58972445Sassar ctx->client_name = strdup(client_name); 59072445Sassar else 59172445Sassar ctx->client_name = NULL; 59272445Sassar if (service_name != NULL) 59372445Sassar ctx->service_name = strdup(service_name); 59472445Sassar else 59572445Sassar ctx->service_name = NULL; 59672445Sassar ctx->prompter = prompter; 59772445Sassar ctx->keytab = keytab; 59872445Sassar ctx->ccache = ccache; 59990926Snectar /* maybe we should copy the params here */ 60072445Sassar ctx->sock = -1; 601233294Sstas 60255682Smarkm *server_handle = ctx; 60355682Smarkm return 0; 60455682Smarkm} 60555682Smarkm 606233294Sstasstatic kadm5_ret_t 607233294Sstasinit_context(const char *client_name, 60855682Smarkm const char *password, 60955682Smarkm krb5_prompter_fct prompter, 61055682Smarkm const char *keytab, 61155682Smarkm krb5_ccache ccache, 61255682Smarkm const char *service_name, 61355682Smarkm kadm5_config_params *realm_params, 61455682Smarkm unsigned long struct_version, 61555682Smarkm unsigned long api_version, 61655682Smarkm void **server_handle) 61755682Smarkm{ 61855682Smarkm krb5_context context; 61955682Smarkm kadm5_ret_t ret; 62055682Smarkm kadm5_server_context *ctx; 621233294Sstas 62272445Sassar ret = krb5_init_context(&context); 62372445Sassar if (ret) 62472445Sassar return ret; 62555682Smarkm ret = kadm5_c_init_with_context(context, 62655682Smarkm client_name, 62755682Smarkm password, 62855682Smarkm prompter, 62955682Smarkm keytab, 63055682Smarkm ccache, 63155682Smarkm service_name, 63255682Smarkm realm_params, 63355682Smarkm struct_version, 63455682Smarkm api_version, 63555682Smarkm server_handle); 63655682Smarkm if(ret){ 63755682Smarkm krb5_free_context(context); 63855682Smarkm return ret; 63955682Smarkm } 64055682Smarkm ctx = *server_handle; 64155682Smarkm ctx->my_context = 1; 64255682Smarkm return 0; 64355682Smarkm} 64455682Smarkm 645233294Sstaskadm5_ret_t 64655682Smarkmkadm5_c_init_with_password_ctx(krb5_context context, 647233294Sstas const char *client_name, 64855682Smarkm const char *password, 64955682Smarkm const char *service_name, 65055682Smarkm kadm5_config_params *realm_params, 65155682Smarkm unsigned long struct_version, 65255682Smarkm unsigned long api_version, 65355682Smarkm void **server_handle) 65455682Smarkm{ 65555682Smarkm return kadm5_c_init_with_context(context, 65655682Smarkm client_name, 65755682Smarkm password, 65855682Smarkm krb5_prompter_posix, 65955682Smarkm NULL, 66055682Smarkm NULL, 66155682Smarkm service_name, 66255682Smarkm realm_params, 66355682Smarkm struct_version, 66455682Smarkm api_version, 66555682Smarkm server_handle); 66655682Smarkm} 66755682Smarkm 668233294Sstaskadm5_ret_t 669233294Sstaskadm5_c_init_with_password(const char *client_name, 67055682Smarkm const char *password, 67155682Smarkm const char *service_name, 67255682Smarkm kadm5_config_params *realm_params, 67355682Smarkm unsigned long struct_version, 67455682Smarkm unsigned long api_version, 67555682Smarkm void **server_handle) 67655682Smarkm{ 677233294Sstas return init_context(client_name, 678233294Sstas password, 67955682Smarkm krb5_prompter_posix, 68055682Smarkm NULL, 68155682Smarkm NULL, 682233294Sstas service_name, 683233294Sstas realm_params, 684233294Sstas struct_version, 685233294Sstas api_version, 68655682Smarkm server_handle); 68755682Smarkm} 68855682Smarkm 689233294Sstaskadm5_ret_t 69055682Smarkmkadm5_c_init_with_skey_ctx(krb5_context context, 691233294Sstas const char *client_name, 69255682Smarkm const char *keytab, 69355682Smarkm const char *service_name, 69455682Smarkm kadm5_config_params *realm_params, 69555682Smarkm unsigned long struct_version, 69655682Smarkm unsigned long api_version, 69755682Smarkm void **server_handle) 69855682Smarkm{ 69955682Smarkm return kadm5_c_init_with_context(context, 70055682Smarkm client_name, 70155682Smarkm NULL, 70255682Smarkm NULL, 70355682Smarkm keytab, 70455682Smarkm NULL, 70555682Smarkm service_name, 70655682Smarkm realm_params, 70755682Smarkm struct_version, 70855682Smarkm api_version, 70955682Smarkm server_handle); 71055682Smarkm} 71155682Smarkm 71255682Smarkm 713233294Sstaskadm5_ret_t 714233294Sstaskadm5_c_init_with_skey(const char *client_name, 71555682Smarkm const char *keytab, 71655682Smarkm const char *service_name, 71755682Smarkm kadm5_config_params *realm_params, 71855682Smarkm unsigned long struct_version, 71955682Smarkm unsigned long api_version, 72055682Smarkm void **server_handle) 72155682Smarkm{ 722233294Sstas return init_context(client_name, 72355682Smarkm NULL, 72455682Smarkm NULL, 72555682Smarkm keytab, 72655682Smarkm NULL, 727233294Sstas service_name, 728233294Sstas realm_params, 729233294Sstas struct_version, 730233294Sstas api_version, 73155682Smarkm server_handle); 73255682Smarkm} 73355682Smarkm 734233294Sstaskadm5_ret_t 73555682Smarkmkadm5_c_init_with_creds_ctx(krb5_context context, 73655682Smarkm const char *client_name, 73755682Smarkm krb5_ccache ccache, 73855682Smarkm const char *service_name, 73955682Smarkm kadm5_config_params *realm_params, 74055682Smarkm unsigned long struct_version, 74155682Smarkm unsigned long api_version, 74255682Smarkm void **server_handle) 74355682Smarkm{ 74455682Smarkm return kadm5_c_init_with_context(context, 74555682Smarkm client_name, 74655682Smarkm NULL, 74755682Smarkm NULL, 74855682Smarkm NULL, 74955682Smarkm ccache, 75055682Smarkm service_name, 75155682Smarkm realm_params, 75255682Smarkm struct_version, 75355682Smarkm api_version, 75455682Smarkm server_handle); 75555682Smarkm} 75655682Smarkm 757233294Sstaskadm5_ret_t 75855682Smarkmkadm5_c_init_with_creds(const char *client_name, 75955682Smarkm krb5_ccache ccache, 76055682Smarkm const char *service_name, 76155682Smarkm kadm5_config_params *realm_params, 76255682Smarkm unsigned long struct_version, 76355682Smarkm unsigned long api_version, 76455682Smarkm void **server_handle) 76555682Smarkm{ 766233294Sstas return init_context(client_name, 76755682Smarkm NULL, 76855682Smarkm NULL, 76955682Smarkm NULL, 77055682Smarkm ccache, 771233294Sstas service_name, 772233294Sstas realm_params, 773233294Sstas struct_version, 774233294Sstas api_version, 77555682Smarkm server_handle); 77655682Smarkm} 77755682Smarkm 77855682Smarkm#if 0 779233294Sstaskadm5_ret_t 78055682Smarkmkadm5_init(char *client_name, char *pass, 78155682Smarkm char *service_name, 78255682Smarkm kadm5_config_params *realm_params, 78355682Smarkm unsigned long struct_version, 78455682Smarkm unsigned long api_version, 78555682Smarkm void **server_handle) 78655682Smarkm{ 78755682Smarkm} 78855682Smarkm#endif 78955682Smarkm 790