summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStef Walter <stef@thewalter.net>2013-06-14 13:02:22 +0200
committerStef Walter <stef@thewalter.net>2013-06-14 13:32:04 +0200
commitbfe10cd0660fd81d78c8c5ce3eaa7d1f046859e1 (patch)
tree7c691c0a82eca27ce905bc448e6f51575b46dae8
parent045df29606ea9853b4fc8bdba062a5e4a7a5be95 (diff)
trust: Correctly reflect the CK_TOKEN_INFO writability flags
Correctly set the CKF_TOKEN_WRITE_PROTECTED flag for paths which we will be able to write to.
-rw-r--r--common/compat.h3
-rw-r--r--trust/module.c5
-rw-r--r--trust/tests/test-module.c57
-rw-r--r--trust/tests/test-token.c76
-rw-r--r--trust/token.c47
-rw-r--r--trust/token.h2
6 files changed, 187 insertions, 3 deletions
diff --git a/common/compat.h b/common/compat.h
index 0f9677b..9127f95 100644
--- a/common/compat.h
+++ b/common/compat.h
@@ -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;
diff --git a/trust/module.c b/trust/module.c
index abfabae..ea514b1 100644
--- a/trust/module.c
+++ b/trust/module.c
@@ -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 ();
diff --git a/trust/tests/test-module.c b/trust/tests/test-module.c
index bf28124..910b9b4 100644
--- a/trust/tests/test-module.c
+++ b/trust/tests/test-module.c
@@ -60,10 +60,13 @@
#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);
}
diff --git a/trust/tests/test-token.c b/trust/tests/test-token.c
index 6f5ccdb..d372814 100644
--- a/trust/tests/test-token.c
+++ b/trust/tests/test-token.c
@@ -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);
}
diff --git a/trust/token.c b/trust/token.c
index f48f66b..c5991df 100644
--- a/trust/token.c
+++ b/trust/token.c
@@ -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;
+}
diff --git a/trust/token.h b/trust/token.h
index d7375e7..49140bb 100644
--- a/trust/token.h
+++ b/trust/token.h
@@ -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_ */