Logo Search packages:      
Sourcecode: ecryptfs-utils version File versions

module_mgr.c

/**
 * Copyright (C) 2006 International Business Machines
 * Author(s): Michael A. Halcrow <mhalcrow@us.ibm.com>
 *          Trevor Highland <trevor.highland@gmail.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 * 02111-1307, USA.
 */

#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include "../include/ecryptfs.h"
#include "../include/decision_graph.h"

static struct param_node key_module_select_node = {
      .num_mnt_opt_names = 1,
      .mnt_opt_names = {"key"},
      .prompt = "Select key type to use for newly created files",
      .val_type = VAL_STR,
      .val = NULL,
      .display_opts = NULL,
      .default_val = NULL,
      .flags = DISPLAY_TRANSITION_NODE_VALS | ECHO_INPUT,
      .num_transitions = 0,
      .tl = {{0}}
};

/**
 * sig_param_node_callback
 *
 * The eCryptfs utilities may modify the decision graph
 * in-flight. This is one example of that happening.
 *
 * By default, root_param_node will pull a "sig=" option out of the
 * already-supplied name/value pair list and skip the key module
 * selection stage altogether. If there is no "sig=" option provided
 * in the list (condition: node->val == NULL), then change the
 * next_token transition node pointer to point to the key module
 * selection node.
 */
static int
sig_param_node_callback(struct ecryptfs_ctx *ctx, struct param_node *node,
                  struct val_node **head, void **foo)
{
      char *param;
      int rc = 0;

      if (!node->val) {
            node->tl[0].next_token = &key_module_select_node;
            goto out;
      }
      if (strcmp(node->val, "NULL") == 0) {
            node->tl[0].next_token = &key_module_select_node;
            goto out;
      }
      rc = asprintf(&param, "ecryptfs_sig=%s", node->val);
      if (rc == -1) {
            rc = -ENOMEM;
            syslog(LOG_ERR, "Out of memory\n");
            goto out;
      }
      stack_push(head, param);
out:
      return rc;
}

static struct param_node cipher_param_node;

static struct param_node root_param_node = {
      .num_mnt_opt_names = 1,
      .mnt_opt_names = {"sig"},
      .prompt = "Existing key signature",
      .val_type = VAL_STR,
      .val = NULL,
      .display_opts = NULL,
      .default_val = "NULL",
      .flags = 0,
      .num_transitions = 1,
      .tl = {{.val = "default",
            .pretty_val = "default",
            .next_token = &cipher_param_node,
            .trans_func = sig_param_node_callback}}
};

static int get_cipher(struct ecryptfs_ctx *ctx, struct param_node *node,
                  struct val_node **head, void **foo)
{
      char *temp, *val;
      char *prompt;
      int rc, i=1;
      struct ecryptfs_cipher_elem cipher_list_head;
      struct ecryptfs_cipher_elem *current;
      struct ecryptfs_cipher_elem *default_cipher;

      memset(&cipher_list_head, 0, sizeof(struct ecryptfs_cipher_elem));
      if (node->val) {
            rc = asprintf(&temp, "ecryptfs_cipher=%s", node->val);
            free(node->val);
            node->val = NULL;
            if (rc == -1)
                  return MOUNT_ERROR;
            goto out;
      }
      if (ctx->verbosity == 0)
            return NULL_TOK;
      rc = ecryptfs_get_current_kernel_ciphers(&cipher_list_head);
      if (rc)
            goto out_error;
      current = cipher_list_head.next;

      asprintf(&prompt, "Cipher\n");
      while (current) {
            rc = asprintf(&temp,"%s%d) %s\n", prompt, i, current->user_name);
            if (rc == -1)
                  goto out_error;
            i++;
            free(prompt);
            prompt = temp;
            current = current->next;
      }
      rc = ecryptfs_default_cipher(&default_cipher, &cipher_list_head);
      asprintf(&temp, "%sSelection [%s]", prompt, default_cipher->user_name);
      free(prompt);
      prompt = temp;

get_cipher:
      (ctx->get_string)(&val, prompt, ECHO_INPUT);

      i = atoi(val);
      if (i)
            current = cipher_list_head.next;
      while (current) {
            if (i == 1)
                  break;
            current = current->next;
            i--;
      }
      if (current && i == 1) {
            rc = asprintf(&temp, "ecryptfs_key_bytes=%d", current->bytes);
            stack_push(head, temp);
            rc = asprintf(&temp, "ecryptfs_cipher=%s",
                        current->kernel_name);
            if (rc == -1)
                  goto out_error;
      }
      else if (val[0] == '\0'){
            rc = asprintf(&temp, "ecryptfs_key_bytes=%d",
                        default_cipher->bytes);
            stack_push(head, temp);
            rc = asprintf(&temp, "ecryptfs_cipher=%s",
                        default_cipher->kernel_name);
            if (rc == -1)
                  goto out_error;
      } else {
            goto get_cipher;
      }
      free(node->val);
      node->val = NULL;
      if (rc == -1)
            goto out_error;
out:
      ecryptfs_free_cipher_list(cipher_list_head);
      stack_push(head, temp);
      return NULL_TOK;
out_error:
      ecryptfs_free_cipher_list(cipher_list_head);
            return MOUNT_ERROR;
}

static int get_passthrough(struct ecryptfs_ctx *ctx, struct param_node *node,
                     struct val_node **head, void **foo)
{
      if (node->val && (*(node->val) == 'y')) {
            stack_push(head, "ecryptfs_passthrough");
      } else if (node->flags & PARAMETER_SET) {
            stack_push(head, "ecryptfs_passthrough");
            return 0;
      }
      free(node->val);
      return 0;
}

static int get_xattr(struct ecryptfs_ctx *ctx, struct param_node *node,
                     struct val_node **head, void **foo)
{
      if (node->val && (*(node->val) == 'y')) {
            stack_push(head, "ecryptfs_xattr_metadata");
      } else if (node->flags & PARAMETER_SET) {
            stack_push(head, "ecryptfs_xattr_metadata");
            return 0;
      }
      free(node->val);
      return 0;
}

static int get_encrypted_passthrough(struct ecryptfs_ctx *ctx,
                             struct param_node *node,
                             struct val_node **head, void **foo)
{
      if (node->val && (*(node->val) == 'y')) {
            stack_push(head, "ecryptfs_encrypted_view");
      } else if (node->flags & PARAMETER_SET) {
            stack_push(head, "ecryptfs_encrypted_view");
            return 0;
      }
      free(node->val);
      return 0;
}

static struct param_node end_param_node = {
      .num_mnt_opt_names = 1,
      .mnt_opt_names = {"cipher"},
      .prompt = "Select cipher",
      .val_type = VAL_STR,
      .val = NULL,
      .display_opts = NULL,
      .default_val = NULL,
      .flags = NO_VALUE,
      .num_transitions = 0,
      .tl = {{.val = "default",
            .pretty_val = "default",
            .next_token = NULL,
            .trans_func = get_cipher}}
};

static struct param_node encrypted_passthrough_param_node = {
      .num_mnt_opt_names = 1,
      .mnt_opt_names = {"encrypted_view"},
      .prompt = "Pass through encrypted versions of all files (y/n)",
      .val_type = VAL_STR,
      .val = NULL,
      .display_opts = NULL,
      .default_val = "n",
      .flags = ECHO_INPUT,
      .num_transitions = 1,
      .tl = {{.val = "default",
            .pretty_val = "default",
            .next_token = &end_param_node,
            .trans_func = get_encrypted_passthrough}}
};

static struct param_node xattr_param_node = {
      .num_mnt_opt_names = 1,
      .mnt_opt_names = {"xattr"},
      .prompt = "Write metadata to extended attribute region (y/n)",
      .val_type = VAL_STR,
      .val = NULL,
      .display_opts = NULL,
      .default_val = "n",
      .flags = ECHO_INPUT,
      .num_transitions = 1,
      .tl = {{.val = "default",
            .pretty_val = "default",
            .next_token = &end_param_node,
            .trans_func = get_xattr}}
};

static struct param_node passthrough_param_node = {
      .num_mnt_opt_names = 1,
      .mnt_opt_names = {"passthrough"},
      .prompt = "Enable plaintext passthrough (y/n)",
      .val_type = VAL_STR,
      .val = NULL,
      .display_opts = NULL,
      .default_val = NULL,
      .flags = ECHO_INPUT,
      .num_transitions = 1,
      .tl = {{.val = "default",
            .pretty_val = "default",
            .next_token = &end_param_node,
            .trans_func = get_passthrough}}
};

static struct param_node cipher_param_node = {
      .num_mnt_opt_names = 1,
      .mnt_opt_names = {"cipher"},
      .prompt = "Select cipher",
      .val_type = VAL_STR,
      .val = NULL,
      .display_opts = NULL,
      .default_val = NULL,
      .flags = NO_VALUE,
      .num_transitions = 1,
      .tl = {{.val = "default",
            .pretty_val = "default",
            .next_token = &end_param_node,
            .trans_func = get_cipher}}
};

static int
another_key_param_node_callback(struct ecryptfs_ctx *ctx,
                        struct param_node *node,
                        struct val_node **head, void **foo)
{
      struct ecryptfs_name_val_pair *nvp = ctx->nvp_head->next;
      int rc = 0;

      syslog(LOG_INFO, "%s: Called\n", __FUNCTION__);
      while (nvp) {
            int i;

            if (nvp->flags & ECRYPTFS_PROCESSED) {
                  nvp = nvp->next;
                  continue;
            }
            if (ecryptfs_verbosity)
                  syslog(LOG_INFO, "Comparing nvp->name = [%s] to "
                         "key_module_select_node.mnt_opt_names[0] = "
                         "[%s]\n", nvp->name,
                         key_module_select_node.mnt_opt_names[0]);
            if (strcmp(nvp->name,
                     key_module_select_node.mnt_opt_names[0]) != 0) {
                  nvp = nvp->next;
                  continue;
            }
            for (i = 0; i < key_module_select_node.num_transitions; i++)
                  if (strcmp(nvp->value,
                           key_module_select_node.tl[i].val) == 0) {
                        node->tl[0].next_token =
                              &key_module_select_node;
                        if (ecryptfs_verbosity)
                              syslog(LOG_INFO,
                                     "Found another nvp match\n");
                        goto out;
                  }
            nvp = nvp->next;
      }
      node->tl[0].next_token = &cipher_param_node;
out:
      return rc;
}

/**
 * Check for the existence of another transition node match in the
 * name/value pair list.
 */
static struct param_node another_key_param_node = {
      .num_mnt_opt_names = 1,
      .mnt_opt_names = {"another_key"},
      .prompt = "Internal check for another key",
      .val_type = VAL_STR,
      .val = NULL,
      .display_opts = NULL,
      .default_val = "NULL",
      .flags = 0,
      .num_transitions = 1,
      .tl = {{.val = "default",
            .pretty_val = "default",
            .next_token = &cipher_param_node,
            .trans_func = another_key_param_node_callback}}
};

static void
fill_in_decision_graph_based_on_version_support(struct param_node *root,
                                    uint32_t version)
{
      struct param_node *last_param_node = &cipher_param_node;

      ecryptfs_set_exit_param_on_graph(root, &another_key_param_node);
      if (ecryptfs_supports_plaintext_passthrough(version)) {
            last_param_node->tl[0].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;
            last_param_node = &xattr_param_node;
            last_param_node->tl[0].next_token =
                  &encrypted_passthrough_param_node;
            last_param_node = &encrypted_passthrough_param_node;
      }
}

int ecryptfs_process_decision_graph(struct ecryptfs_ctx *ctx,
                            struct val_node **head, uint32_t version,

                            char *opts_str)
{
      struct ecryptfs_name_val_pair nvp_head;
      struct ecryptfs_name_val_pair rc_file_nvp_head;
      struct ecryptfs_pki_elem *pki_elem;
      struct ecryptfs_name_val_pair allowed_duplicates;
      struct ecryptfs_name_val_pair *ad_cursor;
      int rc;

      ad_cursor = &allowed_duplicates;
      ad_cursor->next = NULL;
      /* Start with the key module type. Generate the options from
       * the detected modules that are available */
      rc = ecryptfs_get_pki_list(ctx);
      if (rc) {
            syslog(LOG_ERR, "Error attempting to get key module list; "
                   "rc = [%d]\n", rc);
            goto out;
      }
      if ((ad_cursor->next = malloc(sizeof(allowed_duplicates))) == NULL) {
            rc = -ENOMEM;
            goto out;
      }
      ad_cursor = ad_cursor->next;
      ad_cursor->next = NULL;
      if ((rc = asprintf(&ad_cursor->name,
                     key_module_select_node.mnt_opt_names[0])) == -1) {
            rc = -ENOMEM;
            goto out_free_allowed_duplicates;
      }
      pki_elem = ctx->pki_list_head.next;
      while (pki_elem) {
            struct transition_node *trans_node;

            if ((rc =
                 pki_elem->ops.get_param_subgraph_trans_node(&trans_node,
                                                 version))) {
                  pki_elem = pki_elem->next;
                  continue;
            }
            if ((rc =
                 add_transition_node_to_param_node(&key_module_select_node,
                                           trans_node))) {
                  syslog(LOG_ERR, "Error attempting to add transition "
                         "node to param node; rc = [%d]\n", rc);
                  goto out_free_allowed_duplicates;
            }
            if ((rc = ecryptfs_insert_params_in_subgraph(ad_cursor,
                                               trans_node))) {
                  syslog(LOG_ERR, "Error attempting to insert allowed "
                         "duplicate parameters into subgraph for key "
                         "module; rc = [%d]\n", rc);
                  goto out_free_allowed_duplicates;
            }
            pki_elem = pki_elem->next;
      }
      fill_in_decision_graph_based_on_version_support(&key_module_select_node,
                                          version);
      memset(&nvp_head, 0, sizeof(struct ecryptfs_name_val_pair));
      memset(&rc_file_nvp_head, 0, sizeof(struct ecryptfs_name_val_pair));
      ecryptfs_parse_rc_file(&rc_file_nvp_head);
      rc = ecryptfs_parse_options(opts_str, &nvp_head);
      ecryptfs_nvp_list_union(&rc_file_nvp_head, &nvp_head,
                        &allowed_duplicates);
      if (ecryptfs_verbosity) {
            struct ecryptfs_name_val_pair *nvp_item = rc_file_nvp_head.next;

            while (nvp_item) {
                  if (ecryptfs_verbosity)
                        syslog(LOG_INFO, "name = [%s]; value = [%s]\n",
                               nvp_item->name, nvp_item->value);
                  nvp_item = nvp_item->next;
            }
      }
      ctx->nvp_head = &rc_file_nvp_head;
      decision_graph_mount(ctx, head, &root_param_node, &rc_file_nvp_head);
out_free_allowed_duplicates:
      ad_cursor = allowed_duplicates.next;
      while (ad_cursor) {
            struct ecryptfs_name_val_pair *next;
            
            next = ad_cursor->next;
            free(ad_cursor->name);
            free(ad_cursor);
            ad_cursor = next;
      }
out:
      return rc;
}

Generated by  Doxygen 1.6.0   Back to index