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

Reply via email to