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

decision_graph.c

/**
 * Copyright (C) 2006 International Business Machines Corp.
 *   Author(s): Michael A. Halcrow <mahalcro@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 <stdint.h>
#ifndef S_SPLINT_S
#include <stdio.h>
#include <syslog.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "../include/ecryptfs.h"
#include "../include/decision_graph.h"

int stack_push(struct val_node **head, void *val)
{
      struct val_node *node = malloc(sizeof(struct val_node));
      int rc = 0;

      if (!node) {
            rc = -ENOMEM;
            goto out;
      }
      node->val = val;
      node->prev = *head;
      *head = node;
out:
      return rc;
}

int stack_pop(struct val_node **head)
{
      struct val_node *tmp = (*head)->prev;

      free((*head)->val);
      free(*head);
      *head = tmp;
      return 0;
}

int stack_pop_val(struct val_node **head, void **val)
{
      if (*head && val) {
            struct val_node *tmp = (*head)->prev;

            *val = (*head)->val;
            free(*head);
            *head = tmp;
            return 0;
      }
      return -1;
}

int free_name_val_pairs(struct ecryptfs_name_val_pair *pair)
{
      struct ecryptfs_name_val_pair *next;

      while (pair) {
            if (pair->value)
                  free(pair->value);
            next = pair->next;
            free(pair);
            pair = next;
      }
      return 0;
}

int add_transition_node_to_param_node(struct param_node *param_node,
                              struct transition_node *trans_node)
{
      int rc;

      if (param_node->num_transitions >= MAX_NUM_TRANSITIONS) {
            syslog(LOG_ERR, "Too many transitions on node with primary "
                   "alias [%s]\n", param_node->mnt_opt_names[0]);
            rc = -ENOMEM;
            goto out;
      }
      memcpy(&(param_node->tl[param_node->num_transitions++]),
             trans_node, sizeof(*trans_node));
      rc = 0;
out:
      return rc;
}

int set_exit_param_node_for_node(struct param_node *param_node,
                         struct param_node *exit_param_node,
                         int recursive)
{
      int i;
      int rc = 0;

      for (i = 0; i < param_node->num_transitions; i++)
            if (param_node->tl[i].next_token == NULL) {
                  param_node->tl[i].val = "default";
                  param_node->tl[i].pretty_val = "default";
                  param_node->tl[i].next_token = exit_param_node;
            } else if (recursive) {
                  rc = set_exit_param_node_for_node(
                        param_node->tl[i].next_token,
                        exit_param_node, 1);
                  if (rc)
                        goto out;
            }
out:
      return rc;
}

/**
 * Sets the exist param node for all NULL transitions throughout an
 * entire graph.
 */
int ecryptfs_set_exit_param_on_graph(struct param_node *param_node,
                             struct param_node *exit_param_node)
{
      return set_exit_param_node_for_node(param_node, exit_param_node, 1);
}

int set_exit_param_node_for_arr(struct param_node param_node_arr[],
                        struct param_node *exit_param_node)
{
      int arr_len = sizeof(param_node_arr) / sizeof(param_node_arr[0]);
      int i;

      for (i = 0; i < arr_len; i++)
            set_exit_param_node_for_node(&param_node_arr[i],
                                   exit_param_node, 0);
      return 0;
}

void ecryptfs_destroy_nvp(struct ecryptfs_name_val_pair *nvp)
{
      return;
}

int ecryptfs_delete_nvp(struct ecryptfs_name_val_pair *nvp_head,
                  struct ecryptfs_name_val_pair *nvp)
{
      int rc = 0;

      while (nvp_head) {
            if (nvp_head->next == nvp) {
                  nvp_head->next = nvp->next;
                  ecryptfs_destroy_nvp(nvp);
                  goto out;
            }
            nvp_head = nvp_head->next;
      }
      rc = -EINVAL;
out:
      return rc;
}

/**
 * do_transition
 * @ctx:
 * @next:
 * @current:
 * @nvp_head:
 * @val_stack_head:
 * @foo:
 *
 * This function needs to compare transition nodes to options.
 * It is currently comparing them to values provided to options.
 * i.e., each transition is an option; this is incorrect.
 */
int do_transition(struct ecryptfs_ctx *ctx, struct param_node **next,
              struct param_node *current,
              struct ecryptfs_name_val_pair *nvp_head,
              struct val_node **val_stack_head, void **foo)
{
      int i, rc;

      for (i = 0; i < current->num_transitions; i++) {
            struct transition_node *tn = &current->tl[i];
            struct ecryptfs_name_val_pair *nvp = nvp_head->next;

            if (tn->val && current->val
                && strcmp(current->val, tn->val) == 0) {
                  rc = 0;
                  if (tn->trans_func)
                        rc = tn->trans_func(ctx, current,
                                        val_stack_head, foo);
                  if ((*next = tn->next_token)) {
                        if (ecryptfs_verbosity) {
                              syslog(LOG_INFO, "Transitioning from [%p]; name = [%s] to [%p]; name = [%s] per transition node's next_token\n", current, current->mnt_opt_names[0], (*next), (*next)->mnt_opt_names[0]);
                        }
                        return rc;
                  }
                  else return -EINVAL;
            }
            while (nvp) {
                  int trans_func_tok_id = NULL_TOK;

                  if (tn->val && strcmp(nvp->name, tn->val)) {
                        nvp = nvp->next;
                        continue;
                  }
                  if (tn->trans_func)
                        trans_func_tok_id =
                              tn->trans_func(ctx, current,
                                           val_stack_head, foo);
                  if (trans_func_tok_id == MOUNT_ERROR) {
                        return trans_func_tok_id;
                  }
                  if (trans_func_tok_id == DEFAULT_TOK) {
                        if ((*next = tn->next_token))
                              return 0;
                        else
                              return -EINVAL;
                  } else if (trans_func_tok_id == NULL_TOK) {
                        if ((*next = tn->next_token))
                              return 0;
                        else
                              return -EINVAL;
                  }
                  nvp = nvp->next;
            }
      }
      for (i = 0; i < current->num_transitions; i++) {
            struct transition_node *tn = &current->tl[i];

            if (tn->val && strcmp("default", tn->val) == 0){
                  int trans_func_tok_id = NULL_TOK;

                  if (tn->trans_func)
                        trans_func_tok_id =
                              tn->trans_func(ctx, current,
                                           val_stack_head, foo);
                  if (trans_func_tok_id == MOUNT_ERROR)
                        return trans_func_tok_id;
                  if ((*next = tn->next_token))
                        return 0;
                  else return -EINVAL;
            }
      }
      return MOUNT_ERROR;
}

/**
 * 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.
 */
static int retrieve_val(struct ecryptfs_name_val_pair *nvp_head,
                  struct param_node *node)
{
      int i = node->num_mnt_opt_names;

      if (ecryptfs_verbosity)
            syslog(LOG_INFO, "%s: Called on node [%s]\n", __FUNCTION__,
                   node->mnt_opt_names[0]);
      while (i > 0) {
            struct ecryptfs_name_val_pair *temp = nvp_head->next;

            i--;
            while (temp) {
                  if (strcmp(temp->name, node->mnt_opt_names[i]) == 0
                      && !(temp->flags & ECRYPTFS_PROCESSED)) {
                        if (ecryptfs_verbosity)
                              syslog(LOG_INFO, "From param_node = "
                                     "[%p]; mnt_opt_names[0] = [%s]"
                                     ": Setting "
                                     "ECRYPTFS_PROCESSED to nvp with "
                                     "nvp->name = [%s]\n",
                                     node, node->mnt_opt_names[0],
                                     temp->name);
                        temp->flags |= ECRYPTFS_PROCESSED;
                        if (temp->value
                            && (strcmp(temp->value, "(null)") != 0)) {
                              if (asprintf(&node->val, "%s",
                                         temp->value) == -1)
                                    return -ENOMEM;
                        } else {
                              node->flags |= PARAMETER_SET;
                              return -1;
                        }
                        return 0;
                  }
                  temp = temp->next;
            }
      }
      if (node->default_val) {
            if (asprintf(&node->val, "%s", node->default_val) == -1)
                  return -ENOMEM;
            return 0;
      }
      return -1;
}

/**
 * This function can prompt the user and/or check some list of values
 * to get what it needs. Caller must free node->val if it winds up
 * being non-NULL.
 */
int alloc_and_get_val(struct ecryptfs_ctx *ctx, struct param_node *node,
                  struct ecryptfs_name_val_pair *nvp_head)
{
      char *verify_prompt;
      char *verify;
      int rc = 0;
      int val;

      if (!retrieve_val(nvp_head, node))
            return 0;
      if (node->flags & NO_VALUE)
            return 0;
      if (ctx->verbosity == 0 && !(node->flags & STDIN_REQUIRED))
            return 0;
      if ((node->flags & PARAMETER_SET) && !(node->flags & STDIN_REQUIRED))
            return 0;
      if (ctx->get_string) {
            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;
                  char *prompt;

                  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 (asprintf(&(node->val), "%s",
                                   node->tl[0].val) == -1)
                              return MOUNT_ERROR;
                        return 0;
                  }
                  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';
                  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';
                  }
                  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[strpos] = '\0';
get_value:
                  rc = (ctx->get_string)(&(node->val), prompt,
                                     node->flags & ECHO_INPUT);
                  val = atoi(node->val);
                  if (val > 0 && val <= node->num_transitions) {
                        free(node->val);
                        asprintf(&(node->val), "%s",
                               node->tl[val - 1].val);
                  } else {
                        goto get_value;
                  }
                  free(prompt);
                  return rc;
            } else {
                  char *prompt;

obtain_value:
                  if (node->suggested_val)
                        asprintf(&prompt, "%s [%s]", node->prompt,
                               node->suggested_val);
                  else
                        asprintf(&prompt, "%s", node->prompt);
                  rc = (ctx->get_string)(&(node->val), prompt,
                                     node->flags & ECHO_INPUT);
                  free(prompt);
                  if (node->flags & VERIFY_VALUE) {
                        rc = asprintf(&verify_prompt, "Verify %s",
                                    node->prompt);
                        if (rc == -1)
                              return MOUNT_ERROR;
                        rc = (ctx->get_string)(&verify, verify_prompt,
                                          node->flags & ECHO_INPUT);
                        if (rc)
                              return MOUNT_ERROR;
                        if (strcmp(verify, node->val))
                              goto obtain_value;
                  }
                  if (node->val[0] == '\0') {
                        free(node->val);
                        node->val = node->suggested_val;
                  }
                  return rc;
            }
      }
      return MOUNT_ERROR;
}

static void get_verbosity(struct ecryptfs_name_val_pair *nvp_head,
                    int *verbosity)
{
      struct ecryptfs_name_val_pair *temp = nvp_head->next;

      *verbosity = 1;
      while (temp) {
            if (strcmp(temp->name, "verbosity") == 0) {
                  *verbosity = atoi(temp->value);
                  return ;
            }
            temp = temp->next;
      }
      return;
}

int eval_param_tree(struct ecryptfs_ctx *ctx, struct param_node *node,
                struct ecryptfs_name_val_pair *nvp_head,
                struct val_node **val_stack_head)
{
      void *foo = NULL;
      int rc;

      get_verbosity(nvp_head, &(ctx->verbosity));
      do {
            if (ecryptfs_verbosity)
                  syslog(LOG_INFO, "%s: Calling alloc_and_get_val() on "
                         "node = [%p]; node->mnt_opt_names[0] = [%s]\n",
                         __FUNCTION__, node, node->mnt_opt_names[0]);
            if ((rc = alloc_and_get_val(ctx, node, nvp_head)))
                  return rc;
      } while (!(rc = do_transition(ctx, &node, node, nvp_head,
                              val_stack_head, &foo)));
      return rc;
}

int decision_graph_mount(struct ecryptfs_ctx *ctx, struct val_node **head,
                   struct param_node *root_node,
                   struct ecryptfs_name_val_pair *nvp_head) {
      int rc;

      memset(*head, 0, sizeof(struct val_node));
      rc = eval_param_tree(ctx, root_node, nvp_head, head);
      if (rc == MOUNT_ERROR)
            goto out;
      else
            rc = 0;
out:
      return rc;
}


static void print_whitespace(FILE *file_stream, int depth)
{
      int i;

      for (i = 0; i < depth; i++)
            fprintf(file_stream, " ");
}

void ecryptfs_dump_param_node(FILE *file_stream,
                        struct param_node *param_node, int depth,
                        int recursive);

void ecryptfs_dump_transition_node(FILE *file_stream,
                           struct transition_node *trans_node,
                           int depth, int recursive)
{
      print_whitespace(file_stream, depth);
      fprintf(file_stream, "---------------\n");
      print_whitespace(file_stream, depth);
      fprintf(file_stream, "transition_node\n");
      print_whitespace(file_stream, depth);
      fprintf(file_stream, "---------------\n");
      print_whitespace(file_stream, depth);
      fprintf(file_stream, "val = [%s]\n", trans_node->val);
      print_whitespace(file_stream, depth);
      fprintf(file_stream, "next_token = [%p]\n", trans_node->next_token);
      if (recursive && trans_node->next_token)
            ecryptfs_dump_param_node(file_stream, trans_node->next_token,
                               depth + 1, recursive);
      print_whitespace(file_stream, depth);
      fprintf(file_stream, "---------------\n");
}

void ecryptfs_dump_param_node(FILE *file_stream,
                        struct param_node *param_node, int depth,
                        int recursive)
{
      int i;

      print_whitespace(file_stream, depth);
      fprintf(file_stream, "----------\n");
      print_whitespace(file_stream, depth);
      fprintf(file_stream, "param_node\n");
      print_whitespace(file_stream, depth);
      fprintf(file_stream, "----------\n");
      print_whitespace(file_stream, depth);
      fprintf(file_stream, "mnt_opt_names[0] = [%s]\n",
            param_node->mnt_opt_names[0]);
      print_whitespace(file_stream, depth);
      fprintf(file_stream, "num_transitions = [%d]\n",
            param_node->num_transitions);
      for (i = 0; i < param_node->num_transitions; i++) {
            print_whitespace(file_stream, depth);
            fprintf(file_stream, "transition node [%d]:\n", i);
            ecryptfs_dump_transition_node(file_stream, &param_node->tl[i],
                                    depth + 1, recursive);
      }
      print_whitespace(file_stream, depth);
      fprintf(file_stream, "----------\n");

}

void ecryptfs_dump_decision_graph(FILE *file_stream,
                          struct param_node *param_node, int depth)
{
      ecryptfs_dump_param_node(file_stream, param_node, depth, 1);
}

int ecryptfs_insert_params(struct ecryptfs_name_val_pair *nvp,
                     struct param_node *param_node)
{
      int i;
      struct ecryptfs_name_val_pair *cursor = nvp;
      int rc = 0;

      while (cursor->next)
            cursor = cursor->next;
      for (i = 0; i < param_node->num_mnt_opt_names; i++) {
            if ((cursor->next =
                 malloc(sizeof(struct ecryptfs_name_val_pair))) == NULL) {
                  syslog(LOG_ERR, "Error attempting to allocate nvp\n");
                  rc = -ENOMEM;
                  goto out;
            }
            cursor = cursor->next;
            cursor->next = NULL;
            if ((rc = asprintf(&cursor->name, "%s",
                           param_node->mnt_opt_names[i])) == -1) {
                  syslog(LOG_ERR, "Error attempting to allocate nvp "
                         "entry for param_node->mnt_opt_names[%d] = "
                         "[%s]\n", i, param_node->mnt_opt_names[i]);
                  rc = -ENOMEM;
                  goto out;
            }
            rc = 0;
      }
      for (i = 0; i < param_node->num_transitions; i++) {
            if (param_node->tl[i].next_token == NULL)
                  continue;
            if ((rc =
                 ecryptfs_insert_params(cursor,
                                  param_node->tl[i].next_token))) {
                  syslog(LOG_ERR, "Error inserting param; param_node->"
                         "mnt_opt_names[0] = [%s]; transition token "
                         "index = [%d]\n", param_node->mnt_opt_names[0],
                         i);
                  goto out;
            }
      }
out:
            return rc;
}

int ecryptfs_insert_params_in_subgraph(struct ecryptfs_name_val_pair *nvp,
                               struct transition_node *trans_node)
{
      int rc = 0;

      if (trans_node->next_token)
            rc = ecryptfs_insert_params(nvp, trans_node->next_token);
out:
      return rc;
}

Generated by  Doxygen 1.6.0   Back to index