2004-01-29 00:58:18 +01:00
|
|
|
|
/* gpgconf-comp.c - Configuration utility for GnuPG.
|
2004-02-01 16:30:50 +01:00
|
|
|
|
Copyright (C) 2004 Free Software Foundation, Inc.
|
2004-01-29 00:58:18 +01:00
|
|
|
|
|
|
|
|
|
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 2 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 GnuPG; if not, write to the Free Software Foundation,
|
|
|
|
|
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
|
|
|
|
|
|
|
|
|
#if HAVE_CONFIG_H
|
|
|
|
|
#include <config.h>
|
|
|
|
|
#endif
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <time.h>
|
2004-01-30 13:15:53 +01:00
|
|
|
|
#include <stdarg.h>
|
2004-03-23 13:21:48 +01:00
|
|
|
|
#include <signal.h>
|
2004-01-29 00:58:18 +01:00
|
|
|
|
|
2004-01-30 13:15:53 +01:00
|
|
|
|
/* For log_logv(), asctimestamp(), gnupg_get_time (). */
|
|
|
|
|
#define JNLIB_NEED_LOG_LOGV
|
2004-01-30 11:38:07 +01:00
|
|
|
|
#include "util.h"
|
2004-09-29 18:16:47 +02:00
|
|
|
|
#include "i18n.h"
|
2004-01-30 11:38:07 +01:00
|
|
|
|
|
2004-01-29 00:58:18 +01:00
|
|
|
|
#include "gpgconf.h"
|
|
|
|
|
|
2004-09-29 18:16:47 +02:00
|
|
|
|
|
2004-01-29 00:58:18 +01:00
|
|
|
|
|
|
|
|
|
/* TODO:
|
|
|
|
|
Components: Add more components and their options.
|
|
|
|
|
Robustness: Do more validation. Call programs to do validation for us.
|
2004-01-30 11:38:07 +01:00
|
|
|
|
Don't use popen, as this will not tell us if the program had a
|
|
|
|
|
non-zero exit code.
|
2004-01-30 13:15:53 +01:00
|
|
|
|
Add options to change backend binary path.
|
|
|
|
|
Extract binary path for some backends from gpgsm/gpg config.
|
2004-01-29 00:58:18 +01:00
|
|
|
|
*/
|
|
|
|
|
|
2004-01-30 13:15:53 +01:00
|
|
|
|
|
2004-03-09 15:34:12 +01:00
|
|
|
|
#if (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 ))
|
2004-01-30 13:15:53 +01:00
|
|
|
|
void gc_error (int status, int errnum, const char *fmt, ...) \
|
|
|
|
|
__attribute__ ((format (printf, 3, 4)));
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* Output a diagnostic message. If ERRNUM is not 0, then the output
|
|
|
|
|
is followed by a colon, a white space, and the error string for the
|
|
|
|
|
error number ERRNUM. In any case the output is finished by a
|
|
|
|
|
newline. The message is prepended by the program name, a colon,
|
|
|
|
|
and a whitespace. The output may be further formatted or
|
|
|
|
|
redirected by the jnlib logging facility. */
|
|
|
|
|
void
|
|
|
|
|
gc_error (int status, int errnum, const char *fmt, ...)
|
|
|
|
|
{
|
|
|
|
|
va_list arg_ptr;
|
|
|
|
|
|
|
|
|
|
va_start (arg_ptr, fmt);
|
|
|
|
|
log_logv (JNLIB_LOG_ERROR, fmt, arg_ptr);
|
|
|
|
|
va_end (arg_ptr);
|
|
|
|
|
|
|
|
|
|
if (errnum)
|
|
|
|
|
log_printf (": %s\n", strerror (errnum));
|
|
|
|
|
else
|
|
|
|
|
log_printf ("\n");
|
|
|
|
|
|
|
|
|
|
if (status)
|
|
|
|
|
{
|
|
|
|
|
log_printf (NULL);
|
|
|
|
|
log_printf ("fatal error (exit status %i)\n", status);
|
|
|
|
|
exit (status);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2004-01-29 00:58:18 +01:00
|
|
|
|
|
2004-03-23 13:21:48 +01:00
|
|
|
|
/* Forward declaration. */
|
|
|
|
|
void gpg_agent_runtime_change (void);
|
|
|
|
|
|
2004-01-29 00:58:18 +01:00
|
|
|
|
/* Backend configuration. Backends are used to decide how the default
|
|
|
|
|
and current value of an option can be determined, and how the
|
|
|
|
|
option can be changed. To every option in every component belongs
|
|
|
|
|
exactly one backend that controls and determines the option. Some
|
|
|
|
|
backends are programs from the GPG system. Others might be
|
|
|
|
|
implemented by GPGConf itself. If you change this enum, don't
|
|
|
|
|
forget to update GC_BACKEND below. */
|
|
|
|
|
typedef enum
|
|
|
|
|
{
|
|
|
|
|
/* Any backend, used for find_option (). */
|
|
|
|
|
GC_BACKEND_ANY,
|
|
|
|
|
|
|
|
|
|
/* The Gnu Privacy Guard. */
|
|
|
|
|
GC_BACKEND_GPG,
|
|
|
|
|
|
|
|
|
|
/* The Gnu Privacy Guard for S/MIME. */
|
|
|
|
|
GC_BACKEND_GPGSM,
|
|
|
|
|
|
|
|
|
|
/* The GPG Agent. */
|
|
|
|
|
GC_BACKEND_GPG_AGENT,
|
|
|
|
|
|
2004-03-16 20:00:25 +01:00
|
|
|
|
/* The GnuPG SCDaemon. */
|
|
|
|
|
GC_BACKEND_SCDAEMON,
|
|
|
|
|
|
2004-01-29 00:58:18 +01:00
|
|
|
|
/* The Aegypten directory manager. */
|
|
|
|
|
GC_BACKEND_DIRMNGR,
|
|
|
|
|
|
|
|
|
|
/* The LDAP server list file for the Aegypten director manager. */
|
|
|
|
|
GC_BACKEND_DIRMNGR_LDAP_SERVER_LIST,
|
|
|
|
|
|
|
|
|
|
/* The number of the above entries. */
|
|
|
|
|
GC_BACKEND_NR
|
|
|
|
|
} gc_backend_t;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* To be able to implement generic algorithms for the various
|
|
|
|
|
backends, we collect all information about them in this struct. */
|
|
|
|
|
static struct
|
|
|
|
|
{
|
|
|
|
|
/* The name of the backend. */
|
|
|
|
|
const char *name;
|
|
|
|
|
|
|
|
|
|
/* The name of the program that acts as the backend. Some backends
|
|
|
|
|
don't have an associated program, but are implemented directly by
|
|
|
|
|
GPGConf. In this case, PROGRAM is NULL. */
|
|
|
|
|
char *program;
|
|
|
|
|
|
2004-03-23 13:21:48 +01:00
|
|
|
|
/* The runtime change callback. */
|
|
|
|
|
void (*runtime_change) (void);
|
|
|
|
|
|
2004-01-29 00:58:18 +01:00
|
|
|
|
/* The option name for the configuration filename of this backend.
|
|
|
|
|
This must be an absolute pathname. It can be an option from a
|
|
|
|
|
different backend (but then ordering of the options might
|
|
|
|
|
matter). */
|
|
|
|
|
const char *option_config_filename;
|
|
|
|
|
|
|
|
|
|
/* If this is a file backend rather than a program backend, then
|
|
|
|
|
this is the name of the option associated with the file. */
|
|
|
|
|
const char *option_name;
|
|
|
|
|
} gc_backend[GC_BACKEND_NR] =
|
|
|
|
|
{
|
2004-03-23 13:21:48 +01:00
|
|
|
|
{ NULL }, /* GC_BACKEND_ANY dummy entry. */
|
|
|
|
|
{ "GnuPG", "gpg", NULL, "gpgconf-gpg.conf" },
|
|
|
|
|
{ "GPGSM", "gpgsm", NULL, "gpgconf-gpgsm.conf" },
|
|
|
|
|
{ "GPG Agent", "gpg-agent", gpg_agent_runtime_change,
|
|
|
|
|
"gpgconf-gpg-agent.conf" },
|
|
|
|
|
{ "SCDaemon", "scdaemon", NULL, "gpgconf-scdaemon.conf" },
|
|
|
|
|
{ "DirMngr", "dirmngr", NULL, "gpgconf-dirmngr.conf" },
|
|
|
|
|
{ "DirMngr LDAP Server List", NULL, NULL, "ldapserverlist-file",
|
|
|
|
|
"LDAP Server" },
|
2004-01-29 00:58:18 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Option configuration. */
|
|
|
|
|
|
|
|
|
|
/* An option might take an argument, or not. Argument types can be
|
|
|
|
|
basic or complex. Basic types are generic and easy to validate.
|
|
|
|
|
Complex types provide more specific information about the intended
|
|
|
|
|
use, but can be difficult to validate. If you add to this enum,
|
|
|
|
|
don't forget to update GC_ARG_TYPE below. YOU MUST NOT CHANGE THE
|
|
|
|
|
NUMBERS OF THE EXISTING ENTRIES, AS THEY ARE PART OF THE EXTERNAL
|
|
|
|
|
INTERFACE. */
|
|
|
|
|
typedef enum
|
|
|
|
|
{
|
|
|
|
|
/* Basic argument types. */
|
|
|
|
|
|
|
|
|
|
/* No argument. */
|
|
|
|
|
GC_ARG_TYPE_NONE = 0,
|
|
|
|
|
|
|
|
|
|
/* A String argument. */
|
|
|
|
|
GC_ARG_TYPE_STRING = 1,
|
|
|
|
|
|
|
|
|
|
/* A signed integer argument. */
|
|
|
|
|
GC_ARG_TYPE_INT32 = 2,
|
|
|
|
|
|
|
|
|
|
/* An unsigned integer argument. */
|
|
|
|
|
GC_ARG_TYPE_UINT32 = 3,
|
|
|
|
|
|
2004-02-24 15:31:59 +01:00
|
|
|
|
/* ADD NEW BASIC TYPE ENTRIES HERE. */
|
2004-01-29 00:58:18 +01:00
|
|
|
|
|
|
|
|
|
/* Complex argument types. */
|
|
|
|
|
|
|
|
|
|
/* A complete pathname. */
|
2004-02-24 15:31:59 +01:00
|
|
|
|
GC_ARG_TYPE_PATHNAME = 32,
|
2004-01-29 00:58:18 +01:00
|
|
|
|
|
|
|
|
|
/* An LDAP server in the format
|
|
|
|
|
HOSTNAME:PORT:USERNAME:PASSWORD:BASE_DN. */
|
2004-02-24 15:31:59 +01:00
|
|
|
|
GC_ARG_TYPE_LDAP_SERVER = 33,
|
2004-01-29 00:58:18 +01:00
|
|
|
|
|
|
|
|
|
/* A 40 character fingerprint. */
|
2004-02-24 15:31:59 +01:00
|
|
|
|
GC_ARG_TYPE_KEY_FPR = 34,
|
2004-01-29 00:58:18 +01:00
|
|
|
|
|
2004-02-24 15:31:59 +01:00
|
|
|
|
/* ADD NEW COMPLEX TYPE ENTRIES HERE. */
|
2004-01-29 00:58:18 +01:00
|
|
|
|
|
|
|
|
|
/* The number of the above entries. */
|
|
|
|
|
GC_ARG_TYPE_NR
|
|
|
|
|
} gc_arg_type_t;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* For every argument, we record some information about it in the
|
|
|
|
|
following struct. */
|
|
|
|
|
static struct
|
|
|
|
|
{
|
|
|
|
|
/* For every argument type exists a basic argument type that can be
|
|
|
|
|
used as a fallback for input and validation purposes. */
|
|
|
|
|
gc_arg_type_t fallback;
|
|
|
|
|
|
|
|
|
|
/* Human-readable name of the type. */
|
|
|
|
|
const char *name;
|
|
|
|
|
} gc_arg_type[GC_ARG_TYPE_NR] =
|
|
|
|
|
{
|
|
|
|
|
/* The basic argument types have their own types as fallback. */
|
|
|
|
|
{ GC_ARG_TYPE_NONE, "none" },
|
|
|
|
|
{ GC_ARG_TYPE_STRING, "string" },
|
|
|
|
|
{ GC_ARG_TYPE_INT32, "int32" },
|
|
|
|
|
{ GC_ARG_TYPE_UINT32, "uint32" },
|
|
|
|
|
|
2004-02-24 15:31:59 +01:00
|
|
|
|
/* Reserved basic type entries for future extension. */
|
|
|
|
|
{ GC_ARG_TYPE_NR, NULL }, { GC_ARG_TYPE_NR, NULL },
|
|
|
|
|
{ GC_ARG_TYPE_NR, NULL }, { GC_ARG_TYPE_NR, NULL },
|
|
|
|
|
{ GC_ARG_TYPE_NR, NULL }, { GC_ARG_TYPE_NR, NULL },
|
|
|
|
|
{ GC_ARG_TYPE_NR, NULL }, { GC_ARG_TYPE_NR, NULL },
|
|
|
|
|
{ GC_ARG_TYPE_NR, NULL }, { GC_ARG_TYPE_NR, NULL },
|
|
|
|
|
{ GC_ARG_TYPE_NR, NULL }, { GC_ARG_TYPE_NR, NULL },
|
|
|
|
|
{ GC_ARG_TYPE_NR, NULL }, { GC_ARG_TYPE_NR, NULL },
|
|
|
|
|
{ GC_ARG_TYPE_NR, NULL }, { GC_ARG_TYPE_NR, NULL },
|
|
|
|
|
{ GC_ARG_TYPE_NR, NULL }, { GC_ARG_TYPE_NR, NULL },
|
|
|
|
|
{ GC_ARG_TYPE_NR, NULL }, { GC_ARG_TYPE_NR, NULL },
|
|
|
|
|
{ GC_ARG_TYPE_NR, NULL }, { GC_ARG_TYPE_NR, NULL },
|
|
|
|
|
{ GC_ARG_TYPE_NR, NULL }, { GC_ARG_TYPE_NR, NULL },
|
|
|
|
|
{ GC_ARG_TYPE_NR, NULL }, { GC_ARG_TYPE_NR, NULL },
|
|
|
|
|
{ GC_ARG_TYPE_NR, NULL }, { GC_ARG_TYPE_NR, NULL },
|
|
|
|
|
|
2004-01-29 00:58:18 +01:00
|
|
|
|
/* The complex argument types have a basic type as fallback. */
|
|
|
|
|
{ GC_ARG_TYPE_STRING, "pathname" },
|
|
|
|
|
{ GC_ARG_TYPE_STRING, "ldap server" },
|
|
|
|
|
{ GC_ARG_TYPE_STRING, "key fpr" },
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Every option has an associated expert level, than can be used to
|
|
|
|
|
hide advanced and expert options from beginners. If you add to
|
|
|
|
|
this list, don't forget to update GC_LEVEL below. YOU MUST NOT
|
|
|
|
|
CHANGE THE NUMBERS OF THE EXISTING ENTRIES, AS THEY ARE PART OF THE
|
|
|
|
|
EXTERNAL INTERFACE. */
|
|
|
|
|
typedef enum
|
|
|
|
|
{
|
|
|
|
|
/* The basic options should always be displayed. */
|
|
|
|
|
GC_LEVEL_BASIC,
|
|
|
|
|
|
|
|
|
|
/* The advanced options may be hidden from beginners. */
|
|
|
|
|
GC_LEVEL_ADVANCED,
|
|
|
|
|
|
|
|
|
|
/* The expert options should only be displayed to experts. */
|
|
|
|
|
GC_LEVEL_EXPERT,
|
|
|
|
|
|
|
|
|
|
/* The invisible options should normally never be displayed. */
|
|
|
|
|
GC_LEVEL_INVISIBLE,
|
|
|
|
|
|
|
|
|
|
/* The internal options are never exported, they mark options that
|
|
|
|
|
are recorded for internal use only. */
|
|
|
|
|
GC_LEVEL_INTERNAL,
|
|
|
|
|
|
|
|
|
|
/* ADD NEW ENTRIES HERE. */
|
|
|
|
|
|
|
|
|
|
/* The number of the above entries. */
|
|
|
|
|
GC_LEVEL_NR
|
|
|
|
|
} gc_expert_level_t;
|
|
|
|
|
|
|
|
|
|
/* A description for each expert level. */
|
|
|
|
|
static struct
|
|
|
|
|
{
|
|
|
|
|
const char *name;
|
|
|
|
|
} gc_level[] =
|
|
|
|
|
{
|
|
|
|
|
{ "basic" },
|
|
|
|
|
{ "advanced" },
|
|
|
|
|
{ "expert" },
|
|
|
|
|
{ "invisible" },
|
|
|
|
|
{ "internal" }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Option flags. YOU MUST NOT CHANGE THE NUMBERS OF THE EXISTING
|
|
|
|
|
FLAGS, AS THEY ARE PART OF THE EXTERNAL INTERFACE. */
|
2004-02-24 15:31:59 +01:00
|
|
|
|
#define GC_OPT_FLAG_NONE 0UL
|
2004-01-29 00:58:18 +01:00
|
|
|
|
/* Some entries in the option list are not options, but mark the
|
|
|
|
|
beginning of a new group of options. These entries have the GROUP
|
|
|
|
|
flag set. */
|
2004-02-24 15:31:59 +01:00
|
|
|
|
#define GC_OPT_FLAG_GROUP (1UL << 0)
|
2004-01-29 00:58:18 +01:00
|
|
|
|
/* The ARG_OPT flag for an option indicates that the argument is
|
2004-02-26 17:28:27 +01:00
|
|
|
|
optional. This is never set for GC_ARG_TYPE_NONE options. */
|
2004-02-24 15:31:59 +01:00
|
|
|
|
#define GC_OPT_FLAG_ARG_OPT (1UL << 1)
|
2004-01-29 00:58:18 +01:00
|
|
|
|
/* The LIST flag for an option indicates that the option can occur
|
|
|
|
|
several times. A comma separated list of arguments is used as the
|
|
|
|
|
argument value. */
|
2004-02-24 15:31:59 +01:00
|
|
|
|
#define GC_OPT_FLAG_LIST (1UL << 2)
|
2004-01-29 00:58:18 +01:00
|
|
|
|
/* The RUNTIME flag for an option indicates that the option can be
|
|
|
|
|
changed at runtime. */
|
2004-02-24 15:31:59 +01:00
|
|
|
|
#define GC_OPT_FLAG_RUNTIME (1UL << 3)
|
|
|
|
|
|
|
|
|
|
/* The following flags are incorporated from the backend. */
|
|
|
|
|
/* The DEFAULT flag for an option indicates that the option has a
|
|
|
|
|
default value. */
|
|
|
|
|
#define GC_OPT_FLAG_DEFAULT (1UL << 4)
|
|
|
|
|
/* The DEF_DESC flag for an option indicates that the option has a
|
|
|
|
|
default, which is described by the value of the default field. */
|
|
|
|
|
#define GC_OPT_FLAG_DEF_DESC (1UL << 5)
|
|
|
|
|
/* The NO_ARG_DESC flag for an option indicates that the argument has
|
|
|
|
|
a default, which is described by the value of the ARGDEF field. */
|
|
|
|
|
#define GC_OPT_FLAG_NO_ARG_DESC (1UL << 6)
|
2004-01-29 00:58:18 +01:00
|
|
|
|
|
|
|
|
|
/* A human-readable description for each flag. */
|
|
|
|
|
static struct
|
|
|
|
|
{
|
|
|
|
|
const char *name;
|
|
|
|
|
} gc_flag[] =
|
|
|
|
|
{
|
|
|
|
|
{ "group" },
|
|
|
|
|
{ "optional arg" },
|
|
|
|
|
{ "list" },
|
2004-03-23 13:33:59 +01:00
|
|
|
|
{ "runtime" },
|
|
|
|
|
{ "default" },
|
|
|
|
|
{ "default desc" },
|
|
|
|
|
{ "no arg desc" }
|
2004-01-29 00:58:18 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* To each option, or group marker, the information in the GC_OPTION
|
|
|
|
|
struct is provided. If you change this, don't forget to update the
|
|
|
|
|
option list of each component. */
|
|
|
|
|
struct gc_option
|
|
|
|
|
{
|
|
|
|
|
/* If this is NULL, then this is a terminator in an array of unknown
|
|
|
|
|
length. Otherwise, if this entry is a group marker (see FLAGS),
|
|
|
|
|
then this is the name of the group described by this entry.
|
|
|
|
|
Otherwise it is the name of the option described by this
|
|
|
|
|
entry. The name must not contain a colon. */
|
|
|
|
|
const char *name;
|
|
|
|
|
|
|
|
|
|
/* The option flags. If the GROUP flag is set, then this entry is a
|
|
|
|
|
group marker, not an option, and only the fields LEVEL,
|
|
|
|
|
DESC_DOMAIN and DESC are valid. In all other cases, this entry
|
|
|
|
|
describes a new option and all fields are valid. */
|
2004-02-24 15:31:59 +01:00
|
|
|
|
unsigned long flags;
|
2004-01-29 00:58:18 +01:00
|
|
|
|
|
|
|
|
|
/* The expert level. This field is valid for options and groups. A
|
|
|
|
|
group has the expert level of the lowest-level option in the
|
|
|
|
|
group. */
|
|
|
|
|
gc_expert_level_t level;
|
|
|
|
|
|
|
|
|
|
/* A gettext domain in which the following description can be found.
|
|
|
|
|
If this is NULL, then DESC is not translated. Valid for groups
|
2004-09-29 18:16:47 +02:00
|
|
|
|
and options.
|
|
|
|
|
|
|
|
|
|
Note that we try to keep the description of groups within the
|
2004-10-01 14:53:09 +02:00
|
|
|
|
gnupg domain.
|
|
|
|
|
|
|
|
|
|
IMPORTANT: If you add a new domain please make sure to add a code
|
|
|
|
|
set switching call to the function my_dgettext further below. */
|
2004-01-29 00:58:18 +01:00
|
|
|
|
const char *desc_domain;
|
|
|
|
|
|
|
|
|
|
/* A gettext description for this group or option. If it starts
|
|
|
|
|
with a '|', then the string up to the next '|' describes the
|
2004-09-29 18:16:47 +02:00
|
|
|
|
argument, and the description follows the second '|'.
|
|
|
|
|
|
|
|
|
|
In general enclosing these description in N_() is not required
|
|
|
|
|
because the description should be identical to the one in the
|
|
|
|
|
help menu of the respective program. */
|
2004-01-29 00:58:18 +01:00
|
|
|
|
const char *desc;
|
|
|
|
|
|
|
|
|
|
/* The following fields are only valid for options. */
|
|
|
|
|
|
|
|
|
|
/* The type of the option argument. */
|
|
|
|
|
gc_arg_type_t arg_type;
|
|
|
|
|
|
|
|
|
|
/* The backend that implements this option. */
|
|
|
|
|
gc_backend_t backend;
|
|
|
|
|
|
|
|
|
|
/* The following fields are set to NULL at startup (because all
|
|
|
|
|
option's are declared as static variables). They are at the end
|
|
|
|
|
of the list so that they can be omitted from the option
|
|
|
|
|
declarations. */
|
|
|
|
|
|
2004-01-31 14:58:27 +01:00
|
|
|
|
/* This is true if the option is supported by this version of the
|
|
|
|
|
backend. */
|
|
|
|
|
int active;
|
|
|
|
|
|
2004-01-29 00:58:18 +01:00
|
|
|
|
/* The default value for this option. This is NULL if the option is
|
|
|
|
|
not present in the backend, the empty string if no default is
|
|
|
|
|
available, and otherwise a quoted string. */
|
|
|
|
|
char *default_value;
|
|
|
|
|
|
2004-02-24 15:31:59 +01:00
|
|
|
|
/* The default argument is only valid if the "optional arg" flag is
|
|
|
|
|
set, and specifies the default argument (value) that is used if
|
|
|
|
|
the argument is omitted. */
|
|
|
|
|
char *default_arg;
|
|
|
|
|
|
2004-01-29 00:58:18 +01:00
|
|
|
|
/* The current value of this option. */
|
|
|
|
|
char *value;
|
|
|
|
|
|
2004-02-25 21:24:53 +01:00
|
|
|
|
/* The new flags for this option. The only defined flag is actually
|
|
|
|
|
GC_OPT_FLAG_DEFAULT, and it means that the option should be
|
|
|
|
|
deleted. In this case, NEW_VALUE is NULL. */
|
|
|
|
|
unsigned long new_flags;
|
|
|
|
|
|
2004-01-29 00:58:18 +01:00
|
|
|
|
/* The new value of this option. */
|
|
|
|
|
char *new_value;
|
|
|
|
|
};
|
|
|
|
|
typedef struct gc_option gc_option_t;
|
|
|
|
|
|
|
|
|
|
/* Use this macro to terminate an option list. */
|
|
|
|
|
#define GC_OPTION_NULL { NULL }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* The options of the GC_COMPONENT_GPG_AGENT component. */
|
|
|
|
|
static gc_option_t gc_options_gpg_agent[] =
|
|
|
|
|
{
|
2004-03-16 11:48:13 +01:00
|
|
|
|
/* The configuration file to which we write the changes. */
|
|
|
|
|
{ "gpgconf-gpg-agent.conf", GC_OPT_FLAG_NONE, GC_LEVEL_INTERNAL,
|
|
|
|
|
NULL, NULL, GC_ARG_TYPE_PATHNAME, GC_BACKEND_GPG_AGENT },
|
|
|
|
|
|
|
|
|
|
{ "Monitor",
|
|
|
|
|
GC_OPT_FLAG_GROUP, GC_LEVEL_BASIC,
|
2004-09-29 18:16:47 +02:00
|
|
|
|
"gnupg", N_("Options controlling the diagnostic output") },
|
2004-04-30 05:03:34 +02:00
|
|
|
|
{ "verbose", GC_OPT_FLAG_LIST|GC_OPT_FLAG_RUNTIME, GC_LEVEL_BASIC,
|
2004-03-16 11:48:13 +01:00
|
|
|
|
"gnupg", "verbose",
|
|
|
|
|
GC_ARG_TYPE_NONE, GC_BACKEND_GPG_AGENT },
|
2004-04-30 05:03:34 +02:00
|
|
|
|
{ "quiet", GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME, GC_LEVEL_BASIC,
|
2004-03-16 11:48:13 +01:00
|
|
|
|
"gnupg", "be somewhat more quiet",
|
|
|
|
|
GC_ARG_TYPE_NONE, GC_BACKEND_GPG_AGENT },
|
|
|
|
|
{ "no-greeting", GC_OPT_FLAG_NONE, GC_LEVEL_INVISIBLE,
|
|
|
|
|
NULL, NULL,
|
|
|
|
|
GC_ARG_TYPE_NONE, GC_BACKEND_GPG_AGENT },
|
|
|
|
|
|
|
|
|
|
{ "Configuration",
|
|
|
|
|
GC_OPT_FLAG_GROUP, GC_LEVEL_EXPERT,
|
2004-09-29 18:16:47 +02:00
|
|
|
|
"gnupg", N_("Options controlling the configuration") },
|
2004-03-16 11:48:13 +01:00
|
|
|
|
{ "options", GC_OPT_FLAG_NONE, GC_LEVEL_EXPERT,
|
|
|
|
|
"gnupg", "|FILE|read options from FILE",
|
|
|
|
|
GC_ARG_TYPE_PATHNAME, GC_BACKEND_GPG_AGENT },
|
|
|
|
|
|
|
|
|
|
{ "Debug",
|
|
|
|
|
GC_OPT_FLAG_GROUP, GC_LEVEL_ADVANCED,
|
2004-09-29 18:16:47 +02:00
|
|
|
|
"gnupg", N_("Options useful for debugging") },
|
2004-04-30 05:03:34 +02:00
|
|
|
|
{ "debug-level", GC_OPT_FLAG_ARG_OPT|GC_OPT_FLAG_RUNTIME, GC_LEVEL_ADVANCED,
|
2004-03-16 11:48:13 +01:00
|
|
|
|
"gnupg", "|LEVEL|set the debugging level to LEVEL",
|
|
|
|
|
GC_ARG_TYPE_STRING, GC_BACKEND_GPG_AGENT },
|
2004-04-30 05:58:43 +02:00
|
|
|
|
{ "log-file", GC_OPT_FLAG_RUNTIME, GC_LEVEL_ADVANCED,
|
2004-10-01 14:53:09 +02:00
|
|
|
|
"gnupg", N_("|FILE|write server mode logs to FILE"),
|
2004-03-16 11:48:13 +01:00
|
|
|
|
GC_ARG_TYPE_PATHNAME, GC_BACKEND_GPG_AGENT },
|
|
|
|
|
{ "faked-system-time", GC_OPT_FLAG_NONE, GC_LEVEL_INVISIBLE,
|
|
|
|
|
NULL, NULL,
|
|
|
|
|
GC_ARG_TYPE_UINT32, GC_BACKEND_GPG_AGENT },
|
|
|
|
|
|
|
|
|
|
{ "Security",
|
|
|
|
|
GC_OPT_FLAG_GROUP, GC_LEVEL_BASIC,
|
2004-09-29 18:16:47 +02:00
|
|
|
|
"gnupg", N_("Options controlling the security") },
|
2004-03-16 11:48:13 +01:00
|
|
|
|
{ "default-cache-ttl", GC_OPT_FLAG_RUNTIME, GC_LEVEL_BASIC,
|
|
|
|
|
"gnupg", "|N|expire cached PINs after N seconds",
|
|
|
|
|
GC_ARG_TYPE_UINT32, GC_BACKEND_GPG_AGENT },
|
|
|
|
|
{ "ignore-cache-for-signing", GC_OPT_FLAG_RUNTIME, GC_LEVEL_BASIC,
|
|
|
|
|
"gnupg", "do not use the PIN cache when signing",
|
2004-04-20 18:02:30 +02:00
|
|
|
|
GC_ARG_TYPE_NONE, GC_BACKEND_GPG_AGENT },
|
2004-05-03 15:37:38 +02:00
|
|
|
|
{ "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 },
|
2004-04-30 05:03:34 +02:00
|
|
|
|
{ "no-grab", GC_OPT_FLAG_RUNTIME, GC_LEVEL_EXPERT,
|
2004-04-05 19:25:43 +02:00
|
|
|
|
"gnupg", "do not grab keyboard and mouse",
|
2004-03-16 11:48:13 +01:00
|
|
|
|
GC_ARG_TYPE_NONE, GC_BACKEND_GPG_AGENT },
|
|
|
|
|
|
|
|
|
|
|
2004-01-29 00:58:18 +01:00
|
|
|
|
GC_OPTION_NULL
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2004-02-18 18:00:56 +01:00
|
|
|
|
/* The options of the GC_COMPONENT_SCDAEMON component. */
|
|
|
|
|
static gc_option_t gc_options_scdaemon[] =
|
|
|
|
|
{
|
2004-03-16 20:00:25 +01:00
|
|
|
|
/* The configuration file to which we write the changes. */
|
|
|
|
|
{ "gpgconf-scdaemon.conf", GC_OPT_FLAG_NONE, GC_LEVEL_INTERNAL,
|
|
|
|
|
NULL, NULL, GC_ARG_TYPE_PATHNAME, GC_BACKEND_SCDAEMON },
|
|
|
|
|
|
|
|
|
|
{ "Monitor",
|
|
|
|
|
GC_OPT_FLAG_GROUP, GC_LEVEL_BASIC,
|
2004-09-29 18:16:47 +02:00
|
|
|
|
"gnupg", N_("Options controlling the diagnostic output") },
|
2004-03-16 20:00:25 +01:00
|
|
|
|
{ "verbose", GC_OPT_FLAG_LIST, GC_LEVEL_BASIC,
|
|
|
|
|
"gnupg", "verbose",
|
|
|
|
|
GC_ARG_TYPE_NONE, GC_BACKEND_SCDAEMON },
|
|
|
|
|
{ "quiet", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
|
|
|
|
|
"gnupg", "be somewhat more quiet",
|
|
|
|
|
GC_ARG_TYPE_NONE, GC_BACKEND_SCDAEMON },
|
|
|
|
|
{ "no-greeting", GC_OPT_FLAG_NONE, GC_LEVEL_INVISIBLE,
|
|
|
|
|
NULL, NULL,
|
|
|
|
|
GC_ARG_TYPE_NONE, GC_BACKEND_SCDAEMON },
|
|
|
|
|
|
|
|
|
|
{ "Configuration",
|
|
|
|
|
GC_OPT_FLAG_GROUP, GC_LEVEL_EXPERT,
|
2004-09-29 18:16:47 +02:00
|
|
|
|
"gnupg", N_("Options controlling the configuration") },
|
2004-03-16 20:00:25 +01:00
|
|
|
|
{ "options", GC_OPT_FLAG_NONE, GC_LEVEL_EXPERT,
|
|
|
|
|
"gnupg", "|FILE|read options from FILE",
|
|
|
|
|
GC_ARG_TYPE_PATHNAME, GC_BACKEND_SCDAEMON },
|
|
|
|
|
{ "reader-port", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
|
|
|
|
|
"gnupg", "|N|connect to reader at port N",
|
|
|
|
|
GC_ARG_TYPE_STRING, GC_BACKEND_SCDAEMON },
|
|
|
|
|
{ "ctapi-driver", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED,
|
|
|
|
|
"gnupg", "|NAME|use NAME as ct-API driver",
|
|
|
|
|
GC_ARG_TYPE_STRING, GC_BACKEND_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 },
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{ "Debug",
|
|
|
|
|
GC_OPT_FLAG_GROUP, GC_LEVEL_ADVANCED,
|
2004-09-29 18:16:47 +02:00
|
|
|
|
"gnupg", N_("Options useful for debugging") },
|
2004-03-16 20:00:25 +01:00
|
|
|
|
{ "debug-level", GC_OPT_FLAG_ARG_OPT, GC_LEVEL_ADVANCED,
|
|
|
|
|
"gnupg", "|LEVEL|set the debugging level to LEVEL",
|
|
|
|
|
GC_ARG_TYPE_STRING, GC_BACKEND_SCDAEMON },
|
|
|
|
|
{ "log-file", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED,
|
2004-10-01 18:51:18 +02:00
|
|
|
|
"gnupg", N_("|FILE|write server mode logs to FILE"),
|
2004-03-16 20:00:25 +01:00
|
|
|
|
GC_ARG_TYPE_PATHNAME, GC_BACKEND_SCDAEMON },
|
|
|
|
|
|
|
|
|
|
{ "Security",
|
|
|
|
|
GC_OPT_FLAG_GROUP, GC_LEVEL_BASIC,
|
2004-09-29 18:16:47 +02:00
|
|
|
|
"gnupg", N_("Options controlling the security") },
|
2004-03-16 20:00:25 +01:00
|
|
|
|
{ "allow-admin", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
|
|
|
|
|
"gnupg", "allow the use of admin card commands",
|
|
|
|
|
GC_ARG_TYPE_NONE, GC_BACKEND_SCDAEMON },
|
|
|
|
|
|
|
|
|
|
|
2004-02-18 18:00:56 +01:00
|
|
|
|
GC_OPTION_NULL
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2004-03-23 14:04:34 +01:00
|
|
|
|
/* The options of the GC_COMPONENT_GPG component. */
|
|
|
|
|
static gc_option_t gc_options_gpg[] =
|
|
|
|
|
{
|
|
|
|
|
/* The configuration file to which we write the changes. */
|
|
|
|
|
{ "gpgconf-gpg.conf", GC_OPT_FLAG_NONE, GC_LEVEL_INTERNAL,
|
|
|
|
|
NULL, NULL, GC_ARG_TYPE_PATHNAME, GC_BACKEND_GPG },
|
|
|
|
|
|
|
|
|
|
{ "Monitor",
|
|
|
|
|
GC_OPT_FLAG_GROUP, GC_LEVEL_BASIC,
|
2004-09-29 18:16:47 +02:00
|
|
|
|
"gnupg", N_("Options controlling the diagnostic output") },
|
2004-03-23 14:04:34 +01:00
|
|
|
|
{ "verbose", GC_OPT_FLAG_LIST, GC_LEVEL_BASIC,
|
|
|
|
|
"gnupg", "verbose",
|
|
|
|
|
GC_ARG_TYPE_NONE, GC_BACKEND_GPG },
|
|
|
|
|
{ "quiet", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
|
|
|
|
|
"gnupg", "be somewhat more quiet",
|
|
|
|
|
GC_ARG_TYPE_NONE, GC_BACKEND_GPG },
|
|
|
|
|
{ "no-greeting", GC_OPT_FLAG_NONE, GC_LEVEL_INVISIBLE,
|
|
|
|
|
NULL, NULL,
|
|
|
|
|
GC_ARG_TYPE_NONE, GC_BACKEND_GPG },
|
|
|
|
|
|
|
|
|
|
{ "Configuration",
|
|
|
|
|
GC_OPT_FLAG_GROUP, GC_LEVEL_EXPERT,
|
2004-09-29 18:16:47 +02:00
|
|
|
|
"gnupg", N_("Options controlling the configuration") },
|
2004-03-23 14:04:34 +01:00
|
|
|
|
{ "options", GC_OPT_FLAG_NONE, GC_LEVEL_EXPERT,
|
|
|
|
|
"gnupg", "|FILE|read options from FILE",
|
|
|
|
|
GC_ARG_TYPE_PATHNAME, GC_BACKEND_GPG },
|
|
|
|
|
|
|
|
|
|
{ "Debug",
|
|
|
|
|
GC_OPT_FLAG_GROUP, GC_LEVEL_ADVANCED,
|
2004-09-29 18:16:47 +02:00
|
|
|
|
"gnupg", N_("Options useful for debugging") },
|
2004-03-23 14:04:34 +01:00
|
|
|
|
{ "debug-level", GC_OPT_FLAG_ARG_OPT, GC_LEVEL_ADVANCED,
|
|
|
|
|
"gnupg", "|LEVEL|set the debugging level to LEVEL",
|
|
|
|
|
GC_ARG_TYPE_STRING, GC_BACKEND_GPG },
|
|
|
|
|
{ "log-file", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED,
|
2004-10-01 18:51:18 +02:00
|
|
|
|
"gnupg", N_("|FILE|write server mode logs to FILE"),
|
2004-03-23 14:04:34 +01:00
|
|
|
|
GC_ARG_TYPE_PATHNAME, GC_BACKEND_GPG },
|
|
|
|
|
/* { "faked-system-time", GC_OPT_FLAG_NONE, GC_LEVEL_INVISIBLE, */
|
|
|
|
|
/* NULL, NULL, */
|
|
|
|
|
/* GC_ARG_TYPE_UINT32, GC_BACKEND_GPG }, */
|
|
|
|
|
|
2004-03-23 14:48:46 +01:00
|
|
|
|
{ "Keyserver",
|
|
|
|
|
GC_OPT_FLAG_GROUP, GC_LEVEL_BASIC,
|
2004-09-29 18:16:47 +02:00
|
|
|
|
"gnupg", N_("Configuration for Keyservers") },
|
2004-03-23 14:48:46 +01:00
|
|
|
|
{ "keyserver", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
|
|
|
|
|
"gnupg", "|URL|use keyserver at URL",
|
|
|
|
|
GC_ARG_TYPE_STRING, GC_BACKEND_GPG },
|
|
|
|
|
|
2004-03-23 14:04:34 +01:00
|
|
|
|
|
|
|
|
|
GC_OPTION_NULL
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-02-18 18:00:56 +01:00
|
|
|
|
/* The options of the GC_COMPONENT_GPGSM component. */
|
|
|
|
|
static gc_option_t gc_options_gpgsm[] =
|
|
|
|
|
{
|
2004-03-16 20:00:25 +01:00
|
|
|
|
/* The configuration file to which we write the changes. */
|
|
|
|
|
{ "gpgconf-gpgsm.conf", GC_OPT_FLAG_NONE, GC_LEVEL_INTERNAL,
|
|
|
|
|
NULL, NULL, GC_ARG_TYPE_PATHNAME, GC_BACKEND_GPGSM },
|
|
|
|
|
|
|
|
|
|
{ "Monitor",
|
|
|
|
|
GC_OPT_FLAG_GROUP, GC_LEVEL_BASIC,
|
2004-09-29 18:16:47 +02:00
|
|
|
|
"gnupg", N_("Options controlling the diagnostic output") },
|
2004-03-16 20:00:25 +01:00
|
|
|
|
{ "verbose", GC_OPT_FLAG_LIST, GC_LEVEL_BASIC,
|
|
|
|
|
"gnupg", "verbose",
|
|
|
|
|
GC_ARG_TYPE_NONE, GC_BACKEND_GPGSM },
|
|
|
|
|
{ "quiet", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
|
|
|
|
|
"gnupg", "be somewhat more quiet",
|
|
|
|
|
GC_ARG_TYPE_NONE, GC_BACKEND_GPGSM },
|
|
|
|
|
{ "no-greeting", GC_OPT_FLAG_NONE, GC_LEVEL_INVISIBLE,
|
|
|
|
|
NULL, NULL,
|
|
|
|
|
GC_ARG_TYPE_NONE, GC_BACKEND_GPGSM },
|
|
|
|
|
|
|
|
|
|
{ "Configuration",
|
|
|
|
|
GC_OPT_FLAG_GROUP, GC_LEVEL_EXPERT,
|
2004-09-29 18:16:47 +02:00
|
|
|
|
"gnupg", N_("Options controlling the configuration") },
|
2004-03-16 20:00:25 +01:00
|
|
|
|
{ "options", GC_OPT_FLAG_NONE, GC_LEVEL_EXPERT,
|
|
|
|
|
"gnupg", "|FILE|read options from FILE",
|
|
|
|
|
GC_ARG_TYPE_PATHNAME, GC_BACKEND_GPGSM },
|
2004-11-23 18:09:51 +01:00
|
|
|
|
{ "prefer-system-dirmngr", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED,
|
|
|
|
|
"gnupg", "use system's dirmngr if available",
|
|
|
|
|
GC_ARG_TYPE_NONE, GC_BACKEND_GPGSM },
|
2004-03-16 20:00:25 +01:00
|
|
|
|
|
|
|
|
|
{ "Debug",
|
|
|
|
|
GC_OPT_FLAG_GROUP, GC_LEVEL_ADVANCED,
|
2004-09-29 18:16:47 +02:00
|
|
|
|
"gnupg", N_("Options useful for debugging") },
|
2004-03-16 20:00:25 +01:00
|
|
|
|
{ "debug-level", GC_OPT_FLAG_ARG_OPT, GC_LEVEL_ADVANCED,
|
|
|
|
|
"gnupg", "|LEVEL|set the debugging level to LEVEL",
|
|
|
|
|
GC_ARG_TYPE_STRING, GC_BACKEND_GPGSM },
|
|
|
|
|
{ "log-file", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED,
|
2004-10-01 18:51:18 +02:00
|
|
|
|
"gnupg", N_("|FILE|write server mode logs to FILE"),
|
2004-03-16 20:00:25 +01:00
|
|
|
|
GC_ARG_TYPE_PATHNAME, GC_BACKEND_GPGSM },
|
|
|
|
|
{ "faked-system-time", GC_OPT_FLAG_NONE, GC_LEVEL_INVISIBLE,
|
|
|
|
|
NULL, NULL,
|
|
|
|
|
GC_ARG_TYPE_UINT32, GC_BACKEND_GPGSM },
|
|
|
|
|
|
|
|
|
|
{ "Security",
|
|
|
|
|
GC_OPT_FLAG_GROUP, GC_LEVEL_BASIC,
|
2004-09-29 18:16:47 +02:00
|
|
|
|
"gnupg", N_("Options controlling the security") },
|
2004-03-16 20:00:25 +01:00
|
|
|
|
{ "disable-crl-checks", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
|
|
|
|
|
"gnupg", "never consult a CRL",
|
|
|
|
|
GC_ARG_TYPE_NONE, GC_BACKEND_GPGSM },
|
|
|
|
|
{ "enable-ocsp", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED,
|
|
|
|
|
"gnupg", "check validity using OCSP",
|
|
|
|
|
GC_ARG_TYPE_NONE, GC_BACKEND_GPGSM },
|
|
|
|
|
{ "include-certs", GC_OPT_FLAG_NONE, GC_LEVEL_EXPERT,
|
|
|
|
|
"gnupg", "|N|number of certificates to include",
|
|
|
|
|
GC_ARG_TYPE_INT32, GC_BACKEND_GPGSM },
|
|
|
|
|
{ "disable-policy-checks", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED,
|
|
|
|
|
"gnupg", "do not check certificate policies",
|
|
|
|
|
GC_ARG_TYPE_NONE, GC_BACKEND_GPGSM },
|
|
|
|
|
{ "auto-issuer-key-retrieve", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
|
|
|
|
|
"gnupg", "fetch missing issuer certificates",
|
|
|
|
|
GC_ARG_TYPE_NONE, GC_BACKEND_GPGSM },
|
|
|
|
|
|
2004-02-18 18:00:56 +01:00
|
|
|
|
GC_OPTION_NULL
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2004-01-29 00:58:18 +01:00
|
|
|
|
/* The options of the GC_COMPONENT_DIRMNGR component. */
|
|
|
|
|
static gc_option_t gc_options_dirmngr[] =
|
|
|
|
|
{
|
|
|
|
|
/* The configuration file to which we write the changes. */
|
2004-01-31 14:58:27 +01:00
|
|
|
|
{ "gpgconf-dirmngr.conf", GC_OPT_FLAG_NONE, GC_LEVEL_INTERNAL,
|
2004-01-29 00:58:18 +01:00
|
|
|
|
NULL, NULL, GC_ARG_TYPE_PATHNAME, GC_BACKEND_DIRMNGR },
|
|
|
|
|
|
|
|
|
|
{ "Monitor",
|
|
|
|
|
GC_OPT_FLAG_GROUP, GC_LEVEL_BASIC,
|
2004-09-29 18:16:47 +02:00
|
|
|
|
"gnupg", N_("Options controlling the diagnostic output") },
|
2004-01-31 14:58:27 +01:00
|
|
|
|
{ "verbose", GC_OPT_FLAG_LIST, GC_LEVEL_BASIC,
|
2004-01-29 00:58:18 +01:00
|
|
|
|
"dirmngr", "verbose",
|
|
|
|
|
GC_ARG_TYPE_NONE, GC_BACKEND_DIRMNGR },
|
|
|
|
|
{ "quiet", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
|
|
|
|
|
"dirmngr", "be somewhat more quiet",
|
|
|
|
|
GC_ARG_TYPE_NONE, GC_BACKEND_DIRMNGR },
|
|
|
|
|
{ "no-greeting", GC_OPT_FLAG_NONE, GC_LEVEL_INVISIBLE,
|
|
|
|
|
NULL, NULL,
|
|
|
|
|
GC_ARG_TYPE_NONE, GC_BACKEND_DIRMNGR },
|
|
|
|
|
|
|
|
|
|
{ "Format",
|
|
|
|
|
GC_OPT_FLAG_GROUP, GC_LEVEL_BASIC,
|
2004-09-29 18:16:47 +02:00
|
|
|
|
"gnupg", N_("Options controlling the format of the output") },
|
2004-01-29 00:58:18 +01:00
|
|
|
|
{ "sh", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
|
|
|
|
|
"dirmngr", "sh-style command output",
|
|
|
|
|
GC_ARG_TYPE_NONE, GC_BACKEND_DIRMNGR },
|
|
|
|
|
{ "csh", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
|
|
|
|
|
"dirmngr", "csh-style command output",
|
|
|
|
|
GC_ARG_TYPE_NONE, GC_BACKEND_DIRMNGR },
|
|
|
|
|
|
|
|
|
|
{ "Configuration",
|
|
|
|
|
GC_OPT_FLAG_GROUP, GC_LEVEL_EXPERT,
|
2004-09-29 18:16:47 +02:00
|
|
|
|
"gnupg", N_("Options controlling the configuration") },
|
2004-01-29 00:58:18 +01:00
|
|
|
|
{ "options", GC_OPT_FLAG_NONE, GC_LEVEL_EXPERT,
|
|
|
|
|
"dirmngr", "|FILE|read options from FILE",
|
|
|
|
|
GC_ARG_TYPE_PATHNAME, GC_BACKEND_DIRMNGR },
|
|
|
|
|
|
|
|
|
|
{ "Debug",
|
|
|
|
|
GC_OPT_FLAG_GROUP, GC_LEVEL_ADVANCED,
|
2004-09-29 18:16:47 +02:00
|
|
|
|
"gnupg", N_("Options useful for debugging") },
|
2004-03-16 20:00:25 +01:00
|
|
|
|
{ "debug-level", GC_OPT_FLAG_ARG_OPT, GC_LEVEL_ADVANCED,
|
|
|
|
|
"dirmngr", "|LEVEL|set the debugging level to LEVEL",
|
|
|
|
|
GC_ARG_TYPE_STRING, GC_BACKEND_DIRMNGR },
|
2004-01-29 00:58:18 +01:00
|
|
|
|
{ "no-detach", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED,
|
|
|
|
|
"dirmngr", "do not detach from the console",
|
|
|
|
|
GC_ARG_TYPE_NONE, GC_BACKEND_DIRMNGR },
|
|
|
|
|
{ "log-file", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED,
|
2004-10-01 18:51:18 +02:00
|
|
|
|
"dirmngr", N_("|FILE|write server mode logs to FILE"),
|
2004-01-29 00:58:18 +01:00
|
|
|
|
GC_ARG_TYPE_PATHNAME, GC_BACKEND_DIRMNGR },
|
|
|
|
|
{ "debug-wait", GC_OPT_FLAG_NONE, GC_LEVEL_INVISIBLE,
|
|
|
|
|
NULL, NULL,
|
|
|
|
|
GC_ARG_TYPE_UINT32, GC_BACKEND_DIRMNGR },
|
|
|
|
|
{ "faked-system-time", GC_OPT_FLAG_NONE, GC_LEVEL_INVISIBLE,
|
|
|
|
|
NULL, NULL,
|
|
|
|
|
GC_ARG_TYPE_UINT32, GC_BACKEND_DIRMNGR },
|
|
|
|
|
|
|
|
|
|
{ "Enforcement",
|
|
|
|
|
GC_OPT_FLAG_GROUP, GC_LEVEL_BASIC,
|
2004-09-29 18:16:47 +02:00
|
|
|
|
"gnupg", N_("Options controlling the interactivity and enforcement") },
|
2004-01-29 00:58:18 +01:00
|
|
|
|
{ "batch", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
|
|
|
|
|
"dirmngr", "run without asking a user",
|
|
|
|
|
GC_ARG_TYPE_NONE, GC_BACKEND_DIRMNGR },
|
|
|
|
|
{ "force", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
|
|
|
|
|
"dirmngr", "force loading of outdated CRLs",
|
|
|
|
|
GC_ARG_TYPE_NONE, GC_BACKEND_DIRMNGR },
|
|
|
|
|
|
2004-11-23 18:09:51 +01:00
|
|
|
|
{ "HTTP",
|
|
|
|
|
GC_OPT_FLAG_GROUP, GC_LEVEL_ADVANCED,
|
|
|
|
|
"gnupg", N_("Configuration for HTTP servers") },
|
|
|
|
|
{ "disable-http", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED,
|
|
|
|
|
"dirmngr", "inhibit the use of HTTP",
|
|
|
|
|
GC_ARG_TYPE_NONE, GC_BACKEND_DIRMNGR },
|
2004-11-24 11:43:53 +01:00
|
|
|
|
{ "ignore-http-dp", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED,
|
|
|
|
|
"dirmngr", "ignore HTTP CRL distribution points",
|
|
|
|
|
GC_ARG_TYPE_NONE, GC_BACKEND_DIRMNGR },
|
2004-11-23 18:09:51 +01:00
|
|
|
|
{ "http-proxy", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED,
|
|
|
|
|
"dirmngr", "|URL|redirect all HTTP requests to URL",
|
|
|
|
|
GC_ARG_TYPE_STRING, GC_BACKEND_DIRMNGR },
|
2005-03-09 11:11:14 +01:00
|
|
|
|
{ "honor-http-proxy", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED,
|
|
|
|
|
"dirmngr", N_("use system's HTTP proxy setting"),
|
|
|
|
|
GC_ARG_TYPE_STRING, GC_BACKEND_DIRMNGR },
|
2004-11-23 18:09:51 +01:00
|
|
|
|
|
2004-01-29 00:58:18 +01:00
|
|
|
|
{ "LDAP",
|
|
|
|
|
GC_OPT_FLAG_GROUP, GC_LEVEL_BASIC,
|
2004-09-29 18:16:47 +02:00
|
|
|
|
"gnupg", N_("Configuration of LDAP servers to use") },
|
2004-11-23 18:09:51 +01:00
|
|
|
|
{ "disable-ldap", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED,
|
|
|
|
|
"dirmngr", "inhibit the use of LDAP",
|
|
|
|
|
GC_ARG_TYPE_NONE, GC_BACKEND_DIRMNGR },
|
2004-11-24 11:43:53 +01:00
|
|
|
|
{ "ignore-ldap-dp", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED,
|
|
|
|
|
"dirmngr", "ignore LDAP CRL distribution points",
|
|
|
|
|
GC_ARG_TYPE_NONE, GC_BACKEND_DIRMNGR },
|
2004-11-23 18:09:51 +01:00
|
|
|
|
{ "ldap-proxy", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
|
|
|
|
|
"dirmngr", "|HOST|use HOST for LDAP queries",
|
|
|
|
|
GC_ARG_TYPE_STRING, GC_BACKEND_DIRMNGR },
|
|
|
|
|
{ "only-ldap-proxy", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED,
|
|
|
|
|
"dirmngr", "do not use fallback hosts with --ldap-proxy",
|
|
|
|
|
GC_ARG_TYPE_NONE, GC_BACKEND_DIRMNGR },
|
|
|
|
|
{ "add-servers", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED,
|
2004-01-29 00:58:18 +01:00
|
|
|
|
"dirmngr", "add new servers discovered in CRL distribution points"
|
|
|
|
|
" to serverlist", GC_ARG_TYPE_NONE, GC_BACKEND_DIRMNGR },
|
|
|
|
|
{ "ldaptimeout", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
|
|
|
|
|
"dirmngr", "|N|set LDAP timeout to N seconds",
|
|
|
|
|
GC_ARG_TYPE_UINT32, GC_BACKEND_DIRMNGR },
|
|
|
|
|
/* The following entry must not be removed, as it is required for
|
|
|
|
|
the GC_BACKEND_DIRMNGR_LDAP_SERVER_LIST. */
|
|
|
|
|
{ "ldapserverlist-file",
|
|
|
|
|
GC_OPT_FLAG_NONE, GC_LEVEL_INTERNAL,
|
|
|
|
|
"dirmngr", "|FILE|read LDAP server list from FILE",
|
|
|
|
|
GC_ARG_TYPE_PATHNAME, GC_BACKEND_DIRMNGR },
|
|
|
|
|
/* This entry must come after at least one entry for
|
|
|
|
|
GC_BACKEND_DIRMNGR in this component, so that the entry for
|
|
|
|
|
"ldapserverlist-file will be initialized before this one. */
|
2004-03-23 19:27:37 +01:00
|
|
|
|
{ "LDAP Server", GC_OPT_FLAG_ARG_OPT|GC_OPT_FLAG_LIST, GC_LEVEL_BASIC,
|
2004-01-29 00:58:18 +01:00
|
|
|
|
NULL, "LDAP server list",
|
|
|
|
|
GC_ARG_TYPE_LDAP_SERVER, GC_BACKEND_DIRMNGR_LDAP_SERVER_LIST },
|
|
|
|
|
{ "max-replies", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
|
|
|
|
|
"dirmngr", "|N|do not return more than N items in one query",
|
|
|
|
|
GC_ARG_TYPE_UINT32, GC_BACKEND_DIRMNGR },
|
|
|
|
|
|
2004-03-16 11:48:13 +01:00
|
|
|
|
{ "OCSP",
|
|
|
|
|
GC_OPT_FLAG_GROUP, GC_LEVEL_ADVANCED,
|
2004-09-29 18:16:47 +02:00
|
|
|
|
"gnupg", N_("Configuration for OCSP") },
|
2004-03-23 19:43:25 +01:00
|
|
|
|
{ "allow-ocsp", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
|
|
|
|
|
"dirmngr", "allow sending OCSP requests",
|
|
|
|
|
GC_ARG_TYPE_NONE, GC_BACKEND_DIRMNGR },
|
2004-12-13 16:49:56 +01:00
|
|
|
|
{ "ignore-ocsp-service-url", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED,
|
2004-11-24 15:50:20 +01:00
|
|
|
|
"dirmngr", "ignore certificate contained OCSP service URLs",
|
|
|
|
|
GC_ARG_TYPE_NONE, GC_BACKEND_DIRMNGR },
|
2004-03-16 11:48:13 +01:00
|
|
|
|
{ "ocsp-responder", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED,
|
2004-10-01 14:53:09 +02:00
|
|
|
|
"dirmngr", "|URL|use OCSP responder at URL",
|
2004-03-16 11:48:13 +01:00
|
|
|
|
GC_ARG_TYPE_STRING, GC_BACKEND_DIRMNGR },
|
2004-04-28 11:04:03 +02:00
|
|
|
|
{ "ocsp-signer", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED,
|
|
|
|
|
"dirmngr", "|FPR|OCSP response signed by FPR",
|
|
|
|
|
GC_ARG_TYPE_STRING, GC_BACKEND_DIRMNGR },
|
2004-03-16 11:48:13 +01:00
|
|
|
|
|
|
|
|
|
|
2004-01-29 00:58:18 +01:00
|
|
|
|
GC_OPTION_NULL
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Component system. Each component is a set of options that can be
|
|
|
|
|
configured at the same time. If you change this, don't forget to
|
|
|
|
|
update GC_COMPONENT below. */
|
|
|
|
|
typedef enum
|
|
|
|
|
{
|
2004-03-23 14:48:46 +01:00
|
|
|
|
/* The classic GPG for OpenPGP. */
|
|
|
|
|
GC_COMPONENT_GPG,
|
|
|
|
|
|
2004-01-29 00:58:18 +01:00
|
|
|
|
/* The GPG Agent. */
|
|
|
|
|
GC_COMPONENT_GPG_AGENT,
|
|
|
|
|
|
2004-02-18 18:00:56 +01:00
|
|
|
|
/* The Smardcard Daemon. */
|
|
|
|
|
GC_COMPONENT_SCDAEMON,
|
|
|
|
|
|
|
|
|
|
/* GPG for S/MIME. */
|
|
|
|
|
GC_COMPONENT_GPGSM,
|
|
|
|
|
|
2004-01-29 00:58:18 +01:00
|
|
|
|
/* The LDAP Directory Manager for CRLs. */
|
|
|
|
|
GC_COMPONENT_DIRMNGR,
|
|
|
|
|
|
|
|
|
|
/* The number of components. */
|
|
|
|
|
GC_COMPONENT_NR
|
|
|
|
|
} gc_component_t;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* The information associated with each component. */
|
|
|
|
|
static struct
|
|
|
|
|
{
|
|
|
|
|
/* The name of this component. Must not contain a colon (':')
|
|
|
|
|
character. */
|
|
|
|
|
const char *name;
|
|
|
|
|
|
|
|
|
|
/* The gettext domain for the description DESC. If this is NULL,
|
|
|
|
|
then the description is not translated. */
|
|
|
|
|
const char *desc_domain;
|
|
|
|
|
|
|
|
|
|
/* The description for this domain. */
|
|
|
|
|
const char *desc;
|
|
|
|
|
|
|
|
|
|
/* The list of options for this component, terminated by
|
|
|
|
|
GC_OPTION_NULL. */
|
|
|
|
|
gc_option_t *options;
|
|
|
|
|
} gc_component[] =
|
|
|
|
|
{
|
2004-03-23 14:48:46 +01:00
|
|
|
|
{ "gpg", NULL, "GPG for OpenPGP", gc_options_gpg },
|
2004-01-29 00:58:18 +01:00
|
|
|
|
{ "gpg-agent", NULL, "GPG Agent", gc_options_gpg_agent },
|
2004-02-18 18:00:56 +01:00
|
|
|
|
{ "scdaemon", NULL, "Smartcard Daemon", gc_options_scdaemon },
|
|
|
|
|
{ "gpgsm", NULL, "GPG for S/MIME", gc_options_gpgsm },
|
2004-05-21 15:55:43 +02:00
|
|
|
|
{ "dirmngr", NULL, "Directory Manager", gc_options_dirmngr }
|
2004-01-29 00:58:18 +01:00
|
|
|
|
};
|
|
|
|
|
|
2004-03-23 13:21:48 +01:00
|
|
|
|
|
|
|
|
|
/* Engine specific support. */
|
|
|
|
|
void
|
|
|
|
|
gpg_agent_runtime_change (void)
|
|
|
|
|
{
|
2004-12-15 15:15:54 +01:00
|
|
|
|
#ifndef HAVE_W32_SYSTEM
|
2004-03-23 13:21:48 +01:00
|
|
|
|
char *agent = getenv ("GPG_AGENT_INFO");
|
|
|
|
|
char *pid_str;
|
|
|
|
|
unsigned long pid_long;
|
|
|
|
|
char *tail;
|
|
|
|
|
pid_t pid;
|
|
|
|
|
|
|
|
|
|
if (!agent)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
pid_str = strchr (agent, ':');
|
|
|
|
|
if (!pid_str)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
pid_str++;
|
|
|
|
|
errno = 0;
|
|
|
|
|
pid_long = strtoul (pid_str, &tail, 0);
|
|
|
|
|
if (errno || (*tail != ':' && *tail != '\0'))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
pid = (pid_t) pid_long;
|
|
|
|
|
|
|
|
|
|
/* Check for overflow. */
|
|
|
|
|
if (pid_long != (unsigned long) pid)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* Ignore any errors here. */
|
|
|
|
|
kill (pid, SIGHUP);
|
2004-12-15 15:15:54 +01:00
|
|
|
|
#endif /*!HAVE_W32_SYSTEM*/
|
2004-03-23 13:21:48 +01:00
|
|
|
|
}
|
|
|
|
|
|
2004-01-29 00:58:18 +01:00
|
|
|
|
|
2004-09-29 18:16:47 +02:00
|
|
|
|
/* More or less Robust version of dgettext. It has the side effect of
|
|
|
|
|
switching the codeset to utf-8 because this is what we want to
|
2004-04-07 18:53:55 +02:00
|
|
|
|
output. In theory it is posible to keep the orginal code set and
|
|
|
|
|
switch back for regular disgnostic output (redefine "_(" for that)
|
|
|
|
|
but given the natur of this tool, being something invoked from
|
|
|
|
|
other pograms, it does not make much sense. */
|
2004-01-29 00:58:18 +01:00
|
|
|
|
static const char *
|
|
|
|
|
my_dgettext (const char *domain, const char *msgid)
|
|
|
|
|
{
|
2004-04-07 18:53:55 +02:00
|
|
|
|
#ifdef ENABLE_NLS
|
2004-01-29 00:58:18 +01:00
|
|
|
|
if (domain)
|
|
|
|
|
{
|
2004-04-07 18:53:55 +02:00
|
|
|
|
static int switched_codeset;
|
|
|
|
|
char *text;
|
|
|
|
|
|
|
|
|
|
if (!switched_codeset)
|
|
|
|
|
{
|
|
|
|
|
switched_codeset = 1;
|
2004-10-01 14:53:09 +02:00
|
|
|
|
bind_textdomain_codeset (PACKAGE_GT, "utf-8");
|
|
|
|
|
|
|
|
|
|
bindtextdomain ("dirmngr", LOCALEDIR);
|
|
|
|
|
bind_textdomain_codeset ("dirmngr", "utf-8");
|
|
|
|
|
|
2004-04-07 18:53:55 +02:00
|
|
|
|
}
|
2004-09-29 18:16:47 +02:00
|
|
|
|
|
|
|
|
|
/* Note: This is a hack to actually use the gnupg2 domain as
|
|
|
|
|
long we are in a transition phase where gnupg 1.x and 1.9 may
|
|
|
|
|
coexist. */
|
|
|
|
|
if (!strcmp (domain, "gnupg"))
|
|
|
|
|
domain = PACKAGE_GT;
|
|
|
|
|
|
2004-04-07 18:53:55 +02:00
|
|
|
|
text = dgettext (domain, msgid);
|
2004-01-29 00:58:18 +01:00
|
|
|
|
return text ? text : msgid;
|
|
|
|
|
}
|
|
|
|
|
else
|
2004-04-07 18:53:55 +02:00
|
|
|
|
#endif
|
2004-01-29 00:58:18 +01:00
|
|
|
|
return msgid;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Percent-Escape special characters. The string is valid until the
|
|
|
|
|
next invocation of the function. */
|
|
|
|
|
static char *
|
|
|
|
|
percent_escape (const char *src)
|
|
|
|
|
{
|
|
|
|
|
static char *esc_str;
|
|
|
|
|
static int esc_str_len;
|
|
|
|
|
int new_len = 3 * strlen (src) + 1;
|
|
|
|
|
char *dst;
|
|
|
|
|
|
|
|
|
|
if (esc_str_len < new_len)
|
|
|
|
|
{
|
|
|
|
|
char *new_esc_str = realloc (esc_str, new_len);
|
|
|
|
|
if (!new_esc_str)
|
2004-01-30 13:15:53 +01:00
|
|
|
|
gc_error (1, errno, "can not escape string");
|
2004-01-29 00:58:18 +01:00
|
|
|
|
esc_str = new_esc_str;
|
|
|
|
|
esc_str_len = new_len;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dst = esc_str;
|
|
|
|
|
while (*src)
|
|
|
|
|
{
|
|
|
|
|
if (*src == '%')
|
|
|
|
|
{
|
|
|
|
|
*(dst++) = '%';
|
|
|
|
|
*(dst++) = '2';
|
|
|
|
|
*(dst++) = '5';
|
|
|
|
|
}
|
|
|
|
|
else if (*src == ':')
|
|
|
|
|
{
|
|
|
|
|
/* The colon is used as field separator. */
|
|
|
|
|
*(dst++) = '%';
|
|
|
|
|
*(dst++) = '3';
|
|
|
|
|
*(dst++) = 'a';
|
|
|
|
|
}
|
|
|
|
|
else if (*src == ',')
|
|
|
|
|
{
|
|
|
|
|
/* The comma is used as list separator. */
|
|
|
|
|
*(dst++) = '%';
|
|
|
|
|
*(dst++) = '2';
|
|
|
|
|
*(dst++) = 'c';
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
*(dst++) = *(src);
|
|
|
|
|
src++;
|
|
|
|
|
}
|
|
|
|
|
*dst = '\0';
|
|
|
|
|
return esc_str;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2004-02-23 20:37:04 +01:00
|
|
|
|
/* Convert two hexadecimal digits from STR to the value they
|
|
|
|
|
represent. Returns -1 if one of the characters is not a
|
|
|
|
|
hexadecimal digit. */
|
|
|
|
|
static int
|
|
|
|
|
hextobyte (const char *str)
|
|
|
|
|
{
|
|
|
|
|
int val = 0;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
#define NROFHEXDIGITS 2
|
|
|
|
|
for (i = 0; i < NROFHEXDIGITS; i++)
|
|
|
|
|
{
|
|
|
|
|
if (*str >= '0' && *str <= '9')
|
|
|
|
|
val += *str - '0';
|
|
|
|
|
else if (*str >= 'A' && *str <= 'F')
|
|
|
|
|
val += 10 + *str - 'A';
|
|
|
|
|
else if (*str >= 'a' && *str <= 'f')
|
|
|
|
|
val += 10 + *str - 'a';
|
|
|
|
|
else
|
|
|
|
|
return -1;
|
|
|
|
|
if (i < NROFHEXDIGITS - 1)
|
|
|
|
|
val *= 16;
|
|
|
|
|
str++;
|
|
|
|
|
}
|
|
|
|
|
return val;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Percent-Deescape special characters. The string is valid until the
|
|
|
|
|
next invocation of the function. */
|
|
|
|
|
static char *
|
|
|
|
|
percent_deescape (const char *src)
|
|
|
|
|
{
|
|
|
|
|
static char *str;
|
|
|
|
|
static int str_len;
|
|
|
|
|
int new_len = 3 * strlen (src) + 1;
|
|
|
|
|
char *dst;
|
|
|
|
|
|
|
|
|
|
if (str_len < new_len)
|
|
|
|
|
{
|
|
|
|
|
char *new_str = realloc (str, new_len);
|
|
|
|
|
if (!new_str)
|
|
|
|
|
gc_error (1, errno, "can not deescape string");
|
|
|
|
|
str = new_str;
|
|
|
|
|
str_len = new_len;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dst = str;
|
|
|
|
|
while (*src)
|
|
|
|
|
{
|
|
|
|
|
if (*src == '%')
|
|
|
|
|
{
|
|
|
|
|
int val = hextobyte (src + 1);
|
|
|
|
|
|
|
|
|
|
if (val < 0)
|
|
|
|
|
gc_error (1, 0, "malformed end of string %s", src);
|
|
|
|
|
|
|
|
|
|
*(dst++) = (char) val;
|
|
|
|
|
src += 3;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
*(dst++) = *(src++);
|
|
|
|
|
}
|
|
|
|
|
*dst = '\0';
|
|
|
|
|
return str;
|
|
|
|
|
}
|
|
|
|
|
|
2004-01-29 00:58:18 +01:00
|
|
|
|
|
|
|
|
|
/* List all components that are available. */
|
|
|
|
|
void
|
|
|
|
|
gc_component_list_components (FILE *out)
|
|
|
|
|
{
|
|
|
|
|
gc_component_t idx;
|
|
|
|
|
|
|
|
|
|
for (idx = 0; idx < GC_COMPONENT_NR; idx++)
|
|
|
|
|
{
|
|
|
|
|
const char *desc = gc_component[idx].desc;
|
|
|
|
|
desc = my_dgettext (gc_component[idx].desc_domain, desc);
|
|
|
|
|
fprintf (out, "%s:%s\n", gc_component[idx].name, percent_escape (desc));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Find the component with the name NAME. Returns -1 if not
|
|
|
|
|
found. */
|
|
|
|
|
int
|
|
|
|
|
gc_component_find (const char *name)
|
|
|
|
|
{
|
|
|
|
|
gc_component_t idx;
|
|
|
|
|
|
|
|
|
|
for (idx = 0; idx < GC_COMPONENT_NR; idx++)
|
|
|
|
|
{
|
|
|
|
|
if (!strcmp (name, gc_component[idx].name))
|
|
|
|
|
return idx;
|
|
|
|
|
}
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2004-02-26 23:45:19 +01:00
|
|
|
|
/* List the option OPTION. */
|
|
|
|
|
static void
|
|
|
|
|
list_one_option (const gc_option_t *option, FILE *out)
|
|
|
|
|
{
|
|
|
|
|
const char *desc = NULL;
|
|
|
|
|
char *arg_name = NULL;
|
2004-01-29 00:58:18 +01:00
|
|
|
|
|
2004-02-26 23:45:19 +01:00
|
|
|
|
if (option->desc)
|
2004-01-29 00:58:18 +01:00
|
|
|
|
{
|
2004-02-26 23:45:19 +01:00
|
|
|
|
desc = my_dgettext (option->desc_domain, option->desc);
|
2004-01-29 00:58:18 +01:00
|
|
|
|
|
2004-02-26 23:45:19 +01:00
|
|
|
|
if (*desc == '|')
|
2004-01-29 00:58:18 +01:00
|
|
|
|
{
|
2004-02-26 23:45:19 +01:00
|
|
|
|
const char *arg_tail = strchr (&desc[1], '|');
|
|
|
|
|
|
|
|
|
|
if (arg_tail)
|
|
|
|
|
{
|
|
|
|
|
int arg_len = arg_tail - &desc[1];
|
|
|
|
|
arg_name = xmalloc (arg_len + 1);
|
|
|
|
|
memcpy (arg_name, &desc[1], arg_len);
|
|
|
|
|
arg_name[arg_len] = '\0';
|
|
|
|
|
desc = arg_tail + 1;
|
|
|
|
|
}
|
2004-01-29 00:58:18 +01:00
|
|
|
|
}
|
2004-02-26 23:45:19 +01:00
|
|
|
|
}
|
|
|
|
|
|
2004-01-29 00:58:18 +01:00
|
|
|
|
|
2004-02-26 23:45:19 +01:00
|
|
|
|
/* YOU MUST NOT REORDER THE FIELDS IN THIS OUTPUT, AS THEIR ORDER IS
|
|
|
|
|
PART OF THE EXTERNAL INTERFACE. YOU MUST NOT REMOVE ANY
|
|
|
|
|
FIELDS. */
|
|
|
|
|
|
|
|
|
|
/* The name field. */
|
|
|
|
|
fprintf (out, "%s", option->name);
|
|
|
|
|
|
|
|
|
|
/* The flags field. */
|
|
|
|
|
fprintf (out, ":%lu", option->flags);
|
|
|
|
|
if (opt.verbose)
|
|
|
|
|
{
|
|
|
|
|
putc (' ', out);
|
|
|
|
|
|
|
|
|
|
if (!option->flags)
|
|
|
|
|
fprintf (out, "none");
|
|
|
|
|
else
|
2004-01-29 00:58:18 +01:00
|
|
|
|
{
|
2004-02-26 23:45:19 +01:00
|
|
|
|
unsigned long flags = option->flags;
|
|
|
|
|
unsigned long flag = 0;
|
|
|
|
|
unsigned long first = 1;
|
2004-01-29 00:58:18 +01:00
|
|
|
|
|
2004-02-26 23:45:19 +01:00
|
|
|
|
while (flags)
|
2004-01-29 00:58:18 +01:00
|
|
|
|
{
|
2004-02-26 23:45:19 +01:00
|
|
|
|
if (flags & 1)
|
2004-01-29 00:58:18 +01:00
|
|
|
|
{
|
2004-02-26 23:45:19 +01:00
|
|
|
|
if (first)
|
|
|
|
|
first = 0;
|
|
|
|
|
else
|
|
|
|
|
putc (',', out);
|
|
|
|
|
fprintf (out, "%s", gc_flag[flag].name);
|
2004-01-29 00:58:18 +01:00
|
|
|
|
}
|
2004-02-26 23:45:19 +01:00
|
|
|
|
flags >>= 1;
|
|
|
|
|
flag++;
|
2004-01-29 00:58:18 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
2004-02-26 23:45:19 +01:00
|
|
|
|
}
|
2004-01-29 00:58:18 +01:00
|
|
|
|
|
2004-02-26 23:45:19 +01:00
|
|
|
|
/* The level field. */
|
|
|
|
|
fprintf (out, ":%u", option->level);
|
|
|
|
|
if (opt.verbose)
|
|
|
|
|
fprintf (out, " %s", gc_level[option->level].name);
|
|
|
|
|
|
|
|
|
|
/* The description field. */
|
|
|
|
|
fprintf (out, ":%s", desc ? percent_escape (desc) : "");
|
|
|
|
|
|
|
|
|
|
/* The type field. */
|
|
|
|
|
fprintf (out, ":%u", option->arg_type);
|
|
|
|
|
if (opt.verbose)
|
|
|
|
|
fprintf (out, " %s", gc_arg_type[option->arg_type].name);
|
|
|
|
|
|
|
|
|
|
/* The alternate type field. */
|
|
|
|
|
fprintf (out, ":%u", gc_arg_type[option->arg_type].fallback);
|
|
|
|
|
if (opt.verbose)
|
|
|
|
|
fprintf (out, " %s",
|
|
|
|
|
gc_arg_type[gc_arg_type[option->arg_type].fallback].name);
|
|
|
|
|
|
|
|
|
|
/* The argument name field. */
|
|
|
|
|
fprintf (out, ":%s", arg_name ? percent_escape (arg_name) : "");
|
|
|
|
|
if (arg_name)
|
|
|
|
|
xfree (arg_name);
|
|
|
|
|
|
|
|
|
|
/* The default value field. */
|
|
|
|
|
fprintf (out, ":%s", option->default_value ? option->default_value : "");
|
|
|
|
|
|
|
|
|
|
/* The default argument field. */
|
|
|
|
|
fprintf (out, ":%s", option->default_arg ? option->default_arg : "");
|
|
|
|
|
|
|
|
|
|
/* The value field. */
|
|
|
|
|
if (gc_arg_type[option->arg_type].fallback == GC_ARG_TYPE_NONE
|
|
|
|
|
&& (option->flags & GC_OPT_FLAG_LIST)
|
|
|
|
|
&& option->value)
|
|
|
|
|
/* The special format "1,1,1,1,...,1" is converted to a number
|
|
|
|
|
here. */
|
|
|
|
|
fprintf (out, ":%u", (strlen (option->value) + 1) / 2);
|
|
|
|
|
else
|
|
|
|
|
fprintf (out, ":%s", option->value ? option->value : "");
|
2004-01-29 00:58:18 +01:00
|
|
|
|
|
2004-02-26 23:45:19 +01:00
|
|
|
|
/* ADD NEW FIELDS HERE. */
|
2004-01-29 00:58:18 +01:00
|
|
|
|
|
2004-02-26 23:45:19 +01:00
|
|
|
|
putc ('\n', out);
|
|
|
|
|
}
|
2004-01-29 00:58:18 +01:00
|
|
|
|
|
2004-02-26 23:45:19 +01:00
|
|
|
|
|
|
|
|
|
/* List all options of the component COMPONENT. */
|
|
|
|
|
void
|
|
|
|
|
gc_component_list_options (int component, FILE *out)
|
|
|
|
|
{
|
|
|
|
|
const gc_option_t *option = gc_component[component].options;
|
|
|
|
|
const gc_option_t *group_option = NULL;
|
|
|
|
|
|
|
|
|
|
while (option->name)
|
|
|
|
|
{
|
|
|
|
|
/* Do not output unknown or internal options. */
|
|
|
|
|
if (!(option->flags & GC_OPT_FLAG_GROUP)
|
|
|
|
|
&& (!option->active || option->level == GC_LEVEL_INTERNAL))
|
|
|
|
|
{
|
|
|
|
|
option++;
|
|
|
|
|
continue;
|
2004-01-29 00:58:18 +01:00
|
|
|
|
}
|
|
|
|
|
|
2004-02-26 23:45:19 +01:00
|
|
|
|
if (option->flags & GC_OPT_FLAG_GROUP)
|
|
|
|
|
group_option = option;
|
2004-02-25 20:35:36 +01:00
|
|
|
|
else
|
2004-02-26 23:45:19 +01:00
|
|
|
|
{
|
|
|
|
|
if (group_option)
|
|
|
|
|
{
|
|
|
|
|
list_one_option (group_option, out);
|
|
|
|
|
group_option = NULL;
|
|
|
|
|
}
|
2004-01-29 00:58:18 +01:00
|
|
|
|
|
2004-02-26 23:45:19 +01:00
|
|
|
|
list_one_option (option, out);
|
|
|
|
|
}
|
2004-01-29 00:58:18 +01:00
|
|
|
|
|
|
|
|
|
option++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Find the option NAME in component COMPONENT, for the backend
|
|
|
|
|
BACKEND. If BACKEND is GC_BACKEND_ANY, any backend will match. */
|
|
|
|
|
static gc_option_t *
|
|
|
|
|
find_option (gc_component_t component, const char *name,
|
|
|
|
|
gc_backend_t backend)
|
|
|
|
|
{
|
|
|
|
|
gc_option_t *option = gc_component[component].options;
|
|
|
|
|
while (option->name)
|
|
|
|
|
{
|
|
|
|
|
if (!(option->flags & GC_OPT_FLAG_GROUP)
|
|
|
|
|
&& !strcmp (option->name, name)
|
|
|
|
|
&& (backend == GC_BACKEND_ANY || option->backend == backend))
|
|
|
|
|
break;
|
|
|
|
|
option++;
|
|
|
|
|
}
|
|
|
|
|
return option->name ? option : NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Determine the configuration pathname for the component COMPONENT
|
|
|
|
|
and backend BACKEND. */
|
|
|
|
|
static char *
|
|
|
|
|
get_config_pathname (gc_component_t component, gc_backend_t backend)
|
|
|
|
|
{
|
2004-01-31 14:58:27 +01:00
|
|
|
|
char *pathname = NULL;
|
2004-01-29 00:58:18 +01:00
|
|
|
|
gc_option_t *option = find_option
|
|
|
|
|
(component, gc_backend[backend].option_config_filename, GC_BACKEND_ANY);
|
|
|
|
|
assert (option);
|
2004-01-31 14:58:27 +01:00
|
|
|
|
assert (option->arg_type == GC_ARG_TYPE_PATHNAME);
|
|
|
|
|
assert (!(option->flags & GC_OPT_FLAG_LIST));
|
2004-01-29 00:58:18 +01:00
|
|
|
|
|
2004-01-31 14:58:27 +01:00
|
|
|
|
if (!option->active || !option->default_value)
|
|
|
|
|
gc_error (1, 0, "Option %s, needed by backend %s, was not initialized",
|
2004-01-30 13:15:53 +01:00
|
|
|
|
gc_backend[backend].option_config_filename,
|
|
|
|
|
gc_backend[backend].name);
|
2004-01-31 14:58:27 +01:00
|
|
|
|
|
|
|
|
|
if (option->value && *option->value)
|
2004-02-23 20:37:04 +01:00
|
|
|
|
pathname = percent_deescape (&option->value[1]);
|
|
|
|
|
else if (option->default_value && *option->default_value)
|
|
|
|
|
pathname = percent_deescape (&option->default_value[1]);
|
2004-01-29 00:58:18 +01:00
|
|
|
|
else
|
2004-02-23 20:37:04 +01:00
|
|
|
|
pathname = "";
|
2004-01-29 00:58:18 +01:00
|
|
|
|
|
2004-12-21 20:05:15 +01:00
|
|
|
|
#ifdef HAVE_DOSISH_SYSTEM
|
|
|
|
|
if (!(pathname[0]
|
|
|
|
|
&& pathname[1] == ':'
|
|
|
|
|
&& (pathname[2] == '/' || pathname[2] == '\\')))
|
|
|
|
|
#else
|
2004-02-23 20:37:04 +01:00
|
|
|
|
if (pathname[0] != '/')
|
2004-12-21 20:05:15 +01:00
|
|
|
|
#endif
|
2004-01-31 14:58:27 +01:00
|
|
|
|
gc_error (1, 0, "Option %s, needed by backend %s, is not absolute",
|
2004-01-30 13:15:53 +01:00
|
|
|
|
gc_backend[backend].option_config_filename,
|
|
|
|
|
gc_backend[backend].name);
|
2004-01-29 00:58:18 +01:00
|
|
|
|
|
2004-02-23 20:37:04 +01:00
|
|
|
|
return pathname;
|
2004-01-29 00:58:18 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Retrieve the options for the component COMPONENT from backend
|
|
|
|
|
BACKEND, which we already know is a program-type backend. */
|
|
|
|
|
static void
|
|
|
|
|
retrieve_options_from_program (gc_component_t component, gc_backend_t backend)
|
|
|
|
|
{
|
|
|
|
|
char *cmd_line;
|
|
|
|
|
char *line = NULL;
|
|
|
|
|
size_t line_len = 0;
|
|
|
|
|
ssize_t length;
|
2004-01-31 14:58:27 +01:00
|
|
|
|
FILE *config;
|
|
|
|
|
char *config_pathname;
|
2004-01-29 00:58:18 +01:00
|
|
|
|
|
2004-01-31 14:58:27 +01:00
|
|
|
|
cmd_line = xasprintf ("%s --gpgconf-list", gc_backend[backend].program);
|
2004-01-29 00:58:18 +01:00
|
|
|
|
|
2004-01-31 14:58:27 +01:00
|
|
|
|
config = popen (cmd_line, "r");
|
|
|
|
|
if (!config)
|
2004-01-30 13:15:53 +01:00
|
|
|
|
gc_error (1, errno, "could not gather active options from %s", cmd_line);
|
2004-01-29 00:58:18 +01:00
|
|
|
|
|
2004-06-14 10:32:07 +02:00
|
|
|
|
while ((length = read_line (config, &line, &line_len, NULL)) > 0)
|
2004-01-29 00:58:18 +01:00
|
|
|
|
{
|
|
|
|
|
gc_option_t *option;
|
2004-02-24 15:31:59 +01:00
|
|
|
|
char *linep;
|
|
|
|
|
unsigned long flags = 0;
|
|
|
|
|
char *default_value = NULL;
|
|
|
|
|
|
2004-01-29 00:58:18 +01:00
|
|
|
|
/* Strip newline and carriage return, if present. */
|
|
|
|
|
while (length > 0
|
|
|
|
|
&& (line[length - 1] == '\n' || line[length - 1] == '\r'))
|
|
|
|
|
line[--length] = '\0';
|
|
|
|
|
|
2004-02-24 15:31:59 +01:00
|
|
|
|
linep = strchr (line, ':');
|
|
|
|
|
if (linep)
|
|
|
|
|
*(linep++) = '\0';
|
|
|
|
|
|
|
|
|
|
/* Extract additional flags. Default to none. */
|
|
|
|
|
if (linep)
|
|
|
|
|
{
|
|
|
|
|
char *end;
|
|
|
|
|
char *tail;
|
|
|
|
|
|
|
|
|
|
end = strchr (linep, ':');
|
|
|
|
|
if (end)
|
|
|
|
|
*(end++) = '\0';
|
|
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
|
flags = strtoul (linep, &tail, 0);
|
|
|
|
|
if (errno)
|
|
|
|
|
gc_error (1, errno, "malformed flags in option %s from %s", line, cmd_line);
|
|
|
|
|
if (!(*tail == '\0' || *tail == ':' || *tail == ' '))
|
|
|
|
|
gc_error (1, 0, "garbage after flags in option %s from %s", line, cmd_line);
|
|
|
|
|
|
|
|
|
|
linep = end;
|
|
|
|
|
}
|
|
|
|
|
|
2004-01-31 14:58:27 +01:00
|
|
|
|
/* Extract default value, if present. Default to empty if
|
|
|
|
|
not. */
|
2004-02-24 15:31:59 +01:00
|
|
|
|
if (linep)
|
2004-01-29 00:58:18 +01:00
|
|
|
|
{
|
2004-01-31 14:58:27 +01:00
|
|
|
|
char *end;
|
2004-01-29 00:58:18 +01:00
|
|
|
|
|
2004-02-24 15:31:59 +01:00
|
|
|
|
end = strchr (linep, ':');
|
2004-01-31 14:58:27 +01:00
|
|
|
|
if (end)
|
2004-02-24 15:31:59 +01:00
|
|
|
|
*(end++) = '\0';
|
|
|
|
|
|
|
|
|
|
if (flags & GC_OPT_FLAG_DEFAULT)
|
|
|
|
|
default_value = linep;
|
|
|
|
|
|
|
|
|
|
linep = end;
|
2004-01-29 00:58:18 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Look up the option in the component and install the
|
|
|
|
|
configuration data. */
|
|
|
|
|
option = find_option (component, line, backend);
|
|
|
|
|
if (option)
|
|
|
|
|
{
|
2004-01-31 14:58:27 +01:00
|
|
|
|
if (option->active)
|
2004-01-30 13:15:53 +01:00
|
|
|
|
gc_error (1, errno, "option %s returned twice from %s",
|
|
|
|
|
line, cmd_line);
|
2004-01-31 14:58:27 +01:00
|
|
|
|
option->active = 1;
|
2004-02-24 15:31:59 +01:00
|
|
|
|
|
|
|
|
|
option->flags |= flags;
|
|
|
|
|
if (default_value && *default_value)
|
|
|
|
|
option->default_value = xstrdup (default_value);
|
2004-01-29 00:58:18 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
2004-06-14 10:32:07 +02:00
|
|
|
|
if (length < 0 || ferror (config))
|
2004-01-30 13:15:53 +01:00
|
|
|
|
gc_error (1, errno, "error reading from %s", cmd_line);
|
2004-01-31 14:58:27 +01:00
|
|
|
|
if (fclose (config) && ferror (config))
|
2004-01-30 13:15:53 +01:00
|
|
|
|
gc_error (1, errno, "error closing %s", cmd_line);
|
2004-01-31 14:58:27 +01:00
|
|
|
|
xfree (cmd_line);
|
|
|
|
|
|
|
|
|
|
/* At this point, we can parse the configuration file. */
|
|
|
|
|
config_pathname = get_config_pathname (component, backend);
|
|
|
|
|
|
|
|
|
|
config = fopen (config_pathname, "r");
|
|
|
|
|
if (!config)
|
|
|
|
|
gc_error (0, errno, "warning: can not open config file %s",
|
|
|
|
|
config_pathname);
|
|
|
|
|
else
|
|
|
|
|
{
|
2004-06-14 10:32:07 +02:00
|
|
|
|
while ((length = read_line (config, &line, &line_len, NULL)) > 0)
|
2004-01-31 14:58:27 +01:00
|
|
|
|
{
|
|
|
|
|
char *name;
|
|
|
|
|
char *value;
|
|
|
|
|
gc_option_t *option;
|
|
|
|
|
|
|
|
|
|
name = line;
|
|
|
|
|
while (*name == ' ' || *name == '\t')
|
|
|
|
|
name++;
|
|
|
|
|
if (!*name || *name == '#' || *name == '\r' || *name == '\n')
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
value = name;
|
|
|
|
|
while (*value && *value != ' ' && *value != '\t'
|
|
|
|
|
&& *value != '#' && *value != '\r' && *value != '\n')
|
|
|
|
|
value++;
|
|
|
|
|
if (*value == ' ' || *value == '\t')
|
|
|
|
|
{
|
|
|
|
|
char *end;
|
|
|
|
|
|
|
|
|
|
*(value++) = '\0';
|
|
|
|
|
while (*value == ' ' || *value == '\t')
|
|
|
|
|
value++;
|
|
|
|
|
|
|
|
|
|
end = value;
|
|
|
|
|
while (*end && *end != '#' && *end != '\r' && *end != '\n')
|
|
|
|
|
end++;
|
|
|
|
|
while (end > value && (end[-1] == ' ' || end[-1] == '\t'))
|
|
|
|
|
end--;
|
|
|
|
|
*end = '\0';
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
*value = '\0';
|
|
|
|
|
|
|
|
|
|
/* Look up the option in the component and install the
|
|
|
|
|
configuration data. */
|
|
|
|
|
option = find_option (component, line, backend);
|
|
|
|
|
if (option)
|
|
|
|
|
{
|
|
|
|
|
char *opt_value;
|
|
|
|
|
|
|
|
|
|
if (gc_arg_type[option->arg_type].fallback == GC_ARG_TYPE_NONE)
|
|
|
|
|
{
|
|
|
|
|
if (*value)
|
|
|
|
|
gc_error (0, 0,
|
|
|
|
|
"warning: ignoring argument %s for option %s",
|
|
|
|
|
value, name);
|
2004-02-24 15:31:59 +01:00
|
|
|
|
opt_value = xstrdup ("1");
|
2004-01-31 14:58:27 +01:00
|
|
|
|
}
|
|
|
|
|
else if (gc_arg_type[option->arg_type].fallback
|
|
|
|
|
== GC_ARG_TYPE_STRING)
|
|
|
|
|
opt_value = xasprintf ("\"%s", percent_escape (value));
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* FIXME: Verify that the number is sane. */
|
|
|
|
|
opt_value = xstrdup (value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Now enter the option into the table. */
|
|
|
|
|
if (!(option->flags & GC_OPT_FLAG_LIST))
|
|
|
|
|
{
|
|
|
|
|
if (option->value)
|
|
|
|
|
free (option->value);
|
|
|
|
|
option->value = opt_value;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (!option->value)
|
|
|
|
|
option->value = opt_value;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
char *opt_val = opt_value;
|
|
|
|
|
|
|
|
|
|
option->value = xasprintf ("%s,%s", option->value,
|
|
|
|
|
opt_val);
|
|
|
|
|
xfree (opt_value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2004-06-14 10:32:07 +02:00
|
|
|
|
if (length < 0 || ferror (config))
|
2004-01-31 14:58:27 +01:00
|
|
|
|
gc_error (1, errno, "error reading from %s", config_pathname);
|
|
|
|
|
if (fclose (config) && ferror (config))
|
|
|
|
|
gc_error (1, errno, "error closing %s", config_pathname);
|
|
|
|
|
}
|
|
|
|
|
|
2004-06-14 10:32:07 +02:00
|
|
|
|
xfree (line);
|
2004-01-29 00:58:18 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Retrieve the options for the component COMPONENT from backend
|
|
|
|
|
BACKEND, which we already know is of type file list. */
|
|
|
|
|
static void
|
|
|
|
|
retrieve_options_from_file (gc_component_t component, gc_backend_t backend)
|
|
|
|
|
{
|
|
|
|
|
gc_option_t *list_option;
|
|
|
|
|
char *list_pathname;
|
|
|
|
|
FILE *list_file;
|
|
|
|
|
char *line = NULL;
|
|
|
|
|
size_t line_len = 0;
|
|
|
|
|
ssize_t length;
|
2004-01-31 14:58:27 +01:00
|
|
|
|
char *list = NULL;
|
2004-01-29 00:58:18 +01:00
|
|
|
|
|
|
|
|
|
list_option = find_option (component,
|
|
|
|
|
gc_backend[backend].option_name, GC_BACKEND_ANY);
|
|
|
|
|
assert (list_option);
|
2004-01-31 14:58:27 +01:00
|
|
|
|
assert (!list_option->active);
|
2004-01-29 00:58:18 +01:00
|
|
|
|
|
|
|
|
|
list_pathname = get_config_pathname (component, backend);
|
|
|
|
|
list_file = fopen (list_pathname, "r");
|
2004-01-31 14:58:27 +01:00
|
|
|
|
if (!list_file)
|
|
|
|
|
gc_error (0, errno, "warning: can not open list file %s", list_pathname);
|
|
|
|
|
else
|
2004-01-29 00:58:18 +01:00
|
|
|
|
{
|
2004-01-31 14:58:27 +01:00
|
|
|
|
|
2004-06-14 10:32:07 +02:00
|
|
|
|
while ((length = read_line (list_file, &line, &line_len, NULL)) > 0)
|
2004-01-29 00:58:18 +01:00
|
|
|
|
{
|
2004-01-31 14:58:27 +01:00
|
|
|
|
char *start;
|
|
|
|
|
char *end;
|
|
|
|
|
char *new_list;
|
|
|
|
|
|
|
|
|
|
start = line;
|
|
|
|
|
while (*start == ' ' || *start == '\t')
|
|
|
|
|
start++;
|
|
|
|
|
if (!*start || *start == '#' || *start == '\r' || *start == '\n')
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
end = start;
|
|
|
|
|
while (*end && *end != '#' && *end != '\r' && *end != '\n')
|
|
|
|
|
end++;
|
|
|
|
|
/* Walk back to skip trailing white spaces. Looks evil, but
|
|
|
|
|
works because of the conditions on START and END imposed
|
|
|
|
|
at this point (END is at least START + 1, and START is
|
|
|
|
|
not a whitespace character). */
|
|
|
|
|
while (*(end - 1) == ' ' || *(end - 1) == '\t')
|
|
|
|
|
end--;
|
|
|
|
|
*end = '\0';
|
2004-03-08 18:59:24 +01:00
|
|
|
|
/* FIXME: Oh, no! This is so lame! Should use realloc and
|
|
|
|
|
really append. */
|
2004-01-31 14:58:27 +01:00
|
|
|
|
if (list)
|
|
|
|
|
{
|
2004-03-08 18:59:24 +01:00
|
|
|
|
new_list = xasprintf ("%s,\"%s", list, percent_escape (start));
|
2004-01-31 14:58:27 +01:00
|
|
|
|
xfree (list);
|
|
|
|
|
list = new_list;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
list = xasprintf ("\"%s", percent_escape (start));
|
2004-01-29 00:58:18 +01:00
|
|
|
|
}
|
2004-06-14 10:32:07 +02:00
|
|
|
|
if (length < 0 || ferror (list_file))
|
2004-01-31 14:58:27 +01:00
|
|
|
|
gc_error (1, errno, "can not read list file %s", list_pathname);
|
2004-01-29 00:58:18 +01:00
|
|
|
|
}
|
2004-01-31 14:58:27 +01:00
|
|
|
|
|
|
|
|
|
list_option->active = 1;
|
2004-01-29 00:58:18 +01:00
|
|
|
|
list_option->value = list;
|
2004-01-31 14:58:27 +01:00
|
|
|
|
|
2004-06-14 10:32:07 +02:00
|
|
|
|
xfree (line);
|
2004-01-29 00:58:18 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Retrieve the currently active options and their defaults from all
|
|
|
|
|
involved backends for this component. */
|
|
|
|
|
void
|
|
|
|
|
gc_component_retrieve_options (int component)
|
|
|
|
|
{
|
|
|
|
|
int backend_seen[GC_BACKEND_NR];
|
|
|
|
|
gc_backend_t backend;
|
|
|
|
|
gc_option_t *option = gc_component[component].options;
|
|
|
|
|
|
|
|
|
|
for (backend = 0; backend < GC_BACKEND_NR; backend++)
|
|
|
|
|
backend_seen[backend] = 0;
|
|
|
|
|
|
|
|
|
|
while (option->name)
|
|
|
|
|
{
|
|
|
|
|
if (!(option->flags & GC_OPT_FLAG_GROUP))
|
|
|
|
|
{
|
|
|
|
|
backend = option->backend;
|
|
|
|
|
|
|
|
|
|
if (backend_seen[backend])
|
|
|
|
|
{
|
|
|
|
|
option++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
backend_seen[backend] = 1;
|
|
|
|
|
|
|
|
|
|
assert (backend != GC_BACKEND_ANY);
|
|
|
|
|
|
|
|
|
|
if (gc_backend[backend].program)
|
|
|
|
|
retrieve_options_from_program (component, backend);
|
|
|
|
|
else
|
|
|
|
|
retrieve_options_from_file (component, backend);
|
|
|
|
|
}
|
|
|
|
|
option++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2004-02-26 17:28:27 +01:00
|
|
|
|
/* Perform a simple validity check based on the type. Return in
|
|
|
|
|
NEW_VALUE_NR the value of the number in NEW_VALUE if OPTION is of
|
|
|
|
|
type GC_ARG_TYPE_NONE. */
|
2004-01-29 00:58:18 +01:00
|
|
|
|
static void
|
2004-02-25 21:24:53 +01:00
|
|
|
|
option_check_validity (gc_option_t *option, unsigned long flags,
|
2004-02-26 17:28:27 +01:00
|
|
|
|
char *new_value, unsigned long *new_value_nr)
|
2004-01-29 00:58:18 +01:00
|
|
|
|
{
|
2004-02-26 19:22:02 +01:00
|
|
|
|
char *arg;
|
|
|
|
|
|
2004-02-26 23:18:36 +01:00
|
|
|
|
if (!option->active)
|
|
|
|
|
gc_error (1, 0, "option %s not supported by backend", option->name);
|
|
|
|
|
|
2004-02-25 21:24:53 +01:00
|
|
|
|
if (option->new_flags || option->new_value)
|
2004-01-30 13:15:53 +01:00
|
|
|
|
gc_error (1, 0, "option %s already changed", option->name);
|
2004-01-29 00:58:18 +01:00
|
|
|
|
|
2004-02-26 17:28:27 +01:00
|
|
|
|
if (flags & GC_OPT_FLAG_DEFAULT)
|
|
|
|
|
{
|
|
|
|
|
if (*new_value)
|
|
|
|
|
gc_error (1, 0, "argument %s provided for deleted option %s",
|
|
|
|
|
new_value, option->name);
|
2004-02-26 19:22:02 +01:00
|
|
|
|
|
|
|
|
|
return;
|
2004-02-26 17:28:27 +01:00
|
|
|
|
}
|
2004-02-26 19:22:02 +01:00
|
|
|
|
|
|
|
|
|
/* GC_ARG_TYPE_NONE options have special list treatment. */
|
|
|
|
|
if (gc_arg_type[option->arg_type].fallback == GC_ARG_TYPE_NONE)
|
2004-02-26 17:28:27 +01:00
|
|
|
|
{
|
2004-02-26 19:22:02 +01:00
|
|
|
|
char *tail;
|
2004-02-26 17:28:27 +01:00
|
|
|
|
|
2004-02-26 19:22:02 +01:00
|
|
|
|
errno = 0;
|
|
|
|
|
*new_value_nr = strtoul (new_value, &tail, 0);
|
|
|
|
|
|
|
|
|
|
if (errno)
|
|
|
|
|
gc_error (1, errno, "invalid argument for option %s",
|
|
|
|
|
option->name);
|
|
|
|
|
if (*tail)
|
|
|
|
|
gc_error (1, 0, "garbage after argument for option %s",
|
|
|
|
|
option->name);
|
|
|
|
|
|
|
|
|
|
if (!(option->flags & GC_OPT_FLAG_LIST))
|
2004-02-26 17:28:27 +01:00
|
|
|
|
{
|
2004-02-26 19:22:02 +01:00
|
|
|
|
if (*new_value_nr != 1)
|
|
|
|
|
gc_error (1, 0, "argument for non-list option %s of type 0 "
|
|
|
|
|
"(none) must be 1", option->name);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (*new_value_nr == 0)
|
|
|
|
|
gc_error (1, 0, "argument for option %s of type 0 (none) "
|
|
|
|
|
"must be positive", option->name);
|
|
|
|
|
}
|
2004-02-26 17:28:27 +01:00
|
|
|
|
|
2004-02-26 19:22:02 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
2004-02-26 17:28:27 +01:00
|
|
|
|
|
2004-02-26 19:22:02 +01:00
|
|
|
|
arg = new_value;
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
if (*arg == '\0' || *arg == ',')
|
|
|
|
|
{
|
|
|
|
|
if (!(option->flags & GC_OPT_FLAG_ARG_OPT))
|
|
|
|
|
gc_error (1, 0, "argument required for option %s", option->name);
|
2004-02-26 17:28:27 +01:00
|
|
|
|
|
2004-02-26 19:22:02 +01:00
|
|
|
|
if (*arg == ',' && !(option->flags & GC_OPT_FLAG_LIST))
|
|
|
|
|
gc_error (1, 0, "list found for non-list option %s", option->name);
|
|
|
|
|
}
|
|
|
|
|
else if (gc_arg_type[option->arg_type].fallback == GC_ARG_TYPE_STRING)
|
|
|
|
|
{
|
|
|
|
|
if (*arg != '"')
|
|
|
|
|
gc_error (1, 0, "string argument for option %s must begin "
|
|
|
|
|
"with a quote (\") character", option->name);
|
|
|
|
|
}
|
|
|
|
|
else if (gc_arg_type[option->arg_type].fallback == GC_ARG_TYPE_INT32)
|
|
|
|
|
{
|
|
|
|
|
errno = 0;
|
|
|
|
|
(void) strtol (arg, &arg, 0);
|
2004-02-26 17:28:27 +01:00
|
|
|
|
|
2004-02-26 19:22:02 +01:00
|
|
|
|
if (errno)
|
|
|
|
|
gc_error (1, errno, "invalid argument for option %s",
|
|
|
|
|
option->name);
|
2004-02-25 21:24:53 +01:00
|
|
|
|
|
2004-02-26 19:22:02 +01:00
|
|
|
|
if (*arg != '\0' && *arg != ',')
|
|
|
|
|
gc_error (1, 0, "garbage after argument for option %s",
|
|
|
|
|
option->name);
|
|
|
|
|
}
|
|
|
|
|
else if (gc_arg_type[option->arg_type].fallback == GC_ARG_TYPE_INT32)
|
|
|
|
|
{
|
|
|
|
|
errno = 0;
|
|
|
|
|
(void) strtoul (arg, &arg, 0);
|
2004-01-29 00:58:18 +01:00
|
|
|
|
|
2004-02-26 19:22:02 +01:00
|
|
|
|
if (errno)
|
|
|
|
|
gc_error (1, errno, "invalid argument for option %s",
|
|
|
|
|
option->name);
|
2004-02-26 17:28:27 +01:00
|
|
|
|
|
2004-02-26 19:22:02 +01:00
|
|
|
|
if (*arg != '\0' && *arg != ',')
|
|
|
|
|
gc_error (1, 0, "garbage after argument for option %s",
|
|
|
|
|
option->name);
|
2004-02-26 17:28:27 +01:00
|
|
|
|
}
|
2004-02-26 19:22:02 +01:00
|
|
|
|
arg = strchr (arg, ',');
|
|
|
|
|
if (arg)
|
|
|
|
|
arg++;
|
2004-02-26 17:28:27 +01:00
|
|
|
|
}
|
2004-02-26 19:22:02 +01:00
|
|
|
|
while (arg && *arg);
|
2004-01-29 00:58:18 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Create and verify the new configuration file for the specified
|
|
|
|
|
backend and component. Returns 0 on success and -1 on error. */
|
|
|
|
|
static int
|
|
|
|
|
change_options_file (gc_component_t component, gc_backend_t backend,
|
|
|
|
|
char **src_filenamep, char **dest_filenamep,
|
|
|
|
|
char **orig_filenamep)
|
|
|
|
|
{
|
2004-02-26 23:18:36 +01:00
|
|
|
|
static const char marker[] = "###+++--- GPGConf ---+++###";
|
|
|
|
|
/* True if we are within the marker in the config file. */
|
|
|
|
|
int in_marker = 0;
|
|
|
|
|
gc_option_t *option;
|
|
|
|
|
char *line = NULL;
|
|
|
|
|
size_t line_len;
|
|
|
|
|
ssize_t length;
|
|
|
|
|
int res;
|
|
|
|
|
int fd;
|
|
|
|
|
FILE *src_file = NULL;
|
|
|
|
|
FILE *dest_file = NULL;
|
|
|
|
|
char *src_filename;
|
|
|
|
|
char *dest_filename;
|
|
|
|
|
char *orig_filename;
|
|
|
|
|
char *arg;
|
|
|
|
|
char *cur_arg = NULL;
|
|
|
|
|
|
|
|
|
|
option = find_option (component,
|
|
|
|
|
gc_backend[backend].option_name, GC_BACKEND_ANY);
|
|
|
|
|
assert (option);
|
|
|
|
|
assert (option->active);
|
|
|
|
|
assert (gc_arg_type[option->arg_type].fallback != GC_ARG_TYPE_NONE);
|
|
|
|
|
|
|
|
|
|
/* FIXME. Throughout the function, do better error reporting. */
|
|
|
|
|
/* Note that get_config_pathname() calls percent_deescape(), so we
|
|
|
|
|
call this before processing the arguments. */
|
|
|
|
|
dest_filename = xstrdup (get_config_pathname (component, backend));
|
|
|
|
|
src_filename = xasprintf ("%s.gpgconf.%i.new", dest_filename, getpid ());
|
|
|
|
|
orig_filename = xasprintf ("%s.gpgconf.%i.bak", dest_filename, getpid ());
|
|
|
|
|
|
|
|
|
|
arg = option->new_value;
|
2004-03-23 19:27:37 +01:00
|
|
|
|
if (arg && arg[0] == '\0')
|
|
|
|
|
arg = NULL;
|
|
|
|
|
else if (arg)
|
2004-02-26 23:18:36 +01:00
|
|
|
|
{
|
|
|
|
|
char *end;
|
|
|
|
|
|
|
|
|
|
arg++;
|
|
|
|
|
end = strchr (arg, ',');
|
|
|
|
|
if (end)
|
|
|
|
|
*end = '\0';
|
|
|
|
|
|
|
|
|
|
cur_arg = percent_deescape (arg);
|
|
|
|
|
if (end)
|
|
|
|
|
{
|
|
|
|
|
*end = ',';
|
|
|
|
|
arg = end + 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
arg = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2004-12-15 15:15:54 +01:00
|
|
|
|
#if HAVE_W32_SYSTEM
|
|
|
|
|
res = 0;
|
|
|
|
|
#warning no backups for W32 yet - need to write a copy function
|
|
|
|
|
#else
|
2004-02-26 23:18:36 +01:00
|
|
|
|
res = link (dest_filename, orig_filename);
|
2004-12-15 15:15:54 +01:00
|
|
|
|
#endif
|
2004-02-26 23:18:36 +01:00
|
|
|
|
if (res < 0 && errno != ENOENT)
|
|
|
|
|
return -1;
|
|
|
|
|
if (res < 0)
|
|
|
|
|
{
|
|
|
|
|
xfree (orig_filename);
|
|
|
|
|
orig_filename = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* We now initialize the return strings, so the caller can do the
|
|
|
|
|
cleanup for us. */
|
|
|
|
|
*src_filenamep = src_filename;
|
|
|
|
|
*dest_filenamep = dest_filename;
|
|
|
|
|
*orig_filenamep = orig_filename;
|
|
|
|
|
|
|
|
|
|
/* Use open() so that we can use O_EXCL. */
|
|
|
|
|
fd = open (src_filename, O_CREAT | O_EXCL | O_WRONLY, 0644);
|
|
|
|
|
if (fd < 0)
|
|
|
|
|
return -1;
|
|
|
|
|
src_file = fdopen (fd, "w");
|
|
|
|
|
res = errno;
|
|
|
|
|
if (!src_file)
|
|
|
|
|
{
|
|
|
|
|
errno = res;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Only if ORIG_FILENAME is not NULL did the configuration file
|
|
|
|
|
exist already. In this case, we will copy its content into the
|
|
|
|
|
new configuration file, changing it to our liking in the
|
|
|
|
|
process. */
|
|
|
|
|
if (orig_filename)
|
|
|
|
|
{
|
|
|
|
|
dest_file = fopen (dest_filename, "r");
|
|
|
|
|
if (!dest_file)
|
|
|
|
|
goto change_file_one_err;
|
|
|
|
|
|
2004-06-14 10:32:07 +02:00
|
|
|
|
while ((length = read_line (dest_file, &line, &line_len, NULL)) > 0)
|
2004-02-26 23:18:36 +01:00
|
|
|
|
{
|
|
|
|
|
int disable = 0;
|
|
|
|
|
char *start;
|
|
|
|
|
|
|
|
|
|
if (!strncmp (marker, line, sizeof (marker) - 1))
|
|
|
|
|
{
|
|
|
|
|
if (!in_marker)
|
|
|
|
|
in_marker = 1;
|
|
|
|
|
else
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
start = line;
|
|
|
|
|
while (*start == ' ' || *start == '\t')
|
|
|
|
|
start++;
|
|
|
|
|
if (*start && *start != '\r' && *start != '\n' && *start != '#')
|
|
|
|
|
{
|
|
|
|
|
char *end;
|
|
|
|
|
char *endp;
|
|
|
|
|
char saved_end;
|
|
|
|
|
|
|
|
|
|
endp = start;
|
|
|
|
|
end = endp;
|
|
|
|
|
|
|
|
|
|
/* Search for the end of the line. */
|
|
|
|
|
while (*endp && *endp != '#' && *endp != '\r' && *endp != '\n')
|
|
|
|
|
{
|
|
|
|
|
endp++;
|
|
|
|
|
if (*endp && *endp != ' ' && *endp != '\t'
|
|
|
|
|
&& *endp != '\r' && *endp != '\n' && *endp != '#')
|
|
|
|
|
end = endp + 1;
|
|
|
|
|
}
|
|
|
|
|
saved_end = *end;
|
|
|
|
|
*end = '\0';
|
|
|
|
|
|
|
|
|
|
if ((option->new_flags & GC_OPT_FLAG_DEFAULT)
|
|
|
|
|
|| !cur_arg || strcmp (start, cur_arg))
|
|
|
|
|
disable = 1;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Find next argument. */
|
|
|
|
|
if (arg)
|
|
|
|
|
{
|
|
|
|
|
char *arg_end;
|
|
|
|
|
|
|
|
|
|
arg++;
|
|
|
|
|
arg_end = strchr (arg, ',');
|
|
|
|
|
if (arg_end)
|
|
|
|
|
*arg_end = '\0';
|
|
|
|
|
|
|
|
|
|
cur_arg = percent_deescape (arg);
|
|
|
|
|
if (arg_end)
|
|
|
|
|
{
|
|
|
|
|
*arg_end = ',';
|
|
|
|
|
arg = arg_end + 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
arg = NULL;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
cur_arg = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*end = saved_end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (disable)
|
|
|
|
|
{
|
|
|
|
|
if (!in_marker)
|
|
|
|
|
{
|
|
|
|
|
fprintf (src_file,
|
|
|
|
|
"# GPGConf disabled this option here at %s\n",
|
|
|
|
|
asctimestamp (gnupg_get_time ()));
|
|
|
|
|
if (ferror (src_file))
|
|
|
|
|
goto change_file_one_err;
|
|
|
|
|
fprintf (src_file, "# %s", line);
|
|
|
|
|
if (ferror (src_file))
|
|
|
|
|
goto change_file_one_err;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
fprintf (src_file, "%s", line);
|
|
|
|
|
if (ferror (src_file))
|
|
|
|
|
goto change_file_one_err;
|
|
|
|
|
}
|
|
|
|
|
}
|
2004-06-14 10:32:07 +02:00
|
|
|
|
if (length < 0 || ferror (dest_file))
|
2004-02-26 23:18:36 +01:00
|
|
|
|
goto change_file_one_err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!in_marker)
|
|
|
|
|
{
|
|
|
|
|
/* There was no marker. This is the first time we edit the
|
|
|
|
|
file. We add our own marker at the end of the file and
|
|
|
|
|
proceed. Note that we first write a newline, this guards us
|
|
|
|
|
against files which lack the newline at the end of the last
|
|
|
|
|
line, while it doesn't hurt us in all other cases. */
|
|
|
|
|
fprintf (src_file, "\n%s\n", marker);
|
|
|
|
|
if (ferror (src_file))
|
|
|
|
|
goto change_file_one_err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* At this point, we have copied everything up to the end marker
|
|
|
|
|
into the new file, except for the arguments we are going to add.
|
|
|
|
|
Now, dump the new arguments and write the end marker, possibly
|
|
|
|
|
followed by the rest of the original file. */
|
|
|
|
|
while (cur_arg)
|
|
|
|
|
{
|
|
|
|
|
fprintf (src_file, "%s\n", cur_arg);
|
|
|
|
|
|
|
|
|
|
/* Find next argument. */
|
|
|
|
|
if (arg)
|
|
|
|
|
{
|
|
|
|
|
char *end;
|
|
|
|
|
|
|
|
|
|
arg++;
|
|
|
|
|
end = strchr (arg, ',');
|
|
|
|
|
if (end)
|
|
|
|
|
*end = '\0';
|
|
|
|
|
|
|
|
|
|
cur_arg = percent_deescape (arg);
|
|
|
|
|
if (end)
|
|
|
|
|
{
|
|
|
|
|
*end = ',';
|
|
|
|
|
arg = end + 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
arg = NULL;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
cur_arg = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fprintf (src_file, "%s %s\n", marker, asctimestamp (gnupg_get_time ()));
|
|
|
|
|
if (ferror (src_file))
|
|
|
|
|
goto change_file_one_err;
|
|
|
|
|
|
|
|
|
|
if (!in_marker)
|
|
|
|
|
{
|
|
|
|
|
fprintf (src_file, "# GPGConf edited this configuration file.\n");
|
|
|
|
|
if (ferror (src_file))
|
|
|
|
|
goto change_file_one_err;
|
|
|
|
|
fprintf (src_file, "# It will disable options before this marked "
|
|
|
|
|
"block, but it will\n");
|
|
|
|
|
if (ferror (src_file))
|
|
|
|
|
goto change_file_one_err;
|
|
|
|
|
fprintf (src_file, "# never change anything below these lines.\n");
|
|
|
|
|
if (ferror (src_file))
|
|
|
|
|
goto change_file_one_err;
|
|
|
|
|
}
|
|
|
|
|
if (dest_file)
|
|
|
|
|
{
|
2004-06-14 10:32:07 +02:00
|
|
|
|
while ((length = read_line (dest_file, &line, &line_len, NULL)) > 0)
|
2004-02-26 23:18:36 +01:00
|
|
|
|
{
|
|
|
|
|
fprintf (src_file, "%s", line);
|
|
|
|
|
if (ferror (src_file))
|
|
|
|
|
goto change_file_one_err;
|
|
|
|
|
}
|
2004-06-14 10:32:07 +02:00
|
|
|
|
if (length < 0 || ferror (dest_file))
|
2004-02-26 23:18:36 +01:00
|
|
|
|
goto change_file_one_err;
|
|
|
|
|
}
|
2004-06-14 10:32:07 +02:00
|
|
|
|
xfree (line);
|
|
|
|
|
line = NULL;
|
|
|
|
|
|
2004-02-26 23:18:36 +01:00
|
|
|
|
res = fclose (src_file);
|
|
|
|
|
if (res)
|
|
|
|
|
{
|
|
|
|
|
res = errno;
|
|
|
|
|
close (fd);
|
|
|
|
|
if (dest_file)
|
|
|
|
|
fclose (dest_file);
|
|
|
|
|
errno = res;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
close (fd);
|
|
|
|
|
if (dest_file)
|
|
|
|
|
{
|
|
|
|
|
res = fclose (dest_file);
|
|
|
|
|
if (res)
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
change_file_one_err:
|
2004-06-14 10:32:07 +02:00
|
|
|
|
xfree (line);
|
2004-02-26 23:18:36 +01:00
|
|
|
|
res = errno;
|
|
|
|
|
if (src_file)
|
|
|
|
|
{
|
|
|
|
|
fclose (src_file);
|
|
|
|
|
close (fd);
|
|
|
|
|
}
|
|
|
|
|
if (dest_file)
|
|
|
|
|
fclose (dest_file);
|
|
|
|
|
errno = res;
|
2004-01-29 00:58:18 +01:00
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Create and verify the new configuration file for the specified
|
|
|
|
|
backend and component. Returns 0 on success and -1 on error. */
|
|
|
|
|
static int
|
|
|
|
|
change_options_program (gc_component_t component, gc_backend_t backend,
|
|
|
|
|
char **src_filenamep, char **dest_filenamep,
|
|
|
|
|
char **orig_filenamep)
|
|
|
|
|
{
|
|
|
|
|
static const char marker[] = "###+++--- GPGConf ---+++###";
|
|
|
|
|
/* True if we are within the marker in the config file. */
|
|
|
|
|
int in_marker = 0;
|
|
|
|
|
gc_option_t *option;
|
2004-01-31 14:58:27 +01:00
|
|
|
|
char *line = NULL;
|
2004-01-30 11:38:07 +01:00
|
|
|
|
size_t line_len;
|
|
|
|
|
ssize_t length;
|
2004-01-29 00:58:18 +01:00
|
|
|
|
int res;
|
|
|
|
|
int fd;
|
|
|
|
|
FILE *src_file = NULL;
|
|
|
|
|
FILE *dest_file = NULL;
|
|
|
|
|
char *src_filename;
|
|
|
|
|
char *dest_filename;
|
|
|
|
|
char *orig_filename;
|
|
|
|
|
|
|
|
|
|
/* FIXME. Throughout the function, do better error reporting. */
|
2004-01-31 14:58:27 +01:00
|
|
|
|
dest_filename = xstrdup (get_config_pathname (component, backend));
|
|
|
|
|
src_filename = xasprintf ("%s.gpgconf.%i.new", dest_filename, getpid ());
|
|
|
|
|
orig_filename = xasprintf ("%s.gpgconf.%i.bak", dest_filename, getpid ());
|
2004-01-29 00:58:18 +01:00
|
|
|
|
|
2004-12-15 15:15:54 +01:00
|
|
|
|
#if HAVE_W32_SYSTEM
|
|
|
|
|
res = 0;
|
|
|
|
|
#warning no backups for W32 yet - need to write a copy function
|
|
|
|
|
#else
|
2004-01-29 00:58:18 +01:00
|
|
|
|
res = link (dest_filename, orig_filename);
|
2004-12-15 15:15:54 +01:00
|
|
|
|
#endif
|
2004-01-29 00:58:18 +01:00
|
|
|
|
if (res < 0 && errno != ENOENT)
|
|
|
|
|
return -1;
|
|
|
|
|
if (res < 0)
|
|
|
|
|
{
|
2004-01-31 14:58:27 +01:00
|
|
|
|
xfree (orig_filename);
|
2004-01-29 00:58:18 +01:00
|
|
|
|
orig_filename = NULL;
|
|
|
|
|
}
|
2004-02-26 19:22:02 +01:00
|
|
|
|
|
2004-01-29 00:58:18 +01:00
|
|
|
|
/* We now initialize the return strings, so the caller can do the
|
|
|
|
|
cleanup for us. */
|
|
|
|
|
*src_filenamep = src_filename;
|
|
|
|
|
*dest_filenamep = dest_filename;
|
|
|
|
|
*orig_filenamep = orig_filename;
|
|
|
|
|
|
|
|
|
|
/* Use open() so that we can use O_EXCL. */
|
|
|
|
|
fd = open (src_filename, O_CREAT | O_EXCL | O_WRONLY, 0644);
|
|
|
|
|
if (fd < 0)
|
|
|
|
|
return -1;
|
|
|
|
|
src_file = fdopen (fd, "w");
|
|
|
|
|
res = errno;
|
|
|
|
|
if (!src_file)
|
|
|
|
|
{
|
|
|
|
|
errno = res;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Only if ORIG_FILENAME is not NULL did the configuration file
|
|
|
|
|
exist already. In this case, we will copy its content into the
|
|
|
|
|
new configuration file, changing it to our liking in the
|
|
|
|
|
process. */
|
|
|
|
|
if (orig_filename)
|
|
|
|
|
{
|
|
|
|
|
dest_file = fopen (dest_filename, "r");
|
|
|
|
|
if (!dest_file)
|
|
|
|
|
goto change_one_err;
|
|
|
|
|
|
2004-06-14 10:32:07 +02:00
|
|
|
|
while ((length = read_line (dest_file, &line, &line_len, NULL)) > 0)
|
2004-01-29 00:58:18 +01:00
|
|
|
|
{
|
|
|
|
|
int disable = 0;
|
|
|
|
|
char *start;
|
|
|
|
|
|
|
|
|
|
if (!strncmp (marker, line, sizeof (marker) - 1))
|
|
|
|
|
{
|
|
|
|
|
if (!in_marker)
|
|
|
|
|
in_marker = 1;
|
|
|
|
|
else
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
start = line;
|
|
|
|
|
while (*start == ' ' || *start == '\t')
|
|
|
|
|
start++;
|
|
|
|
|
if (*start && *start != '\r' && *start != '\n' && *start != '#')
|
|
|
|
|
{
|
2004-02-26 23:18:36 +01:00
|
|
|
|
char *end;
|
2004-01-29 00:58:18 +01:00
|
|
|
|
char saved_end;
|
|
|
|
|
|
|
|
|
|
end = start;
|
|
|
|
|
while (*end && *end != ' ' && *end != '\t'
|
|
|
|
|
&& *end != '\r' && *end != '\n' && *end != '#')
|
|
|
|
|
end++;
|
|
|
|
|
saved_end = *end;
|
|
|
|
|
*end = '\0';
|
|
|
|
|
|
|
|
|
|
option = find_option (component, start, backend);
|
|
|
|
|
*end = saved_end;
|
2004-02-26 17:28:27 +01:00
|
|
|
|
if (option && ((option->new_flags & GC_OPT_FLAG_DEFAULT)
|
|
|
|
|
|| option->new_value))
|
2004-01-29 00:58:18 +01:00
|
|
|
|
disable = 1;
|
|
|
|
|
}
|
|
|
|
|
if (disable)
|
|
|
|
|
{
|
|
|
|
|
if (!in_marker)
|
|
|
|
|
{
|
|
|
|
|
fprintf (src_file,
|
2004-01-30 11:38:07 +01:00
|
|
|
|
"# GPGConf disabled this option here at %s\n",
|
|
|
|
|
asctimestamp (gnupg_get_time ()));
|
2004-01-29 00:58:18 +01:00
|
|
|
|
if (ferror (src_file))
|
|
|
|
|
goto change_one_err;
|
|
|
|
|
fprintf (src_file, "# %s", line);
|
|
|
|
|
if (ferror (src_file))
|
|
|
|
|
goto change_one_err;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
fprintf (src_file, "%s", line);
|
|
|
|
|
if (ferror (src_file))
|
|
|
|
|
goto change_one_err;
|
|
|
|
|
}
|
|
|
|
|
}
|
2004-06-14 10:32:07 +02:00
|
|
|
|
if (length < 0 || ferror (dest_file))
|
2004-01-29 00:58:18 +01:00
|
|
|
|
goto change_one_err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!in_marker)
|
|
|
|
|
{
|
|
|
|
|
/* There was no marker. This is the first time we edit the
|
|
|
|
|
file. We add our own marker at the end of the file and
|
|
|
|
|
proceed. Note that we first write a newline, this guards us
|
|
|
|
|
against files which lack the newline at the end of the last
|
|
|
|
|
line, while it doesn't hurt us in all other cases. */
|
|
|
|
|
fprintf (src_file, "\n%s\n", marker);
|
|
|
|
|
if (ferror (src_file))
|
|
|
|
|
goto change_one_err;
|
|
|
|
|
}
|
|
|
|
|
/* At this point, we have copied everything up to the end marker
|
|
|
|
|
into the new file, except for the options we are going to change.
|
|
|
|
|
Now, dump the changed options (except for those we are going to
|
|
|
|
|
revert to their default), and write the end marker, possibly
|
|
|
|
|
followed by the rest of the original file. */
|
2004-04-29 21:00:37 +02:00
|
|
|
|
|
|
|
|
|
/* We have to turn on UTF8 strings for GnuPG. */
|
|
|
|
|
if (backend == GC_BACKEND_GPG)
|
|
|
|
|
fprintf (src_file, "utf8-strings\n");
|
|
|
|
|
|
2004-01-29 00:58:18 +01:00
|
|
|
|
option = gc_component[component].options;
|
|
|
|
|
while (option->name)
|
|
|
|
|
{
|
|
|
|
|
if (!(option->flags & GC_OPT_FLAG_GROUP)
|
|
|
|
|
&& option->backend == backend
|
2004-02-26 19:39:34 +01:00
|
|
|
|
&& option->new_value)
|
2004-01-29 00:58:18 +01:00
|
|
|
|
{
|
2004-02-26 19:39:34 +01:00
|
|
|
|
char *arg = option->new_value;
|
|
|
|
|
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
if (*arg == '\0' || *arg == ',')
|
|
|
|
|
{
|
|
|
|
|
fprintf (src_file, "%s\n", option->name);
|
|
|
|
|
if (ferror (src_file))
|
|
|
|
|
goto change_one_err;
|
|
|
|
|
}
|
|
|
|
|
else if (gc_arg_type[option->arg_type].fallback
|
|
|
|
|
== GC_ARG_TYPE_NONE)
|
|
|
|
|
{
|
|
|
|
|
assert (*arg == '1');
|
|
|
|
|
fprintf (src_file, "%s\n", option->name);
|
|
|
|
|
if (ferror (src_file))
|
|
|
|
|
goto change_one_err;
|
|
|
|
|
|
|
|
|
|
arg++;
|
|
|
|
|
}
|
|
|
|
|
else if (gc_arg_type[option->arg_type].fallback
|
|
|
|
|
== GC_ARG_TYPE_STRING)
|
|
|
|
|
{
|
|
|
|
|
char *end;
|
|
|
|
|
|
|
|
|
|
assert (*arg == '"');
|
|
|
|
|
arg++;
|
|
|
|
|
|
|
|
|
|
end = strchr (arg, ',');
|
|
|
|
|
if (end)
|
|
|
|
|
*end = '\0';
|
|
|
|
|
|
|
|
|
|
fprintf (src_file, "%s %s\n", option->name,
|
|
|
|
|
percent_deescape (arg));
|
|
|
|
|
if (ferror (src_file))
|
|
|
|
|
goto change_one_err;
|
|
|
|
|
|
|
|
|
|
if (end)
|
|
|
|
|
*end = ',';
|
|
|
|
|
arg = end;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
char *end;
|
|
|
|
|
|
|
|
|
|
end = strchr (arg, ',');
|
|
|
|
|
if (end)
|
|
|
|
|
*end = '\0';
|
|
|
|
|
|
|
|
|
|
fprintf (src_file, "%s %s\n", option->name, arg);
|
|
|
|
|
if (ferror (src_file))
|
|
|
|
|
goto change_one_err;
|
|
|
|
|
|
|
|
|
|
if (end)
|
|
|
|
|
*end = ',';
|
|
|
|
|
arg = end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert (arg == NULL || *arg == '\0' || *arg == ',');
|
|
|
|
|
if (arg && *arg == ',')
|
|
|
|
|
arg++;
|
|
|
|
|
}
|
|
|
|
|
while (arg && *arg);
|
2004-01-29 00:58:18 +01:00
|
|
|
|
}
|
|
|
|
|
option++;
|
|
|
|
|
}
|
2004-02-23 20:37:04 +01:00
|
|
|
|
|
|
|
|
|
fprintf (src_file, "%s %s\n", marker, asctimestamp (gnupg_get_time ()));
|
|
|
|
|
if (ferror (src_file))
|
|
|
|
|
goto change_one_err;
|
|
|
|
|
|
2004-01-29 00:58:18 +01:00
|
|
|
|
if (!in_marker)
|
|
|
|
|
{
|
|
|
|
|
fprintf (src_file, "# GPGConf edited this configuration file.\n");
|
|
|
|
|
if (ferror (src_file))
|
|
|
|
|
goto change_one_err;
|
|
|
|
|
fprintf (src_file, "# It will disable options before this marked "
|
|
|
|
|
"block, but it will\n");
|
|
|
|
|
if (ferror (src_file))
|
|
|
|
|
goto change_one_err;
|
|
|
|
|
fprintf (src_file, "# never change anything below these lines.\n");
|
|
|
|
|
if (ferror (src_file))
|
|
|
|
|
goto change_one_err;
|
|
|
|
|
}
|
|
|
|
|
if (dest_file)
|
|
|
|
|
{
|
2004-06-14 10:32:07 +02:00
|
|
|
|
while ((length = read_line (dest_file, &line, &line_len, NULL)) > 0)
|
2004-01-29 00:58:18 +01:00
|
|
|
|
{
|
|
|
|
|
fprintf (src_file, "%s", line);
|
|
|
|
|
if (ferror (src_file))
|
|
|
|
|
goto change_one_err;
|
|
|
|
|
}
|
2004-06-14 10:32:07 +02:00
|
|
|
|
if (length < 0 || ferror (dest_file))
|
2004-01-29 00:58:18 +01:00
|
|
|
|
goto change_one_err;
|
|
|
|
|
}
|
2004-06-14 10:32:07 +02:00
|
|
|
|
xfree (line);
|
|
|
|
|
line = NULL;
|
|
|
|
|
|
2004-01-29 00:58:18 +01:00
|
|
|
|
res = fclose (src_file);
|
|
|
|
|
if (res)
|
|
|
|
|
{
|
|
|
|
|
res = errno;
|
|
|
|
|
close (fd);
|
|
|
|
|
if (dest_file)
|
|
|
|
|
fclose (dest_file);
|
|
|
|
|
errno = res;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
close (fd);
|
|
|
|
|
if (dest_file)
|
|
|
|
|
{
|
|
|
|
|
res = fclose (dest_file);
|
|
|
|
|
if (res)
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
change_one_err:
|
2004-06-14 10:32:07 +02:00
|
|
|
|
xfree (line);
|
2004-01-29 00:58:18 +01:00
|
|
|
|
res = errno;
|
|
|
|
|
if (src_file)
|
|
|
|
|
{
|
|
|
|
|
fclose (src_file);
|
|
|
|
|
close (fd);
|
|
|
|
|
}
|
|
|
|
|
if (dest_file)
|
|
|
|
|
fclose (dest_file);
|
|
|
|
|
errno = res;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2004-02-26 17:28:27 +01:00
|
|
|
|
|
2004-01-29 00:58:18 +01:00
|
|
|
|
/* Read the modifications from IN and apply them. */
|
|
|
|
|
void
|
|
|
|
|
gc_component_change_options (int component, FILE *in)
|
|
|
|
|
{
|
|
|
|
|
int err = 0;
|
2004-03-23 13:21:48 +01:00
|
|
|
|
int runtime[GC_BACKEND_NR];
|
2004-01-29 00:58:18 +01:00
|
|
|
|
char *src_pathname[GC_BACKEND_NR];
|
|
|
|
|
char *dest_pathname[GC_BACKEND_NR];
|
|
|
|
|
char *orig_pathname[GC_BACKEND_NR];
|
|
|
|
|
gc_backend_t backend;
|
|
|
|
|
gc_option_t *option;
|
|
|
|
|
char *line = NULL;
|
|
|
|
|
size_t line_len = 0;
|
|
|
|
|
ssize_t length;
|
|
|
|
|
|
|
|
|
|
for (backend = 0; backend < GC_BACKEND_NR; backend++)
|
|
|
|
|
{
|
2004-03-23 13:21:48 +01:00
|
|
|
|
runtime[backend] = 0;
|
2004-01-29 00:58:18 +01:00
|
|
|
|
src_pathname[backend] = NULL;
|
|
|
|
|
dest_pathname[backend] = NULL;
|
|
|
|
|
orig_pathname[backend] = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2004-06-14 10:32:07 +02:00
|
|
|
|
while ((length = read_line (in, &line, &line_len, NULL)) > 0)
|
2004-01-29 00:58:18 +01:00
|
|
|
|
{
|
2004-02-24 15:31:59 +01:00
|
|
|
|
char *linep;
|
|
|
|
|
unsigned long flags = 0;
|
2004-02-25 21:24:53 +01:00
|
|
|
|
char *new_value = "";
|
2004-02-26 17:28:27 +01:00
|
|
|
|
unsigned long new_value_nr;
|
2004-01-29 00:58:18 +01:00
|
|
|
|
|
|
|
|
|
/* Strip newline and carriage return, if present. */
|
|
|
|
|
while (length > 0
|
|
|
|
|
&& (line[length - 1] == '\n' || line[length - 1] == '\r'))
|
|
|
|
|
line[--length] = '\0';
|
|
|
|
|
|
2004-02-24 15:31:59 +01:00
|
|
|
|
linep = strchr (line, ':');
|
|
|
|
|
if (linep)
|
|
|
|
|
*(linep++) = '\0';
|
|
|
|
|
|
|
|
|
|
/* Extract additional flags. Default to none. */
|
|
|
|
|
if (linep)
|
|
|
|
|
{
|
|
|
|
|
char *end;
|
|
|
|
|
char *tail;
|
|
|
|
|
|
|
|
|
|
end = strchr (linep, ':');
|
|
|
|
|
if (end)
|
|
|
|
|
*(end++) = '\0';
|
|
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
|
flags = strtoul (linep, &tail, 0);
|
|
|
|
|
if (errno)
|
|
|
|
|
gc_error (1, errno, "malformed flags in option %s", line);
|
|
|
|
|
if (!(*tail == '\0' || *tail == ':' || *tail == ' '))
|
|
|
|
|
gc_error (1, 0, "garbage after flags in option %s", line);
|
|
|
|
|
|
|
|
|
|
linep = end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Extract default value, if present. Default to empty if
|
|
|
|
|
not. */
|
|
|
|
|
if (linep)
|
2004-01-29 00:58:18 +01:00
|
|
|
|
{
|
|
|
|
|
char *end;
|
|
|
|
|
|
2004-02-24 15:31:59 +01:00
|
|
|
|
end = strchr (linep, ':');
|
2004-01-29 00:58:18 +01:00
|
|
|
|
if (end)
|
2004-02-24 15:31:59 +01:00
|
|
|
|
*(end++) = '\0';
|
|
|
|
|
|
2004-02-25 21:24:53 +01:00
|
|
|
|
new_value = linep;
|
2004-02-24 15:31:59 +01:00
|
|
|
|
|
|
|
|
|
linep = end;
|
2004-01-29 00:58:18 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
option = find_option (component, line, GC_BACKEND_ANY);
|
|
|
|
|
if (!option)
|
2004-01-30 13:15:53 +01:00
|
|
|
|
gc_error (1, 0, "unknown option %s", line);
|
2004-01-29 00:58:18 +01:00
|
|
|
|
|
2004-02-26 17:28:27 +01:00
|
|
|
|
option_check_validity (option, flags, new_value, &new_value_nr);
|
2004-02-24 15:31:59 +01:00
|
|
|
|
|
2004-03-23 13:21:48 +01:00
|
|
|
|
if (option->flags & GC_OPT_FLAG_RUNTIME)
|
|
|
|
|
runtime[option->backend] = 1;
|
|
|
|
|
|
2004-02-25 21:24:53 +01:00
|
|
|
|
option->new_flags = flags;
|
|
|
|
|
if (!(flags & GC_OPT_FLAG_DEFAULT))
|
2004-02-26 17:28:27 +01:00
|
|
|
|
{
|
|
|
|
|
if (gc_arg_type[option->arg_type].fallback == GC_ARG_TYPE_NONE
|
|
|
|
|
&& (option->flags & GC_OPT_FLAG_LIST))
|
|
|
|
|
{
|
|
|
|
|
char *str;
|
|
|
|
|
|
|
|
|
|
/* We convert the number to a list of 1's for
|
|
|
|
|
convenient list handling. */
|
|
|
|
|
assert (new_value_nr > 0);
|
|
|
|
|
option->new_value = xmalloc ((2 * (new_value_nr - 1) + 1) + 1);
|
|
|
|
|
str = option->new_value;
|
|
|
|
|
*(str++) = '1';
|
|
|
|
|
while (--new_value_nr > 0)
|
|
|
|
|
{
|
|
|
|
|
*(str++) = ',';
|
|
|
|
|
*(str++) = '1';
|
|
|
|
|
}
|
|
|
|
|
*(str++) = '\0';
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
option->new_value = xstrdup (new_value);
|
|
|
|
|
}
|
2004-01-29 00:58:18 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Now that we have collected and locally verified the changes,
|
|
|
|
|
write them out to new configuration files, verify them
|
|
|
|
|
externally, and then commit them. */
|
|
|
|
|
option = gc_component[component].options;
|
|
|
|
|
while (option->name)
|
|
|
|
|
{
|
|
|
|
|
/* Go on if we have already seen this backend, or if there is
|
|
|
|
|
nothing to do. */
|
2004-03-12 15:29:40 +01:00
|
|
|
|
if (src_pathname[option->backend]
|
|
|
|
|
|| !(option->new_flags || option->new_value))
|
2004-01-29 00:58:18 +01:00
|
|
|
|
{
|
|
|
|
|
option++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (gc_backend[option->backend].program)
|
|
|
|
|
err = change_options_program (component, option->backend,
|
2004-03-12 15:29:40 +01:00
|
|
|
|
&src_pathname[option->backend],
|
|
|
|
|
&dest_pathname[option->backend],
|
|
|
|
|
&orig_pathname[option->backend]);
|
2004-01-29 00:58:18 +01:00
|
|
|
|
else
|
|
|
|
|
err = change_options_file (component, option->backend,
|
2004-03-12 15:29:40 +01:00
|
|
|
|
&src_pathname[option->backend],
|
|
|
|
|
&dest_pathname[option->backend],
|
|
|
|
|
&orig_pathname[option->backend]);
|
2004-01-29 00:58:18 +01:00
|
|
|
|
|
|
|
|
|
if (err)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
option++;
|
|
|
|
|
}
|
2004-02-26 19:39:34 +01:00
|
|
|
|
|
2004-01-29 00:58:18 +01:00
|
|
|
|
if (!err)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
2004-03-12 15:42:31 +01:00
|
|
|
|
for (i = 0; i < GC_BACKEND_NR; i++)
|
2004-01-29 00:58:18 +01:00
|
|
|
|
{
|
|
|
|
|
if (src_pathname[i])
|
|
|
|
|
{
|
|
|
|
|
/* FIXME: Make a verification here. */
|
|
|
|
|
|
|
|
|
|
assert (dest_pathname[i]);
|
|
|
|
|
|
|
|
|
|
if (orig_pathname[i])
|
|
|
|
|
err = rename (src_pathname[i], dest_pathname[i]);
|
|
|
|
|
else
|
|
|
|
|
{
|
2004-12-15 15:15:54 +01:00
|
|
|
|
#ifdef HAVE_W32_SYSTEM
|
|
|
|
|
/* FIXME: Won't work becuase W32 doesn't silently
|
|
|
|
|
overwrite. */
|
|
|
|
|
err = rename (src_pathname[i], dest_pathname[i]);
|
|
|
|
|
#else /*!HAVE_W32_SYSTEM*/
|
2004-01-29 00:58:18 +01:00
|
|
|
|
/* This is a bit safer than rename() because we
|
|
|
|
|
expect DEST_PATHNAME not to be there. If it
|
|
|
|
|
happens to be there, this will fail. */
|
|
|
|
|
err = link (src_pathname[i], dest_pathname[i]);
|
|
|
|
|
if (!err)
|
|
|
|
|
unlink (src_pathname[i]);
|
2004-12-15 15:15:54 +01:00
|
|
|
|
#endif /*!HAVE_W32_SYSTEM*/
|
2004-01-29 00:58:18 +01:00
|
|
|
|
}
|
|
|
|
|
if (err)
|
|
|
|
|
break;
|
|
|
|
|
src_pathname[i] = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
2004-01-30 11:38:07 +01:00
|
|
|
|
int saved_errno = errno;
|
2004-01-29 00:58:18 +01:00
|
|
|
|
|
|
|
|
|
/* An error occured. */
|
2004-03-12 15:42:31 +01:00
|
|
|
|
for (i = 0; i < GC_BACKEND_NR; i++)
|
2004-01-29 00:58:18 +01:00
|
|
|
|
{
|
|
|
|
|
if (src_pathname[i])
|
|
|
|
|
{
|
|
|
|
|
/* The change was not yet committed. */
|
|
|
|
|
unlink (src_pathname[i]);
|
|
|
|
|
if (orig_pathname[i])
|
|
|
|
|
unlink (orig_pathname[i]);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* The changes were already committed. FIXME: This is a
|
|
|
|
|
tad dangerous, as we don't know if we don't overwrite
|
|
|
|
|
a version of the file that is even newer than the one
|
|
|
|
|
we just installed. */
|
|
|
|
|
if (orig_pathname[i])
|
|
|
|
|
rename (orig_pathname[i], dest_pathname[i]);
|
|
|
|
|
else
|
|
|
|
|
unlink (dest_pathname[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
2004-01-30 13:15:53 +01:00
|
|
|
|
gc_error (1, saved_errno, "could not commit changes");
|
2004-01-29 00:58:18 +01:00
|
|
|
|
}
|
2004-03-23 13:21:48 +01:00
|
|
|
|
|
|
|
|
|
/* If it all worked, notify the daemons of the changes. */
|
|
|
|
|
if (opt.runtime)
|
|
|
|
|
for (backend = 0; backend < GC_BACKEND_NR; backend++)
|
|
|
|
|
{
|
|
|
|
|
if (runtime[backend] && gc_backend[backend].runtime_change)
|
|
|
|
|
(*gc_backend[backend].runtime_change) ();
|
|
|
|
|
}
|
|
|
|
|
|
2004-05-21 15:46:13 +02:00
|
|
|
|
/* Move the per-process backup file into its place. */
|
|
|
|
|
for (backend = 0; backend < GC_BACKEND_NR; backend++)
|
|
|
|
|
if (orig_pathname[backend])
|
|
|
|
|
{
|
|
|
|
|
char *backup_pathname;
|
|
|
|
|
|
|
|
|
|
assert (dest_pathname[backend]);
|
|
|
|
|
|
|
|
|
|
backup_pathname = xasprintf ("%s.gpgconf.bak", dest_pathname[backend]);
|
|
|
|
|
rename (orig_pathname[backend], backup_pathname);
|
|
|
|
|
}
|
|
|
|
|
|
2004-06-14 10:32:07 +02:00
|
|
|
|
xfree (line);
|
2004-01-29 00:58:18 +01:00
|
|
|
|
}
|