Add option --card-timeout.

Add a new attribyte to app-openpgp.c
Fix two portability bugs.
Have gpg-connect-agent autostart gpg-agent on W32.
This commit is contained in:
Werner Koch 2008-12-05 12:01:01 +00:00
parent 0ec678b2af
commit 041c764672
43 changed files with 6804 additions and 6553 deletions

6
TODO
View File

@ -63,7 +63,11 @@
would be better to do this just at one place. First we need to see
how we can support cards with multiple applications.
** Resolve fixme in do_sign of app-dinsig.
** Disconnect
Card timeout is currently used as a boolean.
Add disconnect support for the ccid driver.
* Regression tests
** Add a regression test to check the extkeyusage.
* Windows port (W32)
@ -75,8 +79,6 @@
* sm/
** check that we issue NO_SECKEY xxx if a -u key was not found
We don't. The messages returned are also wrong (recipient vs. signer).
** gpgsm_format_name2
Replace by an estream based implementation.
* jnlib/
** Try to remove all jnlib_xmalloc.

View File

@ -1,3 +1,9 @@
2008-12-05 Werner Koch <wk@g10code.com>
* minip12.c (decrypt_block): Fix const modified of CHARSETS.
* learncard.c (sinfo_cb_parm_s): Remove superflous semicolon.
Reported by Stoyan Angelov.
2008-11-18 Werner Koch <wk@g10code.com>
* gpg-agent.c (make_libversion): New.

View File

@ -76,7 +76,7 @@ struct sinfo_s {
typedef struct sinfo_s *SINFO;
struct sinfo_cb_parm_s {
int error;;
int error;
SINFO info;
};

View File

@ -498,7 +498,7 @@ decrypt_block (const void *ciphertext, unsigned char *plaintext, size_t length,
int iter, const char *pw, int cipher_algo,
int (*check_fnc) (const void *, size_t))
{
static const char const *charsets[] = {
static const char * const charsets[] = {
"", /* No conversion - use the UTF-8 passphrase direct. */
"ISO-8859-1",
"ISO-8859-15",

View File

@ -209,5 +209,5 @@ echo "Running autoconf${FORCE} ..."
$AUTOCONF${FORCE}
echo "You may now run:
./configure --sysconfdir=/etc --enable-maintainer-mode && make
./configure --sysconfdir=/etc --enable-maintainer-mode --enable-symcryptrun --enable-mailto && make
"

View File

@ -1,3 +1,8 @@
2008-12-05 Werner Koch <wk@g10code.com>
* exechelp.c (gnupg_spawn_process, gnupg_spawn_process_fd)
(gnupg_spawn_process_detached) [W32]: Remove debug output.
2008-11-20 Werner Koch <wk@g10code.com>
* audit.c (writeout_li): Translate OKTEXT.

View File

@ -396,7 +396,7 @@ gnupg_spawn_process (const char *pgmname, const char *argv[],
| ((flags & 128)? DETACHED_PROCESS : 0)
| GetPriorityClass (GetCurrentProcess ())
| CREATE_SUSPENDED);
log_debug ("CreateProcess, path=`%s' cmdline=`%s'\n", pgmname, cmdline);
/* 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. */
@ -421,10 +421,10 @@ gnupg_spawn_process (const char *pgmname, const char *argv[],
/* Close the other end of the pipe. */
CloseHandle (fd_to_handle (rp[1]));
log_debug ("CreateProcess ready: hProcess=%p hThread=%p"
" dwProcessID=%d dwThreadId=%d\n",
pi.hProcess, pi.hThread,
(int) pi.dwProcessId, (int) pi.dwThreadId);
/* 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);
@ -558,7 +558,7 @@ gnupg_spawn_process_fd (const char *pgmname, const char *argv[],
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);
/* 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. */
@ -585,10 +585,10 @@ gnupg_spawn_process_fd (const char *pgmname, const char *argv[],
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);
/* 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);
@ -796,8 +796,8 @@ gnupg_spawn_process_detached (const char *pgmname, const char *argv[],
| GetPriorityClass (GetCurrentProcess ())
| CREATE_NEW_PROCESS_GROUP
| DETACHED_PROCESS);
log_debug ("CreateProcess(detached), path=`%s' cmdline=`%s'\n",
pgmname, cmdline);
/* log_debug ("CreateProcess(detached), path=`%s' cmdline=`%s'\n", */
/* pgmname, cmdline); */
if (!CreateProcess (pgmname, /* Program to start. */
cmdline, /* Command line arguments. */
&sec_attr, /* Process security attributes. */
@ -817,10 +817,10 @@ gnupg_spawn_process_detached (const char *pgmname, const char *argv[],
xfree (cmdline);
cmdline = NULL;
log_debug ("CreateProcess(detached) ready: hProcess=%p hThread=%p"
" dwProcessID=%d dwThreadId=%d\n",
pi.hProcess, pi.hThread,
(int) pi.dwProcessId, (int) pi.dwThreadId);
/* log_debug ("CreateProcess(detached) ready: hProcess=%p hThread=%p" */
/* " dwProcessID=%d dwThreadId=%d\n", */
/* pi.hProcess, pi.hThread, */
/* (int) pi.dwProcessId, (int) pi.dwThreadId); */
CloseHandle (pi.hThread);

View File

@ -252,6 +252,20 @@ echo scd getinfo reader_list | gpg-connect-agent --decode | awk '/^D/ @{print $2
@end smallexample
@item --card-timeout @var{n}
@opindex card-timeout
If @var{n} is not 0 and no client is actively using the card, the card
will be powered down after @var{n} seconds. Powering down the card
avoids a potential risk of damaging a card when used with certain
cheap readers. This also allows non Scdaemon aware applications to
access the card. The disadvantage of using a card timeout is that
accessing the card takes longer and that the user needs to enter the
PIN again after the next power up.
Note that with the current version of Scdaemon the card is powered
down immediatley at the next timer tick for any value of @var{n} other
than 0.
@item --disable-keypad
@opindex disable-keypad

477
po/be.po

File diff suppressed because it is too large Load Diff

485
po/ca.po

File diff suppressed because it is too large Load Diff

481
po/cs.po

File diff suppressed because it is too large Load Diff

485
po/da.po

File diff suppressed because it is too large Load Diff

495
po/de.po

File diff suppressed because it is too large Load Diff

485
po/el.po

File diff suppressed because it is too large Load Diff

485
po/eo.po

File diff suppressed because it is too large Load Diff

486
po/es.po

File diff suppressed because it is too large Load Diff

485
po/et.po

File diff suppressed because it is too large Load Diff

485
po/fi.po

File diff suppressed because it is too large Load Diff

481
po/fr.po

File diff suppressed because it is too large Load Diff

485
po/gl.po

File diff suppressed because it is too large Load Diff

485
po/hu.po

File diff suppressed because it is too large Load Diff

485
po/id.po

File diff suppressed because it is too large Load Diff

485
po/it.po

File diff suppressed because it is too large Load Diff

481
po/ja.po

File diff suppressed because it is too large Load Diff

481
po/nb.po

File diff suppressed because it is too large Load Diff

483
po/pl.po

File diff suppressed because it is too large Load Diff

485
po/pt.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

485
po/ro.po

File diff suppressed because it is too large Load Diff

483
po/ru.po

File diff suppressed because it is too large Load Diff

485
po/sk.po

File diff suppressed because it is too large Load Diff

486
po/sv.po

File diff suppressed because it is too large Load Diff

483
po/tr.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,15 @@
2008-12-05 Werner Koch <wk@g10code.com>
* app-openpgp.c (app_local_s): Add field ALGO_ATTR_CHANGE.
(app_select_openpgp): Parse new capability.
(show_caps): Show new capability.
2008-12-03 Werner Koch <wk@g10code.com>
* scdaemon.c (opts): Use ARGPARSE_ macros. Add option
--card-timeout.
* command.c (update_reader_status_file): Implement it.
2008-11-18 Werner Koch <wk@g10code.com>
* scdaemon.c (make_libversion): New.

View File

@ -167,13 +167,14 @@ struct app_local_s {
/* Keep track of extended card capabilities. */
struct
{
unsigned int is_v2:1; /* This is a v2.0 compatible card. */
unsigned int is_v2:1; /* This is a v2.0 compatible card. */
unsigned int get_challenge:1;
unsigned int key_import:1;
unsigned int change_force_chv:1;
unsigned int private_dos:1;
unsigned int sm_supported:1; /* Secure Messaging is supported. */
unsigned int sm_aes128:1; /* Use AES-128 for SM. */
unsigned int algo_attr_change:1; /* Algorithm attributes changeable. */
unsigned int sm_supported:1; /* Secure Messaging is supported. */
unsigned int sm_aes128:1; /* Use AES-128 for SM. */
unsigned int max_certlen_3:16;
unsigned int max_get_challenge:16; /* Maximum size for get_challenge. */
unsigned int max_cmd_data:16; /* Maximum data size for a command. */
@ -3154,6 +3155,7 @@ show_caps (struct app_local_s *s)
log_info ("Key-Import .....: %s\n", s->extcap.key_import? "yes":"no");
log_info ("Change-Force-PW1: %s\n", s->extcap.change_force_chv? "yes":"no");
log_info ("Private-DOs ....: %s\n", s->extcap.private_dos? "yes":"no");
log_info ("Algo-Attr-Change: %s\n", s->extcap.algo_attr_change? "yes":"no");
log_info ("SM-Support .....: %s", s->extcap.sm_supported? "yes":"no");
if (s->extcap.sm_supported)
log_printf (" (%s)", s->extcap.sm_aes128? "AES-128":"3DES");
@ -3376,6 +3378,7 @@ app_select_openpgp (app_t app)
app->app_local->extcap.key_import = !!(*buffer & 0x20);
app->app_local->extcap.change_force_chv = !!(*buffer & 0x10);
app->app_local->extcap.private_dos = !!(*buffer & 0x08);
app->app_local->extcap.algo_attr_change = !!(*buffer & 0x04);
}
if (buflen >= 10)
{

View File

@ -2095,14 +2095,18 @@ update_reader_status_file (int set_card_removed_flag)
}
/* Check whether a disconnect is pending. */
for (sl=session_list; sl; sl = sl->next_session)
if (!sl->disconnect_allowed)
break;
if (session_list && !sl)
if (opt.card_timeout)
{
/* At least one connection and all allow a disconnect. */
log_debug ("disconnecting card in slot %d\n", ss->slot);
apdu_disconnect (ss->slot);
for (sl=session_list; sl; sl = sl->next_session)
if (!sl->disconnect_allowed)
break;
if (session_list && !sl)
{
/* FIXME: Use a real timeout. */
/* At least one connection and all allow a disconnect. */
log_debug ("disconnecting card in slot %d\n", ss->slot);
apdu_disconnect (ss->slot);
}
}
}

View File

@ -80,6 +80,7 @@ enum cmd_and_opt_values
oDaemon,
oBatch,
oReaderPort,
oCardTimeout,
octapiDriver,
opcscDriver,
oDisableCCID,
@ -94,46 +95,53 @@ enum cmd_and_opt_values
static ARGPARSE_OPTS opts[] = {
{ aGPGConfList, "gpgconf-list", 256, "@" },
{ aGPGConfTest, "gpgconf-test", 256, "@" },
ARGPARSE_c (aGPGConfList, "gpgconf-list", "@"),
ARGPARSE_c (aGPGConfTest, "gpgconf-test", "@"),
{ 301, NULL, 0, N_("@Options:\n ") },
ARGPARSE_group (301, N_("@Options:\n ")),
{ oServer, "server", 0, N_("run in server mode (foreground)") },
{ oMultiServer, "multi-server", 0,
N_("run in multi server mode (foreground)") },
{ oDaemon, "daemon", 0, N_("run in daemon mode (background)") },
{ oVerbose, "verbose", 0, N_("verbose") },
{ oQuiet, "quiet", 0, N_("be somewhat more quiet") },
{ oSh, "sh", 0, N_("sh-style command output") },
{ oCsh, "csh", 0, N_("csh-style command output") },
{ oOptions, "options" , 2, N_("read options from file")},
{ oDebug, "debug" ,4|16, "@"},
{ oDebugAll, "debug-all" ,0, "@"},
{ oDebugLevel, "debug-level" ,2, "@"},
{ oDebugWait,"debug-wait",1, "@"},
{ oDebugAllowCoreDump, "debug-allow-core-dump", 0, "@" },
{ oDebugCCIDDriver, "debug-ccid-driver", 0, "@"},
{ oDebugDisableTicker, "debug-disable-ticker", 0, "@"},
{ oNoDetach, "no-detach" ,0, N_("do not detach from the console")},
{ oLogFile, "log-file" ,2, N_("use a log file for the server")},
{ oReaderPort, "reader-port", 2, N_("|N|connect to reader at port N")},
{ octapiDriver, "ctapi-driver", 2, N_("|NAME|use NAME as ct-API driver")},
{ opcscDriver, "pcsc-driver", 2, N_("|NAME|use NAME as PC/SC driver")},
{ oDisableCCID, "disable-ccid", 0,
ARGPARSE_s_n (oServer,"server", N_("run in server mode (foreground)")),
ARGPARSE_s_n (oMultiServer, "multi-server",
N_("run in multi server mode (foreground)")),
ARGPARSE_s_n (oDaemon, "daemon", N_("run in daemon mode (background)")),
ARGPARSE_s_n (oVerbose, "verbose", N_("verbose")),
ARGPARSE_s_n (oQuiet, "quiet", N_("be somewhat more quiet")),
ARGPARSE_s_n (oSh, "sh", N_("sh-style command output")),
ARGPARSE_s_n (oCsh, "csh", N_("csh-style command output")),
ARGPARSE_s_s (oOptions, "options", N_("|FILE|read options from FILE")),
ARGPARSE_p_u (oDebug, "debug", "@"),
ARGPARSE_s_n (oDebugAll, "debug-all", "@"),
ARGPARSE_s_s (oDebugLevel, "debug-level" ,
N_("|LEVEL|set the debugging level to LEVEL")),
ARGPARSE_s_i (oDebugWait, "debug-wait", "@"),
ARGPARSE_s_n (oDebugAllowCoreDump, "debug-allow-core-dump", "@"),
ARGPARSE_s_n (oDebugCCIDDriver, "debug-ccid-driver", "@"),
ARGPARSE_s_n (oDebugDisableTicker, "debug-disable-ticker", "@"),
ARGPARSE_s_n (oNoDetach, "no-detach", N_("do not detach from the console")),
ARGPARSE_s_s (oLogFile, "log-file", N_("|FILE|write a log to FILE")),
ARGPARSE_s_s (oReaderPort, "reader-port",
N_("|N|connect to reader at port N")),
ARGPARSE_s_s (octapiDriver, "ctapi-driver",
N_("|NAME|use NAME as ct-API driver")),
ARGPARSE_s_s (opcscDriver, "pcsc-driver",
N_("|NAME|use NAME as PC/SC driver")),
ARGPARSE_s_n (oDisableCCID, "disable-ccid",
#ifdef HAVE_LIBUSB
N_("do not use the internal CCID driver")
#else
"@"
#endif
/* end --disable-ccid */},
{ oDisableKeypad, "disable-keypad", 0, N_("do not use a reader's keypad")},
{ oAllowAdmin, "allow-admin", 0, N_("allow the use of admin card commands")},
{ oDenyAdmin, "deny-admin", 0, "@" },
{ oDisableApplication, "disable-application", 2, "@"},
{0}
/* end --disable-ccid */),
ARGPARSE_s_u (oCardTimeout, "card-timeout",
N_("|N|disconnect the card after N seconds of inactivity")),
ARGPARSE_s_n (oDisableKeypad, "disable-keypad",
N_("do not use a reader's keypad")),
ARGPARSE_s_n (oAllowAdmin, "allow-admin",
N_("allow the use of admin card commands")),
ARGPARSE_s_n (oDenyAdmin, "deny-admin", "@"),
ARGPARSE_s_s (oDisableApplication, "disable-application", "@"),
ARGPARSE_end ()
};
@ -528,12 +536,16 @@ main (int argc, char **argv )
case oAllowAdmin: opt.allow_admin = 1; break;
case oDenyAdmin: opt.allow_admin = 0; break;
case oCardTimeout: opt.card_timeout = pargs.r.ret_ulong; break;
case oDisableApplication:
add_to_strlist (&opt.disabled_applications, pargs.r.ret_str);
break;
default : pargs.err = configfp? 1:2; break;
default:
pargs.err = configfp? ARGPARSE_PRINT_WARNING:ARGPARSE_PRINT_ERROR;
break;
}
}
if (configfp)
@ -619,6 +631,7 @@ main (int argc, char **argv )
#endif
printf ("allow-admin:%lu:\n", GC_OPT_FLAG_NONE );
printf ("disable-keypad:%lu:\n", GC_OPT_FLAG_NONE );
printf ("card-timeout:%lu:%d:\n", GC_OPT_FLAG_DEFAULT, 0);
scd_exit (0);
}

View File

@ -61,6 +61,7 @@ struct
cards. */
strlist_t disabled_applications; /* Card applications we do not
want to use. */
unsigned long card_timeout; /* Disconnect after N seconds of inactivity. */
} opt;

View File

@ -1,3 +1,13 @@
2008-12-05 Werner Koch <wk@g10code.com>
* gpg-connect-agent.c (opts): Use ARGPARSE_ macros.
(start_agent) [W32]: Start agent if not running.
2008-12-03 Werner Koch <wk@g10code.com>
* gpgconf-comp.c <scdaemon>: Add option --card-timeout. Remove
unused option --disable-opensc.
2008-10-20 Werner Koch <wk@g10code.com>
* gpgsplit.c (write_part): Remove unused arg FNAME. Change caller.

View File

@ -34,6 +34,10 @@
#include "../common/sysutils.h"
#include "../common/membuf.h"
#include "../common/ttyio.h"
#ifdef HAVE_W32_SYSTEM
# include "../common/exechelp.h"
#endif
#define CONTROL_D ('D' - 'A' + 1)
#define octdigitp(p) (*(p) >= '0' && *(p) <= '7')
@ -59,25 +63,28 @@ enum cmd_and_opt_values
/* The list of commands and options. */
static ARGPARSE_OPTS opts[] =
{
{ 301, NULL, 0, N_("@\nOptions:\n ") },
static ARGPARSE_OPTS opts[] = {
ARGPARSE_group (301, N_("@\nOptions:\n ")),
{ oVerbose, "verbose", 0, N_("verbose") },
{ oQuiet, "quiet", 0, N_("quiet") },
{ oHex, "hex", 0, N_("print data out hex encoded") },
{ oDecode,"decode", 0, N_("decode received data lines") },
{ oRawSocket, "raw-socket", 2, N_("|NAME|connect to Assuan socket NAME")},
{ oExec, "exec", 0, N_("run the Assuan server given on the command line")},
{ oNoExtConnect, "no-ext-connect",
0, N_("do not use extended connect mode")},
{ oRun, "run", 2, N_("|FILE|run commands from FILE on startup")},
{ oSubst, "subst", 0, N_("run /subst on startup")},
/* hidden options */
{ oNoVerbose, "no-verbose", 0, "@"},
{ oHomedir, "homedir", 2, "@" },
{0}
};
ARGPARSE_s_n (oVerbose, "verbose", N_("verbose")),
ARGPARSE_s_n (oQuiet, "quiet", N_("quiet")),
ARGPARSE_s_n (oHex, "hex", N_("print data out hex encoded")),
ARGPARSE_s_n (oDecode,"decode", N_("decode received data lines")),
ARGPARSE_s_s (oRawSocket, "raw-socket",
N_("|NAME|connect to Assuan socket NAME")),
ARGPARSE_s_n (oExec, "exec",
N_("run the Assuan server given on the command line")),
ARGPARSE_s_n (oNoExtConnect, "no-ext-connect",
N_("do not use extended connect mode")),
ARGPARSE_s_s (oRun, "run",
N_("|FILE|run commands from FILE on startup")),
ARGPARSE_s_n (oSubst, "subst", N_("run /subst on startup")),
ARGPARSE_s_n (oNoVerbose, "no-verbose", "@"),
ARGPARSE_s_s (oHomedir, "homedir", "@" ),
ARGPARSE_end ()
};
/* We keep all global options in the structure OPT. */
@ -2081,6 +2088,38 @@ start_agent (void)
/* Check whether we can connect at the standard socket. */
sockname = make_filename (opt.homedir, "S.gpg-agent", NULL);
rc = assuan_socket_connect (&ctx, sockname, 0);
#ifdef HAVE_W32_SYSTEM
/* If we failed to connect under Windows, we fire up the agent. */
if (gpg_err_code (rc) == GPG_ERR_ASS_CONNECT_FAILED)
{
const char *agent_program;
const char *argv[3];
int save_rc = rc;
if (opt.verbose)
log_info (_("no running gpg-agent - starting one\n"));
agent_program = gnupg_module_name (GNUPG_MODULE_NAME_AGENT);
argv[0] = "--daemon";
argv[1] = "--use-standard-socket";
argv[2] = NULL;
rc = gnupg_spawn_process_detached (agent_program, argv, NULL);
if (rc)
log_debug ("failed to start agent `%s': %s\n",
agent_program, gpg_strerror (rc));
else
{
/* Give the agent some time to prepare itself. */
gnupg_sleep (3);
/* Now try again to connect the agent. */
rc = assuan_socket_connect (&ctx, sockname, 0);
}
if (rc)
rc = save_rc;
}
#endif /*HAVE_W32_SYSTEM*/
xfree (sockname);
}
else

View File

@ -599,15 +599,15 @@ static gc_option_t gc_options_scdaemon[] =
{ "pcsc-driver", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED,
"gnupg", "|NAME|use NAME as PC/SC driver",
GC_ARG_TYPE_STRING, GC_BACKEND_SCDAEMON },
{ "disable-opensc", GC_OPT_FLAG_NONE, GC_LEVEL_EXPERT,
"gnupg", "do not use the OpenSC layer",
GC_ARG_TYPE_NONE, GC_BACKEND_SCDAEMON },
{ "disable-ccid", GC_OPT_FLAG_NONE, GC_LEVEL_EXPERT,
"gnupg", "do not use the internal CCID driver",
GC_ARG_TYPE_NONE, GC_BACKEND_SCDAEMON },
{ "disable-keypad", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
"gnupg", "do not use a reader's keypad",
GC_ARG_TYPE_NONE, GC_BACKEND_SCDAEMON },
{ "card-timeout", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
"gnupg", "|N|disconnect the card after N seconds of inactivity",
GC_ARG_TYPE_UINT32, GC_BACKEND_SCDAEMON },
{ "Debug",
GC_OPT_FLAG_GROUP, GC_LEVEL_ADVANCED,
@ -616,7 +616,7 @@ static gc_option_t gc_options_scdaemon[] =
"gnupg", "|LEVEL|set the debugging level to LEVEL",
GC_ARG_TYPE_STRING, GC_BACKEND_SCDAEMON },
{ "log-file", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED,
"gnupg", N_("|FILE|write server mode logs to FILE"),
"gnupg", N_("|FILE|write a log to FILE"),
GC_ARG_TYPE_FILENAME, GC_BACKEND_SCDAEMON },
{ "Security",