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