It's time to start caring about the cipher selection parameters. (Apologies for the memory leaks, but it is just a mount helper, after all...)
Signed-off-by: Mike Halcrow <[EMAIL PROTECTED]> --- diff --git a/src/include/decision_graph.h b/src/include/decision_graph.h index 6385d07..d3bd29d 100644 --- a/src/include/decision_graph.h +++ b/src/include/decision_graph.h @@ -99,12 +99,20 @@ struct param_node { #define PARAMETER_SET 0x00000080 #define ECRYPTFS_PARAM_FLAG_LOCK_MEM 0x00000100 #define ECRYPTFS_PARAM_FORCE_DISPLAY_NODES 0x00000200 +#define ECRYPTFS_DISPLAY_PRETTY_VALS 0x00000400 uint32_t flags; int num_transitions; -#define MAX_NUM_TRANSITIONS 8 +#define MAX_NUM_TRANSITIONS 64 struct transition_node tl[MAX_NUM_TRANSITIONS]; }; +struct prompt_elem; + +struct prompt_elem { + char *str; + struct prompt_elem *next; +}; + int add_transition_node_to_param_node(struct param_node *param_node, struct transition_node *trans_node); void ecryptfs_dump_param_node(FILE *file_stream, diff --git a/src/include/ecryptfs.h b/src/include/ecryptfs.h index b2a7de3..d0648d4 100644 --- a/src/include/ecryptfs.h +++ b/src/include/ecryptfs.h @@ -218,14 +218,6 @@ struct ecryptfs_daemon_info { char socket_file_full_path[PATH_MAX]; }; -struct ecryptfs_cipher_elem { - uint8_t loaded_cipher; - char *kernel_name; - char *user_name; - uint32_t bytes; - struct ecryptfs_cipher_elem *next; -}; - struct ecryptfs_netlink_message { uint32_t index; uint32_t data_len; @@ -365,12 +357,6 @@ struct ecryptfs_ctx { struct ecryptfs_name_val_pair *nvp_head; }; -struct cipher_str_name_map_elem { - char *kernel_name; - char *user_name; - int keysize_bytes; -}; - enum main_menu_enum { MME_NULL, MME_MOUNT_PASSPHRASE, @@ -382,6 +368,39 @@ enum main_menu_enum { struct val_node; struct param_node; +struct cipher_str_name_map_elem { + char *kernel_name; + char *user_name; + int keysize_bytes; +}; + +struct ecryptfs_cipher_elem; + +struct ecryptfs_cipher_elem { + uint8_t loaded_cipher; + char *kernel_name; + char *user_name; + uint32_t bytes; + struct ecryptfs_cipher_elem *next; +}; + +struct cipher_descriptor; + +struct cipher_descriptor { +#define CIPHER_DESCRIPTOR_FLAG_LOADED 0x00000001 + uint32_t flags; + char *crypto_api_name; + char *descriptive_name; + char *driver_name; + char *module_name; + uint32_t blocksize; + uint32_t min_keysize; + uint32_t max_keysize; + struct cipher_descriptor *next; +}; + +int ecryptfs_get_kernel_ciphers(struct cipher_descriptor *cd_head); +int ecryptfs_get_module_ciphers(struct cipher_descriptor *cd_head); int ecryptfs_get_version(uint32_t *version); int ecryptfs_supports_passphrase(uint32_t version); int ecryptfs_supports_pubkey(uint32_t version); diff --git a/src/libecryptfs/cipher_list.c b/src/libecryptfs/cipher_list.c index e142de2..83907ca 100644 --- a/src/libecryptfs/cipher_list.c +++ b/src/libecryptfs/cipher_list.c @@ -39,14 +39,18 @@ #include "../include/ecryptfs.h" #define MAX_BUF_LEN 128 +#define MTAB_FULLPATH "/etc/mtab" +/** + * Pulling ourselves up by the bootstraps... + */ static int get_proc_mount_point(char **proc_mount_point) { FILE *fp; struct mntent *mntent; int rc = 0; - fp = fopen("/etc/mtab", "r"); + fp = fopen(MTAB_FULLPATH, "r"); if (!fp) { rc = -errno; goto out; @@ -308,3 +312,296 @@ int ecryptfs_free_cipher_list(struct ecryptfs_cipher_elem cipher_list_head) } return 0; } + +int ecryptfs_get_kernel_ciphers(struct cipher_descriptor *cd_head) +{ + struct cipher_descriptor *cd_cursor = cd_head; + char *proc_mount_point = NULL; + char *crypto_full_path = NULL; + FILE *crypto_file = NULL; + char buf[MAX_BUF_LEN]; + char *tmp = NULL; + int rc; + + rc = get_proc_mount_point(&proc_mount_point); + if (rc) { + syslog(LOG_WARNING, "Error attempting to find proc mount " + "point in [/etc/mtab]. Defaulting to [/proc].\n"); + rc = 0; + if (asprintf(&proc_mount_point, "/proc") == -1) { + proc_mount_point = NULL; + rc = -ENOMEM; + goto out; + } + } + if (asprintf(&crypto_full_path, "%s/crypto", proc_mount_point) == -1) { + crypto_full_path = NULL; + rc = -ENOMEM; + goto out; + } + if (!(crypto_file = fopen(crypto_full_path, "r"))) { + rc = -EIO; + goto out; + } + while (fgets(buf, MAX_BUF_LEN, crypto_file)) { + if (!strncmp(buf, "name", 4)) { + struct cipher_descriptor *cd_tmp; + int found_duplicate = 0; + + strtok(buf, ": "); + tmp = strtok(NULL, ": "); + cd_tmp = cd_head->next; + while (cd_tmp) { + if (!strcmp(cd_tmp->crypto_api_name, tmp)) { + found_duplicate = 1; + break; + } + cd_tmp = cd_tmp->next; + } + if (found_duplicate) + continue; + cd_cursor->next = malloc(sizeof(*cd_cursor)); + if (!cd_cursor->next) { + rc = -ENOMEM; + goto out; + } + memset(cd_cursor->next, 0, sizeof(*cd_cursor)); + cd_cursor->next->flags |= CIPHER_DESCRIPTOR_FLAG_LOADED; + if (strlen(tmp) <= 0) { + rc = -EINVAL; + goto out; + } + tmp[strlen(tmp) - 1] = '\0'; + rc = asprintf(&cd_cursor->next->crypto_api_name, + "%s", tmp); + if (rc == -1) { + cd_cursor->next->crypto_api_name = NULL; + free(cd_cursor->next); + rc = -ENOMEM; + goto out; + } + rc = 0; + } else if (!strncmp(buf, "module", 6)) { + if (!cd_cursor->next) + continue; + strtok(buf, ": "); + tmp = strtok(NULL, ": "); + if (strlen(tmp) <= 0) { + rc = -EINVAL; + goto out; + } + tmp[strlen(tmp) - 1] = '\0'; + rc = asprintf(&cd_cursor->next->module_name, "%s.ko", + tmp); + if (rc == -1) { + cd_cursor->next->module_name = NULL; + free(cd_cursor->next->crypto_api_name); + free(cd_cursor->next); + rc = -ENOMEM; + goto out; + } + rc = 0; + } else if (!strncmp(buf, "driver", 6)) { + if (!cd_cursor->next) + continue; + strtok(buf, ": "); + tmp = strtok(NULL, ": "); + if (strlen(tmp) <= 0) { + rc = -EINVAL; + goto out; + } + tmp[strlen(tmp) - 1] = '\0'; + rc = asprintf(&cd_cursor->next->driver_name, "%s", tmp); + if (rc == -1) { + cd_cursor->next->module_name = NULL; + free(cd_cursor->next->module_name); + free(cd_cursor->next->crypto_api_name); + free(cd_cursor->next); + rc = -ENOMEM; + goto out; + } + rc = 0; + } else if (!strncmp(buf, "type", 4)) { + if (!cd_cursor->next) + continue; + strtok(buf, ": "); + tmp = strtok(NULL, ": "); + if (strlen(tmp) <= 0) { + rc = -EINVAL; + goto out; + } + tmp[strlen(tmp) - 1] = '\0'; + /* We only care about ciphers, not hashes, etc. */ + if (strncmp(tmp, "cipher", 6)) { + free(cd_cursor->next->module_name); + free(cd_cursor->next->crypto_api_name); + free(cd_cursor->next->driver_name); + free(cd_cursor->next); + cd_cursor->next = NULL; + continue; + } + } else if (!strncmp(buf, "blocksize", 9)) { + if (!cd_cursor->next) + continue; + strtok(buf, ": "); + tmp = strtok(NULL, ": "); + if (strlen(tmp) <= 0) { + rc = -EINVAL; + goto out; + } + tmp[strlen(tmp) - 1] = '\0'; + cd_cursor->next->blocksize = atoi(tmp); + } else if (!strncmp(buf, "min keysize", 11)) { + if (!cd_cursor->next) + continue; + strtok(buf, ": "); + tmp = strtok(NULL, ": "); + if (strlen(tmp) <= 0) { + rc = -EINVAL; + goto out; + } + tmp[strlen(tmp) - 1] = '\0'; + cd_cursor->next->min_keysize = atoi(tmp); + } else if (!strncmp(buf, "max keysize", 11)) { + if (!cd_cursor->next) + continue; + strtok(buf, ": "); + tmp = strtok(NULL, ": "); + if (strlen(tmp) <= 0) { + rc = -EINVAL; + goto out; + } + tmp[strlen(tmp) - 1] = '\0'; + cd_cursor->next->max_keysize = atoi(tmp); + cd_cursor = cd_cursor->next; + } + } +out: + if (crypto_file) + fclose(crypto_file); + free(proc_mount_point); + free(crypto_full_path); + return rc; +} + +static struct cipher_name_module_map { + char *name; + char *module; + uint32_t blocksize; + uint32_t min_keysize; + uint32_t max_keysize; +} cipher_name_module_map[] = { + {"aes", "aes.ko", 16, 16, 32}, + {"aes", "aes_generic.ko", 16, 16, 32}, + {"serpent", "serpent.ko", 16, 0, 32}, + {"tnepres", "serpent.ko", 16, 0, 32}, + {"arc4", "arc4.ko", 1, 1, 256}, + {"tea", "tea.ko", 8, 16, 16}, + {"xeta", "tea.ko", 8, 16, 16}, + {"xtea", "tea.ko", 8, 16, 16}, + {"blowfish", "blowfish.ko", 16, 16, 32}, + {"twofish", "twofish.ko", 16, 16, 32}, + {"khazad", "khazad.ko", 8, 16, 16}, + {"cast5", "cast5.ko", 8, 5, 16}, + {"cast6", "cast6.ko", 16, 16, 32}, + {"des3_ede", "des.ko", 8, 24, 24}, + {"des3_ede", "des_generic.ko", 8, 24, 24}, + {"anubis", "anubis.ko", 16, 16, 40}, + {"cipher_null", "cipher_null.ko", 1, 0, 0}, + {NULL, NULL} +}; + +int ecryptfs_get_module_ciphers(struct cipher_descriptor *cd_head) +{ + struct cipher_descriptor *cd_cursor = cd_head; + char *kernel_crypto_dir = NULL; + struct utsname kern_info; + DIR *dir = NULL; + struct dirent *dir_entry; + int rc; + + while (cd_cursor->next) + cd_cursor = cd_cursor->next; + rc = uname(&kern_info); + if (rc) { + syslog(LOG_ERR, "%s: uname returned [%d]\n", __FUNCTION__, rc); + goto out; + } + rc = asprintf(&kernel_crypto_dir, "/lib/modules/%s/kernel/crypto", + kern_info.release); + if (rc == -1) { + syslog(LOG_ERR, "%s: Error building kernel location string\n", + __FUNCTION__); + rc = -ENOMEM; + goto out; + } + rc = 0; + dir = opendir(kernel_crypto_dir); + if (!dir) { + syslog(LOG_ERR, "%s: opendir error on [%s]\n", __FUNCTION__, + kernel_crypto_dir); + rc = -EINVAL; + goto out; + } + while ((dir_entry = readdir(dir))) { + struct cipher_descriptor *cd_tmp; + int found_match; + int i; + + if (!strstr(dir_entry->d_name, ".ko")) + continue; + found_match = 0; + cd_tmp = cd_head->next; + while (cd_tmp) { + if (!strcmp(cd_tmp->module_name, dir_entry->d_name)) { + found_match = 1; + break; + } + cd_tmp = cd_tmp->next; + } + if (found_match) + continue; + i = 0; + while (cipher_name_module_map[i].name) { + if (!strcmp(cipher_name_module_map[i].module, + dir_entry->d_name)) { + cd_cursor->next = malloc(sizeof(*cd_cursor)); + if (!cd_cursor->next) { + rc = -ENOMEM; + goto out; + } + memset(cd_cursor->next, 0, sizeof(*cd_cursor)); + rc = asprintf(&cd_cursor->next->crypto_api_name, + "%s", + cipher_name_module_map[i].name); + if (rc == -1) { + free(cd_cursor->next); + rc = -ENOMEM; + goto out; + } + rc = asprintf(&cd_cursor->next->module_name, + "%s", dir_entry->d_name); + if (rc == -1) { + free(cd_cursor->next->crypto_api_name); + free(cd_cursor->next); + rc = -ENOMEM; + goto out; + } + rc = 0; + cd_cursor->next->blocksize = + cipher_name_module_map[i].blocksize; + cd_cursor->next->min_keysize = + cipher_name_module_map[i].min_keysize; + cd_cursor->next->max_keysize = + cipher_name_module_map[i].max_keysize; + cd_cursor = cd_cursor->next; + } + i++; + } + } +out: + free(kernel_crypto_dir); + if (dir) + closedir(dir); + return rc; +} diff --git a/src/libecryptfs/decision_graph.c b/src/libecryptfs/decision_graph.c index 315b434..e46f5d2 100644 --- a/src/libecryptfs/decision_graph.c +++ b/src/libecryptfs/decision_graph.c @@ -269,15 +269,20 @@ int do_transition(struct ecryptfs_ctx *ctx, struct param_node **next, * Try to find one of the aliases for this node in the list of * name-value pairs. If found, set the value from that element in the * list. + * + * Returns non-zero on error condition */ -static int retrieve_val(struct ecryptfs_name_val_pair *nvp_head, +static int retrieve_val(int *value_retrieved, + struct ecryptfs_name_val_pair *nvp_head, struct param_node *node) { int i = node->num_mnt_opt_names; + int rc = 0; if (ecryptfs_verbosity) syslog(LOG_INFO, "%s: Called on node [%s]\n", __FUNCTION__, node->mnt_opt_names[0]); + (*value_retrieved) = 0; while (i > 0) { struct ecryptfs_name_val_pair *temp = nvp_head->next; @@ -299,23 +304,32 @@ static int retrieve_val(struct ecryptfs_name_val_pair *nvp_head, if (temp->value && (strcmp(temp->value, "(null)") != 0)) { if (asprintf(&node->val, "%s", - temp->value) == -1) - return -ENOMEM; - } else { + temp->value) == -1) { + rc = -ENOMEM; + goto out; + } + } else node->flags |= PARAMETER_SET; - return -1; - } - return 0; + (*value_retrieved) = 1; + goto out; } temp = temp->next; } } if (node->default_val) { - if (asprintf(&node->val, "%s", node->default_val) == -1) - return -ENOMEM; - return 0; + if (asprintf(&node->val, "%s", node->default_val) == -1) { + rc = -ENOMEM; + goto out; + } + if (ecryptfs_verbosity) + syslog(LOG_INFO, "%s: Value retrieved from " + "node->default_val = [%s]\n", __FUNCTION__, + node->default_val); + (*value_retrieved) = 1; + goto out; } - return -1; +out: + return rc; } /** @@ -328,75 +342,154 @@ static int alloc_and_get_val(struct ecryptfs_ctx *ctx, struct param_node *node, { char *verify_prompt; char *verify; - int rc = 0; int val; + int value_retrieved; + int rc; - if (!retrieve_val(nvp_head, node)) + rc = retrieve_val(&value_retrieved, nvp_head, node); + if (rc) { + syslog(LOG_ERR, "%s: Error attempting to retrieve value; " + "rc = [%d]\n", __FUNCTION__, rc); goto out; - if (node->flags & ECRYPTFS_PARAM_FLAG_NO_VALUE) + } + if (value_retrieved) { + if (ecryptfs_verbosity) + syslog(LOG_INFO, + "%s: Value retrieved from default_val or from " + "parameter list; returning\n", + __FUNCTION__); goto out; - if (ctx->verbosity == 0 && !(node->flags & STDIN_REQUIRED)) - return 0; - if ((node->flags & PARAMETER_SET) && !(node->flags & STDIN_REQUIRED)) - return 0; + } + if (node->flags & ECRYPTFS_PARAM_FLAG_NO_VALUE) { + if (ecryptfs_verbosity) + syslog(LOG_INFO, + "%s: ECRYPTFS_PARAM_FLAG_NO_VALUE set\n", + __FUNCTION__); + goto out; + } + if (ctx->verbosity == 0 && !(node->flags & STDIN_REQUIRED)) { + if (ecryptfs_verbosity) + syslog(LOG_INFO, "%s: ctx->verbosity == 0 and " + "STDIN_REQUIRED not set\n", __FUNCTION__); + goto out; + } + if ((node->flags & PARAMETER_SET) && !(node->flags & STDIN_REQUIRED)) { + if (ecryptfs_verbosity) + syslog(LOG_INFO, "%s: PARAMETER_SET and " + "STDIN_REQUIRED not set\n", __FUNCTION__); + goto out; + } if (ctx->get_string) { + if (ecryptfs_verbosity) + syslog(LOG_INFO, "%s: ctx->get_string defined\n", + __FUNCTION__); if (node->flags & DISPLAY_TRANSITION_NODE_VALS) { - int i, strpos = 0; - int node_prompt_len = strlen(node->prompt); - int default_val_len = 0; - int len; + struct prompt_elem pe_head; + struct prompt_elem *pe; char *prompt; + uint32_t prompt_len; + int i; - if (node->default_val) - default_val_len = strlen(node->default_val); - len = node_prompt_len + default_val_len + 32; - if (node->num_transitions == 1 + if (ecryptfs_verbosity) + syslog(LOG_INFO, "%s: DISPLAY_TRANSITION_NODE_" + "VALS set\n", __FUNCTION__); + memset(&pe_head, 0, sizeof(pe_head)); + pe = &pe_head; + if ((node->num_transitions == 1) && !(node->flags & ECRYPTFS_PARAM_FORCE_DISPLAY_NODES)) { if (asprintf(&(node->val), "%s", - node->tl[0].val) == -1) - return MOUNT_ERROR; - return 0; + node->tl[0].val) == -1) { + rc = -ENOMEM; + goto out; + } + rc = 0; + goto out; + } + /* === Begin add component to prompt === */ + pe->next = malloc(sizeof(*pe)); + if (!pe->next) { + rc = -ENOMEM; + goto out; + } + pe = pe->next; + memset(pe, 0, sizeof(*pe)); + rc = asprintf(&pe->str, "%s: \n", node->prompt); + if (rc == -1) { + rc = -ENOMEM; + goto out; } - for (i = 0; i < node->num_transitions; i++) - len += (strlen(node->tl[i].val) + 5); - prompt = malloc(len); - if (!prompt) - return -ENOMEM; - memcpy(prompt, node->prompt, node_prompt_len); - prompt[node_prompt_len] = ':'; - strpos = node_prompt_len + 1; - prompt[strpos++] = '\n'; + rc = 0; + /* === End add component to prompt === */ for (i = 0; i < node->num_transitions; i++) { - prompt[strpos++] = ' '; - prompt[strpos++] = '0' + (char)(i + 1); - prompt[strpos++] = ')'; - prompt[strpos++] = ' '; - memcpy(&prompt[strpos], node->tl[i].val, - strlen(node->tl[i].val)); - strpos += strlen(node->tl[i].val); - prompt[strpos++] = '\n'; + pe->next = malloc(sizeof(*pe)); + if (!pe->next) { + rc = -ENOMEM; + goto out; + } + pe = pe->next; + memset(pe, 0, sizeof(*pe)); + if (node->flags & ECRYPTFS_DISPLAY_PRETTY_VALS) + rc = asprintf(&pe->str, " %d) %s\n", + (i + 1), + node->tl[i].pretty_val); + else + rc = asprintf(&pe->str, " %d) %s\n", + (i + 1), + node->tl[i].val); + if (rc == -1) { + rc = -ENOMEM; + goto out; + } + rc = 0; + } + pe->next = malloc(sizeof(*pe)); + if (!pe->next) { + rc = -ENOMEM; + goto out; + } + pe = pe->next; + memset(pe, 0, sizeof(*pe)); + if (node->suggested_val) + rc = asprintf(&pe->str, "Selection [%s]", + node->suggested_val); + else if (node->default_val) + rc = asprintf(&pe->str, "Selection [%s]", + node->default_val); + else + rc = asprintf(&pe->str, "Selection"); + if (rc == -1) { + rc = -ENOMEM; + goto out; + } + rc = 0; + /* Convert prompt_elem linked list into + * single prompt string */ + prompt_len = 0; + pe = pe_head.next; + while (pe) { + prompt_len += strlen(pe->str); + pe = pe->next; } - memcpy(&prompt[strpos], "Selection", 9); - strpos += 9; - if (node->suggested_val) { - memcpy(&prompt[strpos], " [", 2); - strpos += 2; - memcpy(&prompt[strpos], node->default_val, - default_val_len); - strpos += default_val_len; - memcpy(&prompt[strpos], "]", 1); - strpos += 1; - } else if (node->default_val) { - memcpy(&prompt[strpos], " [", 2); - strpos += 2; - memcpy(&prompt[strpos], node->default_val, - default_val_len); - strpos += default_val_len; - memcpy(&prompt[strpos], "]", 1); - strpos += 1; + prompt_len++; + i = 0; + prompt = malloc(prompt_len); + if (!prompt) { + rc = -ENOMEM; + goto out; } - prompt[strpos] = '\0'; + pe = pe_head.next; + while (pe) { + struct prompt_elem *pe_tmp; + + memcpy(&prompt[i], pe->str, strlen(pe->str)); + i += strlen(pe->str); + pe_tmp = pe; + pe = pe->next; + free(pe_tmp->str); + free(pe_tmp); + } + prompt[i] = '\0'; get_value: rc = (ctx->get_string) (&(node->val), prompt, @@ -408,13 +501,38 @@ get_value: asprintf(&(node->val), "%s", node->tl[val - 1].val); } else { - goto get_value; + int valid_val; + + if (node->val[0] == '\0') { + if (!node->suggested_val) + goto get_value; + rc = asprintf(&node->val, "%s", + node->suggested_val); + if (rc == -1) { + rc = -ENOMEM; + goto out; + } + rc = 0; + } + valid_val = 0; + for (i = 0; i < node->num_transitions; i++) { + if (strcmp(node->val, node->tl[i].val) + == 0) { + valid_val = 1; + break; + } + } + if (!valid_val) + goto get_value; } free(prompt); return rc; } else { char *prompt; + if (ecryptfs_verbosity) + syslog(LOG_INFO, "%s: DISPLAY_TRANSITION_NODE_" + "VALS not set\n", __FUNCTION__); obtain_value: if (node->suggested_val) asprintf(&prompt, "%s [%s]", node->prompt, @@ -451,8 +569,12 @@ obtain_value: } return rc; } + } else { + if (ecryptfs_verbosity) + syslog(LOG_INFO, "%s: ctx->get_string not defined", + __FUNCTION__); } - return MOUNT_ERROR; + rc = MOUNT_ERROR; out: return rc; } diff --git a/src/libecryptfs/module_mgr.c b/src/libecryptfs/module_mgr.c index 39b8aa2..820fc00 100644 --- a/src/libecryptfs/module_mgr.c +++ b/src/libecryptfs/module_mgr.c @@ -78,7 +78,7 @@ out: return rc; } -static struct param_node cipher_param_node; +static struct param_node ecryptfs_cipher_param_node; static struct param_node root_param_node = { .num_mnt_opt_names = 1, @@ -92,7 +92,7 @@ static struct param_node root_param_node = { .num_transitions = 1, .tl = {{.val = "default", .pretty_val = "default", - .next_token = &cipher_param_node, + .next_token = &ecryptfs_cipher_param_node, .trans_func = sig_param_node_callback}} }; @@ -222,8 +222,8 @@ static int get_encrypted_passthrough(struct ecryptfs_ctx *ctx, static struct param_node end_param_node = { .num_mnt_opt_names = 1, - .mnt_opt_names = {"cipher"}, - .prompt = "Select cipher", + .mnt_opt_names = {"end"}, + .prompt = "end", .val_type = VAL_STR, .val = NULL, .display_opts = NULL, @@ -233,7 +233,7 @@ static struct param_node end_param_node = { .tl = {{.val = "default", .pretty_val = "default", .next_token = NULL, - .trans_func = get_cipher}} + .trans_func = NULL}} }; static struct param_node encrypted_passthrough_param_node = { @@ -284,22 +284,233 @@ static struct param_node passthrough_param_node = { .trans_func = get_passthrough}} }; -static struct param_node cipher_param_node = { +static struct param_node ecryptfs_key_bytes_param_node = { + .num_mnt_opt_names = 1, + .mnt_opt_names = {"ecryptfs_key_bytes"}, + .prompt = "Select key bytes", + .val_type = VAL_STR, + .val = NULL, + .display_opts = NULL, + .default_val = NULL, + .flags = (DISPLAY_TRANSITION_NODE_VALS + | ECRYPTFS_PARAM_FORCE_DISPLAY_NODES + | ECRYPTFS_PARAM_FLAG_ECHO_INPUT), + .num_transitions = 0, + .tl = {{0}} +}; + +static struct supported_key_bytes { + char *cipher_name; + uint32_t key_bytes; +} supported_key_bytes[] = { + {"aes", 16}, + {"aes", 24}, + {"aes", 32}, + {"anubis", 16}, + {"anubis", 32}, + {"des3_ede", 24}, + {"serpent", 16}, + {"serpent", 32}, + {"tnepres", 16}, + {"tnepres", 32}, + {"tea", 16}, + {"xeta", 16}, + {"xtea", 16}, + {"cast5", 16}, + {"cast6", 16}, + {"cast6", 32}, + {"twofish", 16}, + {"twofish", 32}, + {"blowfish", 16}, + {"blowfish", 32}, + {"khazad", 16}, + {"arc4", 16}, + {"arc4", 32}, + {NULL, 0} +}; + +static int tf_ecryptfs_key_bytes(struct ecryptfs_ctx *ctx, + struct param_node *node, + struct val_node **head, void **foo) +{ + char *opt; + int rc = 0; + + rc = asprintf(&opt, "ecryptfs_key_bytes=%s", node->val); + free(node->val); + node->val = NULL; + if (rc == -1) { + rc = -ENOMEM; + goto out; + } + rc = 0; + stack_push(head, opt); +out: + return rc; +} + +static int init_ecryptfs_key_bytes_param_node(char *cipher_name) +{ + int i; + int rc = 0; + + i = 0; + while (supported_key_bytes[i].cipher_name) { + if (strcmp(cipher_name, supported_key_bytes[i].cipher_name) + == 0) { + struct transition_node *tn; + + tn = &ecryptfs_key_bytes_param_node.tl[ + ecryptfs_key_bytes_param_node.num_transitions]; + rc = asprintf(&tn->val, "%d", + supported_key_bytes[i].key_bytes); + if (rc == -1) { + rc = -ENOMEM; + goto out; + } + rc = 0; + if (!ecryptfs_key_bytes_param_node.suggested_val) { + rc = asprintf(&ecryptfs_key_bytes_param_node.suggested_val, + "%d", + supported_key_bytes[i].key_bytes); + if (rc == -1) { + rc = -ENOMEM; + goto out; + } + rc = 0; + } + tn->next_token = &end_param_node; + tn->trans_func = tf_ecryptfs_key_bytes; + ecryptfs_key_bytes_param_node.num_transitions++; + } + i++; + } +out: + return rc; +} + +static int tf_ecryptfs_cipher(struct ecryptfs_ctx *ctx, struct param_node *node, + struct val_node **head, void **foo) +{ + char *opt; + int rc; + + rc = init_ecryptfs_key_bytes_param_node(node->val); + if (rc) { + syslog(LOG_ERR, "%s: Error initializing key_bytes param node; " + "rc = [%d]\n", __FUNCTION__, rc); + goto out; + } + rc = asprintf(&opt, "ecryptfs_cipher=%s", node->val); + free(node->val); + node->val = NULL; + if (rc == -1) { + rc = -ENOMEM; + goto out; + } + rc = 0; + if (ecryptfs_verbosity) + syslog(LOG_INFO, "%s: Pushing onto stack; opt = [%s]\n", + __FUNCTION__, opt); + stack_push(head, opt); +out: + return rc; +} + +static struct param_node ecryptfs_cipher_param_node = { .num_mnt_opt_names = 1, - .mnt_opt_names = {"cipher"}, + .mnt_opt_names = {"ecryptfs_cipher"}, .prompt = "Select cipher", .val_type = VAL_STR, .val = NULL, .display_opts = NULL, .default_val = NULL, - .flags = ECRYPTFS_PARAM_FLAG_NO_VALUE, - .num_transitions = 1, - .tl = {{.val = "default", - .pretty_val = "default", - .next_token = &end_param_node, - .trans_func = get_cipher}} + .flags = (DISPLAY_TRANSITION_NODE_VALS | ECRYPTFS_DISPLAY_PRETTY_VALS + | ECRYPTFS_PARAM_FLAG_ECHO_INPUT), + .num_transitions = 0, + .tl = {{0}} }; +static int init_ecryptfs_cipher_param_node(uint32_t version) +{ + struct cipher_descriptor cd_head; + struct cipher_descriptor *cd_cursor; + int rc; + + memset(&cd_head, 0, sizeof(cd_head)); + rc = ecryptfs_get_kernel_ciphers(&cd_head); + if (rc) { + syslog(LOG_ERR, "%s: Error getting kernel ciphers; rc = [%d]\n", + __FUNCTION__, rc); + goto out; + } + rc = ecryptfs_get_module_ciphers(&cd_head); + if (rc) { + syslog(LOG_ERR, "%s: Error getting module ciphers; rc = [%d]\n", + __FUNCTION__, rc); + goto out; + } + cd_cursor = cd_head.next; + while (cd_cursor) { + struct transition_node *tn; + struct cipher_descriptor *cd_tmp; + + if (ecryptfs_cipher_param_node.num_transitions + >= MAX_NUM_TRANSITIONS) { + syslog(LOG_WARNING, "%s: Exceeded maximum number of " + "transition nodes [%d] whilst constructing " + "cipher list\n", __FUNCTION__, + MAX_NUM_TRANSITIONS); + goto out; + } + tn = &ecryptfs_cipher_param_node.tl[ + ecryptfs_cipher_param_node.num_transitions]; + rc = asprintf(&tn->val, "%s", cd_cursor->crypto_api_name); + if (rc == -1) { + rc = -ENOMEM; + goto out; + } + rc = 0; + if (!ecryptfs_cipher_param_node.suggested_val) { + rc = asprintf(&ecryptfs_cipher_param_node.suggested_val, + "%s", cd_cursor->crypto_api_name); + if (rc == -1) { + rc = -ENOMEM; + goto out; + } + rc = 0; + } + rc = asprintf(&tn->pretty_val, + "%s: blocksize = %d; " + "min keysize = %d; max keysize = %d (%s)", + cd_cursor->crypto_api_name, + cd_cursor->blocksize, + cd_cursor->min_keysize, + cd_cursor->max_keysize, + ((cd_cursor->flags + & CIPHER_DESCRIPTOR_FLAG_LOADED) ? "loaded" + : "not loaded")); + if (rc == -1) { + rc = -ENOMEM; + goto out; + } + rc = 0; + tn->next_token = &ecryptfs_key_bytes_param_node; + tn->trans_func = tf_ecryptfs_cipher; + ecryptfs_cipher_param_node.num_transitions++; + free(cd_cursor->crypto_api_name); + free(cd_cursor->descriptive_name); + free(cd_cursor->driver_name); + free(cd_cursor->module_name); + cd_tmp = cd_cursor; + cd_cursor = cd_cursor->next; + cd_tmp->next = NULL; + free(cd_tmp); + } +out: + return rc; +} + static int another_key_param_node_callback(struct ecryptfs_ctx *ctx, struct param_node *node, @@ -337,7 +548,7 @@ another_key_param_node_callback(struct ecryptfs_ctx *ctx, } nvp = nvp->next; } - node->tl[0].next_token = &cipher_param_node; + node->tl[0].next_token = &ecryptfs_cipher_param_node; out: return rc; } @@ -358,28 +569,46 @@ static struct param_node another_key_param_node = { .num_transitions = 1, .tl = {{.val = "default", .pretty_val = "default", - .next_token = &cipher_param_node, + .next_token = &ecryptfs_cipher_param_node, .trans_func = another_key_param_node_callback}} }; -static void +static int fill_in_decision_graph_based_on_version_support(struct param_node *root, uint32_t version) { - struct param_node *last_param_node = &cipher_param_node; + struct param_node *last_param_node = &ecryptfs_key_bytes_param_node; + int rc; ecryptfs_set_exit_param_on_graph(root, &another_key_param_node); + rc = init_ecryptfs_cipher_param_node(version); + if (rc) { + syslog(LOG_ERR, + "%s: Error initializing cipher list; rc = [%d]\n", + __FUNCTION__, rc); + goto out; + } if (ecryptfs_supports_plaintext_passthrough(version)) { - last_param_node->tl[0].next_token = &passthrough_param_node; + int i; + + for (i = 0; i < last_param_node->num_transitions; i++) + last_param_node->tl[i].next_token = + &passthrough_param_node; last_param_node = &passthrough_param_node; } if (ecryptfs_supports_xattr(version)) { - last_param_node->tl[0].next_token = &xattr_param_node; + int i; + + for (i = 0; i < last_param_node->num_transitions; i++) + last_param_node->tl[i].next_token = &xattr_param_node; last_param_node = &xattr_param_node; - last_param_node->tl[0].next_token = - &encrypted_passthrough_param_node; + for (i = 0; i < last_param_node->num_transitions; i++) + last_param_node->tl[i].next_token = + &encrypted_passthrough_param_node; last_param_node = &encrypted_passthrough_param_node; } +out: + return rc; } static struct param_node dummy_param_node = { @@ -498,10 +727,15 @@ int ecryptfs_process_decision_graph(struct ecryptfs_ctx *ctx, } key_mod = key_mod->next; } - if (key_module_only == ECRYPTFS_ASK_FOR_ALL_MOUNT_OPTIONS) - fill_in_decision_graph_based_on_version_support(&key_module_select_node, - version); - else + if (key_module_only == ECRYPTFS_ASK_FOR_ALL_MOUNT_OPTIONS) { + rc = fill_in_decision_graph_based_on_version_support( + &key_module_select_node, version); + if (rc) { + syslog(LOG_ERR, "%s: Error attempting to fill in " + "decision graph; rc = [%d]\n", __FUNCTION__, rc); + goto out; + } + } else ecryptfs_set_exit_param_on_graph(&key_module_select_node, &dummy_param_node); memset(&nvp_head, 0, sizeof(struct ecryptfs_name_val_pair)); @@ -521,6 +755,20 @@ int ecryptfs_process_decision_graph(struct ecryptfs_ctx *ctx, } } ctx->nvp_head = &rc_file_nvp_head; +#if 1 + { + struct ecryptfs_name_val_pair *nv_tmp = rc_file_nvp_head.next; + + while (nv_tmp) { + syslog(LOG_INFO, "%s: name = [%s]; value = [%s]\n", + __FUNCTION__, nv_tmp->name, nv_tmp->value); + nv_tmp = nv_tmp->next; + } +/* ecryptfs_dump_param_node(stdout, + &key_module_select_node, 0, + 1); */ + } +#endif ecryptfs_eval_decision_graph(ctx, mnt_params, &root_param_node, &rc_file_nvp_head); out_free_allowed_duplicates: diff --git a/src/testcases/test-cipher-list.c b/src/testcases/test-cipher-list.c new file mode 100644 index 0000000..75ac3b9 --- /dev/null +++ b/src/testcases/test-cipher-list.c @@ -0,0 +1,37 @@ +#include "../include/ecryptfs.h" + +int main() +{ + struct cipher_descriptor cd_head; + struct cipher_descriptor *cd_cursor; + int rc; + + memset(&cd_head, 0, sizeof(cd_head)); + rc = ecryptfs_get_kernel_ciphers(&cd_head); + if (rc) { + printf("rc = [%d]\n", rc); + goto out; + } + rc = ecryptfs_get_module_ciphers(&cd_head); + if (rc) { + printf("rc = [%d]\n", rc); + goto out; + } + cd_cursor = cd_head.next; + while (cd_cursor) { + struct cipher_descriptor *cd_tmp; + + printf("[%s]: [%s] (%s)\n", cd_cursor->crypto_api_name, + cd_cursor->module_name, (cd_cursor->flags & CIPHER_DESCRIPTOR_FLAG_LOADED ? "loaded" : "not loaded")); + free(cd_cursor->crypto_api_name); + free(cd_cursor->descriptive_name); + free(cd_cursor->driver_name); + free(cd_cursor->module_name); + cd_tmp = cd_cursor; + cd_cursor = cd_cursor->next; + cd_tmp->next = NULL; + free(cd_tmp); + } +out: + return rc; +} ------------------------------------------------------------------------- SF.Net email is sponsored by: Check out the new SourceForge.net Marketplace. It's the best place to buy or sell services for just about anything Open Source. http://sourceforge.net/services/buy/index.php _______________________________________________ eCryptfs-devel mailing list eCryptfs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/ecryptfs-devel