diff options
Diffstat (limited to 'tools/gpgconf-comp.c')
-rw-r--r-- | tools/gpgconf-comp.c | 2434 |
1 files changed, 0 insertions, 2434 deletions
diff --git a/tools/gpgconf-comp.c b/tools/gpgconf-comp.c deleted file mode 100644 index cc0751d0c..000000000 --- a/tools/gpgconf-comp.c +++ /dev/null @@ -1,2434 +0,0 @@ -/* gpgconf-comp.c - Configuration utility for GnuPG. - Copyright (C) 2004 Free Software Foundation, Inc. - - This file is part of GnuPG. - - GnuPG is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 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> -/* FIXME use gettext.h */ -#include <libintl.h> -#include <fcntl.h> -#include <unistd.h> -#include <sys/types.h> -#include <assert.h> -#include <errno.h> -#include <time.h> -#include <stdarg.h> -#include <signal.h> - -/* For log_logv(), asctimestamp(), gnupg_get_time (). */ -#define JNLIB_NEED_LOG_LOGV -#include "util.h" - -#include "gpgconf.h" - - -/* TODO: - Components: Add more components and their options. - Robustness: Do more validation. Call programs to do validation for us. - Don't use popen, as this will not tell us if the program had a - non-zero exit code. - Add options to change backend binary path. - Extract binary path for some backends from gpgsm/gpg config. -*/ - - -#if (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 )) -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); - } -} - - -/* Forward declaration. */ -void gpg_agent_runtime_change (void); - -/* 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, - - /* The GnuPG SCDaemon. */ - GC_BACKEND_SCDAEMON, - - /* 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; - - /* The runtime change callback. */ - void (*runtime_change) (void); - - /* 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] = - { - { 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" }, - }; - - -/* 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, - - /* ADD NEW BASIC TYPE ENTRIES HERE. */ - - /* Complex argument types. */ - - /* A complete pathname. */ - GC_ARG_TYPE_PATHNAME = 32, - - /* An LDAP server in the format - HOSTNAME:PORT:USERNAME:PASSWORD:BASE_DN. */ - GC_ARG_TYPE_LDAP_SERVER = 33, - - /* A 40 character fingerprint. */ - GC_ARG_TYPE_KEY_FPR = 34, - - /* ADD NEW COMPLEX TYPE ENTRIES HERE. */ - - /* 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" }, - - /* 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 }, - - /* 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. */ -#define GC_OPT_FLAG_NONE 0UL -/* 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. */ -#define GC_OPT_FLAG_GROUP (1UL << 0) -/* The ARG_OPT flag for an option indicates that the argument is - optional. This is never set for GC_ARG_TYPE_NONE options. */ -#define GC_OPT_FLAG_ARG_OPT (1UL << 1) -/* 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. */ -#define GC_OPT_FLAG_LIST (1UL << 2) -/* The RUNTIME flag for an option indicates that the option can be - changed at runtime. */ -#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) - -/* A human-readable description for each flag. */ -static struct -{ - const char *name; -} gc_flag[] = - { - { "group" }, - { "optional arg" }, - { "list" }, - { "runtime" }, - { "default" }, - { "default desc" }, - { "no arg desc" } - }; - - -/* 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. */ - unsigned long flags; - - /* 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 - and options. */ - 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 - argument, and the description follows the second '|'. */ - 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. */ - - /* This is true if the option is supported by this version of the - backend. */ - int active; - - /* 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; - - /* 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; - - /* The current value of this option. */ - char *value; - - /* 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; - - /* 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[] = - { - /* 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, - NULL, "Options controlling the diagnostic output" }, - { "verbose", GC_OPT_FLAG_LIST|GC_OPT_FLAG_RUNTIME, GC_LEVEL_BASIC, - "gnupg", "verbose", - GC_ARG_TYPE_NONE, GC_BACKEND_GPG_AGENT }, - { "quiet", GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME, GC_LEVEL_BASIC, - "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, - NULL, "Options controlling the configuration" }, - { "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, - "gnupg", "Options useful for debugging" }, - { "debug-level", GC_OPT_FLAG_ARG_OPT|GC_OPT_FLAG_RUNTIME, GC_LEVEL_ADVANCED, - "gnupg", "|LEVEL|set the debugging level to LEVEL", - GC_ARG_TYPE_STRING, GC_BACKEND_GPG_AGENT }, - { "log-file", GC_OPT_FLAG_RUNTIME, GC_LEVEL_ADVANCED, - "gnupg", "|FILE|write logs to FILE", - 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, - NULL, "Options controlling the security" }, - { "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", - GC_ARG_TYPE_NONE, GC_BACKEND_GPG_AGENT }, - { "allow-mark-trusted", GC_OPT_FLAG_RUNTIME, GC_LEVEL_ADVANCED, - "gnupg", "allow clients to mark keys as \"trusted\"", - GC_ARG_TYPE_NONE, GC_BACKEND_GPG_AGENT }, - { "no-grab", GC_OPT_FLAG_RUNTIME, GC_LEVEL_EXPERT, - "gnupg", "do not grab keyboard and mouse", - GC_ARG_TYPE_NONE, GC_BACKEND_GPG_AGENT }, - - - GC_OPTION_NULL - }; - - -/* The options of the GC_COMPONENT_SCDAEMON component. */ -static gc_option_t gc_options_scdaemon[] = - { - /* 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, - NULL, "Options controlling the diagnostic output" }, - { "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, - NULL, "Options controlling the configuration" }, - { "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, - "gnupg", "Options useful for debugging" }, - { "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, - "gnupg", "|FILE|write logs to FILE", - GC_ARG_TYPE_PATHNAME, GC_BACKEND_SCDAEMON }, - - { "Security", - GC_OPT_FLAG_GROUP, GC_LEVEL_BASIC, - NULL, "Options controlling the security" }, - { "allow-admin", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC, - "gnupg", "allow the use of admin card commands", - GC_ARG_TYPE_NONE, GC_BACKEND_SCDAEMON }, - - - GC_OPTION_NULL - }; - - -/* 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, - NULL, "Options controlling the diagnostic output" }, - { "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, - NULL, "Options controlling the configuration" }, - { "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, - "gnupg", "Options useful for debugging" }, - { "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, - "gnupg", "|FILE|write logs to FILE", - 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 }, */ - - { "Keyserver", - GC_OPT_FLAG_GROUP, GC_LEVEL_BASIC, - NULL, "Configuration for Keyservers" }, - { "keyserver", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC, - "gnupg", "|URL|use keyserver at URL", - GC_ARG_TYPE_STRING, GC_BACKEND_GPG }, - - - GC_OPTION_NULL - }; - - - -/* The options of the GC_COMPONENT_GPGSM component. */ -static gc_option_t gc_options_gpgsm[] = - { - /* 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, - NULL, "Options controlling the diagnostic output" }, - { "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, - NULL, "Options controlling the configuration" }, - { "options", GC_OPT_FLAG_NONE, GC_LEVEL_EXPERT, - "gnupg", "|FILE|read options from FILE", - GC_ARG_TYPE_PATHNAME, GC_BACKEND_GPGSM }, - - { "Debug", - GC_OPT_FLAG_GROUP, GC_LEVEL_ADVANCED, - "gnupg", "Options useful for debugging" }, - { "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, - "gnupg", "|FILE|write logs to FILE", - 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, - NULL, "Options controlling the security" }, - { "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 }, - - GC_OPTION_NULL - }; - - -/* The options of the GC_COMPONENT_DIRMNGR component. */ -static gc_option_t gc_options_dirmngr[] = - { - /* The configuration file to which we write the changes. */ - { "gpgconf-dirmngr.conf", GC_OPT_FLAG_NONE, GC_LEVEL_INTERNAL, - NULL, NULL, GC_ARG_TYPE_PATHNAME, GC_BACKEND_DIRMNGR }, - - { "Monitor", - GC_OPT_FLAG_GROUP, GC_LEVEL_BASIC, - NULL, "Options controlling the diagnostic output" }, - { "verbose", GC_OPT_FLAG_LIST, GC_LEVEL_BASIC, - "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, - NULL, "Options controlling the format of the output" }, - { "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, - NULL, "Options controlling the configuration" }, - { "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, - "dirmngr", "Options useful for debugging" }, - { "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 }, - { "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, - "dirmngr", "|FILE|write logs to FILE", - 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, - NULL, "Options controlling the interactivity and enforcement" }, - { "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 }, - - { "LDAP", - GC_OPT_FLAG_GROUP, GC_LEVEL_BASIC, - NULL, "Configuration of LDAP servers to use" }, - { "add-servers", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC, - "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. */ - { "LDAP Server", GC_OPT_FLAG_ARG_OPT|GC_OPT_FLAG_LIST, GC_LEVEL_BASIC, - 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 }, - - { "OCSP", - GC_OPT_FLAG_GROUP, GC_LEVEL_ADVANCED, - NULL, "Configuration for OCSP" }, - { "allow-ocsp", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC, - "dirmngr", "allow sending OCSP requests", - GC_ARG_TYPE_NONE, GC_BACKEND_DIRMNGR }, - { "ocsp-responder", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED, - "dirmngr", "|URL|use OCSP responder URL", - GC_ARG_TYPE_STRING, GC_BACKEND_DIRMNGR }, - { "ocsp-signer", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED, - "dirmngr", "|FPR|OCSP response signed by FPR", - GC_ARG_TYPE_STRING, GC_BACKEND_DIRMNGR }, - - - 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 - { - /* The classic GPG for OpenPGP. */ - GC_COMPONENT_GPG, - - /* The GPG Agent. */ - GC_COMPONENT_GPG_AGENT, - - /* The Smardcard Daemon. */ - GC_COMPONENT_SCDAEMON, - - /* GPG for S/MIME. */ - GC_COMPONENT_GPGSM, - - /* 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[] = - { - { "gpg", NULL, "GPG for OpenPGP", gc_options_gpg }, - { "gpg-agent", NULL, "GPG Agent", gc_options_gpg_agent }, - { "scdaemon", NULL, "Smartcard Daemon", gc_options_scdaemon }, - { "gpgsm", NULL, "GPG for S/MIME", gc_options_gpgsm }, - { "dirmngr", NULL, "Directory Manager", gc_options_dirmngr } - }; - - -/* Engine specific support. */ -void -gpg_agent_runtime_change (void) -{ - 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); -} - - -/* More or less Robust version of dgettext. It has the sidefeect of - switching the codeset to utf-8 becuase this is what we want to - 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. */ -static const char * -my_dgettext (const char *domain, const char *msgid) -{ -#ifdef ENABLE_NLS - if (domain) - { - static int switched_codeset; - char *text; - - if (!switched_codeset) - { - bind_textdomain_codeset (PACKAGE_GT, "utf-8"); - switched_codeset = 1; - } - text = dgettext (domain, msgid); - return text ? text : msgid; - } - else -#endif - 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) - gc_error (1, errno, "can not escape string"); - 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; -} - - -/* 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; -} - - -/* 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; -} - - -/* List the option OPTION. */ -static void -list_one_option (const gc_option_t *option, FILE *out) -{ - const char *desc = NULL; - char *arg_name = NULL; - - if (option->desc) - { - desc = my_dgettext (option->desc_domain, option->desc); - - if (*desc == '|') - { - 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; - } - } - } - - - /* 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 - { - unsigned long flags = option->flags; - unsigned long flag = 0; - unsigned long first = 1; - - while (flags) - { - if (flags & 1) - { - if (first) - first = 0; - else - putc (',', out); - fprintf (out, "%s", gc_flag[flag].name); - } - flags >>= 1; - flag++; - } - } - } - - /* 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 : ""); - - /* ADD NEW FIELDS HERE. */ - - putc ('\n', out); -} - - -/* 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; - } - - if (option->flags & GC_OPT_FLAG_GROUP) - group_option = option; - else - { - if (group_option) - { - list_one_option (group_option, out); - group_option = NULL; - } - - list_one_option (option, out); - } - - 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) -{ - char *pathname = NULL; - gc_option_t *option = find_option - (component, gc_backend[backend].option_config_filename, GC_BACKEND_ANY); - assert (option); - assert (option->arg_type == GC_ARG_TYPE_PATHNAME); - assert (!(option->flags & GC_OPT_FLAG_LIST)); - - if (!option->active || !option->default_value) - gc_error (1, 0, "Option %s, needed by backend %s, was not initialized", - gc_backend[backend].option_config_filename, - gc_backend[backend].name); - - if (option->value && *option->value) - pathname = percent_deescape (&option->value[1]); - else if (option->default_value && *option->default_value) - pathname = percent_deescape (&option->default_value[1]); - else - pathname = ""; - - if (pathname[0] != '/') - gc_error (1, 0, "Option %s, needed by backend %s, is not absolute", - gc_backend[backend].option_config_filename, - gc_backend[backend].name); - - return pathname; -} - - -/* 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; - FILE *config; - char *config_pathname; - - cmd_line = xasprintf ("%s --gpgconf-list", gc_backend[backend].program); - - config = popen (cmd_line, "r"); - if (!config) - gc_error (1, errno, "could not gather active options from %s", cmd_line); - - while ((length = read_line (config, &line, &line_len, NULL)) > 0) - { - gc_option_t *option; - char *linep; - unsigned long flags = 0; - char *default_value = NULL; - - /* Strip newline and carriage return, if present. */ - while (length > 0 - && (line[length - 1] == '\n' || line[length - 1] == '\r')) - line[--length] = '\0'; - - 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; - } - - /* Extract default value, if present. Default to empty if - not. */ - if (linep) - { - char *end; - - end = strchr (linep, ':'); - if (end) - *(end++) = '\0'; - - if (flags & GC_OPT_FLAG_DEFAULT) - default_value = linep; - - linep = end; - } - - /* Look up the option in the component and install the - configuration data. */ - option = find_option (component, line, backend); - if (option) - { - if (option->active) - gc_error (1, errno, "option %s returned twice from %s", - line, cmd_line); - option->active = 1; - - option->flags |= flags; - if (default_value && *default_value) - option->default_value = xstrdup (default_value); - } - } - if (length < 0 || ferror (config)) - gc_error (1, errno, "error reading from %s", cmd_line); - if (fclose (config) && ferror (config)) - gc_error (1, errno, "error closing %s", cmd_line); - 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 - { - while ((length = read_line (config, &line, &line_len, NULL)) > 0) - { - 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); - opt_value = xstrdup ("1"); - } - 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); - } - } - } - } - - if (length < 0 || ferror (config)) - gc_error (1, errno, "error reading from %s", config_pathname); - if (fclose (config) && ferror (config)) - gc_error (1, errno, "error closing %s", config_pathname); - } - - xfree (line); -} - - -/* 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; - char *list = NULL; - - list_option = find_option (component, - gc_backend[backend].option_name, GC_BACKEND_ANY); - assert (list_option); - assert (!list_option->active); - - list_pathname = get_config_pathname (component, backend); - list_file = fopen (list_pathname, "r"); - if (!list_file) - gc_error (0, errno, "warning: can not open list file %s", list_pathname); - else - { - - while ((length = read_line (list_file, &line, &line_len, NULL)) > 0) - { - 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'; - /* FIXME: Oh, no! This is so lame! Should use realloc and - really append. */ - if (list) - { - new_list = xasprintf ("%s,\"%s", list, percent_escape (start)); - xfree (list); - list = new_list; - } - else - list = xasprintf ("\"%s", percent_escape (start)); - } - if (length < 0 || ferror (list_file)) - gc_error (1, errno, "can not read list file %s", list_pathname); - } - - list_option->active = 1; - list_option->value = list; - - xfree (line); -} - - -/* 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++; - } -} - - -/* 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. */ -static void -option_check_validity (gc_option_t *option, unsigned long flags, - char *new_value, unsigned long *new_value_nr) -{ - char *arg; - - if (!option->active) - gc_error (1, 0, "option %s not supported by backend", option->name); - - if (option->new_flags || option->new_value) - gc_error (1, 0, "option %s already changed", option->name); - - if (flags & GC_OPT_FLAG_DEFAULT) - { - if (*new_value) - gc_error (1, 0, "argument %s provided for deleted option %s", - new_value, option->name); - - return; - } - - /* GC_ARG_TYPE_NONE options have special list treatment. */ - if (gc_arg_type[option->arg_type].fallback == GC_ARG_TYPE_NONE) - { - char *tail; - - 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)) - { - 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); - } - - return; - } - - 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); - - 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); - - if (errno) - gc_error (1, errno, "invalid argument for option %s", - option->name); - - 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); - - if (errno) - gc_error (1, errno, "invalid argument for option %s", - option->name); - - if (*arg != '\0' && *arg != ',') - gc_error (1, 0, "garbage after argument for option %s", - option->name); - } - arg = strchr (arg, ','); - if (arg) - arg++; - } - while (arg && *arg); -} - - -/* 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) -{ - 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; - if (arg && arg[0] == '\0') - arg = NULL; - else 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; - } - - res = link (dest_filename, orig_filename); - 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; - - while ((length = read_line (dest_file, &line, &line_len, NULL)) > 0) - { - 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; - } - } - if (length < 0 || ferror (dest_file)) - 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) - { - while ((length = read_line (dest_file, &line, &line_len, NULL)) > 0) - { - fprintf (src_file, "%s", line); - if (ferror (src_file)) - goto change_file_one_err; - } - if (length < 0 || ferror (dest_file)) - goto change_file_one_err; - } - xfree (line); - line = NULL; - - 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: - xfree (line); - res = errno; - if (src_file) - { - fclose (src_file); - close (fd); - } - if (dest_file) - fclose (dest_file); - errno = res; - 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; - 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; - - /* FIXME. Throughout the function, do better error reporting. */ - 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 ()); - - res = link (dest_filename, orig_filename); - 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_one_err; - - while ((length = read_line (dest_file, &line, &line_len, NULL)) > 0) - { - 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 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; - if (option && ((option->new_flags & GC_OPT_FLAG_DEFAULT) - || option->new_value)) - disable = 1; - } - 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_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; - } - } - if (length < 0 || ferror (dest_file)) - 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. */ - - /* We have to turn on UTF8 strings for GnuPG. */ - if (backend == GC_BACKEND_GPG) - fprintf (src_file, "utf8-strings\n"); - - option = gc_component[component].options; - while (option->name) - { - if (!(option->flags & GC_OPT_FLAG_GROUP) - && option->backend == backend - && option->new_value) - { - 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); - } - option++; - } - - fprintf (src_file, "%s %s\n", marker, asctimestamp (gnupg_get_time ())); - if (ferror (src_file)) - goto change_one_err; - - 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) - { - while ((length = read_line (dest_file, &line, &line_len, NULL)) > 0) - { - fprintf (src_file, "%s", line); - if (ferror (src_file)) - goto change_one_err; - } - if (length < 0 || ferror (dest_file)) - goto change_one_err; - } - xfree (line); - line = NULL; - - 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: - xfree (line); - res = errno; - if (src_file) - { - fclose (src_file); - close (fd); - } - if (dest_file) - fclose (dest_file); - errno = res; - return -1; -} - - -/* Read the modifications from IN and apply them. */ -void -gc_component_change_options (int component, FILE *in) -{ - int err = 0; - int runtime[GC_BACKEND_NR]; - 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++) - { - runtime[backend] = 0; - src_pathname[backend] = NULL; - dest_pathname[backend] = NULL; - orig_pathname[backend] = NULL; - } - - while ((length = read_line (in, &line, &line_len, NULL)) > 0) - { - char *linep; - unsigned long flags = 0; - char *new_value = ""; - unsigned long new_value_nr; - - /* Strip newline and carriage return, if present. */ - while (length > 0 - && (line[length - 1] == '\n' || line[length - 1] == '\r')) - line[--length] = '\0'; - - 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) - { - char *end; - - end = strchr (linep, ':'); - if (end) - *(end++) = '\0'; - - new_value = linep; - - linep = end; - } - - option = find_option (component, line, GC_BACKEND_ANY); - if (!option) - gc_error (1, 0, "unknown option %s", line); - - option_check_validity (option, flags, new_value, &new_value_nr); - - if (option->flags & GC_OPT_FLAG_RUNTIME) - runtime[option->backend] = 1; - - option->new_flags = flags; - if (!(flags & GC_OPT_FLAG_DEFAULT)) - { - 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); - } - } - - /* 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. */ - if (src_pathname[option->backend] - || !(option->new_flags || option->new_value)) - { - option++; - continue; - } - - if (gc_backend[option->backend].program) - err = change_options_program (component, option->backend, - &src_pathname[option->backend], - &dest_pathname[option->backend], - &orig_pathname[option->backend]); - else - err = change_options_file (component, option->backend, - &src_pathname[option->backend], - &dest_pathname[option->backend], - &orig_pathname[option->backend]); - - if (err) - break; - - option++; - } - - if (!err) - { - int i; - - for (i = 0; i < GC_BACKEND_NR; i++) - { - 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 - { - /* 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]); - } - if (err) - break; - src_pathname[i] = NULL; - } - } - } - - if (err) - { - int i; - int saved_errno = errno; - - /* An error occured. */ - for (i = 0; i < GC_BACKEND_NR; i++) - { - 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]); - } - } - gc_error (1, saved_errno, "could not commit changes"); - } - - /* 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) (); - } - - /* 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); - } - - xfree (line); -} |