mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01: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
@ -1,3 +1,10 @@
|
||||
2007-08-27 Werner Koch <wk@g10code.com>
|
||||
|
||||
* configure.ac: Remove remaining support for internal regex.
|
||||
Define DISABLE_REGEX automake conditional. Add option
|
||||
--with-regex.
|
||||
* autogen.sh [--build-w32]: Remove --disable-regex. Use --with-regex.
|
||||
|
||||
2007-08-16 Werner Koch <wk@g10code.com>
|
||||
|
||||
Released 2.0.6.
|
||||
|
6
NEWS
6
NEWS
@ -4,7 +4,11 @@ Noteworthy changes in version 2.0.7
|
||||
* Fixed encryption problem if duplicate certificates are in the
|
||||
keybox.
|
||||
|
||||
* Made it work on Windows Vista.
|
||||
* Made it work on Windows Vista. Note that the entire Windows port
|
||||
is still considered Beta.
|
||||
|
||||
* Add new options min-passphrase-nonalpha, check-passphrase-pattern
|
||||
and enforce-passphrase-constraints to gpg-agent.
|
||||
|
||||
|
||||
Noteworthy changes in version 2.0.6 (2007-08-16)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -91,9 +91,9 @@ if test "$1" = "--build-w32"; then
|
||||
--with-libgcrypt-prefix=${w32root} \
|
||||
--with-libassuan-prefix=${w32root} \
|
||||
--with-zlib=${w32root} \
|
||||
--with-regex=${w32root} \
|
||||
--with-pth-prefix=${w32root} \
|
||||
--without-included-gettext \
|
||||
--disable-regex "$@"
|
||||
--without-included-gettext "$@"
|
||||
rc=$?
|
||||
exit $rc
|
||||
fi
|
||||
|
@ -1,3 +1,12 @@
|
||||
2007-08-27 Werner Koch <wk@g10code.com>
|
||||
|
||||
* util.h (GNUPG_MODULE_NAME_CHECK_PATTERN): New.
|
||||
* homedir.c (gnupg_module_name): Add it.
|
||||
* exechelp.c (w32_fd_or_null) [W32]: New.
|
||||
(gnupg_spawn_process_fd): New.
|
||||
(gnupg_wait_process) [W32]: Close the handle after if the process has
|
||||
returned.
|
||||
|
||||
2007-08-22 Werner Koch <wk@g10code.com>
|
||||
|
||||
Updated estream from libestream.
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* exechelp.c - fork and exec helpers
|
||||
* Copyright (C) 2004 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2004, 2007 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
@ -191,6 +191,23 @@ create_inheritable_pipe (int filedes[2])
|
||||
#endif /*HAVE_W32_SYSTEM*/
|
||||
|
||||
|
||||
#ifdef HAVE_W32_SYSTEM
|
||||
static HANDLE
|
||||
w32_open_null (int for_write)
|
||||
{
|
||||
HANDLE hfile;
|
||||
|
||||
hfile = CreateFile ("nul",
|
||||
for_write? GENERIC_WRITE : GENERIC_READ,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL, OPEN_EXISTING, 0, NULL);
|
||||
if (hfile == INVALID_HANDLE_VALUE)
|
||||
log_debug ("can't open `nul': %s\n", w32_strerror (-1));
|
||||
return hfile;
|
||||
}
|
||||
#endif /*HAVE_W32_SYSTEM*/
|
||||
|
||||
|
||||
#ifndef HAVE_W32_SYSTEM
|
||||
/* The exec core used right after the fork. This will never return. */
|
||||
static void
|
||||
@ -257,9 +274,9 @@ do_exec (const char *pgmname, const char *argv[],
|
||||
stdin, write the output to OUTFILE, return a new stream in
|
||||
STATUSFILE for stderr and the pid of the process in PID. The
|
||||
arguments for the process are expected in the NULL terminated array
|
||||
ARGV. The program name itself should not be included there. if
|
||||
ARGV. The program name itself should not be included there. If
|
||||
PREEXEC is not NULL, that function will be called right before the
|
||||
exec.
|
||||
exec. Calling gnupg_wait_process is required.
|
||||
|
||||
Returns 0 on success or an error code. */
|
||||
gpg_error_t
|
||||
@ -439,6 +456,119 @@ gnupg_spawn_process (const char *pgmname, const char *argv[],
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Simplified version of gnupg_spawn_process. This function forks and
|
||||
then execs PGMNAME, while connecting INFD to stdin, OUTFD to stdout
|
||||
and ERRFD to stderr (any of them may be -1 to connect them to
|
||||
/dev/null). The arguments for the process are expected in the NULL
|
||||
terminated array ARGV. The program name itself should not be
|
||||
included there. Calling gnupg_wait_process is required.
|
||||
|
||||
Returns 0 on success or an error code. */
|
||||
gpg_error_t
|
||||
gnupg_spawn_process_fd (const char *pgmname, const char *argv[],
|
||||
int infd, int outfd, int errfd, pid_t *pid)
|
||||
{
|
||||
#ifdef HAVE_W32_SYSTEM
|
||||
gpg_error_t err;
|
||||
SECURITY_ATTRIBUTES sec_attr;
|
||||
PROCESS_INFORMATION pi = { NULL, 0, 0, 0 };
|
||||
STARTUPINFO si;
|
||||
char *cmdline;
|
||||
int i;
|
||||
HANDLE stdhd[3];
|
||||
|
||||
/* Setup return values. */
|
||||
*pid = (pid_t)(-1);
|
||||
|
||||
/* Prepare security attributes. */
|
||||
memset (&sec_attr, 0, sizeof sec_attr );
|
||||
sec_attr.nLength = sizeof sec_attr;
|
||||
sec_attr.bInheritHandle = FALSE;
|
||||
|
||||
/* Build the command line. */
|
||||
err = build_w32_commandline (pgmname, argv, &cmdline);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
memset (&si, 0, sizeof si);
|
||||
si.cb = sizeof (si);
|
||||
si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
|
||||
si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE;
|
||||
stdhd[0] = infd == -1? w32_open_null (0) : INVALID_HANDLE_VALUE;
|
||||
stdhd[1] = outfd == -1? w32_open_null (1) : INVALID_HANDLE_VALUE;
|
||||
stdhd[2] = errfd == -1? w32_open_null (1) : INVALID_HANDLE_VALUE;
|
||||
si.hStdInput = infd == -1? stdhd[0] : (void*)_get_osfhandle (infd);
|
||||
si.hStdOutput = outfd == -1? stdhd[1] : (void*)_get_osfhandle (outfd);
|
||||
si.hStdError = errfd == -1? stdhd[2] : (void*)_get_osfhandle (errfd);
|
||||
|
||||
log_debug ("CreateProcess, path=`%s' cmdline=`%s'\n", pgmname, cmdline);
|
||||
if (!CreateProcess (pgmname, /* Program to start. */
|
||||
cmdline, /* Command line arguments. */
|
||||
&sec_attr, /* Process security attributes. */
|
||||
&sec_attr, /* Thread security attributes. */
|
||||
TRUE, /* Inherit handles. */
|
||||
(CREATE_DEFAULT_ERROR_MODE
|
||||
| GetPriorityClass (GetCurrentProcess ())
|
||||
| CREATE_SUSPENDED),
|
||||
NULL, /* Environment. */
|
||||
NULL, /* Use current drive/directory. */
|
||||
&si, /* Startup information. */
|
||||
&pi /* Returns process information. */
|
||||
))
|
||||
{
|
||||
log_error ("CreateProcess failed: %s\n", w32_strerror (-1));
|
||||
err = gpg_error (GPG_ERR_GENERAL);
|
||||
}
|
||||
else
|
||||
err = 0;
|
||||
xfree (cmdline);
|
||||
for (i=0; i < 3; i++)
|
||||
if (stdhd[i] != INVALID_HANDLE_VALUE)
|
||||
CloseHandle (stdhd[i]);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
log_debug ("CreateProcess ready: hProcess=%p hThread=%p"
|
||||
" dwProcessID=%d dwThreadId=%d\n",
|
||||
pi.hProcess, pi.hThread,
|
||||
(int) pi.dwProcessId, (int) pi.dwThreadId);
|
||||
|
||||
/* Process has been created suspended; resume it now. */
|
||||
ResumeThread (pi.hThread);
|
||||
CloseHandle (pi.hThread);
|
||||
|
||||
*pid = handle_to_pid (pi.hProcess);
|
||||
return 0;
|
||||
|
||||
#else /* !HAVE_W32_SYSTEM */
|
||||
gpg_error_t err;
|
||||
|
||||
#ifdef USE_GNU_PTH
|
||||
*pid = pth_fork? pth_fork () : fork ();
|
||||
#else
|
||||
*pid = fork ();
|
||||
#endif
|
||||
if (*pid == (pid_t)(-1))
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
log_error (_("error forking process: %s\n"), strerror (errno));
|
||||
return err;
|
||||
}
|
||||
|
||||
if (!*pid)
|
||||
{
|
||||
gcry_control (GCRYCTL_TERM_SECMEM);
|
||||
/* Run child. */
|
||||
do_exec (pgmname, argv, infd, outfd, errfd, NULL);
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
return 0;
|
||||
#endif /* !HAVE_W32_SYSTEM */
|
||||
}
|
||||
|
||||
|
||||
/* Wait for the process identified by PID to terminate. PGMNAME should
|
||||
be the same as suplieed to the spawn fucntion and is only used for
|
||||
diagnostics. Returns 0 if the process succeded, GPG_ERR_GENERAL for
|
||||
@ -483,6 +613,7 @@ gnupg_wait_process (const char *pgmname, pid_t pid)
|
||||
}
|
||||
else
|
||||
ec = 0;
|
||||
CloseHandle (proc);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -28,16 +28,31 @@
|
||||
arguments for the process are expected in the NULL terminated array
|
||||
ARGV. The program name itself should not be included there. if
|
||||
PREEXEC is not NULL, that function will be called right before the
|
||||
exec. Returns 0 on success or an error code. */
|
||||
exec. Calling gnupg_wait_process is required. Returns 0 on
|
||||
success or an error code. */
|
||||
gpg_error_t gnupg_spawn_process (const char *pgmname, const char *argv[],
|
||||
FILE *infile, FILE *outfile,
|
||||
void (*preexec)(void),
|
||||
FILE **statusfile, pid_t *pid);
|
||||
|
||||
|
||||
/* Simplified version of gnupg_spawn_process. This function forks and
|
||||
then execs PGMNAME, while connecting INFD to stdin, OUTFD to stdout
|
||||
and ERRFD to stderr (any of them may be -1 to connect them to
|
||||
/dev/null). The arguments for the process are expected in the NULL
|
||||
terminated array ARGV. The program name itself should not be
|
||||
included there. Calling gnupg_wait_process is required. Returns 0
|
||||
on success or an error code. */
|
||||
gpg_error_t gnupg_spawn_process_fd (const char *pgmname,
|
||||
const char *argv[],
|
||||
int infd, int outfd, int errfd,
|
||||
pid_t *pid);
|
||||
|
||||
|
||||
/* Wait for the process identified by PID to terminate. PGMNAME should
|
||||
be the same as suplieed to the spawn fucntion and is only used for
|
||||
diagnostics. Returns 0 if the process succeded, GPG_ERR_GENERAL for
|
||||
any failures of the spawned program or other error codes.*/
|
||||
be the same as supplied to the spawn fucntion and is only used for
|
||||
diagnostics. Returns 0 if the process succeded, GPG_ERR_GENERAL
|
||||
for any failures of the spawned program or other error codes.*/
|
||||
gpg_error_t gnupg_wait_process (const char *pgmname, pid_t pid);
|
||||
|
||||
|
||||
|
@ -369,6 +369,9 @@ gnupg_module_name (int which)
|
||||
X(libexecdir, "gpg-protect-tool");
|
||||
#endif
|
||||
|
||||
case GNUPG_MODULE_NAME_CHECK_PATTERN:
|
||||
X(libexecdir, "gpg-check-pattern");
|
||||
|
||||
default:
|
||||
BUG ();
|
||||
}
|
||||
|
@ -185,6 +185,7 @@ const char *dirmngr_socket_name (void);
|
||||
#define GNUPG_MODULE_NAME_SCDAEMON 3
|
||||
#define GNUPG_MODULE_NAME_DIRMNGR 4
|
||||
#define GNUPG_MODULE_NAME_PROTECT_TOOL 5
|
||||
#define GNUPG_MODULE_NAME_CHECK_PATTERN 6
|
||||
const char *gnupg_module_name (int which);
|
||||
|
||||
|
||||
|
63
configure.ac
63
configure.ac
@ -1025,7 +1025,6 @@ GNUPG_FUNC_MKDIR_TAKES_ONE_ARG
|
||||
|
||||
#
|
||||
# Sanity check regex. Tests adapted from mutt.
|
||||
# FIXME: We should use the the regex from gnulib
|
||||
#
|
||||
AC_MSG_CHECKING([whether regular expression support is requested])
|
||||
AC_ARG_ENABLE(regex,
|
||||
@ -1035,20 +1034,28 @@ AC_ARG_ENABLE(regex,
|
||||
AC_MSG_RESULT($use_regex)
|
||||
|
||||
if test "$use_regex" = yes ; then
|
||||
AC_MSG_CHECKING([whether the included regex lib is requested])
|
||||
AC_ARG_WITH(included-regex,
|
||||
[ --with-included-regex use the included GNU regex library],
|
||||
[gnupg_cv_included_regex="$withval"],[gnupg_cv_included_regex=no])
|
||||
AC_MSG_RESULT($gnupg_cv_included_regex)
|
||||
_cppflags="${CPPFLAGS}"
|
||||
_ldflags="${LDFLAGS}"
|
||||
AC_ARG_WITH(regex,
|
||||
AC_HELP_STRING([--with-regex=DIR],[look for regex in DIR]),
|
||||
[
|
||||
if test -d "$withval" ; then
|
||||
CPPFLAGS="${CPPFLAGS} -I$withval/include"
|
||||
LDFLAGS="${LDFLAGS} -L$withval/lib"
|
||||
fi
|
||||
],withval="")
|
||||
|
||||
if test $gnupg_cv_included_regex = no ; then
|
||||
# Does the system have regex functions at all?
|
||||
AC_CHECK_FUNC(regcomp,gnupg_cv_included_regex=no,
|
||||
gnupg_cv_included_regex=yes)
|
||||
fi
|
||||
# Does the system have regex functions at all?
|
||||
AC_SEARCH_LIBS([regcomp], [regex])
|
||||
AC_CHECK_FUNC(regcomp, gnupg_cv_have_regex=yes, gnupg_cv_have_regex=no)
|
||||
|
||||
if test $gnupg_cv_included_regex = no ; then
|
||||
AC_CACHE_CHECK([whether your system's regexp library is broken],
|
||||
if test $gnupg_cv_have_regex = no; then
|
||||
use_regex=no
|
||||
else
|
||||
if test x"$cross_compiling" = xyes; then
|
||||
AC_MSG_WARN([cross compiling; assuming regexp libray is not broken])
|
||||
else
|
||||
AC_CACHE_CHECK([whether your system's regexp library is broken],
|
||||
[gnupg_cv_regex_broken],
|
||||
AC_TRY_RUN([
|
||||
#include <unistd.h>
|
||||
@ -1056,20 +1063,20 @@ if test "$use_regex" = yes ; then
|
||||
main() { regex_t blah ; regmatch_t p; p.rm_eo = p.rm_eo; return regcomp(&blah, "foo.*bar", REG_NOSUB) || regexec (&blah, "foobar", 0, NULL, 0); }],
|
||||
gnupg_cv_regex_broken=no, gnupg_cv_regex_broken=yes, gnupg_cv_regex_broken=yes))
|
||||
|
||||
if test $gnupg_cv_regex_broken = yes ; then
|
||||
AC_MSG_WARN(your regex is broken - using the included GNU regex instead.)
|
||||
gnupg_cv_included_regex=yes
|
||||
fi
|
||||
if test $gnupg_cv_regex_broken = yes; then
|
||||
AC_MSG_WARN([your regex is broken - disabling regex use])
|
||||
use_regex=no
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if test $gnupg_cv_included_regex = yes; then
|
||||
AC_DEFINE(USE_INTERNAL_REGEX,1,[ Define if you want to use the included regex lib ])
|
||||
fi
|
||||
else
|
||||
AC_DEFINE(DISABLE_REGEX,1,[ Define to disable regular expression support ])
|
||||
CPPFLAGS="${_cppflags}"
|
||||
LDFLAGS="${_ldflags}"
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL(USE_INTERNAL_REGEX, test x"$gnupg_cv_included_regex" = xyes)
|
||||
if test "$use_regex" != yes ; then
|
||||
AC_DEFINE(DISABLE_REGEX,1, [Define to disable regular expression support])
|
||||
fi
|
||||
AM_CONDITIONAL(DISABLE_REGEX, test x"$use_regex" != xyes)
|
||||
|
||||
|
||||
|
||||
@ -1397,6 +1404,12 @@ echo "
|
||||
Default scdaemon: $show_gnupg_scdaemon_pgm
|
||||
Default dirmngr: $show_gnupg_dirmngr_pgm
|
||||
|
||||
PKITS based tests: $run_pkits_tests
|
||||
PKITS based tests: $run_pkits_tests"
|
||||
if test x"$use_regex" != xyes ; then
|
||||
echo "
|
||||
Warning: No regular expression support available.
|
||||
OpenPGP trust signatures won't work.
|
||||
gpg-check-pattern will not be build.
|
||||
"
|
||||
fi
|
||||
|
||||
|
@ -1,3 +1,7 @@
|
||||
2007-08-27 Werner Koch <wk@g10code.com>
|
||||
|
||||
* examples/pwpattern.list: New.
|
||||
|
||||
2007-08-24 Werner Koch <wk@g10code.com>
|
||||
|
||||
* debugging.texi (Common Problems): Add "A root certifciate does
|
||||
|
@ -18,7 +18,7 @@
|
||||
## Process this file with automake to produce Makefile.in
|
||||
|
||||
examples = examples/README examples/scd-event examples/trustlist.txt \
|
||||
examples/gpgconf.conf
|
||||
examples/gpgconf.conf examples/pwpattern.list
|
||||
|
||||
EXTRA_DIST = DETAILS HACKING TRANSLATE OpenPGP KEYSERVER samplekeys.asc \
|
||||
gnupg-logo.eps gnupg-logo.pdf gnupg-logo.png \
|
||||
|
48
doc/examples/pwpattern.list
Normal file
48
doc/examples/pwpattern.list
Normal file
@ -0,0 +1,48 @@
|
||||
# pwpattern.list -*- default-generic -*-
|
||||
#
|
||||
# This is an example for a pattern file as used by gpg-check-pattern.
|
||||
# The file is line based with comment lines beginning on the *first*
|
||||
# position with a '#'. Empty lines and lines with just spaces are
|
||||
# ignored. The other lines may be verbatim patterns and match as they
|
||||
# are (trailing spaces are ignored) or extended regular expressions
|
||||
# indicated by a / in the first column and terminated by another / or
|
||||
# end of line. All comparisons are case insensitive.
|
||||
|
||||
# Reject the usual metavariables. Usual not required because
|
||||
# gpg-agent can be used to reject all passphrases shorter than 8
|
||||
# charactes.
|
||||
foo
|
||||
bar
|
||||
baz
|
||||
|
||||
# As well as very common passwords. Note that gpg-agent can be used
|
||||
# to reject them due to missing non-alpha characters.
|
||||
password
|
||||
passwort
|
||||
passphrase
|
||||
mantra
|
||||
test
|
||||
abc
|
||||
egal
|
||||
|
||||
# German number plates.
|
||||
/^[A-Z]{1,3}[ ]*-[ ]*[A-Z]{1,2}[ ]*[0-9]+/
|
||||
|
||||
# Dates (very limited, only ISO dates). */
|
||||
/^[012][0-9][0-9][0-9]-[012][0-9]-[0123][0-9]$/
|
||||
|
||||
# Arbitrary strings
|
||||
the quick brown fox jumps over the lazy dogs back
|
||||
no-password
|
||||
no password
|
||||
|
||||
12345678
|
||||
123456789
|
||||
1234567890
|
||||
87654321
|
||||
987654321
|
||||
0987654321
|
||||
qwertyuiop
|
||||
qwertzuiop
|
||||
asdfghjkl
|
||||
zxcvbnm
|
@ -334,11 +334,38 @@ Set the maximum time a cache entry used for SSH keys is valid to @var{n}
|
||||
seconds. After this time a cache entry will get expired even if it has
|
||||
been accessed recently. The default are 2 hours (7200 seconds).
|
||||
|
||||
@item --enforce-passphrase-constraints
|
||||
@opindex enforce-passphrase-constraints
|
||||
Enforce the passphrase constraints by not allowing the user to bypass
|
||||
them using the ``Take it anyway'' button.
|
||||
|
||||
@item --min-passphrase-len @var{n}
|
||||
@opindex min-passphrase-len
|
||||
Set the minimal length of a passphrase. When entering a new passphrase
|
||||
shorter than this value a warning will be displayed. Defaults to 8.
|
||||
|
||||
@item --min-passphrase-nonalpha @var{n}
|
||||
@opindex min-passphrase-nonalpha
|
||||
Set the minimal number of digits or special characters required in a
|
||||
passphrase. When entering a new passphrase with less than this number
|
||||
of digits or special characters a warning will be displayed. Defaults
|
||||
to 1.
|
||||
|
||||
@item --check-passphrase-pattern @var{file}
|
||||
@opindex check-passphrase-pattern
|
||||
Check the passphrase against the pattern given in @var{file}. When
|
||||
entering a new passphrase matching one of these pattern a warning will
|
||||
be displayed. @var{file} should be an absolute filename. The default is
|
||||
not to use any pattern file.
|
||||
|
||||
Security note: It is known that checking a passphrase against a list of
|
||||
pattern or even against a complete dictionary is not very effective to
|
||||
enforce good passphrases. Users will soon figure up ways to bypass such
|
||||
a policy. A better policy is to educate users on good security
|
||||
behavior and optional to run a passphrase cracker regularly on all
|
||||
users passphrases t catch the very simple ones.
|
||||
|
||||
|
||||
@item --pinentry-program @var{filename}
|
||||
@opindex pinentry-program
|
||||
Use program @var{filename} as the PIN entry. The default is installation
|
||||
|
@ -1,3 +1,7 @@
|
||||
2007-08-27 Werner Koch <wk@g10code.com>
|
||||
|
||||
* trustdb.c (USE_INTERNAL_REGEX): Remove support.
|
||||
|
||||
2007-08-24 Werner Koch <wk@g10code.com>
|
||||
|
||||
* keyring.c (keyring_register_filename): Use same_file_p().
|
||||
|
@ -26,11 +26,7 @@
|
||||
|
||||
#ifndef DISABLE_REGEX
|
||||
#include <sys/types.h>
|
||||
#ifdef USE_INTERNAL_REGEX
|
||||
#include "_regex.h"
|
||||
#else
|
||||
#include <regex.h>
|
||||
#endif
|
||||
#endif /* !DISABLE_REGEX */
|
||||
|
||||
#include "gpg.h"
|
||||
|
@ -339,7 +339,7 @@ make_filename( const char *first_part, ... )
|
||||
|
||||
|
||||
/* Compare whether the filenames are identical. This is a
|
||||
specialversion of strcmp() taking the semantics of filenames in
|
||||
special version of strcmp() taking the semantics of filenames in
|
||||
account. Note that this function works only on the supplied names
|
||||
without considereing any context like the current directory. See
|
||||
also same_file_p(). */
|
||||
|
@ -1,3 +1,7 @@
|
||||
2007-08-24 Werner Koch <wk@g10code.com>
|
||||
|
||||
* Makefile.am (common_libs): Swap libkeybox and jnlib.
|
||||
|
||||
2007-08-23 Werner Koch <wk@g10code.com>
|
||||
|
||||
* certlist.c (gpgsm_certs_identical_p): New.
|
||||
|
@ -52,7 +52,7 @@ gpgsm_SOURCES = \
|
||||
qualified.c
|
||||
|
||||
|
||||
common_libs = $(libcommon) ../jnlib/libjnlib.a ../kbx/libkeybox.a \
|
||||
common_libs = $(libcommon) ../kbx/libkeybox.a ../jnlib/libjnlib.a \
|
||||
../gl/libgnu.a
|
||||
|
||||
gpgsm_LDADD = $(common_libs) ../common/libgpgrl.a \
|
||||
|
@ -1,3 +1,15 @@
|
||||
2007-08-27 Werner Koch <wk@g10code.com>
|
||||
|
||||
* gpg-check-pattern.c: New
|
||||
* Makefile.am (libexec_PROGRAMS): Add unless DISABLE_REGEX.
|
||||
|
||||
2007-08-24 Werner Koch <wk@g10code.com>
|
||||
|
||||
* gpgconf-comp.c <gpg-agent>: Add options --check-passphrase-pattern,
|
||||
--min-passphrase-nonalpha and --enforce-passphrase-constraints and
|
||||
move them into a new "passphrase policy" group.
|
||||
(gc_component) [W32]: Enable dirmngr.
|
||||
|
||||
2007-08-21 Werner Koch <wk@g10code.com>
|
||||
|
||||
* gpgkey2ssh.c (key_to_blob): Use gnupg_tmpfile().
|
||||
|
@ -46,6 +46,10 @@ if !HAVE_W32_SYSTEM
|
||||
bin_PROGRAMS += watchgnupg gpgparsemail
|
||||
endif
|
||||
|
||||
if !DISABLE_REGEX
|
||||
libexec_PROGRAMS = gpg-check-pattern
|
||||
endif
|
||||
|
||||
noinst_PROGRAMS = clean-sat mk-tdata make-dns-cert gpgsplit
|
||||
|
||||
common_libs = $(libcommon) ../jnlib/libjnlib.a ../gl/libgnu.a
|
||||
@ -86,6 +90,13 @@ gpgkey2ssh_LDADD = $(common_libs) \
|
||||
$(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) $(LIBINTL) $(LIBICONV)
|
||||
|
||||
|
||||
if !DISABLE_REGEX
|
||||
gpg_check_pattern_SOURCES = gpg-check-pattern.c
|
||||
gpg_check_pattern_CFLAGS = $(LIBGCRYPT_CFLAGS) $(GPG_ERROR_CFLAGS)
|
||||
gpg_check_pattern_LDADD = $(common_libs) $(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) \
|
||||
$(LIBINTL) $(LIBICONV) $(W32SOCKLIBS)
|
||||
endif
|
||||
|
||||
# Make sure that all libs are build before we use them. This is
|
||||
# important for things like make -j2.
|
||||
$(PROGRAMS): $(common_libs) $(pwquery_libs)
|
||||
|
504
tools/gpg-check-pattern.c
Normal file
504
tools/gpg-check-pattern.c
Normal file
@ -0,0 +1,504 @@
|
||||
/* gpg-check-pattern.c - A tool to check passphrases against pattern.
|
||||
* Copyright (C) 2007 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
* GnuPG is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GnuPG is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#ifdef HAVE_LOCALE_H
|
||||
# include <locale.h>
|
||||
#endif
|
||||
#ifdef HAVE_LANGINFO_CODESET
|
||||
# include <langinfo.h>
|
||||
#endif
|
||||
#ifdef HAVE_DOSISH_SYSTEM
|
||||
# include <fcntl.h> /* for setmode() */
|
||||
#endif
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <regex.h>
|
||||
#include <ctype.h>
|
||||
|
||||
|
||||
#define JNLIB_NEED_LOG_LOGV
|
||||
#include "util.h"
|
||||
#include "i18n.h"
|
||||
#include "sysutils.h"
|
||||
|
||||
|
||||
enum cmd_and_opt_values
|
||||
{ aNull = 0,
|
||||
oVerbose = 'v',
|
||||
oArmor = 'a',
|
||||
oPassphrase = 'P',
|
||||
|
||||
oProtect = 'p',
|
||||
oUnprotect = 'u',
|
||||
oNull = '0',
|
||||
|
||||
oNoVerbose = 500,
|
||||
oCheck,
|
||||
|
||||
oHomedir
|
||||
};
|
||||
|
||||
|
||||
/* The list of commands and options. */
|
||||
static ARGPARSE_OPTS opts[] = {
|
||||
|
||||
{ 301, NULL, 0, N_("@Options:\n ") },
|
||||
|
||||
{ oVerbose, "verbose", 0, "verbose" },
|
||||
|
||||
{ oHomedir, "homedir", 2, "@" },
|
||||
{ oCheck, "check", 0, "run only a syntax check on the patternfile" },
|
||||
{ oNull, "null", 0, "input is expected to be null delimited" },
|
||||
|
||||
{0}
|
||||
};
|
||||
|
||||
|
||||
/* Global options are accessed through the usual OPT structure. */
|
||||
static struct
|
||||
{
|
||||
int verbose;
|
||||
const char *homedir;
|
||||
int checkonly;
|
||||
int null;
|
||||
} opt;
|
||||
|
||||
|
||||
enum {
|
||||
PAT_NULL, /* Indicates end of the array. */
|
||||
PAT_STRING, /* The pattern is a simple string. */
|
||||
PAT_REGEX /* The pattern is an extended regualr expression. */
|
||||
};
|
||||
|
||||
|
||||
/* An object to decibe an item of our pattern table. */
|
||||
struct pattern_s
|
||||
{
|
||||
int type;
|
||||
unsigned int lineno; /* Line number of the pattern file. */
|
||||
union {
|
||||
struct {
|
||||
const char *string; /* Pointer to the actual string (nul termnated). */
|
||||
size_t length; /* The length of this string (strlen). */
|
||||
} s; /*PAT_STRING*/
|
||||
struct {
|
||||
/* We allocate the regex_t because this type is larger than what
|
||||
we need for PAT_STRING and we expect only a few regex in a
|
||||
patternfile. It would be a waste of core to have so many
|
||||
unused stuff in the table. */
|
||||
regex_t *regex;
|
||||
} r; /*PAT_REGEX*/
|
||||
} u;
|
||||
};
|
||||
typedef struct pattern_s pattern_t;
|
||||
|
||||
|
||||
|
||||
/*** Local prototypes ***/
|
||||
static char *read_file (const char *fname, size_t *r_length);
|
||||
static pattern_t *parse_pattern_file (char *data, size_t datalen);
|
||||
static void process (FILE *fp, pattern_t *patarray);
|
||||
|
||||
|
||||
|
||||
|
||||
/* Info function for usage(). */
|
||||
static const char *
|
||||
my_strusage (int level)
|
||||
{
|
||||
const char *p;
|
||||
switch (level)
|
||||
{
|
||||
case 11: p = "gpg-check-pattern (GnuPG)";
|
||||
break;
|
||||
case 13: p = VERSION; break;
|
||||
case 17: p = PRINTABLE_OS_NAME; break;
|
||||
case 19: p = _("Please report bugs to <" PACKAGE_BUGREPORT ">.\n");
|
||||
break;
|
||||
case 1:
|
||||
case 40:
|
||||
p = _("Usage: gpg-check-pattern [options] patternfile (-h for help)\n");
|
||||
break;
|
||||
case 41:
|
||||
p = _("Syntax: gpg-check-pattern [options] patternfile\n"
|
||||
"Check a passphrase given on stdin against the patternfile\n");
|
||||
break;
|
||||
|
||||
default: p = NULL;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main (int argc, char **argv )
|
||||
{
|
||||
ARGPARSE_ARGS pargs;
|
||||
char *raw_pattern;
|
||||
size_t raw_pattern_length;
|
||||
pattern_t *patternarray;
|
||||
|
||||
set_strusage (my_strusage);
|
||||
gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
|
||||
log_set_prefix ("gpg-check-pattern", 1);
|
||||
|
||||
/* Make sure that our subsystems are ready. */
|
||||
init_common_subsystems ();
|
||||
|
||||
i18n_init ();
|
||||
|
||||
/* We need Libgcrypt for hashing. */
|
||||
if (!gcry_check_version (NEED_LIBGCRYPT_VERSION) )
|
||||
{
|
||||
log_fatal ( _("%s is too old (need %s, have %s)\n"), "libgcrypt",
|
||||
NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) );
|
||||
}
|
||||
|
||||
setup_libgcrypt_logging ();
|
||||
gcry_control (GCRYCTL_INIT_SECMEM, 4096, 0);
|
||||
|
||||
opt.homedir = default_homedir ();
|
||||
|
||||
pargs.argc = &argc;
|
||||
pargs.argv = &argv;
|
||||
pargs.flags= 1; /* (do not remove the args) */
|
||||
while (arg_parse (&pargs, opts) )
|
||||
{
|
||||
switch (pargs.r_opt)
|
||||
{
|
||||
case oVerbose: opt.verbose++; break;
|
||||
case oHomedir: opt.homedir = pargs.r.ret_str; break;
|
||||
case oCheck: opt.checkonly = 1; break;
|
||||
case oNull: opt.null = 1; break;
|
||||
|
||||
default : pargs.err = 2; break;
|
||||
}
|
||||
}
|
||||
if (log_get_errorcount(0))
|
||||
exit (2);
|
||||
|
||||
if (argc != 1)
|
||||
usage (1);
|
||||
|
||||
/* We read the entire pattern file into our memory and parse it
|
||||
using a separate function. This allows us to eventual do the
|
||||
reading while running setuid so that the pattern file can be
|
||||
hidden from regular users. I am not sure whether this makes
|
||||
sense, but lets be prepared for it. */
|
||||
raw_pattern = read_file (*argv, &raw_pattern_length);
|
||||
if (!raw_pattern)
|
||||
exit (2);
|
||||
|
||||
patternarray = parse_pattern_file (raw_pattern, raw_pattern_length);
|
||||
if (!patternarray)
|
||||
exit (1);
|
||||
if (opt.checkonly)
|
||||
return 0;
|
||||
|
||||
#ifdef HAVE_DOSISH_SYSTEM
|
||||
setmode (fileno (stdin) , O_BINARY );
|
||||
#endif
|
||||
process (stdin, patternarray);
|
||||
|
||||
return log_get_errorcount(0)? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Read a file FNAME into a buffer and return that malloced buffer.
|
||||
Caller must free the buffer. On error NULL is returned, on success
|
||||
the valid length of the buffer is stored at R_LENGTH. The returned
|
||||
buffer is guarnteed to be nul terminated. */
|
||||
static char *
|
||||
read_file (const char *fname, size_t *r_length)
|
||||
{
|
||||
FILE *fp;
|
||||
char *buf;
|
||||
size_t buflen;
|
||||
|
||||
if (!strcmp (fname, "-"))
|
||||
{
|
||||
size_t nread, bufsize = 0;
|
||||
|
||||
fp = stdin;
|
||||
#ifdef HAVE_DOSISH_SYSTEM
|
||||
setmode ( fileno(fp) , O_BINARY );
|
||||
#endif
|
||||
buf = NULL;
|
||||
buflen = 0;
|
||||
#define NCHUNK 8192
|
||||
do
|
||||
{
|
||||
bufsize += NCHUNK;
|
||||
if (!buf)
|
||||
buf = xmalloc (bufsize+1);
|
||||
else
|
||||
buf = xrealloc (buf, bufsize+1);
|
||||
|
||||
nread = fread (buf+buflen, 1, NCHUNK, fp);
|
||||
if (nread < NCHUNK && ferror (fp))
|
||||
{
|
||||
log_error ("error reading `[stdin]': %s\n", strerror (errno));
|
||||
xfree (buf);
|
||||
return NULL;
|
||||
}
|
||||
buflen += nread;
|
||||
}
|
||||
while (nread == NCHUNK);
|
||||
#undef NCHUNK
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
fp = fopen (fname, "rb");
|
||||
if (!fp)
|
||||
{
|
||||
log_error ("can't open `%s': %s\n", fname, strerror (errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (fstat (fileno(fp), &st))
|
||||
{
|
||||
log_error ("can't stat `%s': %s\n", fname, strerror (errno));
|
||||
fclose (fp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buflen = st.st_size;
|
||||
buf = xmalloc (buflen+1);
|
||||
if (fread (buf, buflen, 1, fp) != 1)
|
||||
{
|
||||
log_error ("error reading `%s': %s\n", fname, strerror (errno));
|
||||
fclose (fp);
|
||||
xfree (buf);
|
||||
return NULL;
|
||||
}
|
||||
fclose (fp);
|
||||
}
|
||||
buf[buflen] = 0;
|
||||
*r_length = buflen;
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static char *
|
||||
get_regerror (int errcode, regex_t *compiled)
|
||||
{
|
||||
size_t length = regerror (errcode, compiled, NULL, 0);
|
||||
char *buffer = xmalloc (length);
|
||||
regerror (errcode, compiled, buffer, length);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/* Parse the pattern given in the memory aread DATA/DATALEN and return
|
||||
a new pattern array. The end of the array is indicated by a NULL
|
||||
entry. On error an error message is printed and the fucntion
|
||||
returns NULL. Note that the function modifies DATA and assumes
|
||||
that data is nul terminated (even if this is one byte past
|
||||
DATALEN). */
|
||||
static pattern_t *
|
||||
parse_pattern_file (char *data, size_t datalen)
|
||||
{
|
||||
char *p, *p2;
|
||||
size_t n;
|
||||
pattern_t *array;
|
||||
size_t arraysize, arrayidx;
|
||||
unsigned int lineno = 0;
|
||||
|
||||
/* Estimate the number of entries by counting the non-comment lines. */
|
||||
arraysize = 0;
|
||||
p = data;
|
||||
for (n = datalen; n && (p2 = memchr (p, '\n', n)); p2++, n -= p2 - p, p = p2)
|
||||
if (*p != '#')
|
||||
arraysize++;
|
||||
arraysize += 2; /* For the terminating NULL and a last line w/o a LF. */
|
||||
|
||||
array = xcalloc (arraysize, sizeof *array);
|
||||
arrayidx = 0;
|
||||
|
||||
/* Loop over all lines. */
|
||||
while (datalen && data)
|
||||
{
|
||||
lineno++;
|
||||
p = data;
|
||||
p2 = data = memchr (p, '\n', datalen);
|
||||
if (p2)
|
||||
{
|
||||
*data++ = 0;
|
||||
datalen -= data - p;
|
||||
}
|
||||
else
|
||||
p2 = p + datalen;
|
||||
assert (!*p2);
|
||||
p2--;
|
||||
while (isascii (*p) && isspace (*p))
|
||||
p++;
|
||||
if (*p == '#')
|
||||
continue;
|
||||
while (p2 > p && isascii (*p2) && isspace (*p2))
|
||||
*p2-- = 0;
|
||||
if (!*p)
|
||||
continue;
|
||||
assert (arrayidx < arraysize);
|
||||
array[arrayidx].lineno = lineno;
|
||||
if (*p == '/')
|
||||
{
|
||||
int rerr;
|
||||
|
||||
p++;
|
||||
array[arrayidx].type = PAT_REGEX;
|
||||
if (*p && p[strlen(p)-1] == '/')
|
||||
p[strlen(p)-1] = 0; /* Remove optional delimiter. */
|
||||
array[arrayidx].u.r.regex = xcalloc (1, sizeof (regex_t));
|
||||
rerr = regcomp (array[arrayidx].u.r.regex, p,
|
||||
REG_ICASE|REG_NOSUB|REG_EXTENDED);
|
||||
if (rerr)
|
||||
{
|
||||
char *rerrbuf = get_regerror (rerr, array[arrayidx].u.r.regex);
|
||||
log_error ("invalid r.e. at line %u: %s\n", lineno, rerrbuf);
|
||||
xfree (rerrbuf);
|
||||
if (!opt.checkonly)
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
array[arrayidx].type = PAT_STRING;
|
||||
array[arrayidx].u.s.string = p;
|
||||
array[arrayidx].u.s.length = strlen (p);
|
||||
}
|
||||
arrayidx++;
|
||||
}
|
||||
assert (arrayidx < arraysize);
|
||||
array[arrayidx].type = PAT_NULL;
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
|
||||
/* Check whether string macthes any of the pattern in PATARRAY and
|
||||
returns the matching pattern item or NULL. */
|
||||
static pattern_t *
|
||||
match_p (const char *string, pattern_t *patarray)
|
||||
{
|
||||
pattern_t *pat;
|
||||
|
||||
if (!*string)
|
||||
{
|
||||
if (opt.verbose)
|
||||
log_info ("zero length input line - ignored\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (pat = patarray; pat->type != PAT_NULL; pat++)
|
||||
{
|
||||
if (pat->type == PAT_STRING)
|
||||
{
|
||||
if (!strcasecmp (pat->u.s.string, string))
|
||||
return pat;
|
||||
}
|
||||
else if (pat->type == PAT_REGEX)
|
||||
{
|
||||
int rerr;
|
||||
|
||||
rerr = regexec (pat->u.r.regex, string, 0, NULL, 0);
|
||||
if (!rerr)
|
||||
return pat;
|
||||
else if (rerr != REG_NOMATCH)
|
||||
{
|
||||
char *rerrbuf = get_regerror (rerr, pat->u.r.regex);
|
||||
log_error ("matching r.e. failed: %s\n", rerrbuf);
|
||||
xfree (rerrbuf);
|
||||
return pat; /* Better indicate a match on error. */
|
||||
}
|
||||
}
|
||||
else
|
||||
BUG ();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Actual processing of the input. This fucntion does not return an
|
||||
error code but exits as soon as a match has been found. */
|
||||
static void
|
||||
process (FILE *fp, pattern_t *patarray)
|
||||
{
|
||||
char buffer[2048];
|
||||
size_t idx;
|
||||
int c;
|
||||
unsigned long lineno = 0;
|
||||
pattern_t *pat;
|
||||
|
||||
idx = 0;
|
||||
c = 0;
|
||||
while (idx < sizeof buffer -1 && c != EOF )
|
||||
{
|
||||
if ((c = getc (fp)) != EOF)
|
||||
buffer[idx] = c;
|
||||
if ((c == '\n' && !opt.null) || (!c && opt.null) || c == EOF)
|
||||
{
|
||||
lineno++;
|
||||
if (!opt.null)
|
||||
{
|
||||
while (idx && isascii (buffer[idx-1]) && isspace (buffer[idx-1]))
|
||||
idx--;
|
||||
}
|
||||
buffer[idx] = 0;
|
||||
pat = match_p (buffer, patarray);
|
||||
if (pat)
|
||||
{
|
||||
if (opt.verbose)
|
||||
log_error ("input line %lu matches pattern at line %u"
|
||||
" - rejected\n",
|
||||
lineno, pat->lineno);
|
||||
exit (1);
|
||||
}
|
||||
idx = 0;
|
||||
}
|
||||
else
|
||||
idx++;
|
||||
}
|
||||
if (c != EOF)
|
||||
{
|
||||
log_error ("input line %lu too long - rejected\n", lineno+1);
|
||||
exit (1);
|
||||
}
|
||||
if (ferror (fp))
|
||||
{
|
||||
log_error ("input read error at line %lu: %s - rejected\n",
|
||||
lineno+1, strerror (errno));
|
||||
exit (1);
|
||||
}
|
||||
if (opt.verbose)
|
||||
log_info ("no input line matches the pattern - accepted\n");
|
||||
}
|
||||
|
@ -505,14 +505,30 @@ static gc_option_t gc_options_gpg_agent[] =
|
||||
{ "allow-mark-trusted", GC_OPT_FLAG_RUNTIME,
|
||||
GC_LEVEL_ADVANCED, "gnupg", "allow clients to mark keys as \"trusted\"",
|
||||
GC_ARG_TYPE_NONE, GC_BACKEND_GPG_AGENT },
|
||||
{ "min-passphrase-len", GC_OPT_FLAG_RUNTIME,
|
||||
GC_LEVEL_EXPERT, "gnupg",
|
||||
N_("|N|set minimal required length for new passphrases to N"),
|
||||
GC_ARG_TYPE_UINT32, GC_BACKEND_GPG_AGENT },
|
||||
{ "no-grab", GC_OPT_FLAG_RUNTIME, GC_LEVEL_EXPERT,
|
||||
"gnupg", "do not grab keyboard and mouse",
|
||||
GC_ARG_TYPE_NONE, GC_BACKEND_GPG_AGENT },
|
||||
|
||||
{ "Passphrase policy",
|
||||
GC_OPT_FLAG_GROUP, GC_LEVEL_ADVANCED,
|
||||
"gnupg", N_("Options enforcing a passphrase policy") },
|
||||
{ "enforce-passphrases-constraints", GC_OPT_FLAG_RUNTIME,
|
||||
GC_LEVEL_EXPERT, "gnupg",
|
||||
N_("do not allow to bypass the passphrase policy"),
|
||||
GC_ARG_TYPE_NONE, GC_BACKEND_GPG_AGENT },
|
||||
{ "min-passphrase-len", GC_OPT_FLAG_RUNTIME,
|
||||
GC_LEVEL_ADVANCED, "gnupg",
|
||||
N_("|N|set minimal required length for new passphrases to N"),
|
||||
GC_ARG_TYPE_UINT32, GC_BACKEND_GPG_AGENT },
|
||||
{ "min-passphrase-nonalpha", GC_OPT_FLAG_RUNTIME,
|
||||
GC_LEVEL_EXPERT, "gnupg",
|
||||
N_("|N|require at least N non-alpha characters for a new passphrase"),
|
||||
GC_ARG_TYPE_UINT32, GC_BACKEND_GPG_AGENT },
|
||||
{ "check-passphrase-pattern", GC_OPT_FLAG_RUNTIME,
|
||||
GC_LEVEL_EXPERT,
|
||||
"gnupg", N_("|FILE|check new passphrases against pattern in FILE"),
|
||||
GC_ARG_TYPE_PATHNAME, GC_BACKEND_SCDAEMON },
|
||||
|
||||
GC_OPTION_NULL
|
||||
};
|
||||
|
||||
@ -915,9 +931,7 @@ static struct
|
||||
{ "gpg-agent", NULL, "GPG Agent", gc_options_gpg_agent },
|
||||
{ "scdaemon", NULL, "Smartcard Daemon", gc_options_scdaemon },
|
||||
{ "gpgsm", NULL, "GPG for S/MIME", gc_options_gpgsm },
|
||||
#ifndef HAVE_W32_SYSTEM
|
||||
{ "dirmngr", NULL, "Directory Manager", gc_options_dirmngr }
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user