mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-18 14:17:03 +01:00
agent: Update key files by first writing to a temp file.
* agent/findkey.c (fname_from_keygrip): New. (agent_write_private_key): Use here. Use temp file for updating. (agent_update_private_key): Use fname_from_keygrip and use gnupg rename function instead of a vanilla rename.
This commit is contained in:
parent
13013ec1c0
commit
05f29b5c7c
169
agent/findkey.c
169
agent/findkey.c
@ -50,6 +50,22 @@ struct try_unprotect_arg_s
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* Return the file name for the 20 byte keygrip GRIP. With FOR_NEW
|
||||||
|
* create a file name for later renaming to the actual name. Return
|
||||||
|
* NULL on error. */
|
||||||
|
static char *
|
||||||
|
fname_from_keygrip (const unsigned char *grip, int for_new)
|
||||||
|
{
|
||||||
|
char hexgrip[40+4+4+1];
|
||||||
|
|
||||||
|
bin2hex (grip, 20, hexgrip);
|
||||||
|
strcpy (hexgrip+40, for_new? ".key.tmp" : ".key");
|
||||||
|
|
||||||
|
return make_filename_try (gnupg_homedir (), GNUPG_PRIVATE_KEYS_DIR,
|
||||||
|
hexgrip, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Replace all linefeeds in STRING by "%0A" and return a new malloced
|
/* Replace all linefeeds in STRING by "%0A" and return a new malloced
|
||||||
* string. May return NULL on memory error. */
|
* string. May return NULL on memory error. */
|
||||||
static char *
|
static char *
|
||||||
@ -94,26 +110,22 @@ agent_write_private_key (const unsigned char *grip,
|
|||||||
time_t timestamp)
|
time_t timestamp)
|
||||||
{
|
{
|
||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
char *fname;
|
char *fname = NULL;
|
||||||
|
char *tmpfname = NULL;
|
||||||
estream_t fp;
|
estream_t fp;
|
||||||
char hexgrip[40+4+1];
|
|
||||||
int update, newkey;
|
int update, newkey;
|
||||||
nvc_t pk = NULL;
|
nvc_t pk = NULL;
|
||||||
gcry_sexp_t key = NULL;
|
gcry_sexp_t key = NULL;
|
||||||
int remove = 0;
|
int removetmp = 0;
|
||||||
char *token0 = NULL;
|
char *token0 = NULL;
|
||||||
char *token = NULL;
|
char *token = NULL;
|
||||||
char *dispserialno_buffer = NULL;
|
char *dispserialno_buffer = NULL;
|
||||||
char **tokenfields = NULL;
|
char **tokenfields = NULL;
|
||||||
|
int blocksigs = 0;
|
||||||
|
|
||||||
bin2hex (grip, 20, hexgrip);
|
fname = fname_from_keygrip (grip, 0);
|
||||||
strcpy (hexgrip+40, ".key");
|
if (!fname)
|
||||||
|
return gpg_error_from_syserror ();
|
||||||
fname = make_filename (gnupg_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 && !gnupg_access (fname, F_OK))
|
if (!force && !gnupg_access (fname, F_OK))
|
||||||
{
|
{
|
||||||
@ -213,7 +225,8 @@ agent_write_private_key (const unsigned char *grip,
|
|||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
es_clearerr (fp);
|
es_fclose (fp);
|
||||||
|
fp = NULL;
|
||||||
|
|
||||||
/* Turn (BUFFER,LENGTH) into a gcrypt s-expression and set it into
|
/* Turn (BUFFER,LENGTH) into a gcrypt s-expression and set it into
|
||||||
* our name value container. */
|
* our name value container. */
|
||||||
@ -299,46 +312,55 @@ agent_write_private_key (const unsigned char *grip,
|
|||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Back to start and write. */
|
/* Create a temporary file for writing. */
|
||||||
err = es_fseek (fp, 0, SEEK_SET);
|
tmpfname = fname_from_keygrip (grip, 1);
|
||||||
if (err)
|
fp = tmpfname ? es_fopen (tmpfname, "wbx,mode=-rw") : NULL;
|
||||||
goto leave;
|
if (!fp)
|
||||||
|
|
||||||
err = nvc_write (pk, fp);
|
|
||||||
if (!err)
|
|
||||||
err = es_fflush (fp);
|
|
||||||
if (err)
|
|
||||||
{
|
{
|
||||||
log_error ("error writing '%s': %s\n", fname, gpg_strerror (err));
|
err = gpg_error_from_syserror ();
|
||||||
remove = 1;
|
log_error ("can't create '%s': %s\n", tmpfname, gpg_strerror (err));
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ftruncate (es_fileno (fp), es_ftello (fp)))
|
err = nvc_write (pk, fp);
|
||||||
|
if (!err && es_fflush (fp))
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
if (err)
|
||||||
{
|
{
|
||||||
err = gpg_error_from_syserror ();
|
log_error ("error writing '%s': %s\n", tmpfname, gpg_strerror (err));
|
||||||
log_error ("error truncating '%s': %s\n", fname, gpg_strerror (err));
|
removetmp = 1;
|
||||||
remove = 1;
|
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (es_fclose (fp))
|
if (es_fclose (fp))
|
||||||
{
|
{
|
||||||
err = gpg_error_from_syserror ();
|
err = gpg_error_from_syserror ();
|
||||||
log_error ("error closing '%s': %s\n", fname, gpg_strerror (err));
|
log_error ("error closing '%s': %s\n", tmpfname, gpg_strerror (err));
|
||||||
remove = 1;
|
removetmp = 1;
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
fp = NULL;
|
fp = NULL;
|
||||||
|
|
||||||
|
err = gnupg_rename_file (tmpfname, fname, &blocksigs);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
log_error ("error renaming '%s': %s\n", tmpfname, gpg_strerror (err));
|
||||||
|
removetmp = 1;
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
bump_key_eventcounter ();
|
bump_key_eventcounter ();
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
|
if (blocksigs)
|
||||||
|
gnupg_unblock_all_signals ();
|
||||||
es_fclose (fp);
|
es_fclose (fp);
|
||||||
if (remove && fname)
|
if (removetmp && fname)
|
||||||
gnupg_remove (fname);
|
gnupg_remove (fname);
|
||||||
xfree (fname);
|
xfree (fname);
|
||||||
|
xfree (tmpfname);
|
||||||
xfree (token);
|
xfree (token);
|
||||||
xfree (token0);
|
xfree (token0);
|
||||||
xfree (dispserialno_buffer);
|
xfree (dispserialno_buffer);
|
||||||
@ -352,53 +374,63 @@ agent_write_private_key (const unsigned char *grip,
|
|||||||
gpg_error_t
|
gpg_error_t
|
||||||
agent_update_private_key (const unsigned char *grip, nvc_t pk)
|
agent_update_private_key (const unsigned char *grip, nvc_t pk)
|
||||||
{
|
{
|
||||||
char *fname, *fname0;
|
|
||||||
estream_t fp;
|
|
||||||
char hexgrip[40+8+1];
|
|
||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
|
char *fname0 = NULL; /* The existing file name. */
|
||||||
|
char *fname = NULL; /* The temporary new file name. */
|
||||||
|
estream_t fp = NULL;
|
||||||
|
int removetmp = 0;
|
||||||
|
int blocksigs = 0;
|
||||||
|
|
||||||
bin2hex (grip, 20, hexgrip);
|
fname0 = fname_from_keygrip (grip, 0);
|
||||||
strcpy (hexgrip+40, ".key.tmp");
|
if (!fname)
|
||||||
|
|
||||||
fname = make_filename (gnupg_homedir (), GNUPG_PRIVATE_KEYS_DIR,
|
|
||||||
hexgrip, NULL);
|
|
||||||
fname0 = xstrdup (fname);
|
|
||||||
if (!fname0)
|
|
||||||
{
|
{
|
||||||
err = gpg_error_from_syserror ();
|
err = gpg_error_from_syserror ();
|
||||||
xfree (fname);
|
goto leave;
|
||||||
return err;
|
}
|
||||||
|
fname = fname_from_keygrip (grip, 1);
|
||||||
|
if (!fname)
|
||||||
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
goto leave;
|
||||||
}
|
}
|
||||||
fname0[strlen (fname)-4] = 0;
|
|
||||||
|
|
||||||
fp = es_fopen (fname, "wbx,mode=-rw");
|
fp = es_fopen (fname, "wbx,mode=-rw");
|
||||||
if (!fp)
|
if (!fp)
|
||||||
{
|
{
|
||||||
err = gpg_error_from_syserror ();
|
err = gpg_error_from_syserror ();
|
||||||
|
|
||||||
log_error ("can't create '%s': %s\n", fname, gpg_strerror (err));
|
log_error ("can't create '%s': %s\n", fname, gpg_strerror (err));
|
||||||
xfree (fname);
|
goto leave;
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err = nvc_write (pk, fp);
|
err = nvc_write (pk, fp);
|
||||||
if (err)
|
if (err)
|
||||||
log_error ("error writing '%s': %s\n", fname, gpg_strerror (err));
|
|
||||||
|
|
||||||
es_fclose (fp);
|
|
||||||
|
|
||||||
#ifdef HAVE_W32_SYSTEM
|
|
||||||
/* No atomic mv on W32 systems. */
|
|
||||||
gnupg_remove (fname0);
|
|
||||||
#endif
|
|
||||||
if (rename (fname, fname0))
|
|
||||||
{
|
{
|
||||||
err = gpg_error_from_errno (errno);
|
log_error ("error writing '%s': %s\n", fname, gpg_strerror (err));
|
||||||
log_error (_("error renaming '%s' to '%s': %s\n"),
|
removetmp = 1;
|
||||||
fname, fname0, strerror (errno));
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
es_fclose (fp);
|
||||||
|
fp = NULL;
|
||||||
|
|
||||||
|
err = gnupg_rename_file (fname, fname0, &blocksigs);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
log_error ("error renaming '%s': %s\n", fname, gpg_strerror (err));
|
||||||
|
removetmp = 1;
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
leave:
|
||||||
|
if (blocksigs)
|
||||||
|
gnupg_unblock_all_signals ();
|
||||||
|
es_fclose (fp);
|
||||||
|
if (removetmp && fname)
|
||||||
|
gnupg_remove (fname);
|
||||||
xfree (fname);
|
xfree (fname);
|
||||||
|
xfree (fname0);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -885,18 +917,17 @@ read_key_file (const unsigned char *grip, gcry_sexp_t *result, nvc_t *r_keymeta)
|
|||||||
unsigned char *buf;
|
unsigned char *buf;
|
||||||
size_t buflen, erroff;
|
size_t buflen, erroff;
|
||||||
gcry_sexp_t s_skey;
|
gcry_sexp_t s_skey;
|
||||||
char hexgrip[40+4+1];
|
|
||||||
char first;
|
char first;
|
||||||
|
|
||||||
*result = NULL;
|
*result = NULL;
|
||||||
if (r_keymeta)
|
if (r_keymeta)
|
||||||
*r_keymeta = NULL;
|
*r_keymeta = NULL;
|
||||||
|
|
||||||
bin2hex (grip, 20, hexgrip);
|
fname = fname_from_keygrip (grip, 0);
|
||||||
strcpy (hexgrip+40, ".key");
|
if (!fname)
|
||||||
|
{
|
||||||
fname = make_filename (gnupg_homedir (), GNUPG_PRIVATE_KEYS_DIR,
|
return gpg_error_from_syserror ();
|
||||||
hexgrip, NULL);
|
}
|
||||||
fp = es_fopen (fname, "rb");
|
fp = es_fopen (fname, "rb");
|
||||||
if (!fp)
|
if (!fp)
|
||||||
{
|
{
|
||||||
@ -1012,12 +1043,12 @@ remove_key_file (const unsigned char *grip)
|
|||||||
{
|
{
|
||||||
gpg_error_t err = 0;
|
gpg_error_t err = 0;
|
||||||
char *fname;
|
char *fname;
|
||||||
char hexgrip[40+4+1];
|
|
||||||
|
|
||||||
bin2hex (grip, 20, hexgrip);
|
fname = fname_from_keygrip (grip, 0);
|
||||||
strcpy (hexgrip+40, ".key");
|
if (!fname)
|
||||||
fname = make_filename (gnupg_homedir (), GNUPG_PRIVATE_KEYS_DIR,
|
{
|
||||||
hexgrip, NULL);
|
return gpg_error_from_syserror ();
|
||||||
|
}
|
||||||
if (gnupg_remove (fname))
|
if (gnupg_remove (fname))
|
||||||
err = gpg_error_from_syserror ();
|
err = gpg_error_from_syserror ();
|
||||||
xfree (fname);
|
xfree (fname);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user