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

cipher_list.c

/**
 * Copyright (C) 2006 International Business Machines Corp.
 * Authors: Trevor Highland <tshighla@us.ibm.com>
 *          Theresa Nelson <tmnelson@us.ibm.com>
 *          Tyler Hicks <tyhicks@ou.edu>
 *
 * 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 <dirent.h>
#include <stdlib.h>
#include <string.h>
#ifndef S_SPLINT_S
#include <syslog.h>
#include <stdio.h>
#endif
#include <errno.h>
#include <fcntl.h>
#include <mntent.h>
#ifndef S_SPLINT_S
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/utsname.h>
#endif
#include "../include/ecryptfs.h"

#define MAX_BUF_LEN 128

static int get_proc_mount_point(char **proc_mount_point)
{
      FILE *fp;
      struct mntent *mntent;
      int rc = 0;

      fp = fopen("/etc/mtab", "r");
      if (!fp) {
            rc = -errno;
            goto out;
      }
      while ((mntent = getmntent(fp)))
            if (strcmp(mntent->mnt_type, "proc") == 0) {
                  asprintf(proc_mount_point, "%s", mntent->mnt_dir);
                  fclose(fp);
                  goto out;
            }
      rc = -EINVAL;
      fclose(fp);
out:
      return rc;
}

static struct cipher_str_name_map_elem cipher_str_name_map[] = {
      {"aes", "AES-128", 16},
      {"blowfish", "Blowfish", 16},
      {"des3_ede", "Triple-DES", 24},
      {"twofish", "Twofish", 16},
      {"cast5", "CAST5", 16},
      {"cast6", "CAST6", 16},
      {"aes", "AES-192", 24},
      {"aes", "AES-256", 32}
};

static int add_cipher(char *name, struct ecryptfs_cipher_elem **current,
                  uint8_t flag)
{
      int i;
      int rc = 0;
      struct cipher_str_name_map_elem *cipher;

      for(i = 0;
          i < (sizeof(cipher_str_name_map) / sizeof(*cipher_str_name_map));
          i++) {
            cipher = &(cipher_str_name_map[i]);
            if(strcmp(name, cipher->kernel_name))
                  continue;
            (*current)->next = malloc(sizeof(struct ecryptfs_cipher_elem));
            if ((*current)->next == NULL)
                  return -ENOMEM;
            memset((*current)->next, 0, sizeof(struct ecryptfs_cipher_elem));
            (*current) = (*current)->next;
            (*current)->loaded_cipher = flag;
            rc = asprintf(&(*current)->kernel_name, "%s",
                        cipher->kernel_name);
            if (rc == -1)
                  return -ENOMEM;
            rc = asprintf(&(*current)->user_name, "%s", cipher->user_name);
            if (rc == -1)
                  return -ENOMEM;
            (*current)->bytes = cipher->keysize_bytes;
      }
      return 0;
}

static int get_proc_crypto_value(char *line, char **value)
{
      int len;

      *value = strtok(line, ": ");
      if (!(*value))
            return 1;

      len = strlen(*value);
      if ((*value)[len - 1] == '\n')
            (*value)[len - 1] = '\0';

      return 0;
}

int ecryptfs_get_current_kernel_ciphers(
      struct ecryptfs_cipher_elem *cipher_list_head)
{
      int rc;

      if (!(rc = ecryptfs_get_loaded_ciphers(cipher_list_head)))
            rc = ecryptfs_add_crypto_modules(cipher_list_head);
      return rc;
}

/**
 * ecryptfs_get_loaded_cipher - creates a linked list of ciphers in
 * the kernel
 * @cipher_list_head: the head of the cipher list
 *
 * Parses the /proc/crypto file to determine which ciphers are
 * built-in or loaded into the kernel.
 *
 * Returns 0 after a successful read of /proc/cypto, 1 otherwise.
 */
int ecryptfs_get_loaded_ciphers(struct ecryptfs_cipher_elem *cipher_list_head)
{
      FILE *crypto_file = NULL;
      char buf[MAX_BUF_LEN];
      char name[MAX_BUF_LEN];
      char *tmp = NULL;
      char *proc_mount_point = NULL;
      char *crypto_full_path = NULL;
      struct ecryptfs_cipher_elem *current_cipher = cipher_list_head;
      int rc;

      if (!cipher_list_head) {
            rc = -EINVAL;
            goto out;
      }
      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)) {
                  if (!get_proc_crypto_value(buf, &tmp))
                        memcpy(name, tmp, MAX_BUF_LEN);
            }
            else if (!strncmp(buf, "type", 4)) {
                  if (get_proc_crypto_value(buf, &tmp))
                        continue;
                  if (strncmp(tmp, "cipher", 6))
                        continue;
                  rc = add_cipher(name, &current_cipher, 1);
                  if (rc)
                        goto out;
            }
      }
out:
      if (crypto_file)
            fclose(crypto_file);
      free(proc_mount_point);
      free(crypto_full_path);
      return rc;
}

/**
 * ecryptfs_add_crypto_modules - adds cyrpt modules to cipher list
 * @cipher_list_head: the head of the cipher list
 *
 * This function determines what kernel is currently being used
 * and then adds available modules to the cipher list for
 * user selection.
 *
 * Returns 0 on a successful read of the /lib/modules/`uname -r`/kernel/crypto
 * directory, 1 otherwise.
 */
int ecryptfs_add_crypto_modules(struct ecryptfs_cipher_elem *cipher_list_head)
{
      DIR *dp;
      int rc = 0;
      char *mod_ext;
      struct dirent *ep;
      struct utsname kern_info;
      char kern_vers[MAX_NAME_SIZE];
      char dir_name[MAX_NAME_SIZE];
      char mod_name[MAX_NAME_SIZE];
      struct ecryptfs_cipher_elem *current_cipher;

      if (uname(&kern_info) == -1)
            return 1;

      strncpy(kern_vers, kern_info.release, MAX_NAME_SIZE);
      strncpy(dir_name, "/lib/modules/", MAX_NAME_SIZE);
      strncat(dir_name, kern_vers, MAX_NAME_SIZE - strlen(dir_name));
      strncat(dir_name, "/kernel/crypto", MAX_NAME_SIZE - strlen(dir_name));

      if (!(dp = opendir(dir_name)))
            return 1;

      while((ep = readdir(dp))) {
            strncpy(mod_name, ep->d_name, MAX_NAME_SIZE);
            if (!(mod_ext = strstr(mod_name, ".ko")))
                  continue;
            *mod_ext = '\0';
            if (!strcmp(mod_name, "des\0"))
                  strncpy(mod_name, "des3_ede\0", 9);
            current_cipher = cipher_list_head;
            while (current_cipher->next) {
                  if (strcmp(current_cipher->next->kernel_name, mod_name))
                        current_cipher = current_cipher->next;
                  else
                        break;
            }
            if (current_cipher->next)
                  continue;
            rc = add_cipher(mod_name, &current_cipher, 0);
            if (rc)
                  goto out;
      }
out:
      closedir(dp);
      return rc;
}

/*
 * default_cipher - parses the default cipher from the cipher struct
 * @default_cipher: Pointer to cipher selected to be default
 * @keysize: indicates the keysize in bytes of the default cipher
 *
 * This function determines which cipher is the first crosslisted cipher
 * between the available and supported cipher lists. It then returns
 * that name and the keysize of that cipher to function caller.
 * Returns zero on success.
 **/
int ecryptfs_default_cipher(struct ecryptfs_cipher_elem **default_cipher,
                      struct ecryptfs_cipher_elem *cipher_list_head)
{
      struct ecryptfs_cipher_elem *current_cipher;
      int i, limit;
      int rc = 0;
      limit = (sizeof(cipher_str_name_map)
            / sizeof(struct cipher_str_name_map_elem));
      for (i = 0; i < limit; i++) {
            current_cipher = cipher_list_head->next;
            while (current_cipher) {
                  if (!strcmp(cipher_str_name_map[i].kernel_name,
                                    current_cipher->kernel_name)) {
                        *default_cipher = current_cipher;
                        goto out;
                  }
                  current_cipher = current_cipher->next;
            }
      }
      rc = -ENOSYS;
out:
      return rc;
}



int ecryptfs_free_cipher_list(struct ecryptfs_cipher_elem cipher_list_head)
{
      struct ecryptfs_cipher_elem *next;
      struct ecryptfs_cipher_elem *current = cipher_list_head.next;

      while (current) {
            next = current->next;
            free(current->kernel_name);
            free(current->user_name);
            free(current);
            current = next;
      }
      return 0;
}

Generated by  Doxygen 1.6.0   Back to index