Beispiel #1
0
/* Wrapper for rename(2) to handle Windows peculiarities.  */
gpg_error_t
keybox_file_rename (const char *oldname, const char *newname)
{
  gpg_error_t err = 0;

#ifdef HAVE_DOSISH_SYSTEM
  int wtime = 0;

  gnupg_remove (newname);
 again:
  if (rename (oldname, newname))
    {
      if (GetLastError () == ERROR_SHARING_VIOLATION)
        {
          /* Another process has the file open.  We do not use a lock
           * for read but instead we wait until the other process has
           * closed the file.  This may take long but that would also
           * be the case with a dotlock approach for read and write.
           * Note that we don't need this on Unix due to the inode
           * concept.
           *
           * So let's wait until the rename has worked.  The retry
           * intervals are 50, 100, 200, 400, 800, 50ms, ...  */
          if (!wtime || wtime >= 800)
            wtime = 50;
          else
            wtime *= 2;

          if (wtime >= 800)
            log_info ("waiting for file '%s' to become accessible ...\n",
                      oldname);

          Sleep (wtime);
          goto again;
        }
      err = gpg_error_from_syserror ();
    }

#else /* Unix */

#ifdef __riscos__
  gnupg_remove (newname);
#endif
  if (rename (oldname, newname) )
    err = gpg_error_from_syserror ();

#endif /* Unix */

  if (err)
    log_error ("renaming '%s' to '%s' failed: %s\n",
               oldname, newname, gpg_strerror (err));
  return err;
}
Beispiel #2
0
/* Write an S-expression formatted key to our key storage.  With FORCE
   passed as true an existing key with the given GRIP will get
   overwritten.  */
int
agent_write_private_key (const unsigned char *grip,
                         const void *buffer, size_t length, int force)
{
  char *fname;
  estream_t fp;
  char hexgrip[40+4+1];

  bin2hex (grip, 20, hexgrip);
  strcpy (hexgrip+40, ".key");

  fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);

  /* FIXME: Write to a temp file first so that write failures during
     key updates won't lead to a key loss.  */

  if (!force && !access (fname, F_OK))
    {
      log_error ("secret key file '%s' already exists\n", fname);
      xfree (fname);
      return gpg_error (GPG_ERR_EEXIST);
    }

  fp = es_fopen (fname, force? "wb,mode=-rw" : "wbx,mode=-rw");
  if (!fp)
    {
      gpg_error_t tmperr = gpg_error_from_syserror ();
      log_error ("can't create '%s': %s\n", fname, gpg_strerror (tmperr));
      xfree (fname);
      return tmperr;
    }

  if (es_fwrite (buffer, length, 1, fp) != 1)
    {
      gpg_error_t tmperr = gpg_error_from_syserror ();
      log_error ("error writing '%s': %s\n", fname, gpg_strerror (tmperr));
      es_fclose (fp);
      gnupg_remove (fname);
      xfree (fname);
      return tmperr;
    }
  if (es_fclose (fp))
    {
      gpg_error_t tmperr = gpg_error_from_syserror ();
      log_error ("error closing '%s': %s\n", fname, gpg_strerror (tmperr));
      gnupg_remove (fname);
      xfree (fname);
      return tmperr;
    }
  bump_key_eventcounter ();
  xfree (fname);
  return 0;
}
Beispiel #3
0
/* Remove the key identified by GRIP from the private key directory.  */
static gpg_error_t
remove_key_file (const unsigned char *grip)
{
  gpg_error_t err = 0;
  char *fname;
  char hexgrip[40+4+1];

  bin2hex (grip, 20, hexgrip);
  strcpy (hexgrip+40, ".key");
  fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
  if (gnupg_remove (fname))
    err = gpg_error_from_syserror ();
  xfree (fname);
  return err;
}
Beispiel #4
0
static gpg_error_t
write_extended_private_key (char *fname, estream_t fp,
                            const void *buf, size_t len)
{
  gpg_error_t err;
  pkc_t pk = NULL;
  gcry_sexp_t key = NULL;
  int remove = 0;
  int line;

  err = pkc_parse (&pk, &line, fp);
  if (err)
    {
      log_error ("error parsing '%s' line %d: %s\n",
                 fname, line, gpg_strerror (err));
      goto leave;
    }

  err = gcry_sexp_sscan (&key, NULL, buf, len);
  if (err)
    goto leave;

  err = pkc_set_private_key (pk, key);
  if (err)
    goto leave;

  err = es_fseek (fp, 0, SEEK_SET);
  if (err)
    goto leave;

  err = pkc_write (pk, fp);
  if (err)
    {
      log_error ("error writing '%s': %s\n", fname, gpg_strerror (err));
      remove = 1;
      goto leave;
    }

  if (ftruncate (es_fileno (fp), es_ftello (fp)))
    {
      err = gpg_error_from_syserror ();
      log_error ("error truncating '%s': %s\n", fname, gpg_strerror (err));
      remove = 1;
      goto leave;
    }

  if (es_fclose (fp))
    {
      err = gpg_error_from_syserror ();
      log_error ("error closing '%s': %s\n", fname, gpg_strerror (err));
      remove = 1;
      goto leave;
    }
  else
    fp = NULL;

  bump_key_eventcounter ();

 leave:
  if (fp)
    es_fclose (fp);
  if (remove)
    gnupg_remove (fname);
  xfree (fname);
  gcry_sexp_release (key);
  pkc_release (pk);
  return err;
}
Beispiel #5
0
/* Write an S-expression formatted key to our key storage.  With FORCE
   passed as true an existing key with the given GRIP will get
   overwritten.  */
int
agent_write_private_key (const unsigned char *grip,
                         const void *buffer, size_t length, int force)
{
  char *fname;
  estream_t fp;
  char hexgrip[40+4+1];

  bin2hex (grip, 20, hexgrip);
  strcpy (hexgrip+40, ".key");

  fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);

  /* FIXME: Write to a temp file first so that write failures during
     key updates won't lead to a key loss.  */

  if (!force && !access (fname, F_OK))
    {
      log_error ("secret key file '%s' already exists\n", fname);
      xfree (fname);
      return gpg_error (GPG_ERR_EEXIST);
    }

  fp = es_fopen (fname, force? "rb+,mode=-rw" : "wbx,mode=-rw");
  if (!fp)
    {
      gpg_error_t tmperr = gpg_error_from_syserror ();
      log_error ("can't create '%s': %s\n", fname, gpg_strerror (tmperr));
      xfree (fname);
      return tmperr;
    }

  /* See if an existing key is in extended format.  */
  if (force)
    {
      gpg_error_t rc;
      char first;

      if (es_fread (&first, 1, 1, fp) != 1)
        {
          rc = gpg_error_from_syserror ();
          log_error ("error reading first byte from '%s': %s\n",
                     fname, strerror (errno));
          xfree (fname);
          es_fclose (fp);
          return rc;
        }

      rc = es_fseek (fp, 0, SEEK_SET);
      if (rc)
        {
          log_error ("error seeking in '%s': %s\n", fname, strerror (errno));
          xfree (fname);
          es_fclose (fp);
          return rc;
        }

      if (first != '(')
        {
          /* Key is in extended format.  */
          return write_extended_private_key (fname, fp, buffer, length);
        }
    }

  if (es_fwrite (buffer, length, 1, fp) != 1)
    {
      gpg_error_t tmperr = gpg_error_from_syserror ();
      log_error ("error writing '%s': %s\n", fname, gpg_strerror (tmperr));
      es_fclose (fp);
      gnupg_remove (fname);
      xfree (fname);
      return tmperr;
    }

  /* When force is given, the file might have to be truncated.  */
  if (force && ftruncate (es_fileno (fp), es_ftello (fp)))
    {
      gpg_error_t tmperr = gpg_error_from_syserror ();
      log_error ("error truncating '%s': %s\n", fname, gpg_strerror (tmperr));
      es_fclose (fp);
      gnupg_remove (fname);
      xfree (fname);
      return tmperr;
    }

  if (es_fclose (fp))
    {
      gpg_error_t tmperr = gpg_error_from_syserror ();
      log_error ("error closing '%s': %s\n", fname, gpg_strerror (tmperr));
      gnupg_remove (fname);
      xfree (fname);
      return tmperr;
    }
  bump_key_eventcounter ();
  xfree (fname);
  return 0;
}