Add k5_plugin_register_dyn internal API
authorGreg Hudson <ghudson@mit.edu>
Fri, 17 Jun 2011 13:44:26 +0000 (13:44 +0000)
committerGreg Hudson <ghudson@mit.edu>
Fri, 17 Jun 2011 13:44:26 +0000 (13:44 +0000)
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@24969 dc483132-0cff-0310-8789-dd5450dbe970

src/config-files/krb5.conf.M
src/include/Makefile.in
src/include/k5-int.h
src/include/osconf.hin
src/lib/krb5/krb/Makefile.in
src/lib/krb5/krb/init_ctx.c
src/lib/krb5/krb/plugin.c

index b04d6efd69f7b875a0fc54691f96d7ab0dbc1e31..33f3d920c142aa397e5fca99abd2014839e3cdbd 100644 (file)
@@ -284,6 +284,11 @@ true.  Setting this flag to false is more secure, but may force
 users to exclusively use fully qualified domain names when
 authenticating to services.
 
+.IP plugin_base_dir
+If set, determines the base directory where krb5 plugins are located.
+The default value is the "krb5/plugins" subdirectory of the krb5
+library directory.
+
 .SH APPDEFAULTS SECTION
 
 Each tag in the [appdefaults] section names a Kerberos V5 application
@@ -732,8 +737,7 @@ This tag may have multiple values.  Each value is a string of the form
 "modulename:pathname", which causes the shared object located at
 pathname to be registered as a dynamic module named modulename for the
 pluggable interface.  If pathname is not an absolute path, it will be
-treated as relative to the "krb5/plugins" subdirectory of the krb5
-library directory.
+treated as relative to the plugin base directory.
 
 .IP enable_only
 This tag may have multiple values.  If there are values for this tag,
index ed7d20fbb4bf5f44ae38edcc36e448f9cdf82272..d6a9b3c3890c979def615481f3cbfc8ff061a3ee 100644 (file)
@@ -65,8 +65,9 @@ PROCESS_REPLACE = -e "s+@KRB5RCTMPDIR+$(KRB5RCTMPDIR)+" \
                  -e "s+@SBINDIR+$(SBINDIR)+" \
                  -e "s+@MODULEDIR+$(MODULE_DIR)+" \
                  -e "s+@GSSMODULEDIR+$(GSS_MODULE_DIR)+" \
-       -e 's+@LOCALSTATEDIR+$(LOCALSTATEDIR)+' \
-       -e 's+@SYSCONFDIR+$(SYSCONFDIR)+' 
+                 -e 's+@LOCALSTATEDIR+$(LOCALSTATEDIR)+' \
+                 -e 's+@SYSCONFDIR+$(SYSCONFDIR)+' \
+                 -e 's+@DYNOBJEXT+$(DYNOBJEXT)+'
 
 OSCONFSRC = $(srcdir)/osconf.hin
 
index 0a00f1d28219caf250d4a9bb3fc327bca63fcc30..86ec114b0a31bdeeba9ee5fcd5bd7570ffa030cb 100644 (file)
@@ -256,6 +256,7 @@ typedef INT64_TYPE krb5_int64;
 #define KRB5_CONF_NO_HOST_REFERRAL            "no_host_referral"
 #define KRB5_CONF_PERMITTED_ENCTYPES          "permitted_enctypes"
 #define KRB5_CONF_PLUGINS                     "plugins"
+#define KRB5_CONF_PLUGIN_BASE_DIR             "plugin_base_dir"
 #define KRB5_CONF_PREAUTH_MODULE_DIR          "preauth_module_dir"
 #define KRB5_CONF_PREFERRED_PREAUTH_TYPES     "preferred_preauth_types"
 #define KRB5_CONF_PROXIABLE                   "proxiable"
@@ -1435,6 +1436,15 @@ krb5_error_code
 k5_plugin_register(krb5_context context, int interface_id, const char *modname,
                    krb5_plugin_initvt_fn module);
 
+/*
+ * Register a plugin module which is part of the krb5 tree but is built as a
+ * dynamic plugin.  Look for the module in modsubdir relative to the
+ * context->base_plugin_dir.
+ */
+krb5_error_code
+k5_plugin_register_dyn(krb5_context context, int interface_id,
+                       const char *modname, const char *modsubdir);
+
 /* Destroy the module state within context; used by krb5_free_context. */
 void
 k5_plugin_free_context(krb5_context context);
@@ -1496,6 +1506,7 @@ struct _krb5_context {
     void *trace_callback_data;
 
     struct plugin_interface plugins[PLUGIN_NUM_INTERFACES];
+    char *plugin_base_dir;
 };
 
 /* could be used in a table to find an etype and initialize a block */
index 073ce1422f73b82e8d9b53e32d4af97a056b14ed..04f10ce82e0dcda240ad10a2234ebf3b5a66f067 100644 (file)
@@ -59,6 +59,9 @@
 #define DEFAULT_LNAME_FILENAME  "@PREFIX/lib/krb5.aname"
 #endif /* _WINDOWS  */
 
+#define DEFAULT_PLUGIN_BASE_DIR "@LIBDIR/krb5/plugins"
+#define PLUGIN_EXT              "@DYNOBJEXT"
+
 #define DEFAULT_KDB_FILE        "@LOCALSTATEDIR/krb5kdc/principal"
 #define DEFAULT_KEYFILE_STUB    "@LOCALSTATEDIR/krb5kdc/.k5."
 #define KRB5_DEFAULT_ADMIN_ACL  "@LOCALSTATEDIR/krb5kdc/krb5_adm.acl"
index 6a0faf29db7a1057b322cb928f83ddc73f0cf736..6a93718369faa9c90aae8aba56313434ee7ab550 100644 (file)
@@ -4,7 +4,7 @@ RUN_SETUP = @KRB5_RUN_ENV@
 PROG_LIBPATH=-L$(TOPLIBD)
 PROG_RPATH=$(KRB5_LIBDIR)
 LOCALINCLUDES = -I$(srcdir)/../os -I$(top_srcdir)
-DEFS=-DLIBDIR=\"$(KRB5_LIBDIR)\"
+DEFS=-DLIBDIR=\"$(KRB5_LIBDIR)\" -DDYNOBJEXT=\"$(DYNOBJEXT)\"
 
 ##DOS##BUILDTOP = ..\..\..
 ##DOS##PREFIXDIR=krb
index 99ff5fcdef98118ba013d1d3d989ccbed8f9effe..657b2dbb3135d79494d5c02c21fd8dd01dcba938 100644 (file)
@@ -230,6 +230,13 @@ init_common (krb5_context *context, krb5_boolean secure, krb5_boolean kdc)
                         &tmp);
     ctx->library_options = tmp ? KRB5_LIBOPT_SYNC_KDCTIME : 0;
 
+    retval = profile_get_string(ctx->profile, KRB5_CONF_LIBDEFAULTS,
+                                KRB5_CONF_PLUGIN_BASE_DIR, 0,
+                                DEFAULT_PLUGIN_BASE_DIR,
+                                &ctx->plugin_base_dir);
+    if (retval)
+        goto cleanup;
+
     /*
      * We use a default file credentials cache of 3.  See
      * lib/krb5/krb/ccache/file/fcc.h for a description of the
index 446d4f22e6795c9c8ad8bd28df64934485361752..a9d6b06a7be7d2bc571eb91be85e50492a935d1c 100644 (file)
@@ -136,25 +136,26 @@ parse_modstr(krb5_context context, const char *modstr,
  * plugins directory.
  */
 static krb5_error_code
-expand_relative_modpath(const char *modpath, char **full_modpath_out)
+expand_relative_modpath(krb5_context context, const char *modpath,
+                        char **full_modpath_out)
 {
-    char *fullpath;
+    char *path;
 
     *full_modpath_out = NULL;
 
     /* XXX Unix-specific path handling for now. */
     if (*modpath == '/') {
         /* We already have an absolute path. */
-        fullpath = strdup(modpath);
-        if (fullpath == NULL)
+        path = strdup(modpath);
+        if (path == NULL)
             return ENOMEM;
     } else {
         /* Append the relative path to the system plugins directory. */
-        if (asprintf(&fullpath, "%s/%s", LIBDIR "/krb5/plugins", modpath) < 0)
+        if (asprintf(&path, "%s/%s", context->plugin_base_dir, modpath) < 0)
             return ENOMEM;
     }
 
-    *full_modpath_out = fullpath;
+    *full_modpath_out = path;
     return 0;
 }
 
@@ -195,28 +196,15 @@ filter_builtins(krb5_context context, struct plugin_interface *interface,
     }
 }
 
-/* Register the plugin module given by the profile string mod. */
 static krb5_error_code
 register_dyn_module(krb5_context context, struct plugin_interface *interface,
-                    const char *iname, const char *modstr, char **enable,
-                    char **disable)
+                    const char *iname, const char *modname, const char *path)
 {
     krb5_error_code ret;
-    char *modname = NULL, *modpath = NULL, *full_modpath = NULL;
     char *symname = NULL;
     struct plugin_file_handle *handle = NULL;
     void (*initvt_fn)();
 
-    /* Parse out the module name and path, and make sure it is enabled. */
-    ret = parse_modstr(context, modstr, &modname, &modpath);
-    if (ret != 0)
-        goto cleanup;
-    ret = expand_relative_modpath(modpath, &full_modpath);
-    if (ret != 0)
-        goto cleanup;
-    if (!module_enabled(modname, enable, disable))
-        goto cleanup;
-
     /* Construct the initvt symbol name for this interface and module. */
     if (asprintf(&symname, "%s_%s_initvt", iname, modname) < 0) {
         symname = NULL;
@@ -225,7 +213,7 @@ register_dyn_module(krb5_context context, struct plugin_interface *interface,
     }
 
     /* Open the plugin and resolve the initvt symbol. */
-    ret = krb5int_open_plugin(full_modpath, &handle, &context->err);
+    ret = krb5int_open_plugin(path, &handle, &context->err);
     if (ret != 0)
         goto cleanup;
     ret = krb5int_get_plugin_func(handle, symname, &initvt_fn, &context->err);
@@ -240,15 +228,40 @@ register_dyn_module(krb5_context context, struct plugin_interface *interface,
     handle = NULL;              /* Now owned by the module mapping. */
 
 cleanup:
-    free(modname);
-    free(modpath);
-    free(full_modpath);
     free(symname);
     if (handle != NULL)
         krb5int_close_plugin(handle);
     return ret;
 }
 
+/* Register the plugin module given by the profile string mod, if enabled
+ * according to the values of enable and disable. */
+static krb5_error_code
+register_dyn_mapping(krb5_context context, struct plugin_interface *interface,
+                     const char *iname, const char *modstr, char **enable,
+                     char **disable)
+{
+    krb5_error_code ret;
+    char *modname = NULL, *modpath = NULL, *fullpath = NULL;
+
+    /* Parse out the module name and path, and make sure it is enabled. */
+    ret = parse_modstr(context, modstr, &modname, &modpath);
+    if (ret != 0)
+        goto cleanup;
+    ret = expand_relative_modpath(context, modpath, &fullpath);
+    if (ret != 0)
+        goto cleanup;
+    if (!module_enabled(modname, enable, disable))
+        goto cleanup;
+    ret = register_dyn_module(context, interface, iname, modname, fullpath);
+
+cleanup:
+    free(modname);
+    free(modpath);
+    free(fullpath);
+    return ret;
+}
+
 /* Ensure that a plugin interface is configured.  id is assumed to be valid. */
 static krb5_error_code
 configure_interface(krb5_context context, int id)
@@ -284,8 +297,8 @@ configure_interface(krb5_context context, int id)
 
     /* Create mappings for dynamic modules which aren't filtered out. */
     for (mod = modules; mod && *mod; mod++) {
-        ret = register_dyn_module(context, interface, iname, *mod,
-                                  enable, disable);
+        ret = register_dyn_mapping(context, interface, iname, *mod,
+                                   enable, disable);
         if (ret != 0)
             return ret;
     }
@@ -380,6 +393,27 @@ k5_plugin_register(krb5_context context, int interface_id, const char *modname,
     return register_module(context, interface, modname, module, NULL);
 }
 
+krb5_error_code
+k5_plugin_register_dyn(krb5_context context, int interface_id,
+                       const char *modname, const char *modsubdir)
+{
+    krb5_error_code ret;
+    struct plugin_interface *interface = get_interface(context, interface_id);
+    char *path;
+
+    /* Disallow registering plugins after load. */
+    if (interface == NULL || interface->configured)
+        return EINVAL;
+    if (asprintf(&path, "%s/%s/%s%s", context->plugin_base_dir, modsubdir,
+                 modname, PLUGIN_EXT) < 0)
+        return ENOMEM;
+
+    ret = register_dyn_module(context, interface,
+                              interface_names[interface_id], modname, path);
+    free(path);
+    return ret;
+}
+
 void
 k5_plugin_free_context(krb5_context context)
 {