/ lib / kadm5 / init_c.c
init_c.c
  1  /*
  2   * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan
  3   * (Royal Institute of Technology, Stockholm, Sweden).
  4   * All rights reserved.
  5   *
  6   * Redistribution and use in source and binary forms, with or without
  7   * modification, are permitted provided that the following conditions
  8   * are met:
  9   *
 10   * 1. Redistributions of source code must retain the above copyright
 11   *    notice, this list of conditions and the following disclaimer.
 12   *
 13   * 2. Redistributions in binary form must reproduce the above copyright
 14   *    notice, this list of conditions and the following disclaimer in the
 15   *    documentation and/or other materials provided with the distribution.
 16   *
 17   * 3. Neither the name of the Institute nor the names of its contributors
 18   *    may be used to endorse or promote products derived from this software
 19   *    without specific prior written permission.
 20   *
 21   * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
 22   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 23   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 24   * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
 25   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 26   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 27   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 28   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 29   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 30   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 31   * SUCH DAMAGE.
 32   */
 33  
 34  #include "kadm5_locl.h"
 35  #include <sys/types.h>
 36  #ifdef HAVE_SYS_SOCKET_H
 37  #include <sys/socket.h>
 38  #endif
 39  #ifdef HAVE_NETINET_IN_H
 40  #include <netinet/in.h>
 41  #endif
 42  #ifdef HAVE_NETDB_H
 43  #include <netdb.h>
 44  #endif
 45  
 46  RCSID("$Id$");
 47  
 48  static kadm5_ret_t
 49  kadm5_c_lock(void *server_handle)
 50  {
 51      return ENOTSUP;
 52  }
 53  
 54  static kadm5_ret_t
 55  kadm5_c_unlock(void *server_handle)
 56  {
 57      return ENOTSUP;
 58  }
 59  
 60  static void
 61  set_funcs(kadm5_client_context *c)
 62  {
 63  #define SET(C, F) (C)->funcs.F = kadm5 ## _c_ ## F
 64      SET(c, chpass_principal);
 65      SET(c, chpass_principal_with_key);
 66      SET(c, create_principal);
 67      SET(c, delete_principal);
 68      SET(c, destroy);
 69      SET(c, flush);
 70      SET(c, get_principal);
 71      SET(c, get_principals);
 72      SET(c, get_privs);
 73      SET(c, modify_principal);
 74      SET(c, randkey_principal);
 75      SET(c, rename_principal);
 76      SET(c, lock);
 77      SET(c, unlock);
 78  }
 79  
 80  kadm5_ret_t
 81  _kadm5_c_init_context(kadm5_client_context **ctx,
 82  		      kadm5_config_params *params,
 83  		      krb5_context context)
 84  {
 85      krb5_error_code ret;
 86      char *colon;
 87  
 88      *ctx = malloc(sizeof(**ctx));
 89      if(*ctx == NULL)
 90  	return ENOMEM;
 91      memset(*ctx, 0, sizeof(**ctx));
 92      krb5_add_et_list (context, initialize_kadm5_error_table_r);
 93      set_funcs(*ctx);
 94      (*ctx)->context = context;
 95      if(params->mask & KADM5_CONFIG_REALM) {
 96  	ret = 0;
 97  	(*ctx)->realm = strdup(params->realm);
 98  	if ((*ctx)->realm == NULL)
 99  	    ret = ENOMEM;
100      } else
101  	ret = krb5_get_default_realm((*ctx)->context, &(*ctx)->realm);
102      if (ret) {
103  	free(*ctx);
104  	return ret;
105      }
106      if(params->mask & KADM5_CONFIG_ADMIN_SERVER)
107  	(*ctx)->admin_server = strdup(params->admin_server);
108      else {
109  	krb5_krbhst_handle handle = NULL;
110  	char host[MAXHOSTNAMELEN];
111  
112  	ret = krb5_krbhst_init(context, (*ctx)->realm, KRB5_KRBHST_ADMIN, &handle);
113  	if (ret == 0)
114  	    ret = krb5_krbhst_next_as_string(context, handle, host, sizeof(host));
115  	krb5_krbhst_free(context, handle);
116  	if (ret) {
117  	    free((*ctx)->realm);
118  	    free(*ctx);
119  	    return ret;
120  	}
121  
122  	(*ctx)->admin_server = strdup(host);
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  krb5_error_code
260  _kadm5_c_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 = _kadm5_c_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  	socket_set_nopipe(s, 1);
460  	if (connect (s, a->ai_addr, a->ai_addrlen) < 0) {
461  	    krb5_clear_error_message(context);
462  	    krb5_warn (context, errno, "connect(%s)", hostname);
463  	    rk_closesocket (s);
464  	    continue;
465  	}
466  	break;
467      }
468      if (a == NULL) {
469  	freeaddrinfo (ai);
470  	krb5_clear_error_message(context);
471  	krb5_warnx (context, "failed to contact %s", hostname);
472  	return KADM5_FAILURE;
473      }
474      ret = _kadm5_c_get_cred_cache(context,
475  				  ctx->client_name,
476  				  ctx->service_name,
477  				  NULL, ctx->prompter, ctx->keytab,
478  				  ctx->ccache, &cc);
479  
480      if(ret) {
481  	freeaddrinfo (ai);
482  	rk_closesocket(s);
483  	return ret;
484      }
485  
486      if (ctx->realm)
487  	asprintf(&service_name, "%s@%s", KADM5_ADMIN_SERVICE, ctx->realm);
488      else
489  	asprintf(&service_name, "%s", KADM5_ADMIN_SERVICE);
490  
491      if (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  	(void)_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  	socket_set_nopipe(s, 1);
542  	if (connect (s, a->ai_addr, a->ai_addrlen) < 0) {
543  	    rk_closesocket (s);
544  	    freeaddrinfo (ai);
545  	    krb5_clear_error_message(context);
546  	    return errno;
547  	}
548  	ret = krb5_sendauth(context, &ctx->ac, &s,
549  			    KADMIN_OLD_APPL_VERSION, NULL,
550  			    server, AP_OPTS_MUTUAL_REQUIRED,
551  			    NULL, NULL, cc, NULL, NULL, NULL);
552      }
553      freeaddrinfo (ai);
554      if(ret) {
555  	rk_closesocket(s);
556  	return ret;
557      }
558  
559      krb5_free_principal(context, server);
560      if(ctx->ccache == NULL)
561  	krb5_cc_close(context, cc);
562      ctx->sock = s;
563  
564      return 0;
565  }
566  
567  kadm5_ret_t
568  _kadm5_connect(void *handle)
569  {
570      kadm5_client_context *ctx = handle;
571      if(ctx->sock == -1)
572  	return kadm_connect(ctx);
573      return 0;
574  }
575  
576  static kadm5_ret_t
577  kadm5_c_init_with_context(krb5_context context,
578  			  const char *client_name,
579  			  const char *password,
580  			  krb5_prompter_fct prompter,
581  			  const char *keytab,
582  			  krb5_ccache ccache,
583  			  const char *service_name,
584  			  kadm5_config_params *realm_params,
585  			  unsigned long struct_version,
586  			  unsigned long api_version,
587  			  void **server_handle)
588  {
589      kadm5_ret_t ret;
590      kadm5_client_context *ctx;
591      krb5_ccache cc;
592  
593      ret = _kadm5_c_init_context(&ctx, realm_params, context);
594      if(ret)
595  	return ret;
596  
597      if(password != NULL && *password != '\0') {
598  	ret = _kadm5_c_get_cred_cache(context,
599  				      client_name,
600  				      service_name,
601  				      password, prompter, keytab, ccache, &cc);
602  	if(ret)
603  	    return ret; /* XXX */
604  	ccache = cc;
605      }
606  
607  
608      if (client_name != NULL)
609  	ctx->client_name = strdup(client_name);
610      else
611  	ctx->client_name = NULL;
612      if (service_name != NULL)
613  	ctx->service_name = strdup(service_name);
614      else
615  	ctx->service_name = NULL;
616      ctx->prompter = prompter;
617      ctx->keytab = keytab;
618      ctx->ccache = ccache;
619      /* maybe we should copy the params here */
620      ctx->sock = -1;
621  
622      *server_handle = ctx;
623      return 0;
624  }
625  
626  static kadm5_ret_t
627  init_context(const char *client_name,
628  	     const char *password,
629  	     krb5_prompter_fct prompter,
630  	     const char *keytab,
631  	     krb5_ccache ccache,
632  	     const char *service_name,
633  	     kadm5_config_params *realm_params,
634  	     unsigned long struct_version,
635  	     unsigned long api_version,
636  	     void **server_handle)
637  {
638      krb5_context context;
639      kadm5_ret_t ret;
640      kadm5_server_context *ctx;
641  
642      ret = krb5_init_context(&context);
643      if (ret)
644  	return ret;
645      ret = kadm5_c_init_with_context(context,
646  				    client_name,
647  				    password,
648  				    prompter,
649  				    keytab,
650  				    ccache,
651  				    service_name,
652  				    realm_params,
653  				    struct_version,
654  				    api_version,
655  				    server_handle);
656      if(ret){
657  	krb5_free_context(context);
658  	return ret;
659      }
660      ctx = *server_handle;
661      ctx->my_context = 1;
662      return 0;
663  }
664  
665  kadm5_ret_t
666  kadm5_c_init_with_password_ctx(krb5_context context,
667  			       const char *client_name,
668  			       const char *password,
669  			       const char *service_name,
670  			       kadm5_config_params *realm_params,
671  			       unsigned long struct_version,
672  			       unsigned long api_version,
673  			       void **server_handle)
674  {
675      return kadm5_c_init_with_context(context,
676  				     client_name,
677  				     password,
678  				     krb5_prompter_posix,
679  				     NULL,
680  				     NULL,
681  				     service_name,
682  				     realm_params,
683  				     struct_version,
684  				     api_version,
685  				     server_handle);
686  }
687  
688  kadm5_ret_t
689  kadm5_c_init_with_password(const char *client_name,
690  			   const char *password,
691  			   const char *service_name,
692  			   kadm5_config_params *realm_params,
693  			   unsigned long struct_version,
694  			   unsigned long api_version,
695  			   void **server_handle)
696  {
697      return init_context(client_name,
698  			password,
699  			krb5_prompter_posix,
700  			NULL,
701  			NULL,
702  			service_name,
703  			realm_params,
704  			struct_version,
705  			api_version,
706  			server_handle);
707  }
708  
709  kadm5_ret_t
710  kadm5_c_init_with_skey_ctx(krb5_context context,
711  			   const char *client_name,
712  			   const char *keytab,
713  			   const char *service_name,
714  			   kadm5_config_params *realm_params,
715  			   unsigned long struct_version,
716  			   unsigned long api_version,
717  			   void **server_handle)
718  {
719      return kadm5_c_init_with_context(context,
720  				     client_name,
721  				     NULL,
722  				     NULL,
723  				     keytab,
724  				     NULL,
725  				     service_name,
726  				     realm_params,
727  				     struct_version,
728  				     api_version,
729  				     server_handle);
730  }
731  
732  
733  kadm5_ret_t
734  kadm5_c_init_with_skey(const char *client_name,
735  		     const char *keytab,
736  		     const char *service_name,
737  		     kadm5_config_params *realm_params,
738  		     unsigned long struct_version,
739  		     unsigned long api_version,
740  		     void **server_handle)
741  {
742      return init_context(client_name,
743  			NULL,
744  			NULL,
745  			keytab,
746  			NULL,
747  			service_name,
748  			realm_params,
749  			struct_version,
750  			api_version,
751  			server_handle);
752  }
753  
754  kadm5_ret_t
755  kadm5_c_init_with_creds_ctx(krb5_context context,
756  			    const char *client_name,
757  			    krb5_ccache ccache,
758  			    const char *service_name,
759  			    kadm5_config_params *realm_params,
760  			    unsigned long struct_version,
761  			    unsigned long api_version,
762  			    void **server_handle)
763  {
764      return kadm5_c_init_with_context(context,
765  				     client_name,
766  				     NULL,
767  				     NULL,
768  				     NULL,
769  				     ccache,
770  				     service_name,
771  				     realm_params,
772  				     struct_version,
773  				     api_version,
774  				     server_handle);
775  }
776  
777  kadm5_ret_t
778  kadm5_c_init_with_creds(const char *client_name,
779  			krb5_ccache ccache,
780  			const char *service_name,
781  			kadm5_config_params *realm_params,
782  			unsigned long struct_version,
783  			unsigned long api_version,
784  			void **server_handle)
785  {
786      return init_context(client_name,
787  			NULL,
788  			NULL,
789  			NULL,
790  			ccache,
791  			service_name,
792  			realm_params,
793  			struct_version,
794  			api_version,
795  			server_handle);
796  }
797  
798  #if 0
799  kadm5_ret_t
800  kadm5_init(char *client_name, char *pass,
801  	   char *service_name,
802  	   kadm5_config_params *realm_params,
803  	   unsigned long struct_version,
804  	   unsigned long api_version,
805  	   void **server_handle)
806  {
807  }
808  #endif
809