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

main.c

/**
 * Copyright (C) 2006 International Business Machines Corp.
 *   Author(s): Michael A. Halcrow <mahalcro@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 <errno.h>
#include <gcrypt.h>
#include <mntent.h>
#ifndef S_SPLINT_S
#include <stdio.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/mount.h>
#include <gcrypt.h>
#include <getopt.h>
#include <keyutils.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include "../include/ecryptfs.h"

int ecryptfs_verbosity = 0;

void ecryptfs_get_versions(int *major, int *minor, int *file_version)
{
      *major = ECRYPTFS_VERSION_MAJOR;
      *minor = ECRYPTFS_VERSION_MINOR;
      *file_version = ECRYPTFS_SUPPORTED_FILE_VERSION;
}

inline void to_hex(char *dst, char *src, int src_size)
{
      int x;

      for (x = 0; x < src_size; x++)
            sprintf(&dst[x*2], "%.2x", (unsigned char)src[x] );
      dst[src_size*2] = '\0';
}

void from_hex(char *dst, char *src, int dst_size)
{
        int x;
        char tmp[3] = { 0, };

        for (x = 0; x < dst_size; x++) {
                tmp[0] = src[x * 2];
                tmp[1] = src[x * 2 + 1];
                dst[x] = (char)strtol(tmp, NULL, 16);
        }
}

int do_hash(char *src, int src_size, char *dst, int algo)
{
      gcry_md_hd_t hd;
      gcry_error_t err = 0;
      unsigned char * hash;
      unsigned int mdlen;

      err = gcry_md_open(&hd, algo, 0);
      mdlen = gcry_md_get_algo_dlen(algo);
      if (err) {
            syslog(LOG_ERR, "Failed to open hash algo [%d]: "
                   "[%d]\n", algo, err);
            goto out;
      }
      gcry_md_write(hd, src, src_size);
      hash = gcry_md_read(hd, algo);
      memcpy(dst, hash, mdlen);
      gcry_md_close(hd);
 out:
      return (int) err;
}

/**
 * TODO: We need to support more hash algs
 *
 * @passphrase A NULL-terminated char array
 *
 * @salt A salt
 *
 * @passphrase_sig An allocated char array into which the generated
 * signature is written; PASSWORD_SIG_SIZE bytes should be allocated
 *
 */
int
generate_passphrase_sig(char *passphrase_sig, char *passphrase, char *salt,
                  char *session_key_encryption_key)
{
      char salt_and_passphrase[ECRYPTFS_MAX_PASSPHRASE_BYTES
                                + ECRYPTFS_SALT_SIZE];
      int passphrase_size;
      int alg = GCRY_MD_SHA512;
      int dig_len = SHA512_DIGEST_LENGTH;
      char buf[SHA512_DIGEST_LENGTH];
      int hash_iterations = ECRYPTFS_DEFAULT_NUM_HASH_ITERATIONS;
      int rc = 0;

      passphrase_size = strlen(passphrase);
      if (passphrase_size > ECRYPTFS_MAX_PASSPHRASE_BYTES) {
            passphrase_sig = NULL;
            syslog(LOG_ERR, "Passphrase too large (%d bytes)\n",
                   passphrase_size);
            return -EINVAL;
      }
      memcpy(salt_and_passphrase, salt, ECRYPTFS_SALT_SIZE);
      memcpy((salt_and_passphrase + ECRYPTFS_SALT_SIZE), passphrase,
            passphrase_size);
      if ((rc = do_hash(salt_and_passphrase,
                    (ECRYPTFS_SALT_SIZE + passphrase_size), buf, alg))) {
            return rc;
      }
      hash_iterations--;
      while (hash_iterations--) {
            if ((rc = do_hash(buf, dig_len, buf, alg))) {
                  return rc;
            }
      }
      memcpy(session_key_encryption_key, buf, ECRYPTFS_MAX_KEY_BYTES);
      if ((rc = do_hash(buf, dig_len, buf, alg))) {
            return rc;
      }
      to_hex(passphrase_sig, buf, ECRYPTFS_SIG_SIZE);
      return 0;
}

/**
 * @return Zero on success
 */
int
generate_payload(struct ecryptfs_auth_tok *auth_tok, char *passphrase_sig,
             char *salt, char *session_key_encryption_key)
{
      int rc = 0;
      unsigned char major, minor;

      memset(auth_tok, 0, sizeof(struct ecryptfs_auth_tok));
      rc = generate_version_from_string(&major, &minor, VERSION);
      auth_tok->version = (((uint16_t)(major << 8) & 0xFF00)
                       | ((uint16_t)minor & 0x00FF));
      auth_tok->token_type = ECRYPTFS_PASSWORD;
      strncpy(auth_tok->token.password.signature, passphrase_sig,
            ECRYPTFS_PASSWORD_SIG_SIZE);
      memcpy(auth_tok->token.password.salt, salt, ECRYPTFS_SALT_SIZE);
      memcpy(auth_tok->token.password.session_key_encryption_key,
             session_key_encryption_key, ECRYPTFS_MAX_KEY_BYTES);
      /* TODO: Make the hash parameterizable via policy */
      auth_tok->token.password.session_key_encryption_key_bytes =
            ECRYPTFS_MAX_KEY_BYTES;
      auth_tok->token.password.flags |=
            ECRYPTFS_SESSION_KEY_ENCRYPTION_KEY_SET;
      /* The kernel code will encrypt the session key. */
      auth_tok->session_key.encrypted_key[0] = 0;
      auth_tok->session_key.encrypted_key_size = 0;
      /* Default; subject to change by kernel eCryptfs */
      auth_tok->token.password.hash_algo = PGP_DIGEST_ALGO_SHA512;
      auth_tok->token.password.flags &= ~(ECRYPTFS_PERSISTENT_PASSWORD);
      return rc;
}

/**
 * @return Zero on success
 */
int
generate_private_payload(struct ecryptfs_auth_tok *auth_tok,
                   struct ecryptfs_pki_elem *selected_pki,
                   char *passphrase_sig, int pki_data_len)
{
      size_t key_size;
      unsigned char major, minor;
      int rc = 0;

      memset(auth_tok, 0, sizeof(struct ecryptfs_auth_tok) + pki_data_len);
      rc = generate_version_from_string(&major, &minor, VERSION);
      auth_tok->version = (((uint16_t)(major << 8) & 0xFF00)
                       | ((uint16_t)minor & 0x00FF));
      auth_tok->token_type = ECRYPTFS_PRIVATE_KEY;
      rc = (selected_pki->ops.initialize_key_module_state)
            (auth_tok->token.private_key.data, &selected_pki->nvp_head);
      if (rc)
            goto out;
      rc = (selected_pki->ops.get_key_metadata)
            (passphrase_sig, &key_size, auth_tok->token.private_key.data);
      if (rc)
            goto out;
      /* The pki_type should be set based on the selected pki.
       * Currently the only offered pki is openssl */
      /* TODO: ECRYPTFS_DEFAULT_PKI (see ecryptfs.h TODO) */
      strncpy(auth_tok->token.private_key.pki_type, ECRYPTFS_PKI_OPENSSL,
            ECRYPTFS_MAX_PKI_NAME_BYTES);
      auth_tok->token.private_key.key_size = key_size;
      auth_tok->token.private_key.data_len = pki_data_len;
      strncpy(auth_tok->token.private_key.signature, passphrase_sig,
            ECRYPTFS_PASSWORD_SIG_SIZE);
out:
      return rc;
}

int ecryptfs_mount(char *source, char *target, unsigned long flags, char *opts)
{
      FILE *mtab_fd = NULL;
      struct mntent mountent;
      char cwd[MAX_PATH_SIZE];
      char *cwdptr;
      char *fullpath_source = NULL;
      char *fullpath_target = NULL;
      int i;
      int rc;

      syslog(LOG_INFO, "eCryptfs mount opts: [%s]\n", opts);
      mountent.mnt_opts = NULL;
      if (!source) {
            rc = -EINVAL;
            syslog(LOG_ERR, "Invalid source directory\n");
            goto out;
      }
      if (!target) {
            rc = -EINVAL;
            syslog(LOG_ERR, "Invalid target directory\n");
            goto out;
      }
      if (strlen(opts) > 200) {
            rc = -EINVAL;
            syslog(LOG_ERR, "Invalid mount options length\n");
            goto out;
      }
      if (mount(source, target, "ecryptfs", flags, opts)) {
            rc = -errno;
            syslog(LOG_ERR, "Failed to perform eCryptfs mount: "
                   "[%s]\n", strerror(errno));
            goto out;
      }
      mtab_fd = setmntent("/etc/mtab", "a");
      if (!mtab_fd) {
            rc = -EACCES;
            syslog(LOG_ERR, "Failed to update the mount table\n");
            goto out;
      }
      cwdptr = getcwd(cwd, MAX_PATH_SIZE);
      if (!cwdptr) {
            rc = -errno;
            syslog(LOG_ERR, "Failed to get the current working directory; "
                   "errno = [%d]\n", errno);
            goto out;
      }
      if (source[0] != '/') {
            rc = asprintf(&fullpath_source, "%s%s", cwd, source);
      } else
            rc = asprintf(&fullpath_source, "%s", source);
      if (rc == -1) {
            rc = -ENOMEM;
            fullpath_source = NULL;
            syslog(LOG_ERR, "Out of memory\n");
            goto out;
      }
      if (target[0] != '/') {
            rc = asprintf(&fullpath_target, "%s%s", cwd, target);
      } else
            rc = asprintf(&fullpath_target, "%s", target);
      if (rc == -1) {
            rc = -ENOMEM;
            fullpath_target = NULL;
            syslog(LOG_ERR, "Out of memory\n");
            goto out;
      }
      rc = 0;
      i = strlen(fullpath_source);
      if (i > 1 && fullpath_source[i - 1] == '/')
            fullpath_source[i - 1] = '\0';
      i = strlen(fullpath_target);
      if (i > 1 && fullpath_target[i - 1] == '/')
            fullpath_target[i - 1] = '\0';
      mountent.mnt_fsname = fullpath_source;
      mountent.mnt_dir = fullpath_target;
      mountent.mnt_type = "ecryptfs";
      /* we need the following byte count:
       * 200 max for opts
       * 23  max for strings below
       * 1   the final \0
       */
      mountent.mnt_opts = malloc(224);
      if (!mountent.mnt_opts) {
            rc = -ENOMEM;
            syslog(LOG_ERR, "Failed to allocate memory for mount "
                   "options\n");
            goto out;
      }
      memset(mountent.mnt_opts, 0, 224);
      /* reporting the right mount opts */
      if (flags & MS_RDONLY)
            strcat(mountent.mnt_opts,"ro");
      else
            strcat(mountent.mnt_opts,"rw");
      if (flags & MS_NOEXEC)
            strcat(mountent.mnt_opts,",noexec");
      if (flags & MS_NOSUID)
            strcat(mountent.mnt_opts,",nosuid");
      if (flags & MS_NODEV)
            strcat(mountent.mnt_opts,",nodev");
      if (opts) {
            strcat(mountent.mnt_opts, ",");
            strcat(mountent.mnt_opts, opts);
      }
      mountent.mnt_freq = 0;
      mountent.mnt_passno = 0;
      if (addmntent(mtab_fd, &mountent)) {
            rc = -EIO;
            syslog(LOG_ERR, "Failed to write to the mount "
                   "table\n");
            goto out;
      }
      rc = 0;
out:
      free(fullpath_source);
      free(fullpath_target);
      free(mountent.mnt_opts);
      if (mtab_fd)
            endmntent(mtab_fd);
      return rc;
}

int generate_version_from_string(unsigned char *major, unsigned char *minor,
                                 char *version)
{
        int rc = 0;
        unsigned int tmp_major, tmp_minor;

        rc = sscanf(version, "%d.%d", &tmp_major, &tmp_minor);
        if (tmp_major > 255 || tmp_minor > 255) {
                rc = 1;
                (*major) = 0;
                (*minor) = 0;
                goto out;
        }
        rc = 0;
        (*major) = (unsigned char)tmp_major;
        (*minor) = (unsigned char)tmp_minor;
out:
        return rc;
}

static int zombie_semaphore_get(void)
{
      int sem_id;
      struct semid_ds semid_ds;
      struct sembuf sb;
      int i;
      int rc;

      sem_id = semget(ECRYPTFS_SEM_KEY, 1, (0666 | IPC_EXCL | IPC_CREAT));
      if (sem_id >= 0) {
            sb.sem_op = 1;
            sb.sem_flg = 0;
            sb.sem_num = 0;

            rc = semop(sem_id, &sb, 1);
            if (rc == -1) {
                  semctl(sem_id, 0, IPC_RMID);
                  syslog(LOG_ERR, "Error initializing semaphore\n");
                  rc = -1;
                  goto out;
            }
      } else if (errno == EEXIST) {
            int initialized = 0;

            sem_id = semget(ECRYPTFS_SEM_KEY, 1, 0);
            if (sem_id < 0) {
                  syslog(LOG_ERR, "Error getting existing semaphore");
                  rc = -1;
                  goto out;
            }
#define RETRY_LIMIT 3
            for (i = 0; i < RETRY_LIMIT; i++) {
                  semctl(sem_id, 0, IPC_STAT, &semid_ds);
                  if (semid_ds.sem_otime != 0) {
                        initialized = 1;
                        break;
                  } else
                        sleep(1);
            }
            if (!initialized) {
                  syslog(LOG_ERR, "Waited too long for initialized "
                         "semaphore; something's wrong\n");
                  rc = -1;
                  goto out;
            }
      } else {
            syslog(LOG_ERR, "Error attempting to get semaphore\n");
            rc = -1;
            goto out;
      }
      rc = sem_id;
out:
      return rc;
}

static void zombie_semaphore_lock(int sem_id)
{
      struct sembuf sb;
      int i;
      int rc;

      sb.sem_num = 0;
      sb.sem_op = -1;
      sb.sem_flg = IPC_NOWAIT;
      for (i = 0; i < RETRY_LIMIT; i++) {
            rc = semop(sem_id, &sb, 1);
            if (rc == -1 && errno == EAGAIN) {
                  sleep(1);
            } else if (rc == -1) {
                  syslog(LOG_ERR, "Error locking semaphore; errno "
                         "string = [%m]\n", errno);
                  goto out;
            } else
                  goto out;
      }
      syslog(LOG_ERR, "Error locking semaphore; hit max retries\n");
out:
      return;
}

static void zombie_semaphore_unlock(int sem_id)
{
      struct sembuf sb;
      int rc;

      sb.sem_num = 0;
      sb.sem_op = 1;
      sb.sem_flg = 0;
      rc = semop(sem_id, &sb, 1);
      if (rc == -1) {
            syslog(LOG_ERR, "Error unlocking semaphore\n");
            goto out;
      }
out:
      return;
}

static int get_zombie_shared_mem_locked(int *shm_id, int *sem_id)
{
      int rc;
      
      (*sem_id) = zombie_semaphore_get();
      if ((*sem_id) == -1) {
            syslog(LOG_ERR, "Error attempting to get zombie semaphore\n");
            rc = -EIO;
            goto out;
      }
      zombie_semaphore_lock((*sem_id));
      rc = shmget(ECRYPTFS_SHM_KEY, ECRYPTFS_SHM_SIZE, (0666 | IPC_CREAT
                                            | IPC_EXCL));
      if (rc == -1 && errno == EEXIST)
            rc = shmget(ECRYPTFS_SHM_KEY, ECRYPTFS_SHM_SIZE, 0);
      else {
            char *shm_virt;

            (*shm_id) = rc;
            shm_virt = shmat((*shm_id), NULL, 0);
            if (shm_virt == (void *)-1) {
                  syslog(LOG_ERR, "Error attaching to newly allocated "
                         "shared memory; errno string = [%m]\n", errno);
                  rc = -EIO;
                  zombie_semaphore_unlock((*sem_id));
                  goto out;
            }
            memset(shm_virt, 0, ECRYPTFS_SHM_SIZE);
            if ((rc = shmdt(shm_virt))) {
                  rc = -EIO;
                  zombie_semaphore_unlock((*sem_id));
                  goto out;
            }
            rc = shmget(ECRYPTFS_SHM_KEY, ECRYPTFS_SHM_SIZE, 0);
      }
      if (rc == -1) {
            syslog(LOG_ERR, "Error attempting to get identifier for "
                   "shared memory with key [0x.8x]\n", ECRYPTFS_SHM_KEY);
            rc = -EIO;
            zombie_semaphore_unlock((*sem_id));
            goto out;
      }
      (*shm_id) = rc;
      rc = 0;
out:
      return rc;
}

static int list_pid_sid_pairs(int shm_id)
{
      pid_t sid_tmp;
      pid_t pid_tmp;
      char *shm_virt;
      int i;
      int rc;

      if (sizeof(pid_t) != sizeof(uint32_t)) {
            syslog(LOG_ERR, "sizeof(pid_t) != sizeof(uint32_t); the code "
                   "needs some tweaking to work on this architecture\n");
            rc = -EINVAL;
            goto out;
      }
      shm_virt = shmat(shm_id, NULL, 0);
      if (shm_virt == (void *)-1) {
            rc = -EIO;
            goto out;
      }
      i = 0;
      memcpy(&sid_tmp, &shm_virt[i], sizeof(pid_t));
      i += sizeof(pid_t);
      sid_tmp = ntohl(sid_tmp); /* uint32_t */
      memcpy(&pid_tmp, &shm_virt[i], sizeof(pid_t));
      i += sizeof(pid_t);
      pid_tmp = ntohl(pid_tmp); /* uint32_t */
      while (!(sid_tmp == 0 && pid_tmp == 0)) {
            if ((i + (2 * sizeof(pid_t))) > ECRYPTFS_SHM_SIZE)
                  break;
            memcpy(&sid_tmp, &shm_virt[i], sizeof(pid_t));
            i += sizeof(pid_t);
            sid_tmp = ntohl(sid_tmp); /* uint32_t */
            memcpy(&pid_tmp, &shm_virt[i], sizeof(pid_t));
            i += sizeof(pid_t);
            pid_tmp = ntohl(pid_tmp); /* uint32_t */
      }
      if ((rc = shmdt(shm_virt)))
            rc = -EIO;
out:
      return rc;
}

static int find_pid_for_this_sid(pid_t *pid, int shm_id)
{
      pid_t sid_tmp;
      pid_t sid;
      pid_t pid_tmp;
      pid_t this_pid;
      char *shm_virt;
      int i;
      int rc;

      (*pid) = 0;
      if (sizeof(pid_t) != sizeof(uint32_t)) {
            syslog(LOG_ERR, "sizeof(pid_t) != sizeof(uint32_t); the code "
                   "needs some tweaking to work on this architecture\n");
            rc = -EINVAL;
            goto out;
      }
      shm_virt = shmat(shm_id, NULL, 0);
      if (shm_virt == (void *)-1) {
            rc = -EIO;
            goto out;
      }
      i = 0;
      memcpy(&sid_tmp, &shm_virt[i], sizeof(pid_t));
      i += sizeof(pid_t);
      sid_tmp = ntohl(sid_tmp); /* uint32_t */
      memcpy(&pid_tmp, &shm_virt[i], sizeof(pid_t));
      i += sizeof(pid_t);
      pid_tmp = ntohl(pid_tmp); /* uint32_t */
      this_pid = getpid();
      sid = getsid(this_pid);
      while (!(sid_tmp == 0 && pid_tmp == 0)) {
            if (sid_tmp == sid) {
                  (*pid) = pid_tmp;
                  goto end_search;
            }
            if ((i + (2 * sizeof(pid_t))) > ECRYPTFS_SHM_SIZE)
                  break;
            memcpy(&sid_tmp, &shm_virt[i], sizeof(pid_t));
            i += sizeof(pid_t);
            sid_tmp = ntohl(sid_tmp); /* uint32_t */
            memcpy(&pid_tmp, &shm_virt[i], sizeof(pid_t));
            i += sizeof(pid_t);
            pid_tmp = ntohl(pid_tmp); /* uint32_t */
      }
end_search:
      if ((rc = shmdt(shm_virt))) {
            rc = -EIO;
            (*pid) = 0;
      }
out:
      return rc;
}

static int remove_pid_for_this_sid(int shm_id)
{
      pid_t sid_tmp;
      pid_t sid;
      pid_t pid_tmp;
      pid_t pid;
      pid_t this_pid;
      char *shm_virt;
      int i;
      int rc;

      pid = 0;
      if (sizeof(pid_t) != sizeof(uint32_t)) {
            syslog(LOG_ERR, "sizeof(pid_t) != sizeof(uint32_t); the code "
                   "needs some tweaking to work on this architecture\n");
            rc = -EINVAL;
            goto out;
      }
      shm_virt = shmat(shm_id, NULL, 0);
      if (shm_virt == (void *)-1) {
            rc = -EIO;
            goto out;
      }
      i = 0;
      memcpy(&sid_tmp, &shm_virt[i], sizeof(pid_t));
      i += sizeof(pid_t);
      sid_tmp = ntohl(sid_tmp); /* uint32_t */
      memcpy(&pid_tmp, &shm_virt[i], sizeof(pid_t));
      i += sizeof(pid_t);
      pid_tmp = ntohl(pid_tmp); /* uint32_t */
      this_pid = getpid();
      sid = getsid(this_pid);
      while (!(sid_tmp == 0 && pid_tmp == 0)) {
            if (sid_tmp == sid) {
                  pid = pid_tmp;
                  break;
            }
            if ((i + (2 * sizeof(pid_t))) > ECRYPTFS_SHM_SIZE)
                  break;
            memcpy(&sid_tmp, &shm_virt[i], sizeof(pid_t));
            i += sizeof(pid_t);
            sid_tmp = ntohl(sid_tmp); /* uint32_t */
            memcpy(&pid_tmp, &shm_virt[i], sizeof(pid_t));
            i += sizeof(pid_t);
            pid_tmp = ntohl(pid_tmp); /* uint32_t */
      }
      if (pid != 0) {
            char *tmp;
            int remainder = (ECRYPTFS_SHM_SIZE - i);

            if (remainder != 0) {
                  if ((tmp = malloc(remainder)) == NULL) {
                        rc = -ENOMEM;
                        shmdt(shm_virt);
                        goto out;
                  }
                  memcpy(tmp, &shm_virt[i], remainder);
                  i -= (2 * sizeof(pid_t));
                  memcpy(&shm_virt[i], tmp, remainder);
                  i += remainder;
            } else
                  i -= (2 * sizeof(pid_t));
            memset(&shm_virt[i], 0, (2 * sizeof(pid_t)));
            if (remainder != 0)
                  free(tmp);
      }
      if ((rc = shmdt(shm_virt)))
            rc = -EIO;
out:
      return rc;
}

static int add_sid_pid_pair_to_shm(int shm_id)
{
      pid_t sid_tmp;
      pid_t sid;
      pid_t pid_tmp;
      pid_t pid;
      char *shm_virt;
      int i;
      int rc;

      if (sizeof(pid_t) != sizeof(uint32_t)) {
            syslog(LOG_ERR, "sizeof(pid_t) != sizeof(uint32_t); the code "
                   "needs some tweaking to work on this architecture\n");
            rc = -EINVAL;
            goto out;
      }
      shm_virt = shmat(shm_id, NULL, 0);
      if (shm_virt == (void *)-1) {
            syslog(LOG_ERR, "Error attaching to shared memory; error "
                   "string = [%m]\n", errno);
            shm_virt = shmat(shm_id, NULL, 0);
            if (shm_virt == (void *)-1) {
                  syslog(LOG_ERR, "Error attaching to shared memory; error "
                         "string = [%m]\n", errno);
                  rc = -EIO;
                  goto out;
            }
            rc = -EIO;
            goto out;
      }
      i = 0;
      memcpy(&sid_tmp, &shm_virt[i], sizeof(pid_t));
      i += sizeof(pid_t);
      sid_tmp = ntohl(sid_tmp); /* uint32_t */
      memcpy(&pid_tmp, &shm_virt[i], sizeof(pid_t));
      i += sizeof(pid_t);
      pid_tmp = ntohl(pid_tmp); /* uint32_t */
      while (!(sid_tmp == 0 && pid_tmp == 0)) {
            if ((i + (2 * sizeof(pid_t))) > ECRYPTFS_SHM_SIZE) {
                  syslog(LOG_ERR,
                         "No space left in shared memory region\n");
                  rc = -ENOMEM;
                  shmdt(shm_virt);
                  goto out;
            }
            memcpy(&sid_tmp, &shm_virt[i], sizeof(pid_t));
            i += sizeof(pid_t);
            sid_tmp = ntohl(sid_tmp); /* uint32_t */
            memcpy(&pid_tmp, &shm_virt[i], sizeof(pid_t));
            i += sizeof(pid_t);
            pid_tmp = ntohl(pid_tmp); /* uint32_t */
      }
      pid = getpid();
      sid = getsid(pid);
      sid = htonl(sid);
      pid = htonl(pid);
      i -= (2 * sizeof(pid_t));
      memcpy(&shm_virt[i], &sid, sizeof(pid_t));
      i += sizeof(pid_t);
      memcpy(&shm_virt[i], &pid, sizeof(pid_t));
      i += sizeof(pid_t);
      if ((i + (2 * sizeof(pid_t))) <= ECRYPTFS_SHM_SIZE)
            memset(&shm_virt[i], 0, (i + (2 * sizeof(pid_t))));
      if ((rc = shmdt(shm_virt))) {
            syslog(LOG_ERR, "Error detaching from shared memory\n");
            rc = -EIO;
      }
out:
      return rc;
}

int ecryptfs_set_zombie_session_placeholder(void)
{
      int shm_id;
      int sem_id;
      int rc = 0;

      if ((rc = get_zombie_shared_mem_locked(&shm_id, &sem_id))) {
            syslog(LOG_ERR,
                   "Error getting shared memory segment\n");
            goto out;
      }
      if ((rc = add_sid_pid_pair_to_shm(shm_id))) {
            syslog(LOG_ERR, "Error adding sid/pid pair to shared memory "
                   "segment; rc = [%d]\n", rc);
            zombie_semaphore_unlock(sem_id);
            goto out;
      }
      zombie_semaphore_unlock(sem_id);
      sleep(ECRYPTFS_ZOMBIE_SLEEP_SECONDS);
      if ((rc = get_zombie_shared_mem_locked(&shm_id, &sem_id))) {
            syslog(LOG_ERR,
                   "Error getting shared memory segment\n");
            goto out;
      }
      if ((rc = remove_pid_for_this_sid(shm_id))) {
            syslog(LOG_ERR, "Error attempting to remove pid/sid "
                   "pair from shared memory segment; rc = [%d]\n",
                   rc);
            zombie_semaphore_unlock(sem_id);
            goto out;
      }
      zombie_semaphore_unlock(sem_id);
      exit(1);
out:
      return rc;
}

int ecryptfs_kill_and_clear_zombie_session_placeholder(void)
{
      int shm_id;
      int sem_id;
      int pid;
      int rc = 0;

      if ((rc = get_zombie_shared_mem_locked(&shm_id, &sem_id))) {
            syslog(LOG_ERR, "Error getting shared memory segment\n");
            goto out;
      }
      if ((rc = find_pid_for_this_sid(&pid, shm_id))) {
            syslog(LOG_ERR, "Error finding pid for sid in shared memory "
                   "segment; rc = [%d]\n", rc);
            zombie_semaphore_unlock(sem_id);
            goto out;
      }
      if (pid == 0) {
            syslog(LOG_WARNING, "No valid pid found for this sid\n");
      } else {
            if ((rc = kill(pid, SIGKILL))) {
                  syslog(LOG_ERR, "Error attempting to kill process "
                         "[%d]; rc = [%d]; errno string = [%m]\n", pid,
                         rc, errno);
            }
            if ((rc = remove_pid_for_this_sid(shm_id))) {
                  syslog(LOG_ERR, "Error attempting to remove pid/sid "
                         "pair from shared memory segment; rc = [%d]\n",
                         rc);
                  zombie_semaphore_unlock(sem_id);
                  goto out;
            }
      }
      zombie_semaphore_unlock(sem_id);
out:
      return rc;
}

int ecryptfs_list_zombie_session_placeholders(void)
{
      int shm_id;
      int sem_id;
      int rc = 0;

      if ((rc = get_zombie_shared_mem_locked(&shm_id, &sem_id))) {
            syslog(LOG_ERR,
                   "Error getting shared memory segment\n");
            goto out;
      }
      if ((rc = list_pid_sid_pairs(shm_id))) {
            syslog(LOG_ERR, "Error listing sid/pid pairs in shared memory "
                   "segment; rc = [%d]\n", rc);
            zombie_semaphore_unlock(sem_id);
            goto out;
      }
      zombie_semaphore_unlock(sem_id);
out:
      return rc;
}

Generated by  Doxygen 1.6.0   Back to index