Example #1
0
/* Create a lock file for the container FNAME and store the lock at
 * R_LOCK and return 0.  On error return an error code and store NULL
 * at R_LOCK.  */
gpg_error_t
be_take_lock_for_create (ctrl_t ctrl, const char *fname, dotlock_t *r_lock)
{
  gpg_error_t err;
  dotlock_t lock = NULL;
  struct stat sb;

  *r_lock = NULL;

  /* A DM-crypt container requires special treatment by using the
     syshelper fucntions.  */
  if (ctrl->conttype == CONTTYPE_DM_CRYPT)
    {
      /*  */
      err = call_syshelp_set_device (ctrl, fname);
      goto leave;
    }


  /* A quick check to see that no container with that name already
     exists.  */
  if (!access (fname, F_OK))
    {
      err = gpg_error (GPG_ERR_EEXIST);
      goto leave;
    }

  /* Take a lock and proceed with the creation.  If there is a lock we
     immediately return an error because for creation it does not make
     sense to wait.  */
  lock = dotlock_create (fname, 0);
  if (!lock)
    {
      err = gpg_error_from_syserror ();
      goto leave;
    }
  if (dotlock_take (lock, 0))
    {
      err = gpg_error_from_syserror ();
      goto leave;
    }

  /* Check again that the file does not exist.  */
  err = stat (fname, &sb)? 0 : gpg_error (GPG_ERR_EEXIST);

 leave:
  if (!err)
    {
      *r_lock = lock;
      lock = NULL;
    }
  dotlock_destroy (lock);
  return err;
}
Example #2
0
/*
 * Lock the keyring with the given handle, or unlok if yes is false.
 * We ignore the handle and lock all registered files.
 */
int
keyring_lock (KEYRING_HANDLE hd, int yes)
{
    KR_NAME kr;
    int rc = 0;

    if (yes) {
        /* first make sure the lock handles are created */
        for (kr=kr_names; kr; kr = kr->next) {
            if (!keyring_is_writable(kr))
                continue;
            if (!kr->lockhd) {
                kr->lockhd = dotlock_create (kr->fname, 0);
                if (!kr->lockhd) {
                    log_info ("can't allocate lock for `%s'\n", kr->fname );
                    rc = G10ERR_GENERAL;
                }
            }
        }
        if (rc)
            return rc;

        /* and now set the locks */
        for (kr=kr_names; kr; kr = kr->next) {
            if (!keyring_is_writable(kr))
                continue;
            if (kr->is_locked)
                ;
            else if (dotlock_take (kr->lockhd, -1) ) {
                log_info ("can't lock `%s'\n", kr->fname );
                rc = G10ERR_GENERAL;
            }
            else
                kr->is_locked = 1;
        }
    }

    if (rc || !yes) {
        for (kr=kr_names; kr; kr = kr->next) {
            if (!keyring_is_writable(kr))
                continue;
            if (!kr->is_locked)
                ;
            else if (dotlock_release (kr->lockhd))
                log_info ("can't unlock `%s'\n", kr->fname );
            else
                kr->is_locked = 0;
        }
    }

    return rc;
}
Example #3
0
static int
lock_all (KEYDB_HANDLE hd)
{
  int i, rc = 0;

  /* Fixme: This locking scheme may lead to deadlock if the resources
     are not added in the same order by all processes.  We are
     currently only allowing one resource so it is not a problem. */
  for (i=0; i < hd->used; i++)
    {
      switch (hd->active[i].type)
        {
        case KEYDB_RESOURCE_TYPE_NONE:
          break;
        case KEYDB_RESOURCE_TYPE_KEYBOX:
          if (hd->active[i].lockhandle)
            rc = dotlock_take (hd->active[i].lockhandle, -1);
          break;
        }
      if (rc)
        break;
    }

    if (rc)
      {
        /* revert the already set locks */
        for (i--; i >= 0; i--)
          {
            switch (hd->active[i].type)
              {
              case KEYDB_RESOURCE_TYPE_NONE:
                break;
              case KEYDB_RESOURCE_TYPE_KEYBOX:
                if (hd->active[i].lockhandle)
                  dotlock_release (hd->active[i].lockhandle);
                break;
              }
          }
      }
    else
      hd->locked = 1;

    /* make_dotlock () does not yet guarantee that errno is set, thus
       we can't rely on the error reason and will simply use
       EACCES. */
    return rc? gpg_error (GPG_ERR_EACCES) : 0;
}
Example #4
0
static int
take_write_lock (void)
{
  if (!lockhandle)
    lockhandle = dotlock_create (db_name, 0);
  if (!lockhandle)
    log_fatal ( _("can't create lock for `%s'\n"), db_name );

  if (!is_locked)
    {
      if (dotlock_take (lockhandle, -1) )
        log_fatal ( _("can't lock `%s'\n"), db_name );
      else
        is_locked = 1;
      return 0;
    }
  else
    return 1;
}
Example #5
0
/* Handle the creation of a keyring or a keybox if it does not yet
   exist.  Take into acount that other processes might have the
   keyring/keybox already locked.  This lock check does not work if
   the directory itself is not yet available. */
static int
maybe_create_keyring_or_box (char *filename, int is_box, int force)
{
  dotlock_t lockhd = NULL;
  IOBUF iobuf;
  int rc;
  mode_t oldmask;
  char *last_slash_in_filename;
  int save_slash;

  /* A quick test whether the filename already exists. */
  if (!access (filename, F_OK))
    return 0;

  /* If we don't want to create a new file at all, there is no need to
     go any further - bail out right here.  */
  if (!force)
    return gpg_error (GPG_ERR_ENOENT);

  /* First of all we try to create the home directory.  Note, that we
     don't do any locking here because any sane application of gpg
     would create the home directory by itself and not rely on gpg's
     tricky auto-creation which is anyway only done for some home
     directory name patterns. */
  last_slash_in_filename = strrchr (filename, DIRSEP_C);
#if HAVE_W32_SYSTEM
  {
    /* Windows may either have a slash or a backslash.  Take care of it.  */
    char *p = strrchr (filename, '/');
    if (!last_slash_in_filename || p > last_slash_in_filename)
      last_slash_in_filename = p;
  }
#endif /*HAVE_W32_SYSTEM*/
  if (!last_slash_in_filename)
    return gpg_error (GPG_ERR_ENOENT);  /* No slash at all - should
                                           not happen though.  */
  save_slash = *last_slash_in_filename;
  *last_slash_in_filename = 0;
  if (access(filename, F_OK))
    {
      static int tried;

      if (!tried)
        {
          tried = 1;
          try_make_homedir (filename);
        }
      if (access (filename, F_OK))
        {
          rc = gpg_error_from_syserror ();
          *last_slash_in_filename = save_slash;
          goto leave;
        }
    }
  *last_slash_in_filename = save_slash;

  /* To avoid races with other instances of gpg trying to create or
     update the keyring (it is removed during an update for a short
     time), we do the next stuff in a locked state. */
  lockhd = dotlock_create (filename, 0);
  if (!lockhd)
    {
      rc = gpg_error_from_syserror ();
      /* A reason for this to fail is that the directory is not
         writable. However, this whole locking stuff does not make
         sense if this is the case. An empty non-writable directory
         with no keyring is not really useful at all. */
      if (opt.verbose)
        log_info ("can't allocate lock for '%s': %s\n",
                  filename, gpg_strerror (rc));

      if (!force)
        return gpg_error (GPG_ERR_ENOENT);
      else
        return rc;
    }

  if ( dotlock_take (lockhd, -1) )
    {
      rc = gpg_error_from_syserror ();
      /* This is something bad.  Probably a stale lockfile.  */
      log_info ("can't lock '%s': %s\n", filename, gpg_strerror (rc));
      goto leave;
    }

  /* Now the real test while we are locked. */
  if (!access (filename, F_OK))
    {
      rc = 0;  /* Okay, we may access the file now.  */
      goto leave;
    }

  /* The file does not yet exist, create it now. */
  oldmask = umask (077);
  if (is_secured_filename (filename))
    {
      iobuf = NULL;
      gpg_err_set_errno (EPERM);
    }
  else
    iobuf = iobuf_create (filename);
  umask (oldmask);
  if (!iobuf)
    {
      rc = gpg_error_from_syserror ();
      if (is_box)
        log_error (_("error creating keybox '%s': %s\n"),
                   filename, gpg_strerror (rc));
      else
        log_error (_("error creating keyring '%s': %s\n"),
                   filename, gpg_strerror (rc));
      goto leave;
    }

  iobuf_close (iobuf);
  /* Must invalidate that ugly cache */
  iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, filename);

  /* Make sure that at least one record is in a new keybox file, so
     that the detection magic will work the next time it is used.  */
  if (is_box)
    {
      FILE *fp = fopen (filename, "w");
      if (!fp)
        rc = gpg_error_from_syserror ();
      else
        {
          rc = _keybox_write_header_blob (fp);
          fclose (fp);
        }
      if (rc)
        {
          if (is_box)
            log_error (_("error creating keybox '%s': %s\n"),
                       filename, gpg_strerror (rc));
          else
            log_error (_("error creating keyring '%s': %s\n"),
                       filename, gpg_strerror (rc));
          goto leave;
        }
    }

  if (!opt.quiet)
    {
      if (is_box)
        log_info (_("keybox '%s' created\n"), filename);
      else
        log_info (_("keyring '%s' created\n"), filename);
    }

  rc = 0;

 leave:
  if (lockhd)
    {
      dotlock_release (lockhd);
      dotlock_destroy (lockhd);
    }
  return rc;
}
Example #6
0
/*
 * Register a resource (which currently may only be a keybox file).
 * The first keybox which is added by this function is created if it
 * does not exist.  If AUTO_CREATED is not NULL it will be set to true
 * if the function has created a new keybox.
 */
int
keydb_add_resource (const char *url, int force, int secret, int *auto_created)
{
  static int any_secret, any_public;
  const char *resname = url;
  char *filename = NULL;
  int rc = 0;
  KeydbResourceType rt = KEYDB_RESOURCE_TYPE_NONE;

  if (auto_created)
    *auto_created = 0;

  /* Do we have an URL?
     gnupg-kbx:filename := this is a plain keybox
     filename := See what is is, but create as plain keybox.
  */
  if (strlen (resname) > 10)
    {
      if (!strncmp (resname, "gnupg-kbx:", 10) )
        {
          rt = KEYDB_RESOURCE_TYPE_KEYBOX;
          resname += 10;
	}
#if !defined(HAVE_DRIVE_LETTERS) && !defined(__riscos__)
      else if (strchr (resname, ':'))
        {
          log_error ("invalid key resource URL '%s'\n", url );
          rc = gpg_error (GPG_ERR_GENERAL);
          goto leave;
	}
#endif /* !HAVE_DRIVE_LETTERS && !__riscos__ */
    }

  if (*resname != DIRSEP_C )
    { /* do tilde expansion etc */
      if (strchr(resname, DIRSEP_C) )
        filename = make_filename (resname, NULL);
      else
        filename = make_filename (opt.homedir, resname, NULL);
    }
  else
    filename = xstrdup (resname);

  if (!force)
    force = secret? !any_secret : !any_public;

  /* see whether we can determine the filetype */
  if (rt == KEYDB_RESOURCE_TYPE_NONE)
    {
      FILE *fp = fopen( filename, "rb" );

      if (fp)
        {
          u32 magic;

          /* FIXME: check for the keybox magic */
          if (fread (&magic, 4, 1, fp) == 1 )
            {
              if (magic == 0x13579ace || magic == 0xce9a5713)
                ; /* GDBM magic - no more support */
              else
                rt = KEYDB_RESOURCE_TYPE_KEYBOX;
            }
          else /* maybe empty: assume keybox */
            rt = KEYDB_RESOURCE_TYPE_KEYBOX;
          fclose (fp);
        }
      else /* no file yet: create keybox */
        rt = KEYDB_RESOURCE_TYPE_KEYBOX;
    }

  switch (rt)
    {
    case KEYDB_RESOURCE_TYPE_NONE:
      log_error ("unknown type of key resource '%s'\n", url );
      rc = gpg_error (GPG_ERR_GENERAL);
      goto leave;

    case KEYDB_RESOURCE_TYPE_KEYBOX:
      rc = maybe_create_keybox (filename, force, auto_created);
      if (rc)
        goto leave;
      /* Now register the file */
      {
        void *token = keybox_register_file (filename, secret);
        if (!token)
          ; /* already registered - ignore it */
        else if (used_resources >= MAX_KEYDB_RESOURCES)
          rc = gpg_error (GPG_ERR_RESOURCE_LIMIT);
        else
          {
            all_resources[used_resources].type = rt;
            all_resources[used_resources].u.kr = NULL; /* Not used here */
            all_resources[used_resources].token = token;
            all_resources[used_resources].secret = secret;

            all_resources[used_resources].lockhandle
              = dotlock_create (filename, 0);
            if (!all_resources[used_resources].lockhandle)
              log_fatal ( _("can't create lock for '%s'\n"), filename);

            /* Do a compress run if needed and the file is not locked. */
            if (!dotlock_take (all_resources[used_resources].lockhandle, 0))
              {
                KEYBOX_HANDLE kbxhd = keybox_new_x509 (token, secret);

                if (kbxhd)
                  {
                    keybox_compress (kbxhd);
                    keybox_release (kbxhd);
                  }
                dotlock_release (all_resources[used_resources].lockhandle);
              }

            used_resources++;
          }
      }
      break;

    default:
      log_error ("resource type of '%s' not supported\n", url);
      rc = gpg_error (GPG_ERR_NOT_SUPPORTED);
      goto leave;
    }

  /* fixme: check directory permissions and print a warning */

 leave:
  if (rc)
    log_error ("keyblock resource '%s': %s\n", filename, gpg_strerror(rc));
  else if (secret)
    any_secret = 1;
  else
    any_public = 1;
  xfree (filename);
  return rc;
}
Example #7
0
/* Lock a spawning process.  The caller needs to provide the address
   of a variable to store the lock information and the name or the
   process.  */
static gpg_error_t
lock_spawning (lock_spawn_t *lock, const char *homedir, const char *name,
               int verbose)
{
#ifdef HAVE_W32_SYSTEM
  int waitrc;
  int timeout = (!strcmp (name, "agent")
                 ? SECS_TO_WAIT_FOR_AGENT
                 : SECS_TO_WAIT_FOR_DIRMNGR);

  (void)homedir; /* Not required. */

  *lock = CreateMutexW
    (NULL, FALSE,
     !strcmp (name, "agent")?   L"GnuPG_spawn_agent_sentinel":
     !strcmp (name, "dirmngr")? L"GnuPG_spawn_dirmngr_sentinel":
     /*                    */   L"GnuPG_spawn_unknown_sentinel");
  if (!*lock)
    {
      log_error ("failed to create the spawn_%s mutex: %s\n",
                 name, w32_strerror (-1));
      return gpg_error (GPG_ERR_GENERAL);
    }

 retry:
  waitrc = WaitForSingleObject (*lock, 1000);
  if (waitrc == WAIT_OBJECT_0)
    return 0;

  if (waitrc == WAIT_TIMEOUT && timeout)
    {
      timeout--;
      if (verbose)
        log_info ("another process is trying to start the %s ... (%ds)\n",
                  name, timeout);
      goto retry;
    }
  if (waitrc == WAIT_TIMEOUT)
    log_info ("error waiting for the spawn_%s mutex: timeout\n", name);
  else
    log_info ("error waiting for the spawn_%s mutex: (code=%d) %s\n",
              name, waitrc, w32_strerror (-1));
  return gpg_error (GPG_ERR_GENERAL);
#else /*!HAVE_W32_SYSTEM*/
  char *fname;

  (void)verbose;

  *lock = NULL;

  fname = make_filename
    (homedir,
     !strcmp (name, "agent")?   "gnupg_spawn_agent_sentinel":
     !strcmp (name, "dirmngr")? "gnupg_spawn_dirmngr_sentinel":
     /*                    */   "gnupg_spawn_unknown_sentinel",
     NULL);
  if (!fname)
    return gpg_error_from_syserror ();

  *lock = dotlock_create (fname, 0);
  xfree (fname);
  if (!*lock)
    return gpg_error_from_syserror ();

  /* FIXME: We should use a timeout of 5000 here - however
     make_dotlock does not yet support values other than -1 and 0.  */
  if (dotlock_take (*lock, -1))
    return gpg_error_from_syserror ();

  return 0;
#endif /*!HAVE_W32_SYSTEM*/
}
Example #8
0
/* Mount the container with name FILENAME at MOUNTPOINT.  */
gpg_error_t
g13_mount_container (ctrl_t ctrl, const char *filename, const char *mountpoint)
{
  gpg_error_t err;
  dotlock_t lock;
  void *enckeyblob = NULL;
  size_t enckeybloblen;
  void *keyblob = NULL;
  size_t keybloblen;
  tupledesc_t tuples = NULL;
  size_t n;
  const unsigned char *value;
  int conttype;
  unsigned int rid;
  char *mountpoint_buffer = NULL;

  /* A quick check to see whether the container exists.  */
  if (access (filename, R_OK))
    return gpg_error_from_syserror ();

  if (!mountpoint)
    {
      mountpoint_buffer = xtrystrdup ("/tmp/g13-XXXXXX");
      if (!mountpoint_buffer)
        return gpg_error_from_syserror ();
      if (!gnupg_mkdtemp (mountpoint_buffer))
        {
          err = gpg_error_from_syserror ();
          log_error (_("can't create directory '%s': %s\n"),
                     "/tmp/g13-XXXXXX", gpg_strerror (err));
          xfree (mountpoint_buffer);
          return err;
        }
      mountpoint = mountpoint_buffer;
    }

  /* Try to take a lock.  */
  lock = dotlock_create (filename, 0);
  if (!lock)
    {
      xfree (mountpoint_buffer);
      return gpg_error_from_syserror ();
    }

  if (dotlock_take (lock, 0))
    {
      err = gpg_error_from_syserror ();
      goto leave;
    }
  else
    err = 0;

  /* Check again that the file exists.  */
  {
    struct stat sb;

    if (stat (filename, &sb))
      {
        err = gpg_error_from_syserror ();
        goto leave;
      }
  }

  /* Read the encrypted keyblob.  */
  err = read_keyblob (filename, &enckeyblob, &enckeybloblen);
  if (err)
    goto leave;

  /* Decrypt that keyblob and store it in a tuple descriptor.  */
  err = decrypt_keyblob (ctrl, enckeyblob, enckeybloblen,
                         &keyblob, &keybloblen);
  if (err)
    goto leave;
  xfree (enckeyblob);
  enckeyblob = NULL;

  err = create_tupledesc (&tuples, keyblob, keybloblen);
  if (!err)
    keyblob = NULL;
  else
    {
      if (gpg_err_code (err) == GPG_ERR_NOT_SUPPORTED)
        log_error ("unknown keyblob version\n");
      goto leave;
    }
  if (opt.verbose)
    dump_keyblob (tuples);

  value = find_tuple (tuples, KEYBLOB_TAG_CONTTYPE, &n);
  if (!value || n != 2)
    conttype = 0;
  else
    conttype = (value[0] << 8 | value[1]);
  if (!be_is_supported_conttype (conttype))
    {
      log_error ("content type %d is not supported\n", conttype);
      err = gpg_error (GPG_ERR_NOT_SUPPORTED);
      goto leave;
    }
  err = be_mount_container (ctrl, conttype, filename, mountpoint, tuples, &rid);
  if (!err)
    {
      err = mountinfo_add_mount (filename, mountpoint, conttype, rid,
                                 !!mountpoint_buffer);
      /* Fixme: What shall we do if this fails?  Add a provisional
         mountinfo entry first and remove it on error? */
      if (!err)
        {
          char *tmp = percent_plus_escape (mountpoint);
          if (!tmp)
            err = gpg_error_from_syserror ();
          else
            {
              g13_status (ctrl, STATUS_MOUNTPOINT, tmp, NULL);
              xfree (tmp);
            }
        }
    }

 leave:
  destroy_tupledesc (tuples);
  xfree (keyblob);
  xfree (enckeyblob);
  dotlock_destroy (lock);
  xfree (mountpoint_buffer);
  return err;
}
Example #9
0
/* Check whether a default secring.gpg from GnuPG < 2.1 exists and
   import it if not yet done.  */
void
migrate_secring (ctrl_t ctrl)
{
  dotlock_t lockhd = NULL;
  char *secring = NULL;
  char *flagfile = NULL;
  char *agent_version = NULL;

  secring = make_filename (opt.homedir, "secring" EXTSEP_S "gpg", NULL);
  if (access (secring, F_OK))
    goto leave; /* Does not exist or is not readable.  */
  flagfile = make_filename (opt.homedir, V21_MIGRATION_FNAME, NULL);
  if (!access (flagfile, F_OK))
    goto leave; /* Does exist - fine.  */

  log_info ("starting migration from earlier GnuPG versions\n");

  lockhd = dotlock_create (flagfile, 0);
  if (!lockhd)
    {
      log_error ("can't allocate lock for '%s': %s\n",
                 flagfile, gpg_strerror (gpg_error_from_syserror ()));
      goto leave;
    }
  if (dotlock_take (lockhd, -1))
    {
      log_error ("can't lock '%s': %s\n",
                 flagfile, gpg_strerror (gpg_error_from_syserror ()));
      dotlock_destroy (lockhd);
      lockhd = NULL;
      goto leave;
    }

  if (!agent_get_version (ctrl, &agent_version))
    {
      if (!gnupg_compare_version (agent_version, "2.1.0"))
        {
          log_error ("error: GnuPG agent version \"%s\" is too old. ",
                     agent_version);
          log_info ("Please make sure that a recent gpg-agent is running.\n");
          log_info ("(restarting the user session may achieve this.)\n");
          log_info ("migration aborted\n");
          xfree (agent_version);
          goto leave;
        }
      xfree (agent_version);
    }
  else
    {
      log_error ("error: GnuPG agent unusable. "
                 "Please check that a GnuPG agent can be started.\n");
      log_error ("migration aborted\n");
      goto leave;
    }

  log_info ("porting secret keys from '%s' to gpg-agent\n", secring);
  if (!import_old_secring (ctrl, secring))
    {
      FILE *fp = fopen (flagfile, "w");
      if (!fp || fclose (fp))
        log_error ("error creating flag file '%s': %s\n",
                   flagfile, gpg_strerror (gpg_error_from_syserror ()));
      else
        log_info ("migration succeeded\n");
    }

 leave:
  if (lockhd)
    {
      dotlock_release (lockhd);
      dotlock_destroy (lockhd);
    }
  xfree (flagfile);
  xfree (secring);
}
Example #10
0
/*
 * Lock the keyring with the given handle, or unlock if YES is false.
 * We ignore the handle and lock all registered files.
 */
int
keyring_lock (KEYRING_HANDLE hd, int yes)
{
    KR_RESOURCE kr;
    int rc = 0;

    (void)hd;

    if (yes) {
        /* first make sure the lock handles are created */
        for (kr=kr_resources; kr; kr = kr->next) {
            if (!keyring_is_writable(kr))
                continue;
            if (!kr->lockhd) {
                kr->lockhd = dotlock_create (kr->fname, 0);
                if (!kr->lockhd) {
                    log_info ("can't allocate lock for '%s'\n", kr->fname );
                    rc = GPG_ERR_GENERAL;
                }
            }
        }
        if (rc)
            return rc;

        /* and now set the locks */
        for (kr=kr_resources; kr; kr = kr->next) {
            if (!keyring_is_writable(kr))
                continue;
            if (kr->is_locked)
                continue;

#ifdef HAVE_W32_SYSTEM
            /* Under Windows we need to CloseHandle the file before we
             * try to lock it.  This is because another process might
             * have taken the lock and is using keybox_file_rename to
             * rename the base file.  How if our dotlock_take below is
             * waiting for the lock but we have the base file still
             * open, keybox_file_rename will never succeed as we are
             * in a deadlock.  */
            iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0,
                         (char*)kr->fname);
#endif /*HAVE_W32_SYSTEM*/
            if (dotlock_take (kr->lockhd, -1) ) {
                log_info ("can't lock '%s'\n", kr->fname );
                rc = GPG_ERR_GENERAL;
            }
            else
                kr->is_locked = 1;
        }
    }

    if (rc || !yes) {
        for (kr=kr_resources; kr; kr = kr->next) {
            if (!keyring_is_writable(kr))
                continue;
            if (!kr->is_locked)
                continue;

            if (dotlock_release (kr->lockhd))
                log_info ("can't unlock '%s'\n", kr->fname );
            else
                kr->is_locked = 0;
        }
    }

    return rc;
}