PSARC/2015/144 Kerberos 1.13 Delivery to Userland
19153034 Add MIT Kerberos to the Userland Consolidation
#
# This patch provides support in kadmin and kpropd to work in a
# multi-master environment.
#
# Note that we have discussed support for this with MIT in the past but
# they have been reticent to add such support. It is possible that
# support for this may be introduced at a later time at which point we
# should look at modifying/deleting this patch.
# Patch source: in-house
#
diff -u -r old/src/kadmin/cli/kadmin.c new/src/kadmin/cli/kadmin.c
--- old/src/kadmin/cli/kadmin.c 2015-05-28 15:10:45.129616302 -0500
+++ new/src/kadmin/cli/kadmin.c 2015-05-29 13:32:41.901105712 -0500
@@ -268,7 +268,7 @@
char **db_args = NULL;
int db_args_size = 0;
char *db_name = NULL;
- char *svcname, *realm;
+ char **svcnames = NULL, *realm;
memset(¶ms, 0, sizeof(params));
@@ -380,11 +380,6 @@
params.mask |= KADM5_CONFIG_REALM;
params.realm = def_realm;
- if (params.mask & KADM5_CONFIG_OLD_AUTH_GSSAPI)
- svcname = KADM5_ADMIN_SERVICE;
- else
- svcname = NULL;
-
/*
* Set cc to an open credentials cache, either specified by the -c
* argument or the default.
@@ -515,13 +510,15 @@
if (ccache_name) {
printf(_("Authenticating as principal %s with existing "
"credentials.\n"), princstr);
- retval = kadm5_init_with_creds(context, princstr, cc, svcname, ¶ms,
+ retval = kadm5_init_with_creds_mm(context, princstr, cc, svcnames,
+ ¶ms,
KADM5_STRUCT_VERSION,
KADM5_API_VERSION_4, db_args, &handle);
} else if (use_anonymous) {
printf(_("Authenticating as principal %s with password; "
"anonymous requested.\n"), princstr);
- retval = kadm5_init_anonymous(context, princstr, svcname, ¶ms,
+ retval = kadm5_init_anonymous_mm(context, princstr, svcnames,
+ ¶ms,
KADM5_STRUCT_VERSION,
KADM5_API_VERSION_4, db_args, &handle);
} else if (use_keytab) {
@@ -531,17 +528,20 @@
else
printf(_("Authenticating as principal %s with default keytab.\n"),
princstr);
- retval = kadm5_init_with_skey(context, princstr, keytab_name, svcname,
+ retval = kadm5_init_with_skey_mm(context, princstr, keytab_name,
+ svcnames,
¶ms, KADM5_STRUCT_VERSION,
KADM5_API_VERSION_4, db_args, &handle);
} else {
printf(_("Authenticating as principal %s with password.\n"),
princstr);
- retval = kadm5_init_with_password(context, princstr, password, svcname,
+ retval = kadm5_init_with_password_mm(context, princstr, password,
+ svcnames,
¶ms, KADM5_STRUCT_VERSION,
KADM5_API_VERSION_4, db_args,
&handle);
}
+ free_srv_names(svcnames);
if (retval) {
com_err(whoami, retval, _("while initializing %s interface"), whoami);
if (retval == KADM5_BAD_CLIENT_PARAMS ||
diff -u -r old/src/lib/kadm5/admin.h new/src/lib/kadm5/admin.h
--- old/src/lib/kadm5/admin.h 2015-05-28 15:10:45.095122403 -0500
+++ new/src/lib/kadm5/admin.h 2015-05-28 15:34:35.800877732 -0500
@@ -345,6 +345,51 @@
krb5_ui_4 api_version,
char **db_args,
void **server_handle);
+kadm5_ret_t kadm5_init_with_creds_mm(krb5_context context,
+ char *client_name,
+ krb5_ccache ccache,
+ char **svcnames,
+ kadm5_config_params *params,
+ krb5_ui_4 struct_version,
+ krb5_ui_4 api_version,
+ char **db_args,
+ void **server_handle);
+kadm5_ret_t kadm5_init_with_password_mm(krb5_context context,
+ char *client_name,
+ char *pass,
+ char **svcnames,
+ kadm5_config_params *params,
+ krb5_ui_4 struct_version,
+ krb5_ui_4 api_version,
+ char **db_args,
+ void **server_handle);
+kadm5_ret_t kadm5_init_anonymous_mm(krb5_context context,
+ char *client_name,
+ char **svcnames,
+ kadm5_config_params *params,
+ krb5_ui_4 struct_version,
+ krb5_ui_4 api_version,
+ char **db_args,
+ void **server_handle);
+kadm5_ret_t kadm5_init_mm(krb5_context context,
+ char *client_name,
+ char *pass,
+ char **svcnames,
+ kadm5_config_params *params,
+ krb5_ui_4 struct_version,
+ krb5_ui_4 api_version,
+ char **db_args,
+ void **server_handle);
+kadm5_ret_t kadm5_init_with_skey_mm(krb5_context context,
+ char *client_name,
+ char *keytab,
+ char **svcnames,
+ kadm5_config_params *params,
+ krb5_ui_4 struct_version,
+ krb5_ui_4 api_version,
+ char **db_args,
+ void **server_handle);
+
kadm5_ret_t kadm5_lock(void *server_handle);
kadm5_ret_t kadm5_unlock(void *server_handle);
kadm5_ret_t kadm5_flush(void *server_handle);
diff -u -r old/src/lib/kadm5/clnt/client_init.c new/src/lib/kadm5/clnt/client_init.c
--- old/src/lib/kadm5/clnt/client_init.c 2015-05-28 15:10:45.192975632 -0500
+++ new/src/lib/kadm5/clnt/client_init.c 2015-06-02 10:33:51.639341637 -0500
@@ -55,7 +55,7 @@
static kadm5_ret_t
init_any(krb5_context context, char *client_name, enum init_type init_type,
- char *pass, krb5_ccache ccache_in, char *service_name,
+ char *pass, krb5_ccache ccache_in, char **service_names,
kadm5_config_params *params, krb5_ui_4 struct_version,
krb5_ui_4 api_version, char **db_args, void **server_handle);
@@ -87,8 +87,25 @@
krb5_ui_4 api_version, char **db_args,
void **server_handle)
{
+ char *svcnames[2];
+
+ svcnames[0] = service_name;
+ svcnames[1] = NULL;
+
+ return init_any(context, client_name, INIT_CREDS, NULL, ccache,
+ svcnames, params, struct_version, api_version, db_args,
+ server_handle);
+}
+
+kadm5_ret_t
+kadm5_init_with_creds_mm(krb5_context context, char *client_name,
+ krb5_ccache ccache, char **svcnames,
+ kadm5_config_params *params, krb5_ui_4 struct_version,
+ krb5_ui_4 api_version, char **db_args,
+ void **server_handle)
+{
return init_any(context, client_name, INIT_CREDS, NULL, ccache,
- service_name, params, struct_version, api_version, db_args,
+ svcnames, params, struct_version, api_version, db_args,
server_handle);
}
@@ -99,7 +116,24 @@
krb5_ui_4 api_version, char **db_args,
void **server_handle)
{
- return init_any(context, client_name, INIT_PASS, pass, NULL, service_name,
+ char *svcnames[2];
+
+ svcnames[0] = service_name;
+ svcnames[1] = NULL;
+
+ return init_any(context, client_name, INIT_PASS, pass, NULL, svcnames,
+ params, struct_version, api_version, db_args,
+ server_handle);
+}
+
+kadm5_ret_t
+kadm5_init_with_password_mm(krb5_context context, char *client_name,
+ char *pass, char **svcnames,
+ kadm5_config_params *params, krb5_ui_4 struct_version,
+ krb5_ui_4 api_version, char **db_args,
+ void **server_handle)
+{
+ return init_any(context, client_name, INIT_PASS, pass, NULL, svcnames,
params, struct_version, api_version, db_args,
server_handle);
}
@@ -110,8 +144,24 @@
krb5_ui_4 struct_version, krb5_ui_4 api_version,
char **db_args, void **server_handle)
{
+ char *svcnames[2];
+
+ svcnames[0] = service_name;
+ svcnames[1] = NULL;
+
+ return init_any(context, client_name, INIT_ANONYMOUS, NULL, NULL,
+ svcnames, params, struct_version, api_version,
+ db_args, server_handle);
+}
+
+kadm5_ret_t
+kadm5_init_anonymous_mm(krb5_context context, char *client_name,
+ char **svcnames, kadm5_config_params *params,
+ krb5_ui_4 struct_version, krb5_ui_4 api_version,
+ char **db_args, void **server_handle)
+{
return init_any(context, client_name, INIT_ANONYMOUS, NULL, NULL,
- service_name, params, struct_version, api_version,
+ svcnames, params, struct_version, api_version,
db_args, server_handle);
}
@@ -121,7 +171,23 @@
krb5_ui_4 struct_version, krb5_ui_4 api_version, char **db_args,
void **server_handle)
{
- return init_any(context, client_name, INIT_PASS, pass, NULL, service_name,
+ char *svcnames[2];
+
+ svcnames[0] = service_name;
+ svcnames[1] = NULL;
+
+ return init_any(context, client_name, INIT_PASS, pass, NULL, svcnames,
+ params, struct_version, api_version, db_args,
+ server_handle);
+}
+
+kadm5_ret_t
+kadm5_init_mm(krb5_context context, char *client_name, char *pass,
+ char **svcnames, kadm5_config_params *params,
+ krb5_ui_4 struct_version, krb5_ui_4 api_version, char **db_args,
+ void **server_handle)
+{
+ return init_any(context, client_name, INIT_PASS, pass, NULL, svcnames,
params, struct_version, api_version, db_args,
server_handle);
}
@@ -133,8 +199,25 @@
krb5_ui_4 api_version, char **db_args,
void **server_handle)
{
+ char *svcnames[2];
+
+ svcnames[0] = service_name;
+ svcnames[1] = NULL;
+
return init_any(context, client_name, INIT_SKEY, keytab, NULL,
- service_name, params, struct_version, api_version, db_args,
+ svcnames, params, struct_version, api_version, db_args,
+ server_handle);
+}
+
+kadm5_ret_t
+kadm5_init_with_skey_mm(krb5_context context, char *client_name,
+ char *keytab, char **svcnames,
+ kadm5_config_params *params, krb5_ui_4 struct_version,
+ krb5_ui_4 api_version, char **db_args,
+ void **server_handle)
+{
+ return init_any(context, client_name, INIT_SKEY, keytab, NULL,
+ svcnames, params, struct_version, api_version, db_args,
server_handle);
}
@@ -338,7 +421,7 @@
}
/*
- * iprop fallback logic:
+ * iprop fallback logic:
* - if iprop_port is configured, connect to iprop_port
* - if not, query remote rpc/bind
* - if that fails, try consuming iprop service on kadmin port
@@ -506,9 +589,35 @@
return (code);
}
+/* utility function used below */
+static void
+clean_up(kadm5_server_handle_t handle,
+ krb5_principal *server,
+ krb5_ccache *ccache)
+{
+ if (handle->destroy_cache && handle->cache_name) {
+ if (krb5_cc_resolve(handle->context,
+ handle->cache_name, &ccache) == 0)
+ (void) krb5_cc_destroy (handle->context, ccache);
+ }
+
+ free(handle->cache_name);
+ handle->cache_name = NULL;
+
+ if (handle->clnt && handle->clnt->cl_auth)
+ AUTH_DESTROY(handle->clnt->cl_auth);
+ if (handle->clnt) {
+ clnt_destroy(handle->clnt);
+ handle->clnt = NULL;
+ }
+
+ krb5_free_principal(handle->context, *server);
+ *server = NULL;
+}
+
static kadm5_ret_t
init_any(krb5_context context, char *client_name, enum init_type init_type,
- char *pass, krb5_ccache ccache_in, char *svcname,
+ char *pass, krb5_ccache ccache_in, char **svcnames_in,
kadm5_config_params *params_in, krb5_ui_4 struct_version,
krb5_ui_4 api_version, char **db_args, void **server_handle)
{
@@ -526,6 +635,10 @@
int code = 0;
generic_ret *r;
+ char **kadmin_srv_names = NULL;
+ char *tmp_srv_names[2] = {NULL, NULL};
+ char **svcname_ptr;
+ int i;
initialize_ovk_error_table();
/* initialize_adb_error_table(); */
@@ -593,34 +706,56 @@
if (code)
goto error;
- /* NULL svcname means use host-based. */
- if (svcname == NULL) {
- char **kadmin_srv_names;
+ if (svcnames_in == NULL || svcnames_in[0] == NULL) {
+ if (params_in && params_in->mask & KADM5_CONFIG_ADMIN_SERVER &&
+ params_in->admin_server != NULL) {
+ /* User passed in a admin server host name so use that */
+ if (asprintf(&tmp_srv_names[0], "%s@%s", KADM5_ADMIN_HOST_SERVICE,
+ params_in->admin_server) == -1) {
+ code = ENOMEM;
+ goto error;
+ }
+ svcname_ptr = tmp_srv_names;
+ } else {
+ /* Otherwise punt and get the admin server names. */
+ code = kadm5_get_adm_host_srv_names(context, handle->params.realm,
+ &kadmin_srv_names);
+ if (code)
+ goto error;
+ svcname_ptr = kadmin_srv_names;
+ }
+ } else {
+ svcname_ptr = svcnames_in;
+ }
- code = kadm5_get_adm_host_srv_names(context, handle->params.realm,
- &kadmin_srv_names);
- if (code)
- goto error;
- svcname = strdup(kadmin_srv_names[0]);
- free_srv_names(kadmin_srv_names);
- if (svcname == NULL) {
- code = ENOMEM;
- goto error;
- }
+ for (i = 0; svcname_ptr[i]; i++) {
+ /* Get credentials. */
+ code = get_init_creds(handle, client, init_type, pass, ccache_in,
+ svcname_ptr[i], handle->params.realm, &server);
+ if (code) {
+ if (code == KADM5_SECURE_PRINC_MISSING ||
+ code == KRB5_ERR_BAD_HOSTNAME) {
+ /* clean up for another go around */
+ clean_up(handle, &server, &ccache);
+ continue;
+ } else
+ goto error;
+ }
+
+ code = _kadm5_initialize_rpcsec_gss_handle(handle, client_name,
+ svcname_ptr[i]);
+ if (code) {
+ /* clean up for another go around */
+ clean_up(handle, &server, &ccache);
+ } else {
+ /* inited the rpcsec_gss handle, can stop looping now */
+ break;
+ }
}
- /* Get credentials. */
- code = get_init_creds(handle, client, init_type, pass, ccache_in,
- svcname, handle->params.realm, &server);
if (code)
goto error;
- code = _kadm5_initialize_rpcsec_gss_handle(handle, client_name,
- svcname);
- if (code != 0) {
- goto error;
- }
-
*server_handle = (void *) handle;
goto cleanup;
@@ -653,6 +788,8 @@
krb5_free_principal(handle->context, server);
if (code)
free(handle);
+ free_srv_names(kadmin_srv_names);
+ free(tmp_srv_names[0]);
return code;
}
@@ -665,46 +802,43 @@
{
kadm5_ret_t code;
krb5_ccache ccache = NULL;
- krb5_principal cprinc;
char svcbuf[BUFSIZ], *service, *host, *svcname, *save;
+ char strtok_buf[BUFSIZ];
*server_out = NULL;
- /*
- * Convert the RPCSEC_GSS version to the host based version as this
- * is what gic expects.
- */
- if ((svcname = strdup(svcname_in)) == NULL) {
- code = ENOMEM;
- goto error;
- }
- if ((service = strtok_r(svcname, "@", &save)) != NULL) {
- if ((host = strtok_r(NULL, "@", &save)) != NULL) {
- char *str = NULL;
- /*
- * We want the canonical name here, via sname_to_principal.
- */
- code = krb5_sname_to_principal(handle->context, host, service,
- KRB5_NT_SRV_HST, &cprinc);
- if (code) {
- free(svcname);
- goto error;
- }
- code = krb5_unparse_name_flags(handle->context, cprinc,
- KRB5_PRINCIPAL_UNPARSE_NO_REALM, &str);
- krb5_free_principal(handle->context, cprinc);
- if (code) {
- free(svcname);
- goto error;
- }
- (void) strncpy(svcbuf, str, sizeof(svcbuf));
- krb5_free_unparsed_name(handle->context, str);
- }
+ if (strpbrk(svcname_in, "@") == NULL) {
+ svcname = svcname_in;
} else {
- strncpy(svcbuf, svcname, sizeof(svcbuf));
- svcbuf[sizeof(svcname)-1] = '\0';
+ /*
+ * Convert the RPCSEC_GSS version to the host based version as this
+ * is what gic expects.
+ */
+ (void) strlcpy(strtok_buf, svcname_in, sizeof(strtok_buf));
+ service = strtok_r(strtok_buf, "@", &save);
+ if ((host = strtok_r(NULL, "@", &save)) != NULL) {
+ char *str = NULL;
+ krb5_principal cprinc;
+ /*
+ * We want the canonical name here, via sname_to_principal.
+ */
+ code = krb5_sname_to_principal(handle->context, host, service,
+ KRB5_NT_SRV_HST, &cprinc);
+ if (code)
+ goto error;
+
+ code = krb5_unparse_name_flags(handle->context, cprinc,
+ KRB5_PRINCIPAL_UNPARSE_NO_REALM,
+ &str);
+ krb5_free_principal(handle->context, cprinc);
+ if (code)
+ goto error;
+
+ (void) strlcpy(svcbuf, str, sizeof(svcbuf));
+ krb5_free_unparsed_name(handle->context, str);
+ svcname = svcbuf;
+ }
}
- free(svcname);
/*
* Acquire a service ticket for svcname@realm for client, using password
@@ -741,7 +875,7 @@
}
handle->lhandle->cache_name = handle->cache_name;
- code = gic_iter(handle, init_type, ccache, client, pass, svcbuf, realm,
+ code = gic_iter(handle, init_type, ccache, client, pass, svcname, realm,
server_out);
/* Improved error messages */
if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY) code = KADM5_BAD_PASSWORD;
diff -u -r old/src/lib/kadm5/clnt/libkadm5clnt_mit.exports new/src/lib/kadm5/clnt/libkadm5clnt_mit.exports
--- old/src/lib/kadm5/clnt/libkadm5clnt_mit.exports 2015-02-11 21:16:43.000000000 -0600
+++ new/src/lib/kadm5/clnt/libkadm5clnt_mit.exports 2015-05-28 15:34:35.828495806 -0500
@@ -31,6 +31,11 @@
kadm5_init_with_creds
kadm5_init_with_password
kadm5_init_with_skey
+kadm5_init_mm
+kadm5_init_anonymous_mm
+kadm5_init_with_creds_mm
+kadm5_init_with_password_mm
+kadm5_init_with_skey_mm
kadm5_lock
kadm5_modify_policy
kadm5_modify_principal
diff -u -r old/src/lib/kadm5/srv/server_init.c new/src/lib/kadm5/srv/server_init.c
--- old/src/lib/kadm5/srv/server_init.c 2015-05-28 15:10:45.100182433 -0500
+++ new/src/lib/kadm5/srv/server_init.c 2015-05-29 12:40:47.354397224 -0500
@@ -97,6 +97,29 @@
server_handle);
}
+/*
+ * The following *_mm() functions are also defined here because kadmin.local
+ * shares the same source as kadmin. One difference however is that
+ * kadmin.local links with libkadm5srv_mit.so instead of libkadm5clnt_mit.so so
+ * these functions must also be defined here. Given kadmin.local can only
+ * operate on one server, the *_mm() functions just pass in the first server in
+ * the list of service_names.
+ */
+kadm5_ret_t kadm5_init_with_password_mm(krb5_context context,
+ char *client_name,
+ char *pass, char **service_names,
+ kadm5_config_params *params,
+ krb5_ui_4 struct_version,
+ krb5_ui_4 api_version,
+ char **db_args,
+ void **server_handle)
+{
+ return kadm5_init_with_password(context, client_name, pass,
+ service_names ? service_names[0] : NULL,
+ params, struct_version, api_version,
+ db_args, server_handle);
+}
+
kadm5_ret_t kadm5_init_anonymous(krb5_context context, char *client_name,
char *service_name,
kadm5_config_params *params,
@@ -110,6 +133,20 @@
server_handle);
}
+kadm5_ret_t kadm5_init_anonymous_mm(krb5_context context, char *client_name,
+ char **service_names,
+ kadm5_config_params *params,
+ krb5_ui_4 struct_version,
+ krb5_ui_4 api_version,
+ char **db_args,
+ void **server_handle)
+{
+ return kadm5_init_anonymous(context, client_name,
+ service_names ? service_names[0] : NULL,
+ params, struct_version, api_version,
+ db_args, server_handle);
+}
+
kadm5_ret_t kadm5_init_with_creds(krb5_context context,
char *client_name,
krb5_ccache ccache,
@@ -133,6 +170,22 @@
server_handle);
}
+kadm5_ret_t kadm5_init_with_creds_mm(krb5_context context,
+ char *client_name,
+ krb5_ccache ccache,
+ char **service_names,
+ kadm5_config_params *params,
+ krb5_ui_4 struct_version,
+ krb5_ui_4 api_version,
+ char **db_args,
+ void **server_handle)
+{
+ return kadm5_init_with_creds(context, client_name, ccache,
+ service_names ? service_names[0] : NULL,
+ params, struct_version, api_version,
+ db_args, server_handle);
+}
+
kadm5_ret_t kadm5_init_with_skey(krb5_context context, char *client_name,
char *keytab, char *service_name,
@@ -155,6 +208,20 @@
server_handle);
}
+kadm5_ret_t kadm5_init_with_skey_mm(krb5_context context, char *client_name,
+ char *keytab, char **service_names,
+ kadm5_config_params *params,
+ krb5_ui_4 struct_version,
+ krb5_ui_4 api_version,
+ char **db_args,
+ void **server_handle)
+{
+ return kadm5_init_with_skey(context, client_name, keytab,
+ service_names ? service_names[0] : NULL,
+ params, struct_version, api_version, db_args,
+ server_handle);
+}
+
kadm5_ret_t kadm5_init(krb5_context context, char *client_name, char *pass,
char *service_name,
kadm5_config_params *params_in,
diff -u -r old/src/slave/kpropd.c new/src/slave/kpropd.c
--- old/src/slave/kpropd.c 2015-05-28 15:10:45.194095824 -0500
+++ new/src/slave/kpropd.c 2015-05-29 12:17:56.397347156 -0500
@@ -609,7 +609,7 @@
kadm5_ret_t retval;
krb5_principal iprop_svc_principal;
void *server_handle = NULL;
- char *iprop_svc_princstr = NULL, *master_svc_princstr = NULL;
+ char *iprop_svc_princstr = NULL, **master_svc_princstrs = NULL;
unsigned int pollin, backoff_time;
int backoff_cnt = 0, reinit_cnt = 0;
struct timeval iprop_start, iprop_end;
@@ -639,22 +639,9 @@
params.mask |= KADM5_CONFIG_REALM;
params.realm = def_realm;
- if (master_svc_princstr == NULL) {
-#if 0
- retval = kadm5_get_kiprop_host_srv_name(kpropd_context, def_realm,
- &master_svc_princstr);
- if (retval) {
- com_err(progname, retval,
- _("%s: unable to get kiprop host based "
- "service name for realm %s\n"),
- progname, def_realm);
- return retval;
- }
-#endif
- char **kiprop_srv_names;
-
+ if (master_svc_princstrs == NULL) {
retval = kadm5_get_kiprop_host_srv_names(kpropd_context, def_realm,
- &kiprop_srv_names);
+ &master_svc_princstrs);
if (retval) {
com_err(progname, retval,
_("%s: unable to get kiprop host based "
@@ -662,15 +649,6 @@
progname, def_realm);
return retval;
}
- master_svc_princstr = strdup(kiprop_srv_names[0]);
- free_srv_names(kiprop_srv_names);
- if (master_svc_princstr == NULL) {
- com_err(progname, retval,
- _("%s: unable to allocate memory for kiprop host based "
- "service name for realm %s\n"),
- progname, def_realm);
- return ENOMEM;
- }
}
retval = krb5_sname_to_principal(kpropd_context, NULL, KIPROP_SVC_NAME,
@@ -714,9 +692,9 @@
fprintf(stderr, _("Initializing kadm5 as client %s\n"),
iprop_svc_princstr);
}
- retval = kadm5_init_with_skey(kpropd_context, iprop_svc_princstr,
+ retval = kadm5_init_with_skey_mm(kpropd_context, iprop_svc_princstr,
srvtab,
- master_svc_princstr,
+ master_svc_princstrs,
¶ms,
KADM5_STRUCT_VERSION,
KADM5_API_VERSION_4,
@@ -1014,7 +992,7 @@
syslog(LOG_ERR, _("ERROR returned by master KDC, bailing.\n"));
done:
free(iprop_svc_princstr);
- free(master_svc_princstr);
+ free_srv_names(master_svc_princstrs);
krb5_free_default_realm(kpropd_context, def_realm);
kadm5_destroy(server_handle);
krb5_free_context(kpropd_context);