view cinst/nssstore_linux.c @ 321:824ef90a6721

Move is_elevated into common/util.c file for better reuse
author Andre Heinecke <aheinecke@intevation.de>
date Mon, 07 Apr 2014 10:58:47 +0000
parents 4a3febc6d806
children 5eb7ee4ee819
line wrap: on
line source
#ifndef WIN32

/* @file
   @brief Linux implementation of nssstore process control.
*/

#include <stdbool.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#include <stdlib.h>

#include "nssstore.h"
#include "logging.h"
#include "strhelp.h"

/**@brief Start the process to install / remove
 *
 * This forks the process and executes the NSS installation
 * process. It also writes the Instructions to that process.
 *
 * @param [in] to_install strv of DER encoded certificates to be added.
 * @param [in] to_remove strv of DER encoded certificates to be remvoed.
 * @param [in] uid_t uid of the user to install certificates for.
 * @param [in] gid_t the gid of the user to install certificates for.
 * @param [in] homedir the homedir of the user.
 *
 * @returns childs pid on success. -1 on failure
 */
static int
start_procces_for_user (char **to_install, char **to_remove,
                        uid_t uid, gid_t gid, char *homedir)
{
  int pipe_fd[2];
  pid_t pid = 0;
  char *argv[] = {"mozilla", NULL},
       *envp[2];
  size_t homedir_len = 0;
  int ret = -1,
      i = 0;
  FILE *stream = NULL;
  bool success = false;

  if (homedir == NULL)
    {
      ERRORPRINTF ("Invalid call to start_process_for_user\n");
      return -1;
    }

  homedir_len = strlen (homedir);

  /* Allocate space for HOME=homedir\0 */
  envp[0] = xmalloc (homedir_len + 6);
  envp[1] = NULL;

  ret = snprintf (envp[0], homedir_len + 6, "HOME=%s", homedir);

  if (ret < 0 || (size_t) ret != homedir_len + 5)
    {
      ERRORPRINTF ("Error setting home env variable.\n");
      xfree (envp[0]);
      return -1;
    }

  DEBUGPRINTF ("Home: %s \n", envp[0]);

  if (pipe (pipe_fd))
    {
      ERRORPRINTF ("Failed to create pipe.\n");
      return -1;
    }

  pid = fork();

  if (pid == (pid_t) -1)
    {
      ERRORPRINTF ("Failed to fork child.\n");
      return -1;
    }

  if (pid == (pid_t) 0)
    {
      /* Drop privileges */
      if (setuid (uid) || setgid (gid))
        {
          exit(-1);
        }

      close (pipe_fd[1]);
      dup2 (pipe_fd[0], 0);
      close (pipe_fd[0]);
      /* TODO find path based on current executable */
      execve ("mozilla", argv, envp);
      exit (127);
    }

  close (pipe_fd[0]);
  stream = fdopen(pipe_fd[1], "w");
  if (stream == NULL)
    {
      ERRORPRINTF ("Failed to open pipe for writing\n");
      goto done;
    }

  /* Send the instructions */
  for (i = 0; to_install && to_install[i]; i++)
    {
      if (fprintf (stream, "I:%s\n", to_install[i]) <= 3)
        {
          ERRORPRINTF ("Write failed \n");
          goto done;
        }
    }

  for (i = 0; to_remove && to_remove[i]; i++)
    {
      if (fprintf (stream, "R:%s\n", to_remove[i]) <= 3)
        {
          ERRORPRINTF ("Write failed \n");
          goto done;
        }
    }

  success = true;

done:
  if (stream) {
    fclose (stream);
  }
  xfree (envp[0]);
  close(pipe_fd[0]);
  close(pipe_fd[1]);

  if (success)
    {
      return pid;
    }
  return -1;
}

int
write_stores_nss (char **to_install, char **to_remove)
{
  uid_t my_uid = getuid();

  if (my_uid != 0)
    {
      /* Running as a user */
      char *homedir = getenv ("HOME");
      pid_t childprocess = -1; /* Only one child for single user installation */
      int status = -1;
      if (!homedir)
        {
          ERRORPRINTF ("Failed to find home directory\n");
        }

      childprocess = start_procces_for_user (to_install, to_remove,
                                             my_uid, getgid(), homedir);

      if (childprocess == -1)
        {
          ERRORPRINTF ("Failed to start childprocess!\n");
          return -1;
        }

      childprocess = waitpid (childprocess, &status, 0);
      if (childprocess == -1 || !WIFEXITED(status))
        {
          ERRORPRINTF ("Waitpid failed.\n");
          return -1;
        }
      DEBUGPRINTF ("Child returned status: %i\n", WEXITSTATUS(status));

      return 0;
    }
  printf ("Installation as root is not yet implemented\n");
  /* TODO root parse /etc/passwd for users with a home directory */
  return 0;
}
#endif

http://wald.intevation.org/projects/trustbridge/