]> eyrie.org Git - kerberos/wallet.git/commitdiff
Pass realm to krb5_appdefault_* functions
authorRuss Allbery <eagle@eyrie.org>
Mon, 28 May 2018 22:06:46 +0000 (15:06 -0700)
committerRuss Allbery <eagle@eyrie.org>
Mon, 28 May 2018 22:06:46 +0000 (15:06 -0700)
When getting configuration values from krb5.conf, pass the default
local realm into the Kerberos appdefault functions.  This will produce
more correct results with krb5.conf files that specify wallet
configuration for multiple realms.

NEWS
client/options.c
client/wallet-rekey.c
client/wallet.c
configure.ac
portable/krb5.h

diff --git a/NEWS b/NEWS
index 23137e235cb7a9444d395d8544e5929123b04b38..1af55fc775bc7897e55d51656dccae78d3f28264 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -11,6 +11,11 @@ wallet 1.4 (unreleased)
     service principal, and truncate and make unique long names in AD if
     necessary.  This support should still be considered experimental.
 
+    When getting configuration values from krb5.conf, pass the default
+    local realm into the Kerberos appdefault functions.  This will produce
+    more correct results with krb5.conf files that specify wallet
+    configuration for multiple realms.
+
     Remove stray references to strlcpy and strlcat that broke builds on
     platforms where those functions are part of libc.  Thanks to Karl
     Kornel for the report.
index 3c68cc77a638a3b5fe4c08858c4e8d4ddfed0e7b..f011b79c1064953f005e11d0e193b19cb65a28a6 100644 (file)
 #include <portable/krb5.h>
 #include <portable/system.h>
 
+#include <errno.h>
+
 #include <client/internal.h>
+#include <util/messages.h>
 
 
 /*
- * Load a string option from Kerberos appdefaults.  This requires an annoying
- * workaround because one cannot specify a default value of NULL.
+ * Load a number option from Kerberos appdefaults.  Takes the Kerberos
+ * context, the realm, the option, and the result location.  The native
+ * interface doesn't support numbers, so we actually read a string and then
+ * convert.
  */
 static void
-default_string(krb5_context ctx, const char *opt, const char *defval,
-               char **result)
+default_number(krb5_context ctx, const char *realm, const char *opt,
+               long defval, long *result)
 {
-    if (defval == NULL)
-        defval = "";
-    krb5_appdefault_string(ctx, "wallet", NULL, opt, defval, result);
-    if (*result != NULL && (*result)[0] == '\0') {
-        free(*result);
-        *result = NULL;
+    char *tmp = NULL;
+    char *end;
+    long value;
+#ifdef HAVE_KRB5_REALM
+    krb5_const_realm rdata = realm;
+#else
+    krb5_data realm_struct;
+    const krb5_data *rdata;
+
+    if (realm == NULL)
+        rdata = NULL;
+    else {
+        rdata = &realm_struct;
+        realm_struct.magic = KV5M_DATA;
+        realm_struct.data = (void *) realm;
+        realm_struct.length = (unsigned int) strlen(realm);
     }
+#endif
+
+    *result = defval;
+    krb5_appdefault_string(ctx, "wallet", rdata, opt, "", &tmp);
+    if (tmp != NULL && tmp[0] != '\0') {
+        errno = 0;
+        value = strtol(tmp, &end, 10);
+        if (errno != 0 || *end != '\0')
+            warn("invalid number in krb5.conf setting for %s: %s", opt, tmp);
+        else
+            *result = value;
+    }
+    free(tmp);
 }
 
 
 /*
- * Load a number option from Kerberos appdefaults.  The native interface
- * doesn't support numbers, so we actually read a string and then convert.
+ * Load a string option from Kerberos appdefaults.  Takes the Kerberos
+ * context, the realm, the option, and the result location.
+ *
+ * This requires an annoying workaround because one cannot specify a default
+ * value of NULL with MIT Kerberos, since MIT Kerberos unconditionally calls
+ * strdup on the default value.  There's also no way to determine if memory
+ * allocation failed while parsing or while setting the default value, so we
+ * don't return an error code.
  */
 static void
-default_number(krb5_context ctx, const char *opt, int defval, int *result)
+default_string(krb5_context ctx, const char *realm, const char *opt,
+               const char *defval, char **result)
 {
-    char *tmp = NULL;
+    char *value = NULL;
+#ifdef HAVE_KRB5_REALM
+    krb5_const_realm rdata = realm;
+#else
+    krb5_data realm_struct;
+    const krb5_data *rdata;
 
-    krb5_appdefault_string(ctx, "wallet", NULL, opt, "", &tmp);
-    if (tmp != NULL && tmp[0] != '\0')
-        *result = atoi(tmp);
-    else
-        *result = defval;
-    if (tmp != NULL)
-        free(tmp);
+    if (realm == NULL)
+        rdata = NULL;
+    else {
+        rdata = &realm_struct;
+        realm_struct.magic = KV5M_DATA;
+        realm_struct.data = (void *) realm;
+        realm_struct.length = (unsigned int) strlen(realm);
+    }
+#endif
+
+    if (defval == NULL)
+        defval = "";
+    krb5_appdefault_string(ctx, "wallet", rdata, opt, defval, &value);
+    if (value != NULL) {
+        if (value[0] == '\0')
+            free(value);
+        else {
+            if (*result != NULL)
+                free(*result);
+            *result = value;
+        }
+    }
 }
 
 
@@ -64,15 +119,28 @@ default_number(krb5_context ctx, const char *opt, int defval, int *result)
 void
 default_options(krb5_context ctx, struct options *options)
 {
-    int port;
+    long port;
+    char *realm = NULL;
+
+    /* Having no local realm may be intentional, so don't report an error. */
+    krb5_get_default_realm(ctx, &realm);
+        
+    /* Load the options. */
+    default_string(ctx, realm, "wallet_type", "wallet", &options->type);
+    default_string(ctx, realm, "wallet_server", WALLET_SERVER,
+                   &options->server);
+    default_string(ctx, realm, "wallet_principal", NULL, &options->principal);
+    default_number(ctx, realm, "wallet_port", WALLET_PORT, &port);
 
-    default_string(ctx, "wallet_type", "wallet", &options->type);
-    default_string(ctx, "wallet_server", WALLET_SERVER, &options->server);
-    default_string(ctx, "wallet_principal", NULL, &options->principal);
-    default_number(ctx, "wallet_port", WALLET_PORT, &port);
-    if (port <= 0 || port > 65535)
+    /* Additional checks on the option values. */
+    if (port != WALLET_PORT && (port <= 0 || port > 65535)) {
+        warn("invalid number in krb5.conf setting for wallet_port: %ld", port);
         options->port = WALLET_PORT;
-    else
+    } else {
         options->port = (unsigned short) port;
-    options->user = NULL;
+    }
+
+    /* Clean up. */
+    if (realm != NULL)
+        krb5_free_default_realm(ctx, realm);
 }
index 2809efc83355f21158c8e70bba5736697e6046a1..caab13087733978087f26f6d97f5cecda6ab4b0e 100644 (file)
@@ -69,6 +69,7 @@ main(int argc, char *argv[])
     message_program_name = "wallet";
 
     /* Initialize default configuration. */
+    memset(&options, 0, sizeof(options));
     retval = krb5_init_context(&ctx);
     if (retval != 0)
         die_krb5(ctx, retval, "cannot initialize Kerberos");
index ed6c9b81cf5ab4f1bb12557e4b396a8eb0ac8fd8..5a80876136969c3a8d2e6757dbd9ade41d35836f 100644 (file)
@@ -76,6 +76,7 @@ main(int argc, char *argv[])
     message_program_name = "wallet";
 
     /* Initialize default configuration. */
+    memset(&options, 0, sizeof(options));
     retval = krb5_init_context(&ctx);
     if (retval != 0)
         die_krb5(ctx, retval, "cannot initialize Kerberos");
index 12b93f803bac793cdda61f242d0f11d9a8b4010c..41ae0cf4972c9c69817220614bcc6b3e999a82da 100644 (file)
@@ -57,7 +57,9 @@ dnl Probe for required libraries.
 RRA_LIB_REMCTL
 RRA_LIB_KRB5
 RRA_LIB_KRB5_SWITCH
-AC_CHECK_FUNCS([krb5_get_init_creds_opt_alloc \
+AC_CHECK_TYPES([krb5_realm], [], [], [RRA_INCLUDES_KRB5])
+AC_CHECK_FUNCS([krb5_free_default_realm \
+    krb5_get_init_creds_opt_alloc \
     krb5_get_init_creds_opt_set_default_flags \
     krb5_principal_get_realm])
 AC_CHECK_FUNCS([krb5_get_init_creds_opt_free],
index 63a2e9f95fde6bde0dd91e6fc37d2382e470f38d..d8884a7371daae4eef833b4f6c87b949b0be3595 100644 (file)
@@ -70,6 +70,15 @@ void krb5_appdefault_string(krb5_context, const char *, const krb5_data *,
                             const char *, const char *, char **);
 #endif
 
+/*
+ * MIT-specific.  The Heimdal documentation says to use free(), but that
+ * doesn't actually make sense since the memory is allocated inside the
+ * Kerberos library.  Use krb5_xfree instead.
+ */
+#ifndef HAVE_KRB5_FREE_DEFAULT_REALM
+# define krb5_free_default_realm(c, r) krb5_xfree(r)
+#endif
+
 /*
  * krb5_{get,free}_error_message are the preferred APIs for both current MIT
  * and current Heimdal, but there are tons of older APIs we may have to fall