diff options
Diffstat (limited to 'trust/token.c')
-rw-r--r-- | trust/token.c | 331 |
1 files changed, 263 insertions, 68 deletions
diff --git a/trust/token.c b/trust/token.c index c5991df..ec34f6c 100644 --- a/trust/token.c +++ b/trust/token.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Red Hat Inc. + * Copyright (C) 2012-2013 Red Hat Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -58,48 +58,200 @@ #include <string.h> struct _p11_token { - p11_parser *parser; - p11_index *index; - p11_builder *builder; - char *path; - char *label; - CK_SLOT_ID slot; - int loaded; + p11_parser *parser; /* Parser we use to load files */ + p11_index *index; /* Index we load objects into */ + p11_builder *builder; /* Expands objects and applies policy */ + p11_dict *loaded; /* stat structs for loaded files, track reloads */ + + char *path; /* Main path to load from */ + char *anchors; /* Path to load anchors from */ + char *blacklist; /* Path to load blacklist from */ + char *label; /* The token label */ + CK_SLOT_ID slot; /* The slot id */ bool checked_writable; bool is_writable; }; +static bool +loader_is_necessary (p11_token *token, + const char *filename, + struct stat *sb) +{ + struct stat *last; + + last = p11_dict_get (token->loaded, filename); + + /* Never seen this before, load it */ + if (last == NULL) + return true; + + /* + * If any of these are different assume that the file + * needs to be reloaded + */ + return (sb->st_mode != last->st_mode || + sb->st_mtime != last->st_mtime || + sb->st_size != last->st_size); +} + +static void +loader_was_loaded (p11_token *token, + const char *filename, + struct stat *sb) +{ + char *key; + + key = strdup (filename); + return_if_fail (key != NULL); + + sb = memdup (sb, sizeof (struct stat)); + return_if_fail (sb != NULL); + + /* Track the info about this file, so we don't reload unnecessarily */ + if (!p11_dict_set (token->loaded, key, sb)) + return_if_reached (); +} + +static void +loader_not_loaded (p11_token *token, + const char *filename) +{ + /* No longer track info about this file */ + p11_dict_remove (token->loaded, filename); +} + +static void +loader_gone_file (p11_token *token, + const char *filename) +{ + CK_ATTRIBUTE origin[] = { + { CKA_X_ORIGIN, (void *)filename, strlen (filename) }, + { CKA_INVALID }, + }; + + CK_RV rv; + + /* Remove everything at this origin */ + rv = p11_index_replace_all (token->index, origin, CKA_INVALID, NULL); + return_if_fail (rv == CKR_OK); + + /* No longer track info about this file */ + loader_not_loaded (token, filename); +} + static int loader_load_file (p11_token *token, const char *filename, - struct stat *sb, - int flags) + struct stat *sb) { + CK_ATTRIBUTE origin[] = { + { CKA_X_ORIGIN, (void *)filename, strlen (filename) }, + { CKA_INVALID }, + }; + + CK_BBOOL modifiablev; + + CK_ATTRIBUTE modifiable = { + CKA_MODIFIABLE, + &modifiablev, + sizeof (modifiablev) + }; + + p11_array *parsed; + CK_RV rv; + int flags; int ret; + int i; + + /* Check if this file is already loaded */ + if (!loader_is_necessary (token, filename, sb)) + return 0; + + flags = P11_PARSE_FLAG_NONE; + + /* If it's in the anchors subdirectory, treat as an anchor */ + if (p11_path_prefix (filename, token->anchors)) + flags = P11_PARSE_FLAG_ANCHOR; + + /* If it's in the blacklist subdirectory, treat as a blacklist */ + else if (p11_path_prefix (filename, token->blacklist)) + flags = P11_PARSE_FLAG_BLACKLIST; + + /* If the token is just one path, then assume they are anchors */ + else if (strcmp (filename, token->path) == 0 && !S_ISDIR (sb->st_mode)) + flags = P11_PARSE_FLAG_ANCHOR; ret = p11_parse_file (token->parser, filename, flags); switch (ret) { case P11_PARSE_SUCCESS: p11_debug ("loaded: %s", filename); - return 1; + break; case P11_PARSE_UNRECOGNIZED: p11_debug ("skipped: %s", filename); + loader_gone_file (token, filename); return 0; default: p11_debug ("failed to parse: %s", filename); + loader_gone_file (token, filename); return 0; } + + /* TODO: We should check if in the right format */ + modifiablev = CK_FALSE; + + /* Update each parsed object with the origin */ + parsed = p11_parser_parsed (token->parser); + for (i = 0; i < parsed->num; i++) { + parsed->elem[i] = p11_attrs_build (parsed->elem[i], origin, &modifiable, NULL); + return_val_if_fail (parsed->elem[i] != NULL, 0); + } + + p11_index_batch (token->index); + + /* Now place all of these in the index */ + rv = p11_index_replace_all (token->index, origin, CKA_CLASS, parsed); + + p11_index_finish (token->index); + + if (rv != CKR_OK) { + p11_message ("couldn't load file into objects: %s", filename); + return 0; + } + + loader_was_loaded (token, filename, sb); + return 1; +} + +static int +loader_load_if_file (p11_token *token, + const char *path) +{ + struct stat sb; + + if (stat (path, &sb) < 0) { + if (errno == ENOENT) { + p11_message ("couldn't stat path: %s: %s", + path, strerror (errno)); + } + + } else if (!S_ISDIR (sb.st_mode)) { + return loader_load_file (token, path, &sb); + } + + /* Perhaps the file became unloadable, so track properly */ + loader_gone_file (token, path); + return 0; } static int loader_load_directory (p11_token *token, const char *directory, - int flags) + p11_dict *present) { + p11_dictiter iter; struct dirent *dp; - struct stat sb; char *path; int total = 0; int ret; @@ -110,6 +262,7 @@ loader_load_directory (p11_token *token, if (!dir) { p11_message ("couldn't list directory: %s: %s", directory, strerror (errno)); + loader_not_loaded (token, directory); return 0; } @@ -118,81 +271,81 @@ loader_load_directory (p11_token *token, path = p11_path_build (directory, dp->d_name, NULL); return_val_if_fail (path != NULL, -1); - if (stat (path, &sb) < 0) { - p11_message ("couldn't stat path: %s", path); + ret = loader_load_if_file (token, path); + return_val_if_fail (ret >=0, -1); + total += ret; - } else if (!S_ISDIR (sb.st_mode)) { - ret = loader_load_file (token, path, &sb, flags); - return_val_if_fail (ret >= 0, ret); - total += ret; - } + /* Make note that this file was seen */ + p11_dict_remove (present, path); free (path); } closedir (dir); - return total; -} -static int -loader_load_subdirectory (p11_token *token, - const char *directory, - const char *subdir, - int flags) -{ - struct stat sb; - char *path; - int ret = 0; + /* All other files that were present, not here now */ + p11_dict_iterate (present, &iter); + while (p11_dict_next (&iter, (void **)&path, NULL)) + loader_gone_file (token, path); - if (asprintf (&path, "%s/%s", directory, subdir) < 0) - return_val_if_reached (-1); - - if (stat (path, &sb) >= 0 && S_ISDIR (sb.st_mode)) - ret = loader_load_directory (token, path, flags); - - free (path); - return ret; + return total; } static int loader_load_path (p11_token *token, const char *path) { + p11_dictiter iter; + p11_dict *present; + char *filename; struct stat sb; int total; int ret; if (stat (path, &sb) < 0) { - if (errno == ENOENT) { - p11_message ("trust certificate path does not exist: %s", - path); - } else { + if (errno != ENOENT) { p11_message ("cannot access trust certificate path: %s: %s", path, strerror (errno)); } - + loader_gone_file (token, path); return 0; } if (S_ISDIR (sb.st_mode)) { - total = 0; - ret = loader_load_subdirectory (token, path, "anchors", P11_PARSE_FLAG_ANCHOR); - return_val_if_fail (ret >= 0, ret); - total += ret; + /* All the files we know about at this path */ + present = p11_dict_new (p11_dict_str_hash, p11_dict_str_equal, NULL, NULL); + p11_dict_iterate (token->loaded, &iter); + while (p11_dict_next (&iter, (void **)&filename, NULL)) { + if (p11_path_prefix (filename, path)) { + if (!p11_dict_set (present, filename, filename)) + return_val_if_reached (-1); + } + } - ret = loader_load_subdirectory (token, path, "blacklist", P11_PARSE_FLAG_BLACKLIST); - return_val_if_fail (ret >= 0, ret); - total += ret; + /* If the directory has changed, reload it */ + if (loader_is_necessary (token, path, &sb)) { + ret = loader_load_directory (token, path, present); - ret = loader_load_directory (token, path, P11_PARSE_FLAG_NONE); - return_val_if_fail (ret >= 0, ret); - total += ret; + /* Directory didn't change, but maybe files changed? */ + } else { + total = 0; + p11_dict_iterate (present, &iter); + while (p11_dict_next (&iter, (void **)&filename, NULL)) { + ret = loader_load_if_file (token, filename); + return_val_if_fail (ret >= 0, ret); + total += ret; + } + } + + p11_dict_free (present); + loader_was_loaded (token, path, &sb); - return total; } else { - return loader_load_file (token, path, &sb, P11_PARSE_FLAG_ANCHOR); + ret = loader_load_file (token, path, &sb); } + + return ret; } static int @@ -223,19 +376,49 @@ load_builtin_objects (p11_token *token) int p11_token_load (p11_token *token) { - int builtins; - int count; + int total = 0; + int ret; - if (token->loaded) - return 0; - token->loaded = 1; + ret = loader_load_path (token, token->path); + return_val_if_fail (ret >= 0, -1); + total += ret; + + ret = loader_load_path (token, token->anchors); + return_val_if_fail (ret >= 0, -1); + total += ret; + + ret = loader_load_path (token, token->blacklist); + return_val_if_fail (ret >= 0, -1); + total += ret; + + return total; +} - builtins = load_builtin_objects (token); +void +p11_token_reload (p11_token *token, + CK_ATTRIBUTE *attrs) +{ + CK_ATTRIBUTE *attr; + struct stat sb; + char *origin; - count = loader_load_path (token, token->path); - return_val_if_fail (count >= 0, count); + attr = p11_attrs_find (attrs, CKA_X_ORIGIN); + if (attr == NULL) + return; - return count + builtins; + origin = strndup (attr->pValue, attr->ulValueLen); + return_if_fail (origin != NULL); + + if (stat (origin, &sb) < 0) { + if (errno == ENOENT) { + loader_gone_file (token, origin); + } else { + p11_message ("cannot access trust file: %s: %s", + origin, strerror (errno)); + } + } else { + loader_load_file (token, origin, &sb); + } } void @@ -247,7 +430,10 @@ p11_token_free (p11_token *token) p11_index_free (token->index); p11_parser_free (token->parser); p11_builder_free (token->builder); + p11_dict_free (token->loaded); free (token->path); + free (token->anchors); + free (token->blacklist); free (token->label); free (token); } @@ -273,18 +459,27 @@ p11_token_new (CK_SLOT_ID slot, token->builder); return_val_if_fail (token->index != NULL, NULL); - token->parser = p11_parser_new (token->index, - p11_builder_get_cache (token->builder)); + token->parser = p11_parser_new (p11_builder_get_cache (token->builder)); return_val_if_fail (token->parser != NULL, NULL); + token->loaded = p11_dict_new (p11_dict_str_hash, p11_dict_str_equal, free, free); + return_val_if_fail (token->loaded != NULL, NULL); + token->path = strdup (path); return_val_if_fail (token->path != NULL, NULL); + token->anchors = p11_path_build (token->path, "anchors", NULL); + return_val_if_fail (token->anchors != NULL, NULL); + + token->blacklist = p11_path_build (token->path, "blacklist", NULL); + return_val_if_fail (token->blacklist != NULL, NULL); + token->label = strdup (label); return_val_if_fail (token->label != NULL, NULL); token->slot = slot; - token->loaded = 0; + + load_builtin_objects (token); p11_debug ("token: %s: %s", token->label, token->path); return token; |