Home | History | Annotate | Line # | Download | only in kadm5
      1 /*	$NetBSD: init_c.c,v 1.3 2023/06/19 21:41:44 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1997 - 2006 Kungliga Tekniska Hgskolan
      5  * (Royal Institute of Technology, Stockholm, Sweden).
      6  * All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  *
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  *
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * 3. Neither the name of the Institute nor the names of its contributors
     20  *    may be used to endorse or promote products derived from this software
     21  *    without specific prior written permission.
     22  *
     23  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
     24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
     27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33  * SUCH DAMAGE.
     34  */
     35 
     36 #include "kadm5_locl.h"
     37 #include <sys/types.h>
     38 #ifdef HAVE_SYS_SOCKET_H
     39 #include <sys/socket.h>
     40 #endif
     41 #ifdef HAVE_NETINET_IN_H
     42 #include <netinet/in.h>
     43 #endif
     44 #ifdef HAVE_NETDB_H
     45 #include <netdb.h>
     46 #endif
     47 
     48 __RCSID("$NetBSD: init_c.c,v 1.3 2023/06/19 21:41:44 christos Exp $");
     49 
     50 static kadm5_ret_t
     51 kadm5_c_lock(void *server_handle)
     52 {
     53     return ENOTSUP;
     54 }
     55 
     56 static kadm5_ret_t
     57 kadm5_c_unlock(void *server_handle)
     58 {
     59     return ENOTSUP;
     60 }
     61 
     62 static void
     63 set_funcs(kadm5_client_context *c)
     64 {
     65 #define SET(C, F) (C)->funcs.F = kadm5 ## _c_ ## F
     66 #define SETNOTIMP(C, F) (C)->funcs.F = 0
     67     SET(c, chpass_principal);
     68     SET(c, chpass_principal_with_key);
     69     SET(c, create_principal);
     70     SET(c, delete_principal);
     71     SET(c, destroy);
     72     SET(c, flush);
     73     SET(c, get_principal);
     74     SET(c, get_principals);
     75     SET(c, get_privs);
     76     SET(c, modify_principal);
     77     SET(c, randkey_principal);
     78     SET(c, rename_principal);
     79     SET(c, lock);
     80     SET(c, unlock);
     81     SETNOTIMP(c, setkey_principal_3);
     82 }
     83 
     84 kadm5_ret_t
     85 _kadm5_c_init_context(kadm5_client_context **ctx,
     86 		      kadm5_config_params *params,
     87 		      krb5_context context)
     88 {
     89     krb5_error_code ret;
     90     char *colon;
     91 
     92     *ctx = malloc(sizeof(**ctx));
     93     if(*ctx == NULL)
     94 	return ENOMEM;
     95     memset(*ctx, 0, sizeof(**ctx));
     96     krb5_add_et_list (context, initialize_kadm5_error_table_r);
     97     set_funcs(*ctx);
     98     (*ctx)->context = context;
     99     if(params->mask & KADM5_CONFIG_REALM) {
    100 	ret = 0;
    101 	(*ctx)->realm = strdup(params->realm);
    102 	if ((*ctx)->realm == NULL)
    103 	    ret = ENOMEM;
    104     } else
    105 	ret = krb5_get_default_realm((*ctx)->context, &(*ctx)->realm);
    106     if (ret) {
    107 	free(*ctx);
    108 	return ret;
    109     }
    110     if(params->mask & KADM5_CONFIG_ADMIN_SERVER)
    111 	(*ctx)->admin_server = strdup(params->admin_server);
    112     else {
    113 	char **hostlist;
    114 
    115 	ret = krb5_get_krb_admin_hst (context, &(*ctx)->realm, &hostlist);
    116 	if (ret) {
    117 	    free((*ctx)->realm);
    118 	    free(*ctx);
    119 	    return ret;
    120 	}
    121 	(*ctx)->admin_server = strdup(*hostlist);
    122 	krb5_free_krbhst (context, hostlist);
    123     }
    124 
    125     if ((*ctx)->admin_server == NULL) {
    126 	free((*ctx)->realm);
    127 	free(*ctx);
    128 	return ENOMEM;
    129     }
    130     colon = strchr ((*ctx)->admin_server, ':');
    131     if (colon != NULL)
    132 	*colon++ = '\0';
    133 
    134     (*ctx)->kadmind_port = 0;
    135 
    136     if(params->mask & KADM5_CONFIG_KADMIND_PORT)
    137 	(*ctx)->kadmind_port = params->kadmind_port;
    138     else if (colon != NULL) {
    139 	char *end;
    140 
    141 	(*ctx)->kadmind_port = htons(strtol (colon, &end, 0));
    142     }
    143     if ((*ctx)->kadmind_port == 0)
    144 	(*ctx)->kadmind_port = krb5_getportbyname (context, "kerberos-adm",
    145 						   "tcp", 749);
    146     return 0;
    147 }
    148 
    149 static krb5_error_code
    150 get_kadm_ticket(krb5_context context,
    151 		krb5_ccache id,
    152 		krb5_principal client,
    153 		const char *server_name)
    154 {
    155     krb5_error_code ret;
    156     krb5_creds in, *out;
    157 
    158     memset(&in, 0, sizeof(in));
    159     in.client = client;
    160     ret = krb5_parse_name(context, server_name, &in.server);
    161     if(ret)
    162 	return ret;
    163     ret = krb5_get_credentials(context, 0, id, &in, &out);
    164     if(ret == 0)
    165 	krb5_free_creds(context, out);
    166     krb5_free_principal(context, in.server);
    167     return ret;
    168 }
    169 
    170 static krb5_error_code
    171 get_new_cache(krb5_context context,
    172 	      krb5_principal client,
    173 	      const char *password,
    174 	      krb5_prompter_fct prompter,
    175 	      const char *keytab,
    176 	      const char *server_name,
    177 	      krb5_ccache *ret_cache)
    178 {
    179     krb5_error_code ret;
    180     krb5_creds cred;
    181     krb5_get_init_creds_opt *opt;
    182     krb5_ccache id;
    183 
    184     ret = krb5_get_init_creds_opt_alloc (context, &opt);
    185     if (ret)
    186 	return ret;
    187 
    188     krb5_get_init_creds_opt_set_default_flags(context, "kadmin",
    189 					      krb5_principal_get_realm(context,
    190 								       client),
    191 					      opt);
    192 
    193 
    194     krb5_get_init_creds_opt_set_forwardable (opt, FALSE);
    195     krb5_get_init_creds_opt_set_proxiable (opt, FALSE);
    196 
    197     if(password == NULL && prompter == NULL) {
    198 	krb5_keytab kt;
    199 	if(keytab == NULL)
    200 	    ret = krb5_kt_default(context, &kt);
    201 	else
    202 	    ret = krb5_kt_resolve(context, keytab, &kt);
    203 	if(ret) {
    204 	    krb5_get_init_creds_opt_free(context, opt);
    205 	    return ret;
    206 	}
    207 	ret = krb5_get_init_creds_keytab (context,
    208 					  &cred,
    209 					  client,
    210 					  kt,
    211 					  0,
    212 					  server_name,
    213 					  opt);
    214 	krb5_kt_close(context, kt);
    215     } else {
    216 	ret = krb5_get_init_creds_password (context,
    217 					    &cred,
    218 					    client,
    219 					    password,
    220 					    prompter,
    221 					    NULL,
    222 					    0,
    223 					    server_name,
    224 					    opt);
    225     }
    226     krb5_get_init_creds_opt_free(context, opt);
    227     switch(ret){
    228     case 0:
    229 	break;
    230     case KRB5_LIBOS_PWDINTR:	/* don't print anything if it was just C-c:ed */
    231     case KRB5KRB_AP_ERR_BAD_INTEGRITY:
    232     case KRB5KRB_AP_ERR_MODIFIED:
    233 	return KADM5_BAD_PASSWORD;
    234     default:
    235 	return ret;
    236     }
    237     ret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &id);
    238     if(ret)
    239 	return ret;
    240     ret = krb5_cc_initialize (context, id, cred.client);
    241     if (ret)
    242 	return ret;
    243     ret = krb5_cc_store_cred (context, id, &cred);
    244     if (ret)
    245 	return ret;
    246     krb5_free_cred_contents (context, &cred);
    247     *ret_cache = id;
    248     return 0;
    249 }
    250 
    251 /*
    252  * Check the credential cache `id to figure out what principal to use
    253  * when talking to the kadmind. If there is a initial kadmin/admin@
    254  * credential in the cache, use that client principal. Otherwise, use
    255  * the client principals first component and add /admin to the
    256  * principal.
    257  */
    258 
    259 static krb5_error_code
    260 get_cache_principal(krb5_context context,
    261 		    krb5_ccache *id,
    262 		    krb5_principal *client)
    263 {
    264     krb5_error_code ret;
    265     const char *name, *inst;
    266     krb5_principal p1, p2;
    267 
    268     ret = krb5_cc_default(context, id);
    269     if(ret) {
    270 	*id = NULL;
    271 	return ret;
    272     }
    273 
    274     ret = krb5_cc_get_principal(context, *id, &p1);
    275     if(ret) {
    276 	krb5_cc_close(context, *id);
    277 	*id = NULL;
    278 	return ret;
    279     }
    280 
    281     ret = krb5_make_principal(context, &p2, NULL,
    282 			      "kadmin", "admin", NULL);
    283     if (ret) {
    284 	krb5_cc_close(context, *id);
    285 	*id = NULL;
    286 	krb5_free_principal(context, p1);
    287 	return ret;
    288     }
    289 
    290     {
    291 	krb5_creds in, *out;
    292 	krb5_kdc_flags flags;
    293 
    294 	flags.i = 0;
    295 	memset(&in, 0, sizeof(in));
    296 
    297 	in.client = p1;
    298 	in.server = p2;
    299 
    300 	/* check for initial ticket kadmin/admin */
    301 	ret = krb5_get_credentials_with_flags(context, KRB5_GC_CACHED, flags,
    302 					      *id, &in, &out);
    303 	krb5_free_principal(context, p2);
    304 	if (ret == 0) {
    305 	    if (out->flags.b.initial) {
    306 		*client = p1;
    307 		krb5_free_creds(context, out);
    308 		return 0;
    309 	    }
    310 	    krb5_free_creds(context, out);
    311 	}
    312     }
    313     krb5_cc_close(context, *id);
    314     *id = NULL;
    315 
    316     name = krb5_principal_get_comp_string(context, p1, 0);
    317     inst = krb5_principal_get_comp_string(context, p1, 1);
    318     if(inst == NULL || strcmp(inst, "admin") != 0) {
    319 	ret = krb5_make_principal(context, &p2, NULL, name, "admin", NULL);
    320 	krb5_free_principal(context, p1);
    321 	if(ret != 0)
    322 	    return ret;
    323 
    324 	*client = p2;
    325 	return 0;
    326     }
    327 
    328     *client = p1;
    329 
    330     return 0;
    331 }
    332 
    333 krb5_error_code
    334 _kadm5_c_get_cred_cache(krb5_context context,
    335 			const char *client_name,
    336 			const char *server_name,
    337 			const char *password,
    338 			krb5_prompter_fct prompter,
    339 			const char *keytab,
    340 			krb5_ccache ccache,
    341 			krb5_ccache *ret_cache)
    342 {
    343     krb5_error_code ret;
    344     krb5_ccache id = NULL;
    345     krb5_principal default_client = NULL, client = NULL;
    346 
    347     /* treat empty password as NULL */
    348     if(password && *password == '\0')
    349 	password = NULL;
    350     if(server_name == NULL)
    351 	server_name = KADM5_ADMIN_SERVICE;
    352 
    353     if(client_name != NULL) {
    354 	ret = krb5_parse_name(context, client_name, &client);
    355 	if(ret)
    356 	    return ret;
    357     }
    358 
    359     if(ccache != NULL) {
    360 	id = ccache;
    361 	ret = krb5_cc_get_principal(context, id, &client);
    362 	if(ret)
    363 	    return ret;
    364     } else {
    365 	/* get principal from default cache, ok if this doesn't work */
    366 
    367 	ret = get_cache_principal(context, &id, &default_client);
    368 	if (ret) {
    369 	    /*
    370 	     * No client was specified by the caller and we cannot
    371 	     * determine the client from a credentials cache.
    372 	     */
    373 	    const char *user;
    374 
    375 	    user = get_default_username ();
    376 
    377 	    if(user == NULL) {
    378 		krb5_set_error_message(context, KADM5_FAILURE, "Unable to find local user name");
    379 		return KADM5_FAILURE;
    380 	    }
    381 	    ret = krb5_make_principal(context, &default_client,
    382 				      NULL, user, "admin", NULL);
    383 	    if(ret)
    384 		return ret;
    385 	}
    386     }
    387 
    388 
    389     /*
    390      * No client was specified by the caller, but we have a client
    391      * from the default credentials cache.
    392      */
    393     if (client == NULL && default_client != NULL)
    394 	client = default_client;
    395 
    396 
    397     if(id && client && (default_client == NULL ||
    398 	      krb5_principal_compare(context, client, default_client) != 0)) {
    399 	ret = get_kadm_ticket(context, id, client, server_name);
    400 	if(ret == 0) {
    401 	    *ret_cache = id;
    402 	    krb5_free_principal(context, default_client);
    403 	    if (default_client != client)
    404 		krb5_free_principal(context, client);
    405 	    return 0;
    406 	}
    407 	if(ccache != NULL)
    408 	    /* couldn't get ticket from cache */
    409 	    return -1;
    410     }
    411     /* get creds via AS request */
    412     if(id && (id != ccache))
    413 	krb5_cc_close(context, id);
    414     if (client != default_client)
    415 	krb5_free_principal(context, default_client);
    416 
    417     ret = get_new_cache(context, client, password, prompter, keytab,
    418 			server_name, ret_cache);
    419     krb5_free_principal(context, client);
    420     return ret;
    421 }
    422 
    423 static kadm5_ret_t
    424 kadm_connect(kadm5_client_context *ctx)
    425 {
    426     kadm5_ret_t ret;
    427     krb5_principal server;
    428     krb5_ccache cc;
    429     rk_socket_t s = rk_INVALID_SOCKET;
    430     struct addrinfo *ai, *a;
    431     struct addrinfo hints;
    432     int error;
    433     char portstr[NI_MAXSERV];
    434     char *hostname, *slash;
    435     char *service_name;
    436     krb5_context context = ctx->context;
    437 
    438     memset (&hints, 0, sizeof(hints));
    439     hints.ai_socktype = SOCK_STREAM;
    440     hints.ai_protocol = IPPROTO_TCP;
    441 
    442     snprintf (portstr, sizeof(portstr), "%u", ntohs(ctx->kadmind_port));
    443 
    444     hostname = ctx->admin_server;
    445     slash = strchr (hostname, '/');
    446     if (slash != NULL)
    447 	hostname = slash + 1;
    448 
    449     error = getaddrinfo (hostname, portstr, &hints, &ai);
    450     if (error) {
    451 	krb5_clear_error_message(context);
    452 	return KADM5_BAD_SERVER_NAME;
    453     }
    454 
    455     for (a = ai; a != NULL; a = a->ai_next) {
    456 	s = socket (a->ai_family, a->ai_socktype, a->ai_protocol);
    457 	if (s < 0)
    458 	    continue;
    459 	if (connect (s, a->ai_addr, a->ai_addrlen) < 0) {
    460 	    krb5_clear_error_message(context);
    461 	    krb5_warn (context, errno, "connect(%s)", hostname);
    462 	    rk_closesocket (s);
    463 	    continue;
    464 	}
    465 	break;
    466     }
    467     if (a == NULL) {
    468 	freeaddrinfo (ai);
    469 	krb5_clear_error_message(context);
    470 	krb5_warnx (context, "failed to contact %s", hostname);
    471 	return KADM5_FAILURE;
    472     }
    473     ret = _kadm5_c_get_cred_cache(context,
    474 				  ctx->client_name,
    475 				  ctx->service_name,
    476 				  NULL, ctx->prompter, ctx->keytab,
    477 				  ctx->ccache, &cc);
    478 
    479     if(ret) {
    480 	freeaddrinfo (ai);
    481 	rk_closesocket(s);
    482 	return ret;
    483     }
    484 
    485     if (ctx->realm)
    486 	error = asprintf(&service_name, "%s@%s", KADM5_ADMIN_SERVICE,
    487 			 ctx->realm);
    488     else
    489 	error = asprintf(&service_name, "%s", KADM5_ADMIN_SERVICE);
    490 
    491     if (error == -1 || service_name == NULL) {
    492 	freeaddrinfo (ai);
    493 	rk_closesocket(s);
    494 	krb5_clear_error_message(context);
    495 	return ENOMEM;
    496     }
    497 
    498     ret = krb5_parse_name(context, service_name, &server);
    499     free(service_name);
    500     if(ret) {
    501 	freeaddrinfo (ai);
    502 	if(ctx->ccache == NULL)
    503 	    krb5_cc_close(context, cc);
    504 	rk_closesocket(s);
    505 	return ret;
    506     }
    507     ctx->ac = NULL;
    508 
    509     ret = krb5_sendauth(context, &ctx->ac, &s,
    510 			KADMIN_APPL_VERSION, NULL,
    511 			server, AP_OPTS_MUTUAL_REQUIRED,
    512 			NULL, NULL, cc, NULL, NULL, NULL);
    513     if(ret == 0) {
    514 	krb5_data params;
    515 	kadm5_config_params p;
    516 	memset(&p, 0, sizeof(p));
    517 	if(ctx->realm) {
    518 	    p.mask |= KADM5_CONFIG_REALM;
    519 	    p.realm = ctx->realm;
    520 	}
    521 	ret = _kadm5_marshal_params(context, &p, &params);
    522 
    523 	ret = krb5_write_priv_message(context, ctx->ac, &s, &params);
    524 	krb5_data_free(&params);
    525 	if(ret) {
    526 	    freeaddrinfo (ai);
    527 	    rk_closesocket(s);
    528 	    if(ctx->ccache == NULL)
    529 		krb5_cc_close(context, cc);
    530 	    return ret;
    531 	}
    532     } else if(ret == KRB5_SENDAUTH_BADAPPLVERS) {
    533 	rk_closesocket(s);
    534 
    535 	s = socket (a->ai_family, a->ai_socktype, a->ai_protocol);
    536 	if (s < 0) {
    537 	    freeaddrinfo (ai);
    538 	    krb5_clear_error_message(context);
    539 	    return errno;
    540 	}
    541 	if (connect (s, a->ai_addr, a->ai_addrlen) < 0) {
    542 	    rk_closesocket (s);
    543 	    freeaddrinfo (ai);
    544 	    krb5_clear_error_message(context);
    545 	    return errno;
    546 	}
    547 	ret = krb5_sendauth(context, &ctx->ac, &s,
    548 			    KADMIN_OLD_APPL_VERSION, NULL,
    549 			    server, AP_OPTS_MUTUAL_REQUIRED,
    550 			    NULL, NULL, cc, NULL, NULL, NULL);
    551     }
    552     freeaddrinfo (ai);
    553     if(ret) {
    554 	rk_closesocket(s);
    555 	return ret;
    556     }
    557 
    558     krb5_free_principal(context, server);
    559     if(ctx->ccache == NULL)
    560 	krb5_cc_close(context, cc);
    561     ctx->sock = s;
    562 
    563     return 0;
    564 }
    565 
    566 kadm5_ret_t
    567 _kadm5_connect(void *handle)
    568 {
    569     kadm5_client_context *ctx = handle;
    570     if(ctx->sock == -1)
    571 	return kadm_connect(ctx);
    572     return 0;
    573 }
    574 
    575 static kadm5_ret_t
    576 kadm5_c_init_with_context(krb5_context context,
    577 			  const char *client_name,
    578 			  const char *password,
    579 			  krb5_prompter_fct prompter,
    580 			  const char *keytab,
    581 			  krb5_ccache ccache,
    582 			  const char *service_name,
    583 			  kadm5_config_params *realm_params,
    584 			  unsigned long struct_version,
    585 			  unsigned long api_version,
    586 			  void **server_handle)
    587 {
    588     kadm5_ret_t ret;
    589     kadm5_client_context *ctx = NULL;
    590     krb5_ccache cc;
    591 
    592     ret = _kadm5_c_init_context(&ctx, realm_params, context);
    593     if (ret)
    594 	return ret;
    595 
    596     if (password != NULL && *password != '\0') {
    597 	ret = _kadm5_c_get_cred_cache(context,
    598 				      client_name,
    599 				      service_name,
    600 				      password, prompter, keytab, ccache, &cc);
    601 	if (ret) {
    602             kadm5_c_destroy(ctx);
    603 	    return ret;
    604         }
    605 	ccache = cc;
    606     }
    607 
    608 
    609     if (client_name != NULL)
    610 	ctx->client_name = strdup(client_name);
    611     else
    612 	ctx->client_name = NULL;
    613     if (service_name != NULL)
    614 	ctx->service_name = strdup(service_name);
    615     else
    616 	ctx->service_name = NULL;
    617     ctx->prompter = prompter;
    618     ctx->keytab = keytab;
    619     ctx->ccache = ccache;
    620     /* maybe we should copy the params here */
    621     ctx->sock = -1;
    622 
    623     *server_handle = ctx;
    624     return 0;
    625 }
    626 
    627 static kadm5_ret_t
    628 init_context(const char *client_name,
    629 	     const char *password,
    630 	     krb5_prompter_fct prompter,
    631 	     const char *keytab,
    632 	     krb5_ccache ccache,
    633 	     const char *service_name,
    634 	     kadm5_config_params *realm_params,
    635 	     unsigned long struct_version,
    636 	     unsigned long api_version,
    637 	     void **server_handle)
    638 {
    639     krb5_context context;
    640     kadm5_ret_t ret;
    641     kadm5_server_context *ctx;
    642 
    643     ret = krb5_init_context(&context);
    644     if (ret)
    645 	return ret;
    646     ret = kadm5_c_init_with_context(context,
    647 				    client_name,
    648 				    password,
    649 				    prompter,
    650 				    keytab,
    651 				    ccache,
    652 				    service_name,
    653 				    realm_params,
    654 				    struct_version,
    655 				    api_version,
    656 				    server_handle);
    657     if(ret){
    658 	krb5_free_context(context);
    659 	return ret;
    660     }
    661     ctx = *server_handle;
    662     ctx->my_context = 1;
    663     return 0;
    664 }
    665 
    666 kadm5_ret_t
    667 kadm5_c_init_with_password_ctx(krb5_context context,
    668 			       const char *client_name,
    669 			       const char *password,
    670 			       const char *service_name,
    671 			       kadm5_config_params *realm_params,
    672 			       unsigned long struct_version,
    673 			       unsigned long api_version,
    674 			       void **server_handle)
    675 {
    676     return kadm5_c_init_with_context(context,
    677 				     client_name,
    678 				     password,
    679 				     krb5_prompter_posix,
    680 				     NULL,
    681 				     NULL,
    682 				     service_name,
    683 				     realm_params,
    684 				     struct_version,
    685 				     api_version,
    686 				     server_handle);
    687 }
    688 
    689 kadm5_ret_t
    690 kadm5_c_init_with_password(const char *client_name,
    691 			   const char *password,
    692 			   const char *service_name,
    693 			   kadm5_config_params *realm_params,
    694 			   unsigned long struct_version,
    695 			   unsigned long api_version,
    696 			   void **server_handle)
    697 {
    698     return init_context(client_name,
    699 			password,
    700 			krb5_prompter_posix,
    701 			NULL,
    702 			NULL,
    703 			service_name,
    704 			realm_params,
    705 			struct_version,
    706 			api_version,
    707 			server_handle);
    708 }
    709 
    710 kadm5_ret_t
    711 kadm5_c_init_with_skey_ctx(krb5_context context,
    712 			   const char *client_name,
    713 			   const char *keytab,
    714 			   const char *service_name,
    715 			   kadm5_config_params *realm_params,
    716 			   unsigned long struct_version,
    717 			   unsigned long api_version,
    718 			   void **server_handle)
    719 {
    720     return kadm5_c_init_with_context(context,
    721 				     client_name,
    722 				     NULL,
    723 				     NULL,
    724 				     keytab,
    725 				     NULL,
    726 				     service_name,
    727 				     realm_params,
    728 				     struct_version,
    729 				     api_version,
    730 				     server_handle);
    731 }
    732 
    733 
    734 kadm5_ret_t
    735 kadm5_c_init_with_skey(const char *client_name,
    736 		     const char *keytab,
    737 		     const char *service_name,
    738 		     kadm5_config_params *realm_params,
    739 		     unsigned long struct_version,
    740 		     unsigned long api_version,
    741 		     void **server_handle)
    742 {
    743     return init_context(client_name,
    744 			NULL,
    745 			NULL,
    746 			keytab,
    747 			NULL,
    748 			service_name,
    749 			realm_params,
    750 			struct_version,
    751 			api_version,
    752 			server_handle);
    753 }
    754 
    755 kadm5_ret_t
    756 kadm5_c_init_with_creds_ctx(krb5_context context,
    757 			    const char *client_name,
    758 			    krb5_ccache ccache,
    759 			    const char *service_name,
    760 			    kadm5_config_params *realm_params,
    761 			    unsigned long struct_version,
    762 			    unsigned long api_version,
    763 			    void **server_handle)
    764 {
    765     return kadm5_c_init_with_context(context,
    766 				     client_name,
    767 				     NULL,
    768 				     NULL,
    769 				     NULL,
    770 				     ccache,
    771 				     service_name,
    772 				     realm_params,
    773 				     struct_version,
    774 				     api_version,
    775 				     server_handle);
    776 }
    777 
    778 kadm5_ret_t
    779 kadm5_c_init_with_creds(const char *client_name,
    780 			krb5_ccache ccache,
    781 			const char *service_name,
    782 			kadm5_config_params *realm_params,
    783 			unsigned long struct_version,
    784 			unsigned long api_version,
    785 			void **server_handle)
    786 {
    787     return init_context(client_name,
    788 			NULL,
    789 			NULL,
    790 			NULL,
    791 			ccache,
    792 			service_name,
    793 			realm_params,
    794 			struct_version,
    795 			api_version,
    796 			server_handle);
    797 }
    798 
    799 #if 0
    800 kadm5_ret_t
    801 kadm5_init(char *client_name, char *pass,
    802 	   char *service_name,
    803 	   kadm5_config_params *realm_params,
    804 	   unsigned long struct_version,
    805 	   unsigned long api_version,
    806 	   void **server_handle)
    807 {
    808 }
    809 #endif
    810 
    811