Skip to content

Commit

Permalink
Allow realm in kadm5_init service names
Browse files Browse the repository at this point in the history
Previously, if you passed a service name with a realm part to a
kadm5_init function, you would get a KRB5_PARSE_MALFORMED error
because the code would internally append its own '@realm' suffix
before parsing the name.  Fix this as follows:

Change gic_iter so instead of producing a full service name, it
produces a krb5_principal which is taken from the cred it acquires.
Pass the client and full service name around as principals, rather
than strings, and use the gss_nt_krb5_principal name type to import
them in setup_gss().  Don't append a realm to the input service name;
instead, pass the input service name directly to the gic functions
(which do not need a realm in the service name and will ignore the
realm if one is present).  For the INIT_CREDS case, parse the input
service name with KRB5_PRINCIPAL_PARSE_IGNORE_REALM and then set the
realm.

ticket: 7800
  • Loading branch information
greghudson committed Dec 21, 2013
1 parent 33b0659 commit 5341cfd
Showing 1 changed file with 48 additions and 48 deletions.
96 changes: 48 additions & 48 deletions src/lib/kadm5/clnt/client_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,23 +69,21 @@ init_any(krb5_context context, char *client_name, enum init_type init_type,
krb5_ui_4 api_version, char **db_args, void **server_handle);

static kadm5_ret_t
get_init_creds(kadm5_server_handle_t handle, char *client_name,
get_init_creds(kadm5_server_handle_t handle, krb5_principal client,
enum init_type init_type, char *pass, krb5_ccache ccache_in,
char *svcname_in, char *realm, char *full_svcname,
unsigned int full_svcname_len);
char *svcname_in, char *realm, krb5_principal *server_out);

static kadm5_ret_t
gic_iter(kadm5_server_handle_t handle, enum init_type init_type,
krb5_ccache ccache, krb5_principal client, char *pass,
char *svcname, char *realm, char *full_svcname,
unsigned int full_svcname_len);
char *svcname, char *realm, krb5_principal *server_out);

static kadm5_ret_t
connect_to_server(const char *hostname, int port, int *fd);

static kadm5_ret_t
setup_gss(kadm5_server_handle_t handle, kadm5_config_params *params_in,
char *client_name, char *full_svcname);
krb5_principal client, krb5_principal server);

static void
rpc_auth(kadm5_server_handle_t handle, kadm5_config_params *params_in,
Expand Down Expand Up @@ -161,8 +159,8 @@ init_any(krb5_context context, char *client_name, enum init_type init_type,
int port;
rpcprog_t rpc_prog;
rpcvers_t rpc_vers;
char full_svcname[BUFSIZ];
krb5_ccache ccache;
krb5_principal client = NULL, server = NULL;

kadm5_server_handle_t handle;
kadm5_config_params params_local;
Expand Down Expand Up @@ -231,13 +229,16 @@ init_any(krb5_context context, char *client_name, enum init_type init_type,
return KADM5_MISSING_KRB5_CONF_PARAMS;
}

code = krb5_parse_name(handle->context, client_name, &client);
if (code)
goto error;

/*
* Get credentials. Also does some fallbacks in case kadmin/fqdn
* principal doesn't exist.
*/
code = get_init_creds(handle, client_name, init_type, pass, ccache_in,
service_name, handle->params.realm, full_svcname,
sizeof(full_svcname));
code = get_init_creds(handle, client, init_type, pass, ccache_in,
service_name, handle->params.realm, &server);
if (code)
goto error;

Expand Down Expand Up @@ -281,8 +282,7 @@ init_any(krb5_context context, char *client_name, enum init_type init_type,
* authentication context.
*/
code = setup_gss(handle, params_in,
(init_type == INIT_CREDS) ? client_name : NULL,
full_svcname);
(init_type == INIT_CREDS) ? client : NULL, server);
if (code)
goto error;

Expand Down Expand Up @@ -357,6 +357,8 @@ init_any(krb5_context context, char *client_name, enum init_type init_type,
kadm5_free_config_params(handle->context, &handle->params);

cleanup:
krb5_free_principal(handle->context, client);
krb5_free_principal(handle->context, server);
if (code)
free(handle);

Expand All @@ -366,16 +368,16 @@ init_any(krb5_context context, char *client_name, enum init_type init_type,
/* Get initial credentials for authenticating to server. Perform fallback from
* kadmin/fqdn to kadmin/admin if svcname_in is NULL. */
static kadm5_ret_t
get_init_creds(kadm5_server_handle_t handle, char *client_name,
get_init_creds(kadm5_server_handle_t handle, krb5_principal client,
enum init_type init_type, char *pass, krb5_ccache ccache_in,
char *svcname_in, char *realm, char *full_svcname,
unsigned int full_svcname_len)
char *svcname_in, char *realm, krb5_principal *server_out)
{
kadm5_ret_t code;
krb5_principal client = NULL;
krb5_ccache ccache = NULL;
char svcname[BUFSIZ];

*server_out = NULL;

/* NULL svcname means use host-based. */
if (svcname_in == NULL) {
code = kadm5_get_admin_service_name(handle->context,
Expand All @@ -387,16 +389,12 @@ get_init_creds(kadm5_server_handle_t handle, char *client_name,
strncpy(svcname, svcname_in, sizeof(svcname));
svcname[sizeof(svcname)-1] = '\0';
}

/*
* Acquire a service ticket for svcname@realm in the name of
* client_name, using password pass (which could be NULL), and
* create a ccache to store them in. If INIT_CREDS, use the
* ccache we were provided instead.
* Acquire a service ticket for svcname@realm for client, using password
* pass (which could be NULL), and create a ccache to store them in. If
* INIT_CREDS, use the ccache we were provided instead.
*/
code = krb5_parse_name(handle->context, client_name, &client);
if (code)
goto error;

if (init_type == INIT_CREDS) {
ccache = ccache_in;
if (asprintf(&handle->cache_name, "%s:%s",
Expand Down Expand Up @@ -428,21 +426,19 @@ get_init_creds(kadm5_server_handle_t handle, char *client_name,
handle->lhandle->cache_name = handle->cache_name;

code = gic_iter(handle, init_type, ccache, client, pass, svcname, realm,
full_svcname, full_svcname_len);
server_out);
if ((code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN
|| code == KRB5_CC_NOTFOUND) && svcname_in == NULL) {
/* Retry with old host-independent service principal. */
code = gic_iter(handle, init_type, ccache, client, pass,
KADM5_ADMIN_SERVICE, realm, full_svcname,
full_svcname_len);
KADM5_ADMIN_SERVICE, realm, server_out);
}
/* Improved error messages */
if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY) code = KADM5_BAD_PASSWORD;
if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN)
code = KADM5_SECURE_PRINC_MISSING;

error:
krb5_free_principal(handle->context, client);
if (ccache != NULL && init_type != INIT_CREDS)
krb5_cc_close(handle->context, ccache);
return code;
Expand All @@ -453,27 +449,21 @@ get_init_creds(kadm5_server_handle_t handle, char *client_name,
static kadm5_ret_t
gic_iter(kadm5_server_handle_t handle, enum init_type init_type,
krb5_ccache ccache, krb5_principal client, char *pass, char *svcname,
char *realm, char *full_svcname, unsigned int full_svcname_len)
char *realm, krb5_principal *server_out)
{
kadm5_ret_t code;
krb5_context ctx;
krb5_keytab kt;
krb5_get_init_creds_opt *opt = NULL;
krb5_creds mcreds, outcreds;
int n;

*server_out = NULL;
ctx = handle->context;
kt = NULL;
memset(full_svcname, 0, full_svcname_len);
memset(&opt, 0, sizeof(opt));
memset(&mcreds, 0, sizeof(mcreds));
memset(&outcreds, 0, sizeof(outcreds));

code = ENOMEM;
n = snprintf(full_svcname, full_svcname_len, "%s@%s", svcname, realm);
if (SNPRINTF_OVERFLOW(n, full_svcname_len))
goto error;

/* Credentials for kadmin don't need to be forwardable or proxiable. */
if (init_type != INIT_CREDS) {
code = krb5_get_init_creds_opt_alloc(ctx, &opt);
Expand All @@ -487,8 +477,7 @@ gic_iter(kadm5_server_handle_t handle, enum init_type init_type,
if (init_type == INIT_PASS || init_type == INIT_ANONYMOUS) {
code = krb5_get_init_creds_password(ctx, &outcreds, client, pass,
krb5_prompter_posix,
NULL, 0,
full_svcname, opt);
NULL, 0, svcname, opt);
if (code)
goto error;
} else if (init_type == INIT_SKEY) {
Expand All @@ -498,14 +487,19 @@ gic_iter(kadm5_server_handle_t handle, enum init_type init_type,
goto error;
}
code = krb5_get_init_creds_keytab(ctx, &outcreds, client, kt,
0, full_svcname, opt);
0, svcname, opt);
if (pass)
krb5_kt_close(ctx, kt);
if (code)
goto error;
} else if (init_type == INIT_CREDS) {
mcreds.client = client;
code = krb5_parse_name(ctx, full_svcname, &mcreds.server);
code = krb5_parse_name_flags(ctx, svcname,
KRB5_PRINCIPAL_PARSE_IGNORE_REALM,
&mcreds.server);
if (code)
goto error;
code = krb5_set_principal_realm(ctx, mcreds.server, realm);
if (code)
goto error;
code = krb5_cc_retrieve_cred(ctx, ccache, 0,
Expand All @@ -514,6 +508,12 @@ gic_iter(kadm5_server_handle_t handle, enum init_type init_type,
if (code)
goto error;
}

/* Steal the server principal of the creds we acquired and return it to the
* caller, which needs to knows what service to authenticate to. */
*server_out = outcreds.server;
outcreds.server = NULL;

error:
krb5_free_cred_contents(ctx, &outcreds);
if (opt)
Expand Down Expand Up @@ -568,7 +568,7 @@ connect_to_server(const char *hostname, int port, int *fd)
/* Acquire GSSAPI credentials and set up RPC auth flavor. */
static kadm5_ret_t
setup_gss(kadm5_server_handle_t handle, kadm5_config_params *params_in,
char *client_name, char *full_svcname)
krb5_principal client, krb5_principal server)
{
OM_uint32 gssstat, minor_stat;
gss_buffer_desc buf;
Expand All @@ -592,18 +592,18 @@ setup_gss(kadm5_server_handle_t handle, kadm5_config_params *params_in,
else
ccname_orig = 0;

buf.value = full_svcname;
buf.length = strlen((char *)buf.value) + 1;
buf.value = &server;
buf.length = sizeof(server);
gssstat = gss_import_name(&minor_stat, &buf,
(gss_OID) gss_nt_krb5_name, &gss_target);
(gss_OID)gss_nt_krb5_principal, &gss_target);
if (gssstat != GSS_S_COMPLETE)
goto error;

if (client_name) {
buf.value = client_name;
buf.length = strlen((char *)buf.value) + 1;
if (client != NULL) {
buf.value = &client;
buf.length = sizeof(client);
gssstat = gss_import_name(&minor_stat, &buf,
(gss_OID) gss_nt_krb5_name, &gss_client);
(gss_OID)gss_nt_krb5_principal, &gss_client);
} else gss_client = GSS_C_NO_NAME;

if (gssstat != GSS_S_COMPLETE)
Expand Down

0 comments on commit 5341cfd

Please sign in to comment.