summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStef Walter <stefw@gnome.org>2012-04-01 21:53:04 +0200
committerStef Walter <stefw@gnome.org>2012-04-01 21:53:04 +0200
commita899d9be0cab72dcfe00f100527c52ea598fed70 (patch)
tree8b2e58d055a1cf8e5fced45195a3ffb598eef9c4
parentaf8d28014f97ab0d9e4d00961e72aefd7adb470b (diff)
Add enable-in and disable-in options to module config
* These can be used to load certain modules in certain programs, or prevent loading in others. * Useful for a key manager like seahorse, so we can load extra modules (think NSS) that other modules shouldn't load.
-rw-r--r--.gitignore2
-rw-r--r--configure.ac12
-rw-r--r--doc/p11-kit-config.xml27
-rw-r--r--doc/p11-kit-sections.txt1
-rw-r--r--p11-kit/modules.c75
-rw-r--r--p11-kit/p11-kit.h2
-rw-r--r--p11-kit/private.h4
-rw-r--r--p11-kit/util.c115
-rw-r--r--tests/Makefile.am2
-rw-r--r--tests/progname-test.c110
10 files changed, 346 insertions, 4 deletions
diff --git a/.gitignore b/.gitignore
index 8486423..77f2789 100644
--- a/.gitignore
+++ b/.gitignore
@@ -77,6 +77,8 @@ temp.txt
/tests/p11-test
/tests/pin-test
/tests/print-messages
+/tests/print-progname
+/tests/progname-test
/tests/ptr-array-test
/tests/conf-test
/tests/uri-test
diff --git a/configure.ac b/configure.ac
index 720c95d..401265f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -6,6 +6,8 @@ AC_INIT([p11-kit],
[p11-kit],
[http://p11-glue.freedesktop.org/p11-kit.html])
+AC_USE_SYSTEM_EXTENSIONS
+
# ------------------------------------------------------------------------------
# p11-kit libtool versioning
# CURRENT : REVISION : AGE
@@ -31,7 +33,6 @@ LT_INIT([dlopen disable-static])
AC_PROG_CC
AC_PROG_CPP
AM_PROG_CC_C_O
-AC_USE_SYSTEM_EXTENSIONS
LINGUAS=""
AM_GNU_GETTEXT([external], [need-ngettext])
@@ -66,6 +67,15 @@ if test "$os_unix" = "yes"; then
[AC_MSG_ERROR([could not find dlopen])])
AC_CHECK_MEMBERS([struct dirent.d_type],,,[#include <dirent.h>])
AC_CHECK_HEADERS([err.h])
+ AC_CHECK_FUNCS([getprogname getexecname])
+
+ # Check if these are declared and/or available to link against
+ AC_CHECK_DECLS([program_invocation_short_name])
+ AC_LINK_IFELSE([AC_LANG_SOURCE([extern char *program_invocation_short_name; void main() { }])],
+ [AC_DEFINE(HAVE_PROGRAM_INVOCATION_SHORT_NAME, [1], [Whether program_invocation_short_name available])])
+ AC_CHECK_DECLS([__progname])
+ AC_LINK_IFELSE([AC_LANG_SOURCE([extern char *__progname; void main() { }])],
+ [AC_DEFINE(HAVE___PROGNAME, [1], [Whether __progname available])])
fi
# ------------------------------------------------------------------------------
diff --git a/doc/p11-kit-config.xml b/doc/p11-kit-config.xml
index 7c28f86..11fb41f 100644
--- a/doc/p11-kit-config.xml
+++ b/doc/p11-kit-config.xml
@@ -140,8 +140,35 @@ critical: yes
<para>This argument is optional and defaults to <literal>no</literal>.</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term>enable-in:</term>
+ <listitem>
+ <para>A comma and/or space separated list of names of programs that
+ this module should only be loaded in. The module will not be loaded
+ for other programs using p11-kit. The base name of the process executable
+ should be used here, for example
+ <literal>seahorse, ssh</literal>.</para>
+ <para>This is not a security feature. The argument is optional. If
+ not present, then any process will load the module.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>disable-in:</term>
+ <listitem>
+ <para>A comma and/or space separated list of names of programs that
+ this module should not be loaded in. The module will be loaded for any
+ other programs using p11-kit. The base name of the process
+ executable should be used here, for example
+ <literal>firefox, thunderbird-bin</literal>.</para>
+ <para>This is not a security feature. The argument is optional. If
+ not present, then any process will load the module.</para>
+ </listitem>
+ </varlistentry>
</variablelist>
+ <para>Do not specify both <literal>enable-in</literal> and <literal>disable-in</literal>
+ for the same module.</para>
+
<para>Other fields may be present, but it is recommended that field names
that are not specified in this document start with a <literal>x-</literal>
prefix.</para>
diff --git a/doc/p11-kit-sections.txt b/doc/p11-kit-sections.txt
index 37fceb5..bdd0434 100644
--- a/doc/p11-kit-sections.txt
+++ b/doc/p11-kit-sections.txt
@@ -81,6 +81,7 @@ p11_kit_uri_type_t
<SECTION>
<FILE>p11-kit-future</FILE>
+p11_kit_set_progname
p11_kit_be_quiet
p11_kit_message
</SECTION> \ No newline at end of file
diff --git a/p11-kit/modules.c b/p11-kit/modules.c
index 047a2ca..f059097 100644
--- a/p11-kit/modules.c
+++ b/p11-kit/modules.c
@@ -47,6 +47,7 @@
#include <sys/types.h>
#include <assert.h>
+#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <limits.h>
@@ -336,6 +337,61 @@ expand_module_path (const char *filename)
return path;
}
+static int
+is_list_delimiter (char ch)
+{
+ return ch == ',' || isspace (ch);
+}
+
+static int
+is_string_in_list (const char *list,
+ const char *string)
+{
+ const char *where;
+
+ where = strstr (list, string);
+ if (where == NULL)
+ return 0;
+
+ /* Has to be at beginning/end of string, and delimiter before/after */
+ if (where != list && !is_list_delimiter (*(where - 1)))
+ return 0;
+
+ where += strlen (string);
+ return (*where == '\0' || is_list_delimiter (*where));
+}
+
+static int
+is_module_enabled_unlocked (const char *name,
+ hashmap *config)
+{
+ const char *progname;
+ const char *enable_in;
+ const char *disable_in;
+ int enable;
+
+ enable_in = _p11_hash_get (config, "enable-in");
+ disable_in = _p11_hash_get (config, "disable-in");
+
+ /* Defaults to enabled if neither of these are set */
+ if (!enable_in && !disable_in)
+ return 1;
+
+ progname = _p11_get_progname_unlocked ();
+ if (enable_in && disable_in)
+ _p11_message ("module '%s' has both enable-in and disable-in options", name);
+ if (enable_in)
+ enable = (progname != NULL && is_string_in_list (enable_in, progname));
+ else if (disable_in)
+ enable = (progname == NULL || !is_string_in_list (disable_in, progname));
+
+ _p11_debug ("%s module '%s' running in '%s'",
+ enable ? "enabled" : "disabled",
+ name,
+ progname ? progname : "(null)");
+ return enable;
+}
+
static CK_RV
take_config_and_load_module_unlocked (char **name, hashmap **config)
{
@@ -349,6 +405,9 @@ take_config_and_load_module_unlocked (char **name, hashmap **config)
assert (config);
assert (*config);
+ if (!is_module_enabled_unlocked (*name, *config))
+ return CKR_OK;
+
module_filename = _p11_hash_get (*config, "module");
if (module_filename == NULL) {
_p11_debug ("no module path for module, skipping: %s", *name);
@@ -832,8 +891,22 @@ _p11_kit_registered_modules_unlocked (void)
if (result) {
_p11_hash_iterate (gl.modules, &iter);
while (_p11_hash_next (&iter, NULL, (void **)&mod)) {
- if (mod->ref_count && mod->name)
+
+ /*
+ * We don't include unreferenced modules. We don't include
+ * modules that have been initialized but aren't in the
+ * registry. These have a NULL name.
+ *
+ * In addition we check again that the module isn't disabled
+ * using enable-in or disable-in. This is because a caller
+ * can change the progname we recognize the process as after
+ * having initialized. This is a corner case, but want to make
+ * sure to cover it.
+ */
+ if (mod->ref_count && mod->name &&
+ is_module_enabled_unlocked (mod->name, mod->config)) {
result[i++] = mod->funcs;
+ }
}
}
diff --git a/p11-kit/p11-kit.h b/p11-kit/p11-kit.h
index cf84db6..77cf1b5 100644
--- a/p11-kit/p11-kit.h
+++ b/p11-kit/p11-kit.h
@@ -80,6 +80,8 @@ char* p11_kit_space_strdup (const unsigned char
#ifdef P11_KIT_FUTURE_UNSTABLE_API
+void p11_kit_set_progname (const char *progname);
+
void p11_kit_be_quiet (void);
const char* p11_kit_message (void);
diff --git a/p11-kit/private.h b/p11-kit/private.h
index d23c1e6..36acb7e 100644
--- a/p11-kit/private.h
+++ b/p11-kit/private.h
@@ -92,4 +92,8 @@ void _p11_kit_clear_message (void);
void _p11_kit_default_message (CK_RV rv);
+const char * _p11_get_progname_unlocked (void);
+
+void _p11_set_progname_unlocked (const char *progname);
+
#endif /* __P11_KIT_PRIVATE_H__ */
diff --git a/p11-kit/util.c b/p11-kit/util.c
index c04b636..fd7708a 100644
--- a/p11-kit/util.c
+++ b/p11-kit/util.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2011 Collabora Ltd
+ * Copyright (c) 2012 Stef Walter
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -31,7 +32,7 @@
*
*
* CONTRIBUTORS
- * Stef Walter <stef@memberwebs.com>
+ * Stef Walter <stef@thewalter.net>
*/
#include "config.h"
@@ -246,6 +247,14 @@ _p11_kit_default_message (CK_RV rv)
}
}
+static void
+uninit_common (void)
+{
+ _p11_debug ("uninitializing library");
+
+ _p11_set_progname_unlocked (NULL);
+}
+
#ifdef OS_UNIX
static pthread_key_t thread_local = 0;
@@ -277,10 +286,47 @@ _p11_library_init (void)
void
_p11_library_uninit (void)
{
+ uninit_common ();
+
pthread_key_delete (thread_local);
_p11_mutex_uninit (&_p11_mutex);
}
+#if defined (HAVE_PROGRAM_INVOCATION_SHORT_NAME) && !HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME
+extern char *program_invocation_short_name;
+#endif
+
+#if defined (HAVE___PROGNAME) && !HAVE_DECL___PROGNAME
+extern char *__progname;
+#endif
+
+static char *
+get_default_progname (void)
+{
+ const char *name;
+
+#if defined (HAVE_GETPROGNAME)
+ name = getprogname();
+#elif defined (HAVE_GETEXECNAME)
+ const char *p;
+ name = getexecname();
+ p = strrchr (name ? name : "", '/');
+ if (p != NULL)
+ name = p + 1;
+#elif defined (HAVE_PROGRAM_INVOCATION_SHORT_NAME)
+ name = program_invocation_short_name;
+#elif defined (HAVE___PROGNAME)
+ name = __progname;
+#else
+ #error No way to retrieve program name from p11-kit library
+#endif
+
+ if (name == NULL)
+ return NULL;
+
+ return strdup (name);
+}
+
#endif /* OS_UNIX */
#ifdef OS_WIN32
@@ -331,7 +377,7 @@ _p11_library_uninit (void)
{
LPVOID data;
- _p11_debug ("uninitializing library");
+ uninit_common ();
if (thread_local != TLS_OUT_OF_INDEXES) {
data = TlsGetValue (thread_local);
@@ -376,4 +422,69 @@ DllMain (HINSTANCE instance,
return TRUE;
}
+extern char **__argv;
+
+static char *
+get_default_progname (void)
+{
+ const char *name;
+ const char *p;
+ char *progname;
+ size_t length;
+
+ name = __argv[0];
+ if (name == NULL)
+ return NULL;
+
+ p = strrchr (name, '\\');
+ if (p != NULL)
+ name = p + 1;
+
+ progname = strdup (name);
+ length = strlen (progname);
+ if (length > 4 && _stricmp(progname + (length - 4), ".exe"))
+ progname[length - 4] = '\0';
+
+ return progname;
+}
+
#endif /* OS_WIN32 */
+
+/* This is the progname that we think of this process as. */
+char *_p11_my_progname = NULL;
+
+/**
+ * p11_kit_set_progname:
+ * @progname: the program base name
+ *
+ * Set the program base name that is used by the <literal>enable-in</literal>
+ * and <literal>disable-in</literal> module configuration options.
+ *
+ * Normally this is automatically calculated from the program's argument list.
+ * You would usually call this before initializing p11-kit modules.
+ */
+void
+p11_kit_set_progname (const char *progname)
+{
+ _p11_library_init_once ();
+
+ _p11_lock ();
+ _p11_set_progname_unlocked (progname);
+ _p11_unlock ();
+}
+
+void
+_p11_set_progname_unlocked (const char *progname)
+{
+ /* We can be called with NULL, to cleanup memory usage */
+ free (_p11_my_progname);
+ _p11_my_progname = progname ? strdup (progname) : NULL;
+}
+
+const char *
+_p11_get_progname_unlocked (void)
+{
+ if (_p11_my_progname == NULL)
+ _p11_my_progname = get_default_progname ();
+ return _p11_my_progname;
+}
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 819b74a..0400045 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -13,6 +13,7 @@ LDADD = \
CHECK_PROGS = \
hash-test \
ptr-array-test \
+ progname-test \
conf-test \
uri-test \
pin-test \
@@ -28,6 +29,7 @@ conf_test_SOURCES = conf-test.c $(cutestfiles)
hash_test_SOURCES = hash-test.c $(cutestfiles)
pin_test_SOURCES = pin-test.c $(cutestfiles)
ptr_array_test_SOURCES = ptr-array-test.c $(cutestfiles)
+progname_test_SOURCES = progname-test.c $(cutestfiles)
test_init_SOURCES = \
test-init.c \
mock-module.c mock-module.h $(cutestfiles)
diff --git a/tests/progname-test.c b/tests/progname-test.c
new file mode 100644
index 0000000..1e42056
--- /dev/null
+++ b/tests/progname-test.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2012 Stefan Walter
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ * * Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * The names of contributors to this software may not be
+ * used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * Author: Stef Walter <stef@thewalter.net>
+ */
+
+#include "config.h"
+#include "CuTest.h"
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "p11-kit/uri.h"
+#include "p11-kit/p11-kit.h"
+#include "p11-kit/private.h"
+
+static void
+test_progname_default (CuTest *tc)
+{
+ const char *progname;
+
+ progname = _p11_get_progname_unlocked ();
+ CuAssertStrEquals (tc, "progname-test", progname);
+}
+
+static void
+test_progname_set (CuTest *tc)
+{
+ const char *progname;
+
+ p11_kit_set_progname ("love-generation");
+
+ progname = _p11_get_progname_unlocked ();
+ CuAssertStrEquals (tc, "love-generation", progname);
+
+ _p11_set_progname_unlocked (NULL);
+
+ progname = _p11_get_progname_unlocked ();
+ CuAssertStrEquals (tc, "progname-test", progname);
+}
+
+/* Defined in util.c */
+extern char *_p11_my_progname;
+
+static void
+test_progname_uninit_clears (CuTest *tc)
+{
+ _p11_set_progname_unlocked ("love-generation");
+ CuAssertStrEquals (tc, "love-generation", _p11_my_progname);
+
+ /* Inititialize should clear above variable */
+ _p11_library_uninit ();
+
+ CuAssertPtrEquals (tc, NULL, _p11_my_progname);
+}
+
+int
+main (void)
+{
+ CuString *output = CuStringNew ();
+ CuSuite* suite = CuSuiteNew ();
+ int ret;
+
+ _p11_library_init ();
+
+ SUITE_ADD_TEST (suite, test_progname_default);
+ SUITE_ADD_TEST (suite, test_progname_set);
+
+ /* This test should be last, as it uninitializes the library */
+ SUITE_ADD_TEST (suite, test_progname_uninit_clears);
+
+ CuSuiteRun (suite);
+ CuSuiteSummary (suite, output);
+ CuSuiteDetails (suite, output);
+ printf ("%s\n", output->buffer);
+ ret = suite->failCount;
+ CuSuiteDelete (suite);
+ CuStringDelete (output);
+ return ret;
+}