krb5 commit: Allow realm in kadm5_init service names

Greg Hudson ghudson at MIT.EDU
Sat Dec 21 00:13:15 EST 2013


https://github.com/krb5/krb5/commit/5341cfde2b3e607e294bb0d057dc3540172a8b1b
commit 5341cfde2b3e607e294bb0d057dc3540172a8b1b
Author: Greg Hudson <ghudson at mit.edu>
Date:   Thu Dec 19 13:33:33 2013 -0500

    Allow realm in kadm5_init service names
    
    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

 src/lib/kadm5/clnt/client_init.c |   96 +++++++++++++++++++-------------------
 1 files changed, 48 insertions(+), 48 deletions(-)

diff --git a/src/lib/kadm5/clnt/client_init.c b/src/lib/kadm5/clnt/client_init.c
index 43ebc8b..9176de3 100644
--- a/src/lib/kadm5/clnt/client_init.c
+++ b/src/lib/kadm5/clnt/client_init.c
@@ -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,
@@ -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;
@@ -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;
 
@@ -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;
 
@@ -357,6 +357,8 @@ error:
     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);
 
@@ -366,16 +368,16 @@ cleanup:
 /* 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,
@@ -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 at 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 at 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",
@@ -428,13 +426,12 @@ 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;
@@ -442,7 +439,6 @@ get_init_creds(kadm5_server_handle_t handle, char *client_name,
         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;
@@ -453,27 +449,21 @@ error:
 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);
@@ -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) {
@@ -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,
@@ -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)
@@ -568,7 +568,7 @@ cleanup:
 /* 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;
@@ -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)


More information about the cvs-krb5 mailing list