summaryrefslogtreecommitdiffstats
path: root/crypto/heimdal/lib/kadm5/init_c.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/heimdal/lib/kadm5/init_c.c')
-rw-r--r--crypto/heimdal/lib/kadm5/init_c.c233
1 files changed, 150 insertions, 83 deletions
diff --git a/crypto/heimdal/lib/kadm5/init_c.c b/crypto/heimdal/lib/kadm5/init_c.c
index 05b7adb..be53992 100644
--- a/crypto/heimdal/lib/kadm5/init_c.c
+++ b/crypto/heimdal/lib/kadm5/init_c.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan
+ * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
*
@@ -37,7 +37,7 @@
#include <netinet/in.h>
#include <netdb.h>
-RCSID("$Id: init_c.c,v 1.45.2.1 2003/12/21 22:48:13 lha Exp $");
+RCSID("$Id: init_c.c 21972 2007-10-18 19:11:15Z lha $");
static void
set_funcs(kadm5_client_context *c)
@@ -99,9 +99,9 @@ _kadm5_c_init_context(kadm5_client_context **ctx,
}
if ((*ctx)->admin_server == NULL) {
- return ENOMEM;
free((*ctx)->realm);
free(*ctx);
+ return ENOMEM;
}
colon = strchr ((*ctx)->admin_server, ':');
if (colon != NULL)
@@ -154,19 +154,21 @@ get_new_cache(krb5_context context,
{
krb5_error_code ret;
krb5_creds cred;
- krb5_get_init_creds_opt opt;
+ krb5_get_init_creds_opt *opt;
krb5_ccache id;
- krb5_get_init_creds_opt_init (&opt);
+ ret = krb5_get_init_creds_opt_alloc (context, &opt);
+ if (ret)
+ return ret;
krb5_get_init_creds_opt_set_default_flags(context, "kadmin",
krb5_principal_get_realm(context,
client),
- &opt);
+ opt);
- krb5_get_init_creds_opt_set_forwardable (&opt, FALSE);
- krb5_get_init_creds_opt_set_proxiable (&opt, FALSE);
+ krb5_get_init_creds_opt_set_forwardable (opt, FALSE);
+ krb5_get_init_creds_opt_set_proxiable (opt, FALSE);
if(password == NULL && prompter == NULL) {
krb5_keytab kt;
@@ -174,15 +176,17 @@ get_new_cache(krb5_context context,
ret = krb5_kt_default(context, &kt);
else
ret = krb5_kt_resolve(context, keytab, &kt);
- if(ret)
+ if(ret) {
+ krb5_get_init_creds_opt_free(context, opt);
return ret;
+ }
ret = krb5_get_init_creds_keytab (context,
&cred,
client,
kt,
0,
server_name,
- &opt);
+ opt);
krb5_kt_close(context, kt);
} else {
ret = krb5_get_init_creds_password (context,
@@ -193,8 +197,9 @@ get_new_cache(krb5_context context,
NULL,
0,
server_name,
- &opt);
+ opt);
}
+ krb5_get_init_creds_opt_free(context, opt);
switch(ret){
case 0:
break;
@@ -214,20 +219,102 @@ get_new_cache(krb5_context context,
ret = krb5_cc_store_cred (context, id, &cred);
if (ret)
return ret;
- krb5_free_creds_contents (context, &cred);
+ krb5_free_cred_contents (context, &cred);
*ret_cache = id;
return 0;
}
+/*
+ * Check the credential cache `id´ to figure out what principal to use
+ * when talking to the kadmind. If there is a initial kadmin/admin@
+ * credential in the cache, use that client principal. Otherwise, use
+ * the client principals first component and add /admin to the
+ * principal.
+ */
+
static krb5_error_code
-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)
+get_cache_principal(krb5_context context,
+ krb5_ccache *id,
+ krb5_principal *client)
+{
+ krb5_error_code ret;
+ const char *name, *inst;
+ krb5_principal p1, p2;
+
+ ret = krb5_cc_default(context, id);
+ if(ret) {
+ *id = NULL;
+ return ret;
+ }
+
+ ret = krb5_cc_get_principal(context, *id, &p1);
+ if(ret) {
+ krb5_cc_close(context, *id);
+ *id = NULL;
+ return ret;
+ }
+
+ ret = krb5_make_principal(context, &p2, NULL,
+ "kadmin", "admin", NULL);
+ if (ret) {
+ krb5_cc_close(context, *id);
+ *id = NULL;
+ krb5_free_principal(context, p1);
+ return ret;
+ }
+
+ {
+ krb5_creds in, *out;
+ krb5_kdc_flags flags;
+
+ flags.i = 0;
+ memset(&in, 0, sizeof(in));
+
+ in.client = p1;
+ in.server = p2;
+
+ /* check for initial ticket kadmin/admin */
+ ret = krb5_get_credentials_with_flags(context, KRB5_GC_CACHED, flags,
+ *id, &in, &out);
+ krb5_free_principal(context, p2);
+ if (ret == 0) {
+ if (out->flags.b.initial) {
+ *client = p1;
+ krb5_free_creds(context, out);
+ return 0;
+ }
+ krb5_free_creds(context, out);
+ }
+ }
+ krb5_cc_close(context, *id);
+ *id = NULL;
+
+ name = krb5_principal_get_comp_string(context, p1, 0);
+ inst = krb5_principal_get_comp_string(context, p1, 1);
+ if(inst == NULL || strcmp(inst, "admin") != 0) {
+ ret = krb5_make_principal(context, &p2, NULL, name, "admin", NULL);
+ krb5_free_principal(context, p1);
+ if(ret != 0)
+ return ret;
+
+ *client = p2;
+ return 0;
+ }
+
+ *client = p1;
+
+ return 0;
+}
+
+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)
{
krb5_error_code ret;
krb5_ccache id = NULL;
@@ -245,70 +332,43 @@ get_cred_cache(krb5_context context,
return ret;
}
- if(password != NULL || prompter != NULL) {
+ if(ccache != NULL) {
+ id = ccache;
+ ret = krb5_cc_get_principal(context, id, &client);
+ if(ret)
+ return ret;
+ } else {
/* get principal from default cache, ok if this doesn't work */
- ret = krb5_cc_default(context, &id);
- if(ret == 0) {
- ret = krb5_cc_get_principal(context, id, &default_client);
- if(ret) {
- krb5_cc_close(context, id);
- id = NULL;
- } else {
- const char *name, *inst;
- krb5_principal tmp;
- name = krb5_principal_get_comp_string(context,
- default_client, 0);
- inst = krb5_principal_get_comp_string(context,
- default_client, 1);
- if(inst == NULL || strcmp(inst, "admin") != 0) {
- ret = krb5_make_principal(context, &tmp, NULL,
- name, "admin", NULL);
- if(ret != 0) {
- krb5_free_principal(context, default_client);
- krb5_cc_close(context, id);
- return ret;
- }
- krb5_free_principal(context, default_client);
- default_client = tmp;
- krb5_cc_close(context, id);
- id = NULL;
- }
- }
- }
- if (client != NULL) {
- /* A client was specified by the caller. */
- if (default_client != NULL) {
- krb5_free_principal(context, default_client);
- default_client = NULL;
- }
- }
- else if (default_client != NULL)
- /* No client was specified by the caller, but we have a
- * client from the default credentials cache.
- */
- client = default_client;
- else {
- /* No client was specified by the caller and we cannot determine
- * the client from a credentials cache.
+ ret = get_cache_principal(context, &id, &default_client);
+ if (ret) {
+ /*
+ * No client was specified by the caller and we cannot
+ * determine the client from a credentials cache.
*/
const char *user;
user = get_default_username ();
- if(user == NULL)
+ if(user == NULL) {
+ krb5_set_error_string(context, "Unable to find local user name");
return KADM5_FAILURE;
- ret = krb5_make_principal(context, &client,
+ }
+ ret = krb5_make_principal(context, &default_client,
NULL, user, "admin", NULL);
if(ret)
return ret;
- if (id != NULL) {
- krb5_cc_close(context, id);
- id = NULL;
- }
}
- } else if(ccache != NULL)
- id = ccache;
+ }
+
+
+ /*
+ * No client was specified by the caller, but we have a client
+ * from the default credentials cache.
+ */
+ if (client == NULL && default_client != NULL)
+ client = default_client;
+
if(id && (default_client == NULL ||
krb5_principal_compare(context, client, default_client))) {
@@ -325,7 +385,7 @@ get_cred_cache(krb5_context context,
return -1;
}
/* get creds via AS request */
- if(id)
+ if(id && (id != ccache))
krb5_cc_close(context, id);
if (client != default_client)
krb5_free_principal(context, default_client);
@@ -363,14 +423,17 @@ kadm_connect(kadm5_client_context *ctx)
hostname = slash + 1;
error = getaddrinfo (hostname, portstr, &hints, &ai);
- if (error)
+ if (error) {
+ krb5_clear_error_string(context);
return KADM5_BAD_SERVER_NAME;
+ }
for (a = ai; a != NULL; a = a->ai_next) {
s = socket (a->ai_family, a->ai_socktype, a->ai_protocol);
if (s < 0)
continue;
if (connect (s, a->ai_addr, a->ai_addrlen) < 0) {
+ krb5_clear_error_string(context);
krb5_warn (context, errno, "connect(%s)", hostname);
close (s);
continue;
@@ -379,12 +442,15 @@ kadm_connect(kadm5_client_context *ctx)
}
if (a == NULL) {
freeaddrinfo (ai);
+ krb5_clear_error_string(context);
krb5_warnx (context, "failed to contact %s", hostname);
return KADM5_FAILURE;
}
- ret = get_cred_cache(context, ctx->client_name, ctx->service_name,
- NULL, ctx->prompter, ctx->keytab,
- ctx->ccache, &cc);
+ ret = _kadm5_c_get_cred_cache(context,
+ ctx->client_name,
+ ctx->service_name,
+ NULL, ctx->prompter, ctx->keytab,
+ ctx->ccache, &cc);
if(ret) {
freeaddrinfo (ai);
@@ -400,6 +466,7 @@ kadm_connect(kadm5_client_context *ctx)
if (service_name == NULL) {
freeaddrinfo (ai);
close(s);
+ krb5_clear_error_string(context);
return ENOMEM;
}
@@ -443,11 +510,13 @@ kadm_connect(kadm5_client_context *ctx)
s = socket (a->ai_family, a->ai_socktype, a->ai_protocol);
if (s < 0) {
freeaddrinfo (ai);
+ krb5_clear_error_string(context);
return errno;
}
if (connect (s, a->ai_addr, a->ai_addrlen) < 0) {
close (s);
freeaddrinfo (ai);
+ krb5_clear_error_string(context);
return errno;
}
ret = krb5_sendauth(context, &ctx->ac, &s,
@@ -464,10 +533,6 @@ kadm_connect(kadm5_client_context *ctx)
krb5_free_principal(context, server);
if(ctx->ccache == NULL)
krb5_cc_close(context, cc);
- if(ret) {
- close(s);
- return ret;
- }
ctx->sock = s;
return 0;
@@ -504,8 +569,10 @@ kadm5_c_init_with_context(krb5_context context,
return ret;
if(password != NULL && *password != '\0') {
- ret = get_cred_cache(context, client_name, service_name,
- password, prompter, keytab, ccache, &cc);
+ ret = _kadm5_c_get_cred_cache(context,
+ client_name,
+ service_name,
+ password, prompter, keytab, ccache, &cc);
if(ret)
return ret; /* XXX */
ccache = cc;
OpenPOWER on IntegriCloud