diff options
author | Stef Walter <stefw@gnome.org> | 2012-04-01 21:53:04 +0200 |
---|---|---|
committer | Stef Walter <stefw@gnome.org> | 2012-04-01 21:53:04 +0200 |
commit | a899d9be0cab72dcfe00f100527c52ea598fed70 (patch) | |
tree | 8b2e58d055a1cf8e5fced45195a3ffb598eef9c4 | |
parent | af8d28014f97ab0d9e4d00961e72aefd7adb470b (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-- | .gitignore | 2 | ||||
-rw-r--r-- | configure.ac | 12 | ||||
-rw-r--r-- | doc/p11-kit-config.xml | 27 | ||||
-rw-r--r-- | doc/p11-kit-sections.txt | 1 | ||||
-rw-r--r-- | p11-kit/modules.c | 75 | ||||
-rw-r--r-- | p11-kit/p11-kit.h | 2 | ||||
-rw-r--r-- | p11-kit/private.h | 4 | ||||
-rw-r--r-- | p11-kit/util.c | 115 | ||||
-rw-r--r-- | tests/Makefile.am | 2 | ||||
-rw-r--r-- | tests/progname-test.c | 110 |
10 files changed, 346 insertions, 4 deletions
@@ -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; +} |