]> granicus.if.org Git - p11-kit/commitdiff
trust: Correctly reflect the CK_TOKEN_INFO writability flags
authorStef Walter <stef@thewalter.net>
Fri, 14 Jun 2013 11:02:22 +0000 (13:02 +0200)
committerStef Walter <stef@thewalter.net>
Fri, 14 Jun 2013 11:32:04 +0000 (13:32 +0200)
Correctly set the CKF_TOKEN_WRITE_PROTECTED flag for paths
which we will be able to write to.

common/compat.h
trust/module.c
trust/tests/test-module.c
trust/tests/test-token.c
trust/token.c
trust/token.h

index 0f9677bd22d63d96c9e55d347dbe0704f1a8e9a0..9127f95988bf75434d6dda0754c4f20c0fe75c90 100644 (file)
@@ -103,6 +103,8 @@ char *       strdup_path_mangle (const char *template);
 #define WIN32_LEAN_AND_MEAN 1
 #include <windows.h>
 
+#include <io.h>
+
 /* Oh ... my ... god */
 #undef CreateMutex
 
@@ -164,6 +166,7 @@ void        p11_mmap_close  (p11_mmap *map);
 #include <pthread.h>
 #include <dlfcn.h>
 #include <time.h>
+#include <unistd.h>
 
 typedef pthread_mutex_t p11_mutex_t;
 
index abfabaeb18f8043ad8d03a6b9b5e52536c34f7ac..ea514b16692ebe8934b66c14b886c4e5b84b26db 100644 (file)
@@ -544,7 +544,7 @@ sys_C_GetTokenInfo (CK_SLOT_ID id,
                info->firmwareVersion.minor = 0;
                info->hardwareVersion.major = PACKAGE_MAJOR;
                info->hardwareVersion.minor = PACKAGE_MINOR;
-               info->flags = CKF_TOKEN_INITIALIZED | CKF_WRITE_PROTECTED;
+               info->flags = CKF_TOKEN_INITIALIZED;
                strncpy ((char*)info->manufacturerID, MANUFACTURER_ID, 32);
                strncpy ((char*)info->model, TOKEN_MODEL, 16);
                strncpy ((char*)info->serialNumber, TOKEN_SERIAL_NUMBER, 16);
@@ -566,6 +566,9 @@ sys_C_GetTokenInfo (CK_SLOT_ID id,
                        length = sizeof (info->label);
                memset (info->label, ' ', sizeof (info->label));
                memcpy (info->label, label, length);
+
+               if (!p11_token_is_writable (token))
+                       info->flags |= CKF_WRITE_PROTECTED;
        }
 
        p11_unlock ();
index bf281249d0a1d5a074a98db5997f17662948143d..910b9b49617db088350d8e407719f9916a7cd379 100644 (file)
 #define NUM_SLOTS 3
 
 static CK_OBJECT_CLASS data = CKO_DATA;
+static CK_BBOOL vtrue = CK_TRUE;
+static CK_BBOOL vfalse = CK_FALSE;
 
 struct {
        CK_FUNCTION_LIST *module;
        CK_SLOT_ID slots[NUM_SLOTS];
+       char *directory;
 } test;
 
 static void
@@ -109,7 +112,44 @@ teardown (void *unused)
        rv = test.module->C_Finalize (NULL);
        assert (rv == CKR_OK);
 
+       free (test.directory);
+
+       memset (&test, 0, sizeof (test));
+}
+
+static void
+setup_writable (void *unused)
+{
+       CK_C_INITIALIZE_ARGS args;
+       char *arguments;
+       CK_ULONG count;
+       CK_RV rv;
+
        memset (&test, 0, sizeof (test));
+
+       /* This is the entry point of the trust module, linked to this test */
+       rv = C_GetFunctionList (&test.module);
+       assert (rv == CKR_OK);
+
+       test.directory = p11_path_expand ("$TEMP/test-module.XXXXXX");
+       if (!mkdtemp (test.directory))
+               assert_not_reached ();
+
+       memset (&args, 0, sizeof (args));
+       if (asprintf (&arguments, "paths='%s'", test.directory) < 0)
+               assert (false && "not reached");
+       args.pReserved = arguments;
+       args.flags = CKF_OS_LOCKING_OK;
+
+       rv = test.module->C_Initialize (&args);
+       assert (rv == CKR_OK);
+
+       free (arguments);
+
+       count = 1;
+       rv = test.module->C_GetSlotList (CK_TRUE, test.slots, &count);
+       assert (rv == CKR_OK);
+       assert (count == 1);
 }
 
 static void
@@ -587,8 +627,6 @@ static void
 test_find_builtin (void)
 {
        CK_OBJECT_CLASS klass = CKO_NSS_BUILTIN_ROOT_LIST;
-       CK_BBOOL vtrue = CK_TRUE;
-       CK_BBOOL vfalse = CK_FALSE;
 
        CK_ATTRIBUTE match[] = {
                { CKA_CLASS, &klass, sizeof (klass) },
@@ -987,6 +1025,18 @@ test_login_logout (void)
        assert (rv == CKR_USER_NOT_LOGGED_IN);
 }
 
+static void
+test_token_writable (void)
+{
+       CK_TOKEN_INFO info;
+       CK_RV rv;
+
+       rv = test.module->C_GetTokenInfo (test.slots[0], &info);
+
+       assert_num_eq (rv, CKR_OK);
+       assert_num_eq (info.flags & CKF_WRITE_PROTECTED, 0);
+}
+
 int
 main (int argc,
       char *argv[])
@@ -1020,5 +1070,8 @@ main (int argc,
        p11_test (test_find_serial_der_mismatch, "/module/find_serial_der_mismatch");
        p11_test (test_login_logout, "/module/login_logout");
 
+       p11_fixture (setup_writable, teardown);
+       p11_test (test_token_writable, "/module/token-writable");
+
        return p11_test_run (argc, argv);
 }
index 6f5ccdb1d687c10bdf40af05907a98c8b85f7b59..d3728147f3142eb192e57bcf0cd9172fae7aa467 100644 (file)
@@ -42,6 +42,7 @@
 
 #include "attrs.h"
 #include "debug.h"
+#include "path.h"
 #include "pkcs11x.h"
 #include "message.h"
 #include "token.h"
@@ -206,6 +207,75 @@ test_token_slot (void *path)
        assert_num_eq (333, p11_token_get_slot (test.token));
 }
 
+static void
+test_not_writable (void)
+{
+       p11_token *token;
+
+       token = p11_token_new (333, "/", "Label");
+       assert (!p11_token_is_writable (token));
+       p11_token_free (token);
+
+       token = p11_token_new (333, "", "Label");
+       assert (!p11_token_is_writable (token));
+       p11_token_free (token);
+
+       token = p11_token_new (333, "/non-existant", "Label");
+       assert (!p11_token_is_writable (token));
+       p11_token_free (token);
+}
+
+static void
+test_writable_exists (void)
+{
+       char *directory;
+       p11_token *token;
+
+       directory = p11_path_expand ("$TEMP/test-module.XXXXXX");
+       if (!mkdtemp (directory))
+               assert_not_reached ();
+
+       token = p11_token_new (333, directory, "Label");
+
+       /* A writable directory since we created it */
+       assert (p11_token_is_writable (token));
+
+       p11_token_free (token);
+
+       if (rmdir (directory) < 0)
+               assert_not_reached ();
+
+       free (directory);
+}
+
+static void
+test_writable_no_exist (void)
+{
+       char *directory;
+       p11_token *token;
+       char *path;
+
+       directory = p11_path_expand ("$TEMP/test-module.XXXXXX");
+       if (!mkdtemp (directory))
+               assert_not_reached ();
+
+       path = p11_path_build (directory, "subdir", NULL);
+       assert (path != NULL);
+
+       token = p11_token_new (333, path, "Label");
+       free (path);
+
+       /* A writable directory since parent is writable */
+       assert (p11_token_is_writable (token));
+
+       p11_token_free (token);
+
+       if (rmdir (directory) < 0)
+               assert_not_reached ();
+
+       free (directory);
+}
+
 int
 main (int argc,
       char *argv[])
@@ -218,5 +288,11 @@ main (int argc,
        p11_testx (test_token_path, "/wheee", "/token/path");
        p11_testx (test_token_label, "/wheee", "/token/label");
        p11_testx (test_token_slot, "/unneeded", "/token/slot");
+
+       p11_fixture (NULL, NULL);
+       p11_test (test_not_writable, "/token/not-writable");
+       p11_test (test_writable_exists, "/token/writable-exists");
+       p11_test (test_writable_no_exist, "/token/writable-no-exist");
+
        return p11_test_run (argc, argv);
 }
index f48f66b749a1b2ca7e9c9deb6fafe30c2023f54a..c5991dff00a2b92f175c597351e78bd801723953 100644 (file)
@@ -65,6 +65,9 @@ struct _p11_token {
        char *label;
        CK_SLOT_ID slot;
        int loaded;
+
+       bool checked_writable;
+       bool is_writable;
 };
 
 static int
@@ -314,3 +317,47 @@ p11_token_index (p11_token *token)
        return_val_if_fail (token != NULL, NULL);
        return token->index;
 }
+
+static bool
+check_writable_directory (const char *path)
+{
+       struct stat sb;
+       char *parent;
+       bool ret;
+
+       if (access (path, W_OK) == 0)
+               return stat (path, &sb) == 0 && S_ISDIR (sb.st_mode);
+
+       switch (errno) {
+       case EACCES:
+               return false;
+       case ENOENT:
+               parent = p11_path_parent (path);
+               if (parent == NULL)
+                       ret = false;
+               else
+                       ret = check_writable_directory (parent);
+               free (parent);
+               return ret;
+       default:
+               p11_message ("couldn't access: %s: %s", path, strerror (errno));
+               return false;
+       }
+}
+
+bool
+p11_token_is_writable (p11_token *token)
+{
+       /*
+        * This function attempts to determine whether a later write
+        * to this token will succeed so we can setup the appropriate
+        * token flags. Yes, it is racy, but that's inherent to the problem.
+        */
+
+       if (!token->checked_writable) {
+               token->is_writable = check_writable_directory (token->path);
+               token->checked_writable = true;
+       }
+
+       return token->is_writable;
+}
index d7375e7448ead76febe1c7f23db56168a52e0b2f..49140bb3ef6f6675c898cedb7ab1ca0c166fdd4c 100644 (file)
@@ -57,4 +57,6 @@ const char *    p11_token_get_label   (p11_token *token);
 
 CK_SLOT_ID      p11_token_get_slot    (p11_token *token);
 
+bool            p11_token_is_writable (p11_token *token);
+
 #endif /* P11_TOKEN_H_ */