mirror of
git://git.gnupg.org/gnupg.git
synced 2025-07-02 22:46:30 +02:00
Implemented more gpg-agen options to support certain passphrase policies.
New tool gpg-check-pattern.
This commit is contained in:
parent
503f91e0ae
commit
15d0cb42a1
28 changed files with 1166 additions and 72 deletions
|
@ -1,3 +1,22 @@
|
|||
2007-08-27 Werner Koch <wk@g10code.com>
|
||||
|
||||
* gpg-agent.c: Add options --min-passphrase-nonalpha,
|
||||
--check-passphrase-pattern and --enforce-passphrase-constraints.
|
||||
(MIN_PASSPHRASE_NONALPHA): Init nonalpha option to 1.
|
||||
(main): Declare options for gpgconf.
|
||||
* agent.h (struct): Add members MIN_PASSPHRASE_NONALPHA,
|
||||
ENFORCE_PASSPHRASE_CONSTRAINTS and CHECK_PASSPHRASE_PATTERN.
|
||||
* genkey.c (nonalpha_charcount): New.
|
||||
(check_passphrase_pattern): New.
|
||||
(check_passphrase_constraints): Implement. Factor some code out...
|
||||
(take_this_one_anyway, take_this_one_anyway2): .. New.
|
||||
|
||||
* call-pinentry.c (agent_show_message): New.
|
||||
(agent_askpin): We better reset the pin buffer before asking.
|
||||
|
||||
* trustlist.c (insert_colons): New.
|
||||
(agent_marktrusted): Pretty print the fpr.
|
||||
|
||||
2007-08-22 Werner Koch <wk@g10code.com>
|
||||
|
||||
* findkey.c (O_BINARY): Make sure it is defined.
|
||||
|
|
|
@ -80,8 +80,15 @@ struct
|
|||
unsigned long max_cache_ttl; /* Default. */
|
||||
unsigned long max_cache_ttl_ssh; /* for SSH. */
|
||||
|
||||
/* Flag disallowin bypassing of the warning. */
|
||||
int enforce_passphrase_constraints;
|
||||
/* The require minmum length of a passphrase. */
|
||||
unsigned int min_passphrase_len;
|
||||
/* The minimum number of non-alpha characters in a passphrase. */
|
||||
unsigned int min_passphrase_nonalpha;
|
||||
/* File name with a patternfile or NULL if not enabled. */
|
||||
const char *check_passphrase_pattern;
|
||||
|
||||
|
||||
int running_detached; /* We are running detached from the tty. */
|
||||
|
||||
|
@ -227,6 +234,7 @@ int agent_get_passphrase (ctrl_t ctrl, char **retpass,
|
|||
const char *errtext);
|
||||
int agent_get_confirmation (ctrl_t ctrl, const char *desc, const char *ok,
|
||||
const char *cancel);
|
||||
int agent_show_message (ctrl_t ctrl, const char *desc, const char *ok_btn);
|
||||
int agent_popup_message_start (ctrl_t ctrl,
|
||||
const char *desc, const char *ok_btn);
|
||||
void agent_popup_message_stop (ctrl_t ctrl);
|
||||
|
|
|
@ -213,7 +213,9 @@ start_pinentry (ctrl_t ctrl)
|
|||
#endif
|
||||
if (fflush (NULL))
|
||||
{
|
||||
#ifndef HAVE_W32_SYSTEM
|
||||
gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
|
||||
#endif
|
||||
log_error ("error flushing pending output: %s\n", strerror (errno));
|
||||
/* At least Windows XP fails here with EBADF. According to docs
|
||||
and Wine an fflush(NULL) is the same as _flushall. However
|
||||
|
@ -476,6 +478,7 @@ agent_askpin (ctrl_t ctrl,
|
|||
{
|
||||
memset (&parm, 0, sizeof parm);
|
||||
parm.size = pininfo->max_length;
|
||||
*pininfo->pin = 0; /* Reset the PIN. */
|
||||
parm.buffer = (unsigned char*)pininfo->pin;
|
||||
|
||||
if (errtext)
|
||||
|
@ -671,6 +674,55 @@ agent_get_confirmation (ctrl_t ctrl,
|
|||
}
|
||||
|
||||
|
||||
|
||||
/* Pop up the PINentry, display the text DESC and a button with the
|
||||
text OK_BTN (which may be NULL to use the default of "OK") and waut
|
||||
for the user to hit this button. The return value is not
|
||||
relevant. */
|
||||
int
|
||||
agent_show_message (ctrl_t ctrl, const char *desc, const char *ok_btn)
|
||||
{
|
||||
int rc;
|
||||
char line[ASSUAN_LINELENGTH];
|
||||
|
||||
rc = start_pinentry (ctrl);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (desc)
|
||||
snprintf (line, DIM(line)-1, "SETDESC %s", desc);
|
||||
else
|
||||
snprintf (line, DIM(line)-1, "RESET");
|
||||
line[DIM(line)-1] = 0;
|
||||
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
/* Most pinentries out in the wild return the old Assuan error code
|
||||
for canceled which gets translated to an assuan Cancel error and
|
||||
not to the code for a user cancel. Fix this here. */
|
||||
if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
|
||||
rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
|
||||
|
||||
if (rc)
|
||||
return unlock_pinentry (rc);
|
||||
|
||||
if (ok_btn)
|
||||
{
|
||||
snprintf (line, DIM(line)-1, "SETOK %s", ok_btn);
|
||||
line[DIM(line)-1] = 0;
|
||||
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL,
|
||||
NULL, NULL, NULL);
|
||||
if (rc)
|
||||
return unlock_pinentry (rc);
|
||||
}
|
||||
|
||||
rc = assuan_transact (entry_ctx, "CONFIRM --one-button", NULL, NULL, NULL,
|
||||
NULL, NULL, NULL);
|
||||
if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
|
||||
rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
|
||||
|
||||
return unlock_pinentry (rc);
|
||||
}
|
||||
|
||||
|
||||
/* The thread running the popup message. */
|
||||
static void *
|
||||
popup_message_thread (void *arg)
|
||||
|
|
156
agent/genkey.c
156
agent/genkey.c
|
@ -27,6 +27,8 @@
|
|||
|
||||
#include "agent.h"
|
||||
#include "i18n.h"
|
||||
#include "exechelp.h"
|
||||
#include "sysutils.h"
|
||||
|
||||
static int
|
||||
store_key (gcry_sexp_t private, const char *passphrase, int force)
|
||||
|
@ -70,6 +72,100 @@ store_key (gcry_sexp_t private, const char *passphrase, int force)
|
|||
}
|
||||
|
||||
|
||||
/* Count the number of non-alpha characters in S. Control characters
|
||||
and non-ascii characters are not considered. */
|
||||
static size_t
|
||||
nonalpha_count (const char *s)
|
||||
{
|
||||
size_t n;
|
||||
|
||||
for (n=0; *s; s++)
|
||||
if (isascii (*s) && ( isdigit (*s) || ispunct (*s) ))
|
||||
n++;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
/* Check PW against a list of pattern. Return 0 if PW does not match
|
||||
these pattern. */
|
||||
static int
|
||||
check_passphrase_pattern (ctrl_t ctrl, const char *pw)
|
||||
{
|
||||
gpg_error_t err = 0;
|
||||
const char *pgmname = gnupg_module_name (GNUPG_MODULE_NAME_CHECK_PATTERN);
|
||||
FILE *infp;
|
||||
const char *argv[10];
|
||||
pid_t pid;
|
||||
int result, i;
|
||||
|
||||
infp = gnupg_tmpfile ();
|
||||
if (!infp)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
log_error (_("error creating temporary file: %s\n"), strerror (errno));
|
||||
return 1; /* Error - assume password should not be used. */
|
||||
}
|
||||
|
||||
if (fwrite (pw, strlen (pw), 1, infp) != 1)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
log_error (_("error writing to temporary file: %s\n"),
|
||||
strerror (errno));
|
||||
fclose (infp);
|
||||
return 1; /* Error - assume password should not be used. */
|
||||
}
|
||||
rewind (infp);
|
||||
|
||||
i = 0;
|
||||
argv[i++] = "--null";
|
||||
argv[i++] = "--",
|
||||
argv[i++] = opt.check_passphrase_pattern,
|
||||
argv[i] = NULL;
|
||||
assert (i < sizeof argv);
|
||||
|
||||
if (gnupg_spawn_process_fd (pgmname, argv, fileno (infp), -1, -1, &pid))
|
||||
result = 1; /* Execute error - assume password should no be used. */
|
||||
else if (gnupg_wait_process (pgmname, pid))
|
||||
result = 1; /* Helper returned an error - probably a match. */
|
||||
else
|
||||
result = 0; /* Success; i.e. no match. */
|
||||
|
||||
/* Overwrite our temporary file. */
|
||||
rewind (infp);
|
||||
for (i=((strlen (pw)+99)/100)*100; i > 0; i--)
|
||||
putc ('\xff', infp);
|
||||
fflush (infp);
|
||||
fclose (infp);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
take_this_one_anyway2 (ctrl_t ctrl, const char *desc, const char *anyway_btn)
|
||||
{
|
||||
gpg_error_t err;
|
||||
|
||||
if (opt.enforce_passphrase_constraints)
|
||||
{
|
||||
err = agent_show_message (ctrl, desc, _("Enter new passphrase"));
|
||||
if (!err)
|
||||
err = gpg_error (GPG_ERR_CANCELED);
|
||||
}
|
||||
else
|
||||
err = agent_get_confirmation (ctrl, desc,
|
||||
anyway_btn, _("Enter new passphrase"));
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
take_this_one_anyway (ctrl_t ctrl, const char *desc)
|
||||
{
|
||||
return take_this_one_anyway2 (ctrl, desc, _("Take this one anyway"));
|
||||
}
|
||||
|
||||
|
||||
/* Check whether the passphrase PW is suitable. Returns 0 if the
|
||||
passphrase is suitable and true if it is not and the user should be
|
||||
asked to provide a different one. */
|
||||
|
@ -78,7 +174,8 @@ check_passphrase_constraints (ctrl_t ctrl, const char *pw)
|
|||
{
|
||||
gpg_error_t err;
|
||||
unsigned int minlen = opt.min_passphrase_len;
|
||||
|
||||
unsigned int minnonalpha = opt.min_passphrase_nonalpha;
|
||||
|
||||
if (!pw)
|
||||
pw = "";
|
||||
|
||||
|
@ -93,25 +190,60 @@ check_passphrase_constraints (ctrl_t ctrl, const char *pw)
|
|||
"be at least %u characters long.", minlen), minlen );
|
||||
if (!desc)
|
||||
return gpg_error_from_syserror ();
|
||||
|
||||
err = agent_get_confirmation (ctrl, desc,
|
||||
_("Take this one anyway"),
|
||||
_("Enter new passphrase"));
|
||||
err = take_this_one_anyway (ctrl, desc);
|
||||
xfree (desc);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (nonalpha_count (pw) < minnonalpha )
|
||||
{
|
||||
char *desc = xtryasprintf
|
||||
( ngettext ("Warning: You have entered a passphrase that%%0A"
|
||||
"is obviously not secure. A passphrase should%%0A"
|
||||
"contain at least %u digit or special character.",
|
||||
"Warning: You have entered a passphrase that%%0A"
|
||||
"is obviously not secure. A passphrase should%%0A"
|
||||
"contain at least %u digits or special characters.",
|
||||
minnonalpha), minnonalpha );
|
||||
if (!desc)
|
||||
return gpg_error_from_syserror ();
|
||||
err = take_this_one_anyway (ctrl, desc);
|
||||
xfree (desc);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* If configured check the passphrase against a list of know words
|
||||
and pattern. The actual test is done by an external program.
|
||||
The warning message is generic to give the user no hint on how to
|
||||
circumvent this list. */
|
||||
if (*pw && opt.check_passphrase_pattern &&
|
||||
check_passphrase_pattern (ctrl, pw))
|
||||
{
|
||||
const char *desc =
|
||||
/* */ _("Warning: You have entered a passphrase that%0A"
|
||||
"is obviously not secure. A passphrase may not%0A"
|
||||
"be a known term or match certain pattern.");
|
||||
|
||||
err = take_this_one_anyway (ctrl, desc);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* The final check is to warn about an empty passphrase. */
|
||||
if (!*pw)
|
||||
{
|
||||
const char *desc = _("You have not entered a passphrase - "
|
||||
"this is in general a bad idea!%0A"
|
||||
"Please confirm that you do not want to "
|
||||
"have any protection on your key.");
|
||||
const char *desc = (opt.enforce_passphrase_constraints?
|
||||
_("You have not entered a passphrase!%0A"
|
||||
"An empty passphrase is not allowed.") :
|
||||
_("You have not entered a passphrase - "
|
||||
"this is in general a bad idea!%0A"
|
||||
"Please confirm that you do not want to "
|
||||
"have any protection on your key."));
|
||||
|
||||
err = agent_get_confirmation (ctrl, desc,
|
||||
_("Yes, protection is not needed"),
|
||||
_("Enter new passphrase"));
|
||||
err = take_this_one_anyway2 (ctrl, desc,
|
||||
_("Yes, protection is not needed"));
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -88,7 +88,10 @@ enum cmd_and_opt_values
|
|||
oDefCacheTTLSSH,
|
||||
oMaxCacheTTL,
|
||||
oMaxCacheTTLSSH,
|
||||
oEnforcePassphraseConstraints,
|
||||
oMinPassphraseLen,
|
||||
oMinPassphraseNonalpha,
|
||||
oCheckPassphrasePattern,
|
||||
oUseStandardSocket,
|
||||
oNoUseStandardSocket,
|
||||
|
||||
|
@ -149,7 +152,12 @@ static ARGPARSE_OPTS opts[] = {
|
|||
{ oDefCacheTTLSSH, "default-cache-ttl-ssh", 4, "@" },
|
||||
{ oMaxCacheTTL, "max-cache-ttl", 4, "@" },
|
||||
{ oMaxCacheTTLSSH, "max-cache-ttl-ssh", 4, "@" },
|
||||
|
||||
{ oEnforcePassphraseConstraints, "enforce-passphrase-constraints", 0, "@"},
|
||||
{ oMinPassphraseLen, "min-passphrase-len", 4, "@" },
|
||||
{ oMinPassphraseNonalpha, "min-passphrase-nonalpha", 4, "@" },
|
||||
{ oCheckPassphrasePattern, "check-passphrase-pattern", 2, "@" },
|
||||
|
||||
{ oIgnoreCacheForSigning, "ignore-cache-for-signing", 0,
|
||||
N_("do not use the PIN cache when signing")},
|
||||
{ oAllowMarkTrusted, "allow-mark-trusted", 0,
|
||||
|
@ -168,6 +176,7 @@ static ARGPARSE_OPTS opts[] = {
|
|||
#define MAX_CACHE_TTL (120*60) /* 2 hours */
|
||||
#define MAX_CACHE_TTL_SSH (120*60) /* 2 hours */
|
||||
#define MIN_PASSPHRASE_LEN (8)
|
||||
#define MIN_PASSPHRASE_NONALPHA (1)
|
||||
|
||||
/* The timer tick used for housekeeping stuff. For Windows we use a
|
||||
longer period as the SetWaitableTimer seems to signal earlier than
|
||||
|
@ -362,7 +371,10 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
|
|||
opt.def_cache_ttl_ssh = DEFAULT_CACHE_TTL_SSH;
|
||||
opt.max_cache_ttl = MAX_CACHE_TTL;
|
||||
opt.max_cache_ttl_ssh = MAX_CACHE_TTL_SSH;
|
||||
opt.enforce_passphrase_constraints = 0;
|
||||
opt.min_passphrase_len = MIN_PASSPHRASE_LEN;
|
||||
opt.min_passphrase_nonalpha = MIN_PASSPHRASE_NONALPHA;
|
||||
opt.check_passphrase_pattern = NULL;
|
||||
opt.ignore_cache_for_signing = 0;
|
||||
opt.allow_mark_trusted = 0;
|
||||
opt.disable_scdaemon = 0;
|
||||
|
@ -402,7 +414,16 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
|
|||
case oMaxCacheTTL: opt.max_cache_ttl = pargs->r.ret_ulong; break;
|
||||
case oMaxCacheTTLSSH: opt.max_cache_ttl_ssh = pargs->r.ret_ulong; break;
|
||||
|
||||
case oEnforcePassphraseConstraints:
|
||||
opt.enforce_passphrase_constraints=1;
|
||||
break;
|
||||
case oMinPassphraseLen: opt.min_passphrase_len = pargs->r.ret_ulong; break;
|
||||
case oMinPassphraseNonalpha:
|
||||
opt.min_passphrase_nonalpha = pargs->r.ret_ulong;
|
||||
break;
|
||||
case oCheckPassphrasePattern:
|
||||
opt.check_passphrase_pattern = pargs->r.ret_str;
|
||||
break;
|
||||
|
||||
case oIgnoreCacheForSigning: opt.ignore_cache_for_signing = 1; break;
|
||||
|
||||
|
@ -723,8 +744,15 @@ main (int argc, char **argv )
|
|||
GC_OPT_FLAG_DEFAULT|GC_OPT_FLAG_RUNTIME, MAX_CACHE_TTL );
|
||||
printf ("max-cache-ttl-ssh:%lu:%d:\n",
|
||||
GC_OPT_FLAG_DEFAULT|GC_OPT_FLAG_RUNTIME, MAX_CACHE_TTL_SSH );
|
||||
printf ("enforce-passphrase-constraints:%lu:\n",
|
||||
GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
|
||||
printf ("min-passphrase-len:%lu:%d:\n",
|
||||
GC_OPT_FLAG_DEFAULT|GC_OPT_FLAG_RUNTIME, MIN_PASSPHRASE_LEN );
|
||||
printf ("min-passphrase-nonalpha:%lu:%d:\n",
|
||||
GC_OPT_FLAG_DEFAULT|GC_OPT_FLAG_RUNTIME,
|
||||
MIN_PASSPHRASE_NONALPHA);
|
||||
printf ("check-passphrase-pattern:%lu:\n",
|
||||
GC_OPT_FLAG_DEFAULT|GC_OPT_FLAG_RUNTIME);
|
||||
printf ("no-grab:%lu:\n",
|
||||
GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
|
||||
printf ("ignore-cache-for-signing:%lu:\n",
|
||||
|
|
|
@ -455,13 +455,40 @@ agent_listtrusted (void *assuan_context)
|
|||
}
|
||||
|
||||
|
||||
/* Create a copy of string with colons inserted after each two bytes.
|
||||
Caller needs to release the string. In case of a memory failure,
|
||||
NULL is returned. */
|
||||
static char *
|
||||
insert_colons (const char *string)
|
||||
{
|
||||
char *buffer, *p;
|
||||
size_t n = strlen (string);
|
||||
|
||||
p = buffer = xtrymalloc ( n + (n+2)/3 + 1 );
|
||||
if (!buffer)
|
||||
return NULL;
|
||||
while (*string)
|
||||
{
|
||||
*p++ = *string++;
|
||||
if (*string)
|
||||
{
|
||||
*p++ = *string++;
|
||||
if (*string)
|
||||
*p++ = ':';
|
||||
}
|
||||
}
|
||||
*p = 0;
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
/* Insert the given fpr into our trustdb. We expect FPR to be an all
|
||||
uppercase hexstring of 40 characters. FLAG is either 'P' or 'C'.
|
||||
This function does first check whether that key has alreay been put
|
||||
This function does first check whether that key has already been put
|
||||
into the trustdb and returns success in this case. Before a FPR
|
||||
actually gets inserted, the user is asked by means of the pin-entry
|
||||
whether this is actual wants he want to do.
|
||||
*/
|
||||
actually gets inserted, the user is asked by means of the Pinentry
|
||||
whether this is actual wants he want to do. */
|
||||
gpg_error_t
|
||||
agent_marktrusted (ctrl_t ctrl, const char *name, const char *fpr, int flag)
|
||||
{
|
||||
|
@ -469,6 +496,8 @@ agent_marktrusted (ctrl_t ctrl, const char *name, const char *fpr, int flag)
|
|||
char *desc;
|
||||
char *fname;
|
||||
FILE *fp;
|
||||
char *fprformatted;
|
||||
|
||||
|
||||
/* Check whether we are at all allowed to modify the trustlist.
|
||||
This is useful so that the trustlist may be a symlink to a global
|
||||
|
@ -494,6 +523,9 @@ agent_marktrusted (ctrl_t ctrl, const char *name, const char *fpr, int flag)
|
|||
return gpg_error (GPG_ERR_NOT_SUPPORTED);
|
||||
|
||||
/* Insert a new one. */
|
||||
fprformatted = insert_colons (fpr);
|
||||
if (!fprformatted)
|
||||
return out_of_core ();
|
||||
if (asprintf (&desc,
|
||||
/* TRANSLATORS: This prompt is shown by the Pinentry
|
||||
and has one special property: A "%%0A" is used by
|
||||
|
@ -503,12 +535,15 @@ agent_marktrusted (ctrl_t ctrl, const char *name, const char *fpr, int flag)
|
|||
plain % sign, you need to encode it as "%%25". The
|
||||
second "%s" gets replaced by a hexdecimal
|
||||
fingerprint string whereas the first one receives
|
||||
the name as store in the certificate. */
|
||||
the name as stored in the certificate. */
|
||||
_("Please verify that the certificate identified as:%%0A"
|
||||
" \"%s\"%%0A"
|
||||
"has the fingerprint:%%0A"
|
||||
" %s"), name, fpr) < 0 )
|
||||
return out_of_core ();
|
||||
" %s"), name, fprformatted) < 0 )
|
||||
{
|
||||
xfree (fprformatted);
|
||||
return out_of_core ();
|
||||
}
|
||||
|
||||
/* TRANSLATORS: "Correct" is the label of a button and intended to
|
||||
be hit if the fingerprint matches the one of the CA. The other
|
||||
|
@ -519,8 +554,11 @@ agent_marktrusted (ctrl_t ctrl, const char *name, const char *fpr, int flag)
|
|||
gpgsm may stop asking further questions. We won't do this for
|
||||
the second question of course. */
|
||||
if (err)
|
||||
return (gpg_err_code (err) == GPG_ERR_NOT_CONFIRMED ?
|
||||
gpg_err_make (gpg_err_source (err), GPG_ERR_CANCELED) : err);
|
||||
{
|
||||
xfree (fprformatted);
|
||||
return (gpg_err_code (err) == GPG_ERR_NOT_CONFIRMED ?
|
||||
gpg_err_make (gpg_err_source (err), GPG_ERR_CANCELED) : err);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -537,12 +575,18 @@ agent_marktrusted (ctrl_t ctrl, const char *name, const char *fpr, int flag)
|
|||
" \"%s\"%%0A"
|
||||
"to correctly certify user certificates?"),
|
||||
name) < 0 )
|
||||
return out_of_core ();
|
||||
{
|
||||
xfree (fprformatted);
|
||||
return out_of_core ();
|
||||
}
|
||||
|
||||
err = agent_get_confirmation (ctrl, desc, _("Yes"), _("No"));
|
||||
free (desc);
|
||||
if (err)
|
||||
return err;
|
||||
{
|
||||
xfree (fprformatted);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Now check again to avoid duplicates. We take the lock to make
|
||||
sure that nobody else plays with our file. Frankly we don't work
|
||||
|
@ -552,6 +596,7 @@ agent_marktrusted (ctrl_t ctrl, const char *name, const char *fpr, int flag)
|
|||
if (!agent_istrusted (ctrl, fpr))
|
||||
{
|
||||
unlock_trusttable ();
|
||||
xfree (fprformatted);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -566,6 +611,7 @@ agent_marktrusted (ctrl_t ctrl, const char *name, const char *fpr, int flag)
|
|||
log_error ("can't create `%s': %s\n", fname, gpg_strerror (err));
|
||||
xfree (fname);
|
||||
unlock_trusttable ();
|
||||
xfree (fprformatted);
|
||||
return err;
|
||||
}
|
||||
fputs (headerblurb, fp);
|
||||
|
@ -578,13 +624,14 @@ agent_marktrusted (ctrl_t ctrl, const char *name, const char *fpr, int flag)
|
|||
log_error ("can't open `%s': %s\n", fname, gpg_strerror (err));
|
||||
xfree (fname);
|
||||
unlock_trusttable ();
|
||||
xfree (fprformatted);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Append the key. */
|
||||
fputs ("\n# ", fp);
|
||||
print_sanitized_string (fp, name, 0);
|
||||
fprintf (fp, "\n%s %c\n", fpr, flag);
|
||||
fprintf (fp, "\n%s %c\n", fprformatted, flag);
|
||||
if (ferror (fp))
|
||||
err = gpg_error_from_syserror ();
|
||||
|
||||
|
@ -595,6 +642,7 @@ agent_marktrusted (ctrl_t ctrl, const char *name, const char *fpr, int flag)
|
|||
agent_reload_trustlist ();
|
||||
xfree (fname);
|
||||
unlock_trusttable ();
|
||||
xfree (fprformatted);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue