s4:torture: Adapt KDC canon test to Heimdal upstream changes
[samba.git] / third_party / heimdal / lib / kadm5 / 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 #define SETNOTIMP(C, F) (C)->funcs.F = 0
65     SET(c, chpass_principal);
66     SET(c, chpass_principal_with_key);
67     SET(c, create_principal);
68     SET(c, delete_principal);
69     SET(c, destroy);
70     SET(c, flush);
71     SET(c, get_principal);
72     SET(c, get_principals);
73     SET(c, get_privs);
74     SET(c, modify_principal);
75     SET(c, prune_principal);
76     SET(c, randkey_principal);
77     SET(c, rename_principal);
78     SET(c, lock);
79     SET(c, unlock);
80     SETNOTIMP(c, setkey_principal_3);
81 }
82
83 kadm5_ret_t
84 _kadm5_c_init_context(kadm5_client_context **ctx,
85                       kadm5_config_params *params,
86                       krb5_context context)
87 {
88     krb5_error_code ret;
89     char *colon;
90
91     *ctx = malloc(sizeof(**ctx));
92     if (*ctx == NULL)
93         return krb5_enomem(context);
94     memset(*ctx, 0, sizeof(**ctx));
95     krb5_add_et_list(context, initialize_kadm5_error_table_r);
96     set_funcs(*ctx);
97     (*ctx)->context = context;
98     if (params->mask & KADM5_CONFIG_REALM) {
99         ret = 0;
100         (*ctx)->realm = strdup(params->realm);
101         if ((*ctx)->realm == NULL)
102             ret = krb5_enomem(context);
103     } else
104         ret = krb5_get_default_realm((*ctx)->context, &(*ctx)->realm);
105     if (ret) {
106         free(*ctx);
107         return ret;
108     }
109
110     /*
111      * FIXME: If we have a hostlist, we should use the hostlist so that if we
112      *        can't reach one server we try another.
113      */
114     if (params->mask & KADM5_CONFIG_ADMIN_SERVER)
115         (*ctx)->admin_server = strdup(params->admin_server);
116     else {
117         char **hostlist;
118
119         ret = krb5_get_krb_admin_hst(context, &(*ctx)->realm, &hostlist);
120         if (ret) {
121             free((*ctx)->realm);
122             free(*ctx);
123             return ret;
124         }
125         (*ctx)->admin_server = strdup(*hostlist);
126         krb5_free_krbhst(context, hostlist);
127     }
128
129     if ((*ctx)->admin_server == NULL) {
130         free((*ctx)->realm);
131         free(*ctx);
132         return krb5_enomem(context);
133     }
134     colon = strchr((*ctx)->admin_server, ':');
135     if (colon != NULL)
136         *colon++ = '\0';
137
138     (*ctx)->kadmind_port = 0;
139
140     if (params->mask & KADM5_CONFIG_KADMIND_PORT)
141         (*ctx)->kadmind_port = params->kadmind_port;
142     else if (colon != NULL) {
143         char *end;
144
145         (*ctx)->kadmind_port = htons(strtol(colon, &end, 0));
146     }
147     if ((*ctx)->kadmind_port == 0)
148         (*ctx)->kadmind_port = krb5_getportbyname(context, "kerberos-adm",
149                                                   "tcp", 749);
150
151     if (params->mask & KADM5_CONFIG_READONLY_ADMIN_SERVER) {
152         (*ctx)->readonly_admin_server = strdup(params->readonly_admin_server);
153         if ((*ctx)->readonly_admin_server == NULL) {
154             free((*ctx)->realm);
155             free(*ctx);
156             return krb5_enomem(context);
157         }
158     } else {
159         char **hostlist;
160
161         ret = krb5_get_krb_readonly_admin_hst(context, &(*ctx)->realm,
162                                               &hostlist);
163         if (ret == 0) {
164             (*ctx)->readonly_admin_server = strdup(*hostlist);
165             krb5_free_krbhst(context, hostlist);
166             if ((*ctx)->readonly_admin_server == NULL) {
167                 free((*ctx)->realm);
168                 free(*ctx);
169                 return krb5_enomem(context);
170             }
171         }
172     }
173     if ((*ctx)->readonly_admin_server) {
174         colon = strchr((*ctx)->readonly_admin_server, ':');
175         if (colon != NULL)
176             *colon++ = '\0';
177
178     } else {
179         colon = NULL;
180     }
181
182     (*ctx)->readonly_kadmind_port = 0;
183     if (params->mask & KADM5_CONFIG_READONLY_KADMIN_PORT)
184         (*ctx)->readonly_kadmind_port = params->readonly_kadmind_port;
185     else if (colon != NULL) {
186         char *end;
187
188         (*ctx)->readonly_kadmind_port = htons(strtol(colon, &end, 0));
189     }
190     if ((*ctx)->readonly_kadmind_port == 0)
191         (*ctx)->readonly_kadmind_port = (*ctx)->kadmind_port;
192     return 0;
193 }
194
195 static krb5_error_code
196 get_kadm_ticket(krb5_context context,
197                 krb5_ccache id,
198                 krb5_principal client,
199                 const char *server_name)
200 {
201     krb5_error_code ret;
202     krb5_creds in, *out;
203
204     memset(&in, 0, sizeof(in));
205     in.client = client;
206     ret = krb5_parse_name(context, server_name, &in.server);
207     if(ret)
208         return ret;
209     ret = krb5_get_credentials(context, 0, id, &in, &out);
210     if(ret == 0)
211         krb5_free_creds(context, out);
212     krb5_free_principal(context, in.server);
213     return ret;
214 }
215
216 static krb5_error_code
217 get_new_cache(krb5_context context,
218               krb5_principal client,
219               const char *password,
220               krb5_prompter_fct prompter,
221               const char *keytab,
222               const char *server_name,
223               krb5_ccache *ret_cache)
224 {
225     krb5_error_code ret;
226     krb5_creds cred;
227     krb5_get_init_creds_opt *opt;
228     krb5_ccache id;
229
230     ret = krb5_get_init_creds_opt_alloc (context, &opt);
231     if (ret)
232         return ret;
233
234     krb5_get_init_creds_opt_set_default_flags(context, "kadmin",
235                                               krb5_principal_get_realm(context,
236                                                                        client),
237                                               opt);
238
239
240     krb5_get_init_creds_opt_set_forwardable (opt, FALSE);
241     krb5_get_init_creds_opt_set_proxiable (opt, FALSE);
242
243     if(password == NULL && prompter == NULL) {
244         krb5_keytab kt;
245         if(keytab == NULL)
246             ret = krb5_kt_default(context, &kt);
247         else
248             ret = krb5_kt_resolve(context, keytab, &kt);
249         if(ret) {
250             krb5_get_init_creds_opt_free(context, opt);
251             return ret;
252         }
253         ret = krb5_get_init_creds_keytab (context,
254                                           &cred,
255                                           client,
256                                           kt,
257                                           0,
258                                           server_name,
259                                           opt);
260         krb5_kt_close(context, kt);
261     } else {
262         ret = krb5_get_init_creds_password (context,
263                                             &cred,
264                                             client,
265                                             password,
266                                             prompter,
267                                             NULL,
268                                             0,
269                                             server_name,
270                                             opt);
271     }
272     krb5_get_init_creds_opt_free(context, opt);
273     switch(ret){
274     case 0:
275         break;
276     case KRB5_LIBOS_PWDINTR:    /* don't print anything if it was just C-c:ed */
277     case KRB5KRB_AP_ERR_BAD_INTEGRITY:
278     case KRB5KRB_AP_ERR_MODIFIED:
279         return KADM5_BAD_PASSWORD;
280     default:
281         return ret;
282     }
283     ret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &id);
284     if(ret)
285         return ret;
286     ret = krb5_cc_initialize (context, id, cred.client);
287     if (ret)
288         return ret;
289     ret = krb5_cc_store_cred (context, id, &cred);
290     if (ret)
291         return ret;
292     krb5_free_cred_contents (context, &cred);
293     *ret_cache = id;
294     return 0;
295 }
296
297 /*
298  * Check the credential cache `id´ to figure out what principal to use
299  * when talking to the kadmind. If there is a initial kadmin/admin@
300  * credential in the cache, use that client principal. Otherwise, use
301  * the client principals first component and add /admin to the
302  * principal.
303  */
304
305 static krb5_error_code
306 get_cache_principal(krb5_context context,
307                     krb5_ccache *id,
308                     krb5_principal *client)
309 {
310     krb5_error_code ret;
311     const char *name, *inst;
312     krb5_principal p1, p2;
313
314     ret = krb5_cc_default(context, id);
315     if(ret) {
316         *id = NULL;
317         return ret;
318     }
319
320     ret = krb5_cc_get_principal(context, *id, &p1);
321     if(ret) {
322         krb5_cc_close(context, *id);
323         *id = NULL;
324         return ret;
325     }
326
327     ret = krb5_make_principal(context, &p2, NULL,
328                               "kadmin", "admin", NULL);
329     if (ret) {
330         krb5_cc_close(context, *id);
331         *id = NULL;
332         krb5_free_principal(context, p1);
333         return ret;
334     }
335
336     {
337         krb5_creds in, *out;
338         krb5_kdc_flags flags;
339
340         flags.i = 0;
341         memset(&in, 0, sizeof(in));
342
343         in.client = p1;
344         in.server = p2;
345
346         /* check for initial ticket kadmin/admin */
347         ret = krb5_get_credentials_with_flags(context, KRB5_GC_CACHED, flags,
348                                               *id, &in, &out);
349         krb5_free_principal(context, p2);
350         if (ret == 0) {
351             if (out->flags.b.initial) {
352                 *client = p1;
353                 krb5_free_creds(context, out);
354                 return 0;
355             }
356             krb5_free_creds(context, out);
357         }
358     }
359     krb5_cc_close(context, *id);
360     *id = NULL;
361
362     name = krb5_principal_get_comp_string(context, p1, 0);
363     inst = krb5_principal_get_comp_string(context, p1, 1);
364     if(inst == NULL || strcmp(inst, "admin") != 0) {
365         ret = krb5_make_principal(context, &p2, NULL, name, "admin", NULL);
366         krb5_free_principal(context, p1);
367         if(ret != 0)
368             return ret;
369
370         *client = p2;
371         return 0;
372     }
373
374     *client = p1;
375
376     return 0;
377 }
378
379 krb5_error_code
380 _kadm5_c_get_cred_cache(krb5_context context,
381                         const char *client_name,
382                         const char *server_name,
383                         const char *password,
384                         krb5_prompter_fct prompter,
385                         const char *keytab,
386                         krb5_ccache ccache,
387                         krb5_ccache *ret_cache)
388 {
389     krb5_error_code ret;
390     krb5_ccache id = NULL;
391     krb5_principal default_client = NULL, client = NULL;
392
393     /* treat empty password as NULL */
394     if(password && *password == '\0')
395         password = NULL;
396     if(server_name == NULL)
397         server_name = KADM5_ADMIN_SERVICE;
398
399     if(client_name != NULL) {
400         ret = krb5_parse_name(context, client_name, &client);
401         if(ret)
402             return ret;
403     }
404
405     if(ccache != NULL) {
406         id = ccache;
407         ret = krb5_cc_get_principal(context, id, &client);
408         if(ret)
409             return ret;
410     } else {
411         /* get principal from default cache, ok if this doesn't work */
412
413         ret = get_cache_principal(context, &id, &default_client);
414         if (ret) {
415             /*
416              * No client was specified by the caller and we cannot
417              * determine the client from a credentials cache.
418              */
419             char userbuf[128];
420             const char *user = NULL;
421
422 #ifndef WIN32
423             if (geteuid() == 0)
424                 user = roken_get_loginname(userbuf, sizeof(userbuf));
425 #endif
426             if (user == NULL)
427                 user = roken_get_username(userbuf, sizeof(userbuf));
428             if (user == NULL) {
429                 krb5_set_error_message(context, KADM5_FAILURE, "Unable to find local user name");
430                 return KADM5_FAILURE;
431             }
432             ret = krb5_make_principal(context, &default_client,
433                                       NULL, user, "admin", NULL);
434             if(ret)
435                 return ret;
436         }
437     }
438
439
440     /*
441      * No client was specified by the caller, but we have a client
442      * from the default credentials cache.
443      */
444     if (client == NULL && default_client != NULL)
445         client = default_client;
446
447
448     if(id && client && (default_client == NULL ||
449               krb5_principal_compare(context, client, default_client) != 0)) {
450         ret = get_kadm_ticket(context, id, client, server_name);
451         if(ret == 0) {
452             *ret_cache = id;
453             krb5_free_principal(context, default_client);
454             if (default_client != client)
455                 krb5_free_principal(context, client);
456             return 0;
457         }
458         if(ccache != NULL)
459             /* couldn't get ticket from cache */
460             return -1;
461     }
462     /* get creds via AS request */
463     if(id && (id != ccache))
464         krb5_cc_close(context, id);
465     if (client != default_client)
466         krb5_free_principal(context, default_client);
467
468     ret = get_new_cache(context, client, password, prompter, keytab,
469                         server_name, ret_cache);
470     krb5_free_principal(context, client);
471     return ret;
472 }
473
474 static kadm5_ret_t
475 kadm_connect(kadm5_client_context *ctx)
476 {
477     kadm5_ret_t ret;
478     krb5_principal server = NULL;
479     krb5_ccache cc = NULL;
480     rk_socket_t s = rk_INVALID_SOCKET;
481     struct addrinfo *ai, *a;
482     struct addrinfo hints;
483     int free_ai = 0;
484     int error;
485     int kadmin_port = 0;
486     const char *admin_server = NULL;
487     char portstr[NI_MAXSERV];
488     const char *hostname, *slash;
489     char *service_name = NULL;
490     krb5_context context = ctx->context;
491     int writable = 0;
492
493     if (ctx->ac)
494         krb5_auth_con_free(context, ctx->ac);
495     ctx->ac = NULL;
496
497     if (!ctx->want_write) {
498         admin_server = ctx->readonly_admin_server;
499         kadmin_port = ctx->readonly_kadmind_port;
500     }
501     if (admin_server == NULL) {
502         admin_server = ctx->admin_server;
503         writable = 1;
504     }
505     if (kadmin_port < 1)
506         kadmin_port = ctx->kadmind_port;
507
508     memset(&hints, 0, sizeof(hints));
509     hints.ai_socktype = SOCK_STREAM;
510     hints.ai_protocol = IPPROTO_TCP;
511
512     snprintf(portstr, sizeof(portstr), "%u", ntohs(ctx->kadmind_port));
513
514     hostname = ctx->admin_server;
515     slash = strchr(hostname, '/');
516     if (slash != NULL)
517         hostname = slash + 1;
518
519     error = getaddrinfo(hostname, portstr, &hints, &ai);
520     if (error) {
521         ret = KADM5_BAD_SERVER_NAME;
522         goto out;
523     }
524
525     free_ai = 1;
526     for (a = ai; a != NULL; a = a->ai_next) {
527         s = socket(a->ai_family, a->ai_socktype, a->ai_protocol);
528         if (s < 0)
529             continue;
530         if (connect(s, a->ai_addr, a->ai_addrlen) < 0) {
531             krb5_warn(context, errno, "connect(%s)", hostname);
532             rk_closesocket(s);
533             continue;
534         }
535         break;
536     }
537     if (a == NULL) {
538         krb5_set_error_message(context, ret = KADM5_FAILURE,
539                                "failed to contact %s", hostname);
540         goto out;
541     }
542     ret = _kadm5_c_get_cred_cache(context,
543                                   ctx->client_name,
544                                   ctx->service_name,
545                                   NULL, ctx->prompter, ctx->keytab,
546                                   ctx->ccache, &cc);
547     if (ret)
548         goto out;
549
550     if (ctx->realm)
551         error = asprintf(&service_name, "%s@%s", KADM5_ADMIN_SERVICE,
552                          ctx->realm);
553     else
554         error = asprintf(&service_name, "%s", KADM5_ADMIN_SERVICE);
555
556     if (error == -1 || service_name == NULL) {
557         ret = krb5_enomem(context);
558         goto out;
559     }
560
561     ret = krb5_parse_name(context, service_name, &server);
562     if (ret)
563         goto out;
564
565     ret = krb5_sendauth(context, &ctx->ac, &s,
566                         KADMIN_APPL_VERSION, NULL,
567                         server, AP_OPTS_MUTUAL_REQUIRED,
568                         NULL, NULL, cc, NULL, NULL, NULL);
569     if (ret == 0) {
570         krb5_data params;
571         kadm5_config_params p;
572         memset(&p, 0, sizeof(p));
573         if(ctx->realm) {
574             p.mask |= KADM5_CONFIG_REALM;
575             p.realm = ctx->realm;
576         }
577         ret = _kadm5_marshal_params(context, &p, &params);
578         if (ret == 0) {
579             ret = krb5_write_priv_message(context, ctx->ac, &s, &params);
580             krb5_data_free(&params);
581         }
582     }
583
584     if (ret == 0) {
585         ctx->sock = s;
586         ctx->connected_to_writable = !!writable;
587     }
588
589 out:
590     free(service_name);
591     krb5_cc_close(context, cc);
592     krb5_free_principal(context, server);
593     if (free_ai)
594         freeaddrinfo(ai);
595     if (ret) {
596         if (s != rk_INVALID_SOCKET)
597             rk_closesocket(s);
598         krb5_auth_con_free(context, ctx->ac);
599         ctx->ac = NULL;
600     }
601     return ret;
602 }
603
604 kadm5_ret_t
605 _kadm5_connect(void *handle, int want_write)
606 {
607     kadm5_client_context *ctx = handle;
608
609     /*
610      * Reconnect?  Note that we don't reconnect to read-only kadmin servers if
611      * we're already connected to a writable kadmin server because we sometimes
612      * get a principal record after writing it.  We really need the application
613      * upstairs to tell us when to stop hogging writable kadmin servers.
614      *
615      * FIXME: Add an API for marking a kadm5_client_context as not needing to
616      * connect to writable kadmin servers.
617      */
618     ctx->want_write = !!want_write;
619     if (ctx->sock != rk_INVALID_SOCKET && want_write &&
620         !ctx->connected_to_writable) {
621         rk_closesocket(ctx->sock);
622         ctx->sock = rk_INVALID_SOCKET;
623     }
624     if (ctx->sock == rk_INVALID_SOCKET)
625         return kadm_connect(ctx);
626     return 0;
627 }
628
629 static kadm5_ret_t
630 kadm5_c_init_with_context(krb5_context context,
631                           const char *client_name,
632                           const char *password,
633                           krb5_prompter_fct prompter,
634                           const char *keytab,
635                           krb5_ccache ccache,
636                           const char *service_name,
637                           kadm5_config_params *realm_params,
638                           unsigned long struct_version,
639                           unsigned long api_version,
640                           void **server_handle)
641 {
642     kadm5_ret_t ret;
643     kadm5_client_context *ctx;
644     krb5_ccache cc;
645
646     ret = _kadm5_c_init_context(&ctx, realm_params, context);
647     if (ret)
648         return ret;
649
650     if (password != NULL && *password != '\0') {
651         ret = _kadm5_c_get_cred_cache(context,
652                                       client_name,
653                                       service_name,
654                                       password, prompter, keytab, ccache, &cc);
655         if (ret) {
656             kadm5_c_destroy(ctx);
657             return ret;
658         }
659         ccache = cc;
660     }
661
662
663     if (client_name != NULL)
664         ctx->client_name = strdup(client_name);
665     else
666         ctx->client_name = NULL;
667     if (service_name != NULL)
668         ctx->service_name = strdup(service_name);
669     else
670         ctx->service_name = NULL;
671     ctx->prompter = prompter;
672     ctx->keytab = keytab;
673     ctx->ccache = ccache;
674     /* maybe we should copy the params here */
675     ctx->sock = -1;
676
677     *server_handle = ctx;
678     return 0;
679 }
680
681 static kadm5_ret_t
682 init_context(const char *client_name,
683              const char *password,
684              krb5_prompter_fct prompter,
685              const char *keytab,
686              krb5_ccache ccache,
687              const char *service_name,
688              kadm5_config_params *realm_params,
689              unsigned long struct_version,
690              unsigned long api_version,
691              void **server_handle)
692 {
693     krb5_context context;
694     kadm5_ret_t ret;
695     kadm5_server_context *ctx;
696
697     ret = krb5_init_context(&context);
698     if (ret)
699         return ret;
700     ret = kadm5_c_init_with_context(context,
701                                     client_name,
702                                     password,
703                                     prompter,
704                                     keytab,
705                                     ccache,
706                                     service_name,
707                                     realm_params,
708                                     struct_version,
709                                     api_version,
710                                     server_handle);
711     if(ret){
712         krb5_free_context(context);
713         return ret;
714     }
715     ctx = *server_handle;
716     ctx->my_context = 1;
717     return 0;
718 }
719
720 kadm5_ret_t
721 kadm5_c_init_with_password_ctx(krb5_context context,
722                                const char *client_name,
723                                const char *password,
724                                const char *service_name,
725                                kadm5_config_params *realm_params,
726                                unsigned long struct_version,
727                                unsigned long api_version,
728                                void **server_handle)
729 {
730     return kadm5_c_init_with_context(context,
731                                      client_name,
732                                      password,
733                                      krb5_prompter_posix,
734                                      NULL,
735                                      NULL,
736                                      service_name,
737                                      realm_params,
738                                      struct_version,
739                                      api_version,
740                                      server_handle);
741 }
742
743 kadm5_ret_t
744 kadm5_c_init_with_password(const char *client_name,
745                            const char *password,
746                            const char *service_name,
747                            kadm5_config_params *realm_params,
748                            unsigned long struct_version,
749                            unsigned long api_version,
750                            void **server_handle)
751 {
752     return init_context(client_name,
753                         password,
754                         krb5_prompter_posix,
755                         NULL,
756                         NULL,
757                         service_name,
758                         realm_params,
759                         struct_version,
760                         api_version,
761                         server_handle);
762 }
763
764 kadm5_ret_t
765 kadm5_c_init_with_skey_ctx(krb5_context context,
766                            const char *client_name,
767                            const char *keytab,
768                            const char *service_name,
769                            kadm5_config_params *realm_params,
770                            unsigned long struct_version,
771                            unsigned long api_version,
772                            void **server_handle)
773 {
774     return kadm5_c_init_with_context(context,
775                                      client_name,
776                                      NULL,
777                                      NULL,
778                                      keytab,
779                                      NULL,
780                                      service_name,
781                                      realm_params,
782                                      struct_version,
783                                      api_version,
784                                      server_handle);
785 }
786
787
788 kadm5_ret_t
789 kadm5_c_init_with_skey(const char *client_name,
790                      const char *keytab,
791                      const char *service_name,
792                      kadm5_config_params *realm_params,
793                      unsigned long struct_version,
794                      unsigned long api_version,
795                      void **server_handle)
796 {
797     return init_context(client_name,
798                         NULL,
799                         NULL,
800                         keytab,
801                         NULL,
802                         service_name,
803                         realm_params,
804                         struct_version,
805                         api_version,
806                         server_handle);
807 }
808
809 kadm5_ret_t
810 kadm5_c_init_with_creds_ctx(krb5_context context,
811                             const char *client_name,
812                             krb5_ccache ccache,
813                             const char *service_name,
814                             kadm5_config_params *realm_params,
815                             unsigned long struct_version,
816                             unsigned long api_version,
817                             void **server_handle)
818 {
819     return kadm5_c_init_with_context(context,
820                                      client_name,
821                                      NULL,
822                                      NULL,
823                                      NULL,
824                                      ccache,
825                                      service_name,
826                                      realm_params,
827                                      struct_version,
828                                      api_version,
829                                      server_handle);
830 }
831
832 kadm5_ret_t
833 kadm5_c_init_with_creds(const char *client_name,
834                         krb5_ccache ccache,
835                         const char *service_name,
836                         kadm5_config_params *realm_params,
837                         unsigned long struct_version,
838                         unsigned long api_version,
839                         void **server_handle)
840 {
841     return init_context(client_name,
842                         NULL,
843                         NULL,
844                         NULL,
845                         ccache,
846                         service_name,
847                         realm_params,
848                         struct_version,
849                         api_version,
850                         server_handle);
851 }
852
853 #if 0
854 kadm5_ret_t
855 kadm5_init(char *client_name, char *pass,
856            char *service_name,
857            kadm5_config_params *realm_params,
858            unsigned long struct_version,
859            unsigned long api_version,
860            void **server_handle)
861 {
862 }
863 #endif
864