view cinst/mozilla.c @ 181:bea93c8651b7

Merged
author Sascha Wilde <wilde@intevation.de>
date Tue, 25 Mar 2014 17:56:56 +0100
parents 344b8a79ad2e 8fafd0fc2173
children d4e97c9b199f
line wrap: on
line source
/**
 * @file
 * @brief Mozilla installation process
 *
 * Reads from stdin a list of instructions in the form:
 *
 * I:<base64 DER econded certificate>\r\n
 * R:<base64 DER econded certificate>\r\n
 * ...
 *
 * The maximum size of an input line is 9999 characters
 * (including the \r\n) at the end of the line.
 *
 * Certificates marked with I: will be installed and the ones
 * marked with R: will be searched and if available removed from
 * the databases.
 *
 * This tool tries to find all NSS databases the user has
 * access to and to execute the instructions on all of them.
 *
 * If there are other processes accessing the databases the caller
 * has to ensure that those are terminated before this process is
 * executed.
 *
 * Returns 0 on success (Even when no stores where found) an error value
 * as defined in errorcodes.h otherwise.
 *
 * Success messages are written to stdout. Errors to stderr. For logging
 * purposes each installation / removal of a certificate will be reported
 * with the profile name that it modified.
 *
 */

/* @brief IniParser for mozilla profiles.ini
 *
 * Parse data to find values formed in
 *
 * [Profile99]
 * IsRelative=1
 * Path=Profiles/fooo.bar
 *
 * or
 * [Profile0]
 * IsRelative=0
 * Path=c:\foo\bar\baz
 *
 * Mozilla also accepts the ini file on Windows even if it is UTF-16
 * encoded.
 * */

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

#include <debug.h>
#include <errorcodes.h>
#include <portpath.h>
#include <strhelp.h>

#ifndef _WIN32
#define LINUX 1
#else
#define LINUX 0
#endif

#define LINEBUFLEN 1000

/**
 * @brief Global Return Code
 *
 * This will be retuned by the programm and might be set to an
 * error code on fatal errors and to and warning code on non-fatal
 * errors.  In case of mor than one warning the warning codes will be
 * ORed together.
 */
int return_code = 0;

/**
 * @brief Return users home path, on windows including drive letter
 * @returns a pointer to a string containing the home path, it should
 * be freed by the caller.
 */
static char *
get_home()
{
  char *home, *homevar, *fqhome;
  char *homedrive = NULL;

  size_t len;
  if (LINUX)
    homevar = "HOME";
  else
    homevar = "HOMEPATH";

  if ((home = getenv(homevar)) == NULL)
    {
      DEBUGFPRINT("DEBUG: FATAL!  No HOME in environment.\n");
      exit(ERR_MOZ_HOMELESS);
    }

  len = strlen(home);
  if (!LINUX)
    homedrive = getenv("HOMEDRIVE");

  if (homedrive != NULL)
    len += strlen(homedrive);

  len++;                        /* Room for \0 */
  fqhome = xmalloc(len);

  if (homedrive == NULL)
    snprintf(fqhome, len, "%s", home);
  else
    snprintf(fqhome, len, "%s%s", homedrive, home);

  return fqhome;
}

/**
 * @brief Get a list of all mozilla profile directories
 *
 * Read the profiles.ini and extract all profile paths from that.
 *
 * @param[in] inifile_name path of the profile.ini to read.
 * @return NULL terminated array of strings containing containing the
 * absolute path of the profile directories. The array needs to
 * be freed by the caller.
 */
static char **
get_profile_dirs (char *inifile_name)
{
  char **dirs = NULL;
  char *inifile_dirname;
  FILE *inifile;
  char line[LINEBUFLEN];
  char *key;
  char *value;
  char path[LINEBUFLEN];
  char *fqpath;
  bool inprofile = false;
  bool relative_path = false;

  if ((inifile = fopen(inifile_name, "r")) != NULL)
    {
      DEBUGFPRINT("DEBUG: Searching for profile paths in: '%s'\n", inifile_name);

      inifile_dirname = port_dirname(inifile_name);
      while (fgets(line, LINEBUFLEN, inifile) != NULL)
        {
          /* Determine if we are in an profile section */
          if (str_starts_with(line, "[Profile"))
            {
              relative_path = false;
              inprofile = true;
            }
          else if (line[0] == '[')
            inprofile = false;

          /* If we are in a profile parse path related stuff */
          if (inprofile)
            {
              key = strtok(line, "=");
              value = strtok(NULL, "=");
              str_trim(&value);
              if (str_equal(key, "Path"))
                {
                  if (relative_path)
                    snprintf(path, LINEBUFLEN, "%s/%s", inifile_dirname, value);
                  else
                    strncpy(path, value, LINEBUFLEN);
                  if ((fqpath = port_realpath(path)) != NULL)
                    {
                      DEBUGFPRINT("DEBUG: Found profile path: '%s'\n", fqpath);
                      strv_append(&dirs, fqpath, strlen(fqpath));
                      free (fqpath);
                    }
                  else
                    {
                      DEBUGFPRINT("DEBUG: WARN!  Non existent profile path: '%s'\n", path);
                      return_code |= WARN_MOZ_PROFILE_DOES_NOT_EXIST;
                    }
                }
              else if (str_equal(key, "IsRelative") &&
                       str_starts_with(value, "1"))
                relative_path = true;
            }
        }
      fclose(inifile);
    }
  else
    {
      DEBUGFPRINT("DEBUG: WARN!  Could not open ini file: '%s'\n", inifile_name);
      return_code |= WARN_MOZ_FAILED_TO_OPEN_INI;
    }
  return dirs;
}

/**
 * @brief Search for mozilla profiles.ini files
 *
 * Use well known paths and heuristics to find the current users
 * profiles.ini files on GNU/Linux and Windows systems.
 *
 * @return NULL terminated array of strings containing the absolute
 * path of the profiles.ini files.  The array needs to be freed by the
 * caller.
 */
static char **
get_profile_inis ()
{
  char **inis = NULL;
  char path[LINEBUFLEN];
  char *fqpath;
  char *mozdirname;
  DIR *mozdir;
  struct dirent *mozdirent;
  char *home = get_home();

  if (LINUX)
    {
      mozdirname = ".mozilla";
    }
  else
    {
      mozdirname = "AppData/Roaming/Mozilla";
    }

  snprintf(path, LINEBUFLEN, "%s/%s", home, mozdirname);
  if ((mozdir = opendir(path)) != NULL)
    {
      while ((mozdirent = readdir(mozdir)) != NULL)
        {
          snprintf(path, LINEBUFLEN, "%s/%s/%s",
                   home,
                   mozdirname,
                   mozdirent->d_name);
          if (port_isdir(path))
            {
              snprintf(path, LINEBUFLEN, "%s/%s/%s/%s",
                       home,
                       mozdirname,
                       mozdirent->d_name,
                       "profiles.ini");
              DEBUGFPRINT("DEBUG: checking for %s...\n", path);
              if ((fqpath = port_realpath(path)) != NULL)
                {
                  strv_append(&inis, fqpath, strlen(fqpath));
                  DEBUGFPRINT("DEBUG: Found mozilla ini file: '%s'\n", fqpath);
                  free(fqpath);
                }
            }
        }
      closedir(mozdir);
    }
  else
    {
      DEBUGFPRINT("DEBUG: Could not open %s/%s\n", home, mozdirname);
      exit(WARN_MOZ_NO_PROFILES);
    }
  return inis;
}


int
main ()
{
  int x = 0;
  int y = 0;
  char **mozinis, **pdirs;
  if ((mozinis = get_profile_inis()) != NULL)
    while (mozinis[y] != NULL)
      {
        pdirs =
          get_profile_dirs(mozinis[y++]);
        if (pdirs != NULL)
          {
            while (pdirs[x] != NULL)
              puts(pdirs[x++]);
            strv_free(pdirs);
          }
      }
  exit(return_code);
}

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