diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/ChangeLog | 252 | ||||
-rw-r--r-- | tools/Makefile.am | 39 | ||||
-rw-r--r-- | tools/Manifest | 6 | ||||
-rw-r--r-- | tools/README.gpgconf | 422 | ||||
-rwxr-xr-x | tools/addgnupghome | 122 | ||||
-rwxr-xr-x | tools/der-to-pem | 27 | ||||
-rw-r--r-- | tools/gpgconf-comp.c | 2434 | ||||
-rw-r--r-- | tools/gpgconf.c | 206 | ||||
-rw-r--r-- | tools/gpgconf.h | 58 | ||||
-rw-r--r-- | tools/gpgparsemail.c | 705 | ||||
-rw-r--r-- | tools/no-libgcrypt.c | 105 | ||||
-rw-r--r-- | tools/rfc822parse.c | 1235 | ||||
-rw-r--r-- | tools/rfc822parse.h | 79 | ||||
-rw-r--r-- | tools/watchgnupg.c | 389 |
14 files changed, 0 insertions, 6079 deletions
diff --git a/tools/ChangeLog b/tools/ChangeLog deleted file mode 100644 index a81a2d301..000000000 --- a/tools/ChangeLog +++ /dev/null @@ -1,252 +0,0 @@ -2004-06-14 Werner Koch <[email protected]> - - * no-libgcrypt.c (gcry_realloc, gcry_xmalloc, gcry_xcalloc): New. - - * gpgconf-comp.c (retrieve_options_from_program) - (retrieve_options_from_file, change_options_file) - (change_options_program, gc_component_change_options): Replaced - getline by read_line and test for allocation failure. - -2004-05-21 Marcus Brinkmann <[email protected]> - - * gpgconf-comp.c (gc_options_dirmngr): Remove CRL group, put its - only option "max-replies" into LDAP group. - (gc_component): Change description of dirmngr to "Directory - Manager". - - * gpgconf-comp.c (gc_component_change_options): Move the - per-process backup file into a standard location. - -2004-05-03 Werner Koch <[email protected]> - - * gpgconf-comp.c: Add --allow-mark-trusted for the gpg-agent. - -2004-04-30 Werner Koch <[email protected]> - - * gpgconf-comp.c: Added more runtime flags for the gpg-agent - backend. - -2004-04-29 Marcus Brinkmann <[email protected]> - - * gpgconf-comp.c (change_options_program): Turn on utf8-strings in - the gpgconf specific part of the config file for the GnuPG - backend. - -2004-04-28 Werner Koch <[email protected]> - - * gpgconf-comp.c: Add --ocsp-signer for the dirmngr backend. - -2004-04-20 Marcus Brinkmann <[email protected]> - - * gpgconf-comp.c (gc_options_gpg_agent): Change type of - ignore-cache-for-signing option to GC_ARG_TYPE_NONE. - -2004-04-07 Werner Koch <[email protected]> - - * gpgconf-comp.c (my_dgettext): Switch the codeset once to utf-8. - Allow building with out NLS. - -2004-03-23 Marcus Brinkmann <[email protected]> - - * gpgconf-comp.c (gc_options_dirmngr): Set GC_OPT_FLAG_ARG_OPT for - "LDAP Server". - (change_options_file): Remove assertion that tests that this flag - is not present. Handle an empty string in OPTION->new_value. - - * gpgconf.c (main): Remove obsolete warning. - -2004-03-23 Werner Koch <[email protected]> - - * gpgconf-comp.c (gc_options_gpg): New. - (gc_component_t, gc_component): Add GC_BACKEND_GPG. - (gc_options_dirmngr): Add allow-ocsp. - -2004-03-23 Marcus Brinkmann <[email protected]> - - * gpgconf-comp.c (gc_flag): Add missing flags. - - * gpgconf-comp.c: Include <signal.h>. - (gc_backend): Add new member runtime_change. - (gpg_agent_runtime_change): New function. - (gc_component_change_options): New variable runtime. Initialize - it. If an option is changed that has the GC_OPT_FLAG_RUNTIME bit - set, also set the corresponding runtime variable. Finally, call - the runtime_change callback of the backend if needed. - -2004-03-16 Werner Koch <[email protected]> - - * gpgconf-comp.c (gc_options_gpg_agent): Implemented. - (gc_options_gpgsm, gc_options_scdaemon): Implemented. - (gc_backend_t): Add GC_BACKEND_SCDAEMON. - -2004-03-12 Marcus Brinkmann <[email protected]> - - * gpgconf-comp.c (gc_component_change_options): Set the filenames - of the option's backend, not of the component. - Also use GC_BACKEND_NR, not GC_COMPONENT_NR. - -2004-03-09 Werner Koch <[email protected]> - - * gpgconf-comp.c [_riscos_]: Removed special code for RISC OS; we - don't want to clutter our code with system dependent stuff. - -2004-03-08 Marcus Brinkmann <[email protected]> - - * gpgconf-comp.c (retrieve_options_from_file): Quote each string - in the list, not only the first. - -2004-02-26 Marcus Brinkmann <[email protected]> - - * gpgconf-comp.c (gc_component_list_options): Do not print empty - groups. - - * gpgconf-comp.c (option_check_validity): Check if option is - active. - (change_options_file): Implement. - - * gpgconf-comp.c (retrieve_options_from_program): Remove broken - string handling. - - * gpgconf-comp.c (change_options_program): Support all types of - options, including list types. - - * README.gpgconf: Fix description of arguments. - * gpgconf-comp.c (option_check_validity): Rewritten to properly - support optional arguments in lists. - - * README.gpgconf: Add info about optional arg and arg type 0. - * gpgconf-comp.c (gc_component_change_options): Parse list of - arg type 0 options. - (option_check_validity): Add new argument NEW_VALUE_NR. Perform - rigorous validity checks. - (change_options_program): Disable an option also if we have a new - value for it. - -2004-02-25 Marcus Brinkmann <[email protected]> - - * gpgconf-comp.c (gc_component_list_options): Correct output for - lists of arg type none. - (struct gc_option): Add new member new_flags. - (option_check_validity): Check OPTION->new_flags beside - OPTION->new_value. Add new argument FLAGS. - (gc_component_change_options): Support default flag correctly. - (change_options_program): Likewise. - -2004-02-24 Marcus Brinkmann <[email protected]> - - * README.gpgconf: Revert last change. Add new flags "default", - "default desc" and "no arg desc". Add new field ARGDEF. Add new - field FLAG to backend interface. - * gpgconf-comp.c (struct gc_option): Make flags of type unsigned - long. - (gc_component_list_options): Adjust type for flags. - Add default argument field. - (retrieve_options_from_program): Use "1" as value for non-option - arguments, not "Y". - (gc_component_change_options): Read in flags from input. - -2004-02-23 Marcus Brinkmann <[email protected]> - - * README.gpgconf: Change meaning of type 0 options value if it is - the empty string or "0". - - * gpgconf.h (struct): Add member runtime. - * gpgconf.c: Add new option oRuntime. - (main): Same here. - - * gpgconf-comp.c (hextobyte): New function. - (percent_deescape): New function. - (get_config_pathname): Percent deescape pathname if taken from - option (default) value. Use default value only if it exists and - is not empty. Use empty string otherwise. Don't include leading - quote in pathname. - (change_options_program): Percent deescape string before writing - it out. - - * gpgconf-comp.c (gc_component_list_options): Do not skip groups - on output. - -2004-02-18 Werner Koch <[email protected]> - - * gpgconf-comp.c: Added empty components for gpgsm and scdaemon. - -2004-02-12 Werner Koch <[email protected]> - - * watchgnupg.c (main): Implement option "--". - (print_version): New. - - * Makefile.am: Include cmacros.am for common flags. - -2004-02-03 Werner Koch <[email protected]> - - * addgnupghome: Try to use getent, so that it also works for NIS - setups. - -2004-01-31 Marcus Brinkmann <[email protected]> - - * gpgconf-comp.c: Some bug fixes, parse only defaults from the - program, and read the current values from the configuration file - directly. - -2004-01-30 Marcus Brinkmann <[email protected]> - - * gpgconf-comp.c (gc_error): New function, use it instead of - error() throughout. - - * gpgconf-comp.c: Use xmalloc, libcommon's asctimestamp and - gnupg_get_time, fix error() invocation and use getline() - consistently. - -2004-01-30 Werner Koch <[email protected]> - - * addgnupghome: Also set the group of copied files. - -2004-01-30 Werner Koch <[email protected]> - - * Makefile.am (sbin_SCRIPTS): New, to install addgnupghome. - (EXTRA_DIST): Added rfc822parse.c rfc822parse.h gpgparsemail.c - which might be useful for debugging. - -2004-01-29 Werner Koch <[email protected]> - - * addgnupghome: New. - -2004-01-29 Marcus Brinkmann <[email protected]> - - * gpgconf-list.c: File removed. - * README.gpgconf: New file. - * gpgconf-comp.c: New file. - * Makefile.am (gpgconf_SOURCES): Remove gpgconf-list.c, add - gpgconf-comp.c. - -2004-01-16 Werner Koch <[email protected]> - - * watchgnupg.c (main): Need to use FD_ISSET for the client - descriptors too; aiiih. Set the listening socket to non-blocking. - -2004-01-10 Werner Koch <[email protected]> - - * Makefile.am: Use GPG_ERROR_CFLAGS - -2004-01-05 Werner Koch <[email protected]> - - * Manifest: New. - * gpgconf.c, gpgconf.h, gpgconf-list.c: New. A skeleton for now. - * no-libgcrypt.c: New. - * Makefile.am: Add above. - -2003-12-23 Werner Koch <[email protected]> - - * Makefile.am: New. - * watchgnupg.c: New. - - - Copyright 2003, 2004 Free Software Foundation, Inc. - - This file is free software; as a special exception the author gives - unlimited permission to copy and/or distribute it, with or without - modifications, as long as this notice is preserved. - - This file is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY, to the extent permitted by law; without even the - implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. diff --git a/tools/Makefile.am b/tools/Makefile.am deleted file mode 100644 index 71a77356f..000000000 --- a/tools/Makefile.am +++ /dev/null @@ -1,39 +0,0 @@ -# Makefile.am - Tools directory -# Copyright (C) 2003 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 this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - -EXTRA_DIST = Manifest watchgnupg.c \ - rfc822parse.c rfc822parse.h gpgparsemail.c \ - addgnupghome - -AM_CPPFLAGS = -I$(top_srcdir)/intl -I$(top_srcdir)/common -include $(top_srcdir)/am/cmacros.am - -# Note, that we require GPG_ERROR_CFLAGS only because some share header files -# require that file. It is not actually used in gpgconf. -AM_CFLAGS = @GPG_ERROR_CFLAGS@ - -sbin_SCRIPTS = addgnupghome - -bin_PROGRAMS = gpgconf watchgnupg - -gpgconf_SOURCES = gpgconf.c gpgconf.h gpgconf-comp.c no-libgcrypt.c - -gpgconf_LDADD = ../jnlib/libjnlib.a ../common/libcommon.a @INTLLIBS@ - -watchgnupg_SOURCES = watchgnupg.c diff --git a/tools/Manifest b/tools/Manifest deleted file mode 100644 index 96423352d..000000000 --- a/tools/Manifest +++ /dev/null @@ -1,6 +0,0 @@ -Makefile.am -watchgnupg.c -gpgconf.c -gpgconf.h -gpgconf-list.c -$names$ diff --git a/tools/README.gpgconf b/tools/README.gpgconf deleted file mode 100644 index c0d3c7c61..000000000 --- a/tools/README.gpgconf +++ /dev/null @@ -1,422 +0,0 @@ -============ - GPG Conf -============ - -CONCEPT -======= - -gpgconf provides access to the configuration of one or more components -of the GnuPG system. These components correspond more or less to the -programs that exist in the GnuPG framework, like GnuPG, GPGSM, -DirMngr, etc. But this is not a strict one-to-one relationship. Not -all configuration options are available through GPGConf. GPGConf -provides a generic and abstract method to access the most important -configuration options that can feasibly be controlled via such a -mechanism. - -GPGConf can be used to gather and change the options available in each -component, and can also provide their default values. GPGConf will -give detailed type information that can be used to restrict the user's -input without making an attempt to commit the changes. - -GPGConf provides the backend of a configuration editor. The -configuration editor would usually be a graphical user interface -program, that allows to display the current options, their default -values, and allows the user to make changes to the options. These -changes can then be made active with GPGConf again. Such a program -that uses GPGConf in this way will be called 'GUI' throughout this -document. - - -Format Conventions -================== - -Some lines in the output of GPGConf contain a list of colon-separated -fields. The following conventions apply: - -The GUI program is required to strip off trailing newline and/or carriage -return characters from the output. - -GPGConf will never leave out fields. If a certain version documents a -certain field, this field will always be present in all GPGConf -versions from that time on. - -Future versions of GPGConf might append fields to the list. New -fields will always be separated from the previously last field by a -colon separator. The GUI should be prepared to parse the last field -it knows about up until a colon or end of line. - -Not all fields are defined under all conditions. You are required to -ignore the content of undefined fields. - -Some fields contain strings that are not escaped in any way. Such -fields are described to be used "verbatim". These fields will never -contain a colon character (for obvious reasons). No de-escaping or -other formatting is required to use the field content. This is for -easy parsing of the output, when it is known that the content can -never contain any special characters. - -Some fields contain strings that are described to be -"percent-escaped". Such strings need to be de-escaped before their -content can be presented to the user. A percent-escaped string is -de-escaped by replacing all occurences of %XY by the byte that has the -hexadecimal value XY. X and Y are from the set { '0'..'9', 'a'..'f' }. - -Some fields contain strings that are described to be "localised". Such -strings are translated to the active language and formatted in the -active character set. - -Some fields contain an unsigned number. This number will always fit -into a 32-bit unsigned integer variable. The number may be followed -by a space, followed by a human readable description of that value. -You should ignore everything in the field that follows the number. - -Some fields contain a signed number. This number will always fit into -a 32-bit signed integer variable. The number may be followed by a -space, followed by a human readable description of that value. You -should ignore everything in the field that follows the number. - -Some fields contain an option argument. The format of an option -argument depends on the type of the option and on some flags: - -The simplest case is that the option does not take an argument at all -(TYPE is 0). Then the option argument is an unsigned number that -specifies how often the option occurs. If the LIST flag is not set, -then the only valid number is 1. Options that don't take an argument -never have the "default" or "optional arg" flag set. - -If the option takes a number argument (ALT-TYPE is 2 or 3), and it can -only occur once (LIST flag is not set), then the option argument is -either empty (only allowed if the argument is optional), or it is a -number. A number is a string that begins with an optional minus -character, followed by one or more digits. The number must fit into -an integer variable (unsigned or signed, depending on ALT-TYPE). - -If the option takes a number argument and it can occur more than once, -then the option argument is either empty, or it is a comma-separated -list of numbers as described above. - -If the option takes a string argument (ALT-TYPE is 1), and it can only -occur once (LIST flag is not set) then the option argument is either -empty (only allowed if the argument is optional), or it starts with a -double quote character (") followed by a percent-escaped string that -is the argument value. Note that there is only a leading double quote -character, no trailing one. The double quote character is only needed -to be able to differentiate between no value and the empty string as -value. - -If the option takes a number argument and it can occur more than once, -then the option argument is either empty, or it is a comma-separated -list of string arguments as described above. - -FIXME: Document the active language and active character set. Allow -to change it via the command line? - - -Components -========== - -A component is a set of configuration options that semantically belong -together. Furthermore, several changes to a component can be made in -an atomic way with a single operation. The GUI could for example -provide a menu with one entry for each component, or a window with one -tabulator sheet per component. - -The following interface is provided to list the available components: - -Command --list-components -------------------------- - -Outputs a list of all components available, one per line. The format -of each line is: - -NAME:DESCRIPTION - -NAME - -This field contains a name tag of the component. The name tag is used -to specify the component in all communication with GPGConf. The name -tag is to be used verbatim. It is not in any escaped format. - -DESCRIPTION - -The string in this field contains a human-readable description of the -component. It can be displayed to the user of the GUI for -informational purposes. It is percent-escaped and localized. - -Example: -$ gpgconf --list-components -gpg-agent:GPG Agent -dirmngr:CRL Manager - - -OPTIONS -======= - -Every component contains one or more options. Options may belong to a -group. The following command lists all options and the groups they -belong to: - -Command --list-options COMPONENT --------------------------------- - -Lists all options (and the groups they belong to) in the component -COMPONENT. COMPONENT is the string in the field NAME in the -output of the --list-components command. - -There is one line for each option and each group. First come all -options that are not in any group. Then comes a line describing a -group. Then come all options that belong into each group. Then comes -the next group and so on. - -The format of each line is: - -NAME:FLAGS:LEVEL:DESCRIPTION:TYPE:ALT-TYPE:ARGNAME:DEFAULT:ARGDEF:VALUE - -NAME - -This field contains a name tag for the group or option. The name tag -is used to specify the group or option in all communication with -GPGConf. The name tag is to be used verbatim. It is not in any -escaped format. - -FLAGS - -The flags field contains an unsigned number. Its value is the -OR-wise combination of the following flag values: - - 1 group If this flag is set, this is a line describing - a group and not an option. - O 2 optional arg If this flag is set, the argument is optional. - This is never set for arg type 0 (none) options. - O 4 list If this flag is set, the option can be given - multiple times. - O 8 runtime If this flag is set, the option can be changed - at runtime. - O 16 default If this flag is set, a default value is available. - O 32 default desc If this flag is set, a (runtime) default is available. - This and the 'default' flag are mutually exclusive. - O 64 no arg desc If this flag is set, and the 'optional arg' flag - is set, then the option has a special meaning if no - argument is given. - -Flags marked with a 'O' are only defined for options (ie, if the GROUP -flag is not set). - -LEVEL - -This field is defined for options and for groups. It contains an -unsigned number that specifies the expert level under which this group -or option should be displayed. The following expert levels are -defined for options (they have analogous meaning for groups): - - 0 basic This option should always be offered to the user. - 1 advanced This option may be offered to advanced users. - 2 expert This option should only be offered to expert users. - 3 invisible This option should normally never be displayed, - not even to expert users. - 4 internal This option is for internal use only. Ignore it. - -The level of a group will always be the lowest level of all options it -contains. - -DESCRIPTION - -This field is defined for options and groups. The string in this -field contains a human-readable description of the option or group. -It can be displayed to the user of the GUI for informational purposes. -It is percent-escaped and localized. - -TYPE - -This field is only defined for options. It contains an unsigned -number that specifies the type of the option's argument, if any. -The following types are defined: - - Basic types - 0 none No argument allowed. - 1 string An unformatted string. - 2 int32 A signed integer number. - 3 uint32 An unsigned integer number. - - Complex types - 32 pathname A string that describes the pathname of a file. - The file does not necessarily need to exist. - 33 ldap server A string that describes an LDAP server in the format - HOSTNAME:PORT:USERNAME:PASSWORD:BASE_DN. - -More types will be added in the future. Please see the ALT-TYPE field -for information on how to cope with unknown types. - -ALT-TYPE - -This field is identical to TYPE, except that only the types 0 to 31 -are allowed. The GUI is expected to present the user the option in -the format specified by TYPE. But if the argument type TYPE is not -supported by the GUI, it can still display the option in the more -generic basic type ALT-TYPE. The GUI must support all the defined -basic types to be able to display all options. More basic types may -be added in future versions. If the GUI encounters a basic type it -doesn't support, it should report an error and abort the operation. - -ARGNAME - -This field is only defined for options with an argument type TYPE that -is not 0. In this case it may contain a percent-escaped and localised -string that gives a short name for the argument. The field may also -be empty, though, in which case a short name is not known. - -DEFAULT - -This field is defined only for options. Its format is that of an -option argument (see section Format Conventions for details). If the -default value is empty, then no default is known. Otherwise, the -value specifies the default value for this option. Note that this -field is also meaningful if the option itself does not take a real -argument. - -ARGDEF - -This field is defined only for options for which the "optional arg" -flag is set. If the "no arg desc" flag is not set, its format is that -of an option argument (see section Format Conventions for details). -If the default value is empty, then no default is known. Otherwise, -the value specifies the default value for this option. If the "no arg -desc" flag is set, the field is either empty or contains a description -of the effect of this option if no argument is given. Note that this -field is also meaningful if the option itself does not take a real -argument. - -VALUE - -This field is defined only for options. Its format is that of an -option argument. If it is empty, then the option is not explicitely -set in the current configuration, and the default applies (if any). -Otherwise, it contains the current value of the option. Note that -this field is also meaningful if the option itself does not take a -real argument. - - -CHANGING OPTIONS -================ - -To change the options for a component, you must provide them in the -following format: - -NAME:FLAGS:NEW-VALUE - -NAME - -This is the name of the option to change. - -FLAGS - -The flags field contains an unsigned number. Its value is the -OR-wise combination of the following flag values: - - 16 default If this flag is set, the option is deleted and the - default value is used instead (if applicable). - -NEW-VALUE - -The new value for the option. This field is only defined if the -"default" flag is not set. The format is that of an option argument. -If it is empty (or the field is omitted), the default argument is used -(only allowed if the argument is optional for this option). -Otherwise, the option will be set to the specified value. - - -Example: -To set the option force, which is of basic type 0 (none). -$ echo 'force:0:1' | gpgconf --change-options dirmngr -To delete the option force: -$ echo 'force:16:' | gpgconf --change-options dirmngr - - -Option --runtime ----------------- - -If this option is set, the changes will take effect at run-time, as -far as this is possible. Otherwise, they will take effect at the next -start of the respective backend programs. - - -BACKENDS -======== - -Backends should support the following commands: - -Command --gpgconf-list ----------------------- - -List the location of the configuration file, and all default values of -all options. The location of the configuration file must be an -absolute pathname. - -The format of each line is: - -NAME:FLAGS:DEFAULT:ARGDEF - -NAME - -This field contains a name tag for the group or option. The name tag -is used to specify the group or option in all communication with -GPGConf. The name tag is to be used verbatim. It is not in any -escaped format. - -FLAGS - -The flags field contains an unsigned number. Its value is the -OR-wise combination of the following flag values: - - 16 default If this flag is set, a default value is available. - 32 default desc If this flag is set, a (runtime) default is available. - This and the "default" flag are mutually exclusive. - 64 no arg desc If this flag is set, and the "optional arg" flag - is set, then the option has a special meaning if no - argument is given. - -DEFAULT - -This field is defined only for options. Its format is that of an -option argument (see section Format Conventions for details). If the -default value is empty, then no default is known. Otherwise, the -value specifies the default value for this option. Note that this -field is also meaningful if the option itself does not take a real -argument. - -ARGDEF - -This field is defined only for options for which the "optional arg" -flag is set. If the "no arg desc" flag is not set, its format is that -of an option argument (see section Format Conventions for details). -If the default value is empty, then no default is known. Otherwise, -the value specifies the default value for this option. If the "no arg -desc" flag is set, the field is either empty or contains a description -of the effect of this option if no argument is given. Note that this -field is also meaningful if the option itself does not take a real -argument. - - -Example: -$ dirmngr --gpgconf-list -gpgconf-config-file:/mnt/marcus/.gnupg/dirmngr.conf -ldapservers-file:/mnt/marcus/.gnupg/dirmngr_ldapservers.conf -add-servers:0 -max-replies:10 - - -TODO ----- - -* Extend the backend interface to include gettext domain and -description, if available, to avoid repeating this information in -gpgconf. - -* Left out string arguments (optional) are written out exactly as -empty string arguments. Should we do quoting? - -* More string argument trouble: Special characters like newlines etc -cause trouble. Again, should we do quoting? - - diff --git a/tools/addgnupghome b/tools/addgnupghome deleted file mode 100755 index 37a427bf2..000000000 --- a/tools/addgnupghome +++ /dev/null @@ -1,122 +0,0 @@ -# !/bin/sh -*- sh -*- -# Add a new .gnupg home directory for a list of users -# -# Copyright 2004 Free Software Foundation, Inc. -# -# This file is free software; as a special exception the author gives -# unlimited permission to copy and/or distribute it, with or without -# modifications, as long as this notice is preserved. -# -# This file is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -PGM=addgnupghome -any_error=0 - - -error () { - echo "$PGM: $*" >&2 - any_error=1 -} - -info () { - echo "$PGM: $*" >&2 -} - -# Do it for one user -one_user () { - user="$1" - home=$(${cat_passwd} | awk -F: -v n="$user" '$1 == n {print $6}') - if [ -z "$home" ]; then - if ${cat_passwd} | awk -F: -v n="$user" '$1 == n {exit 1}'; then - error "no such user \`$user'" - else - error "no home directory for user \`$user'" - fi - return - fi - if [ ! -d "$home" ]; then - error "home directory \`$home' of user \`$user' does not exist" - return - fi - if [ -d "$home/.gnupg" ]; then - info "skipping user \`$user': \`.gnupg' already exists" - return - fi - info "creating home directory \`$home/.gnupg' for \`$user'" - if ! mkdir "$home/.gnupg" ; then - error "error creating \`$home/.gnupg'" - return - fi - - if ! chown $user "$home/.gnupg" ; then - error "error changing ownership of \`$home/.gnupg'" - return - fi - - group=$(id -g "$user") - [ -z "$group" ] && group="0" - - if [ "$group" -gt 0 ]; then - if ! chgrp $group "$home/.gnupg" ; then - error "error changing group of \`$home/.gnupg'" - return - fi - fi - - if ! cd "$home/.gnupg" ; then - error "error cd-ing to \`$home/.gnupg'" - return - fi - for f in $filelist; do - if [ -d /etc/skel/.gnupg/$f ]; then - mkdir $f - else - cp /etc/skel/.gnupg/$f $f - fi - if ! chown $user $f ; then - error "error changing ownership of \`$f'" - return - fi - if [ "$group" -gt 0 ]; then - if ! chgrp $group "$f" ; then - error "error changing group of \`$f'" - return - fi - fi - done - -} - -if [ -z "$1" ]; then - echo "usage: $PGM userids" - exit 1 -fi - -# Check whether we can use getent -if getent --help </dev/null >/dev/null 2>&1 ; then - cat_passwd='getent passwd' -else - cat_passwd='cat /etc/passwd' - info "please note that only users from /etc/passwd are checked" -fi - -if [ ! -d /etc/skel/.gnupg ]; then - error "skeleton directory \`/etc/skel/.gnupg' does not exist" - exit 1 -fi -cd "/etc/skel/.gnupg" || (error "error cd-ing to \`/etc/skel/.gnupg'"; exit 1) -filelist=$(find . \( -type f -or -type d \) -not -name '*~' -not -name . -print) - - -if ! umask 0077 ; then - error "error setting umask" - exit 1 -fi - -for name in $*; do - one_user $name -done - -exit $any_error diff --git a/tools/der-to-pem b/tools/der-to-pem deleted file mode 100755 index 183996654..000000000 --- a/tools/der-to-pem +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/sh -# Convert A BER or DER encoding to PEM format. -# -# Copyright 20032 Free Software Foundation, Inc. -# -# This program is Free Software; as a special exception the author gives -# unlimited permission to copy and/or distribute it, with or without -# modifications, as long as this notice is preserved. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -PGM="der-to-pem" -if [ $# == 0 ]; then - input="" -elif [ $# == 1 ]; then - input="$1" -else - echo "usage: $PGM [<inputfile>]" >&2 - exit 1 -fi - -echo "-----BEGIN CERTIFICATE-----" -mimencode $input -echo "-----END CERTIFICATE-----" - 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); -} diff --git a/tools/gpgconf.c b/tools/gpgconf.c deleted file mode 100644 index 7aca335fa..000000000 --- a/tools/gpgconf.c +++ /dev/null @@ -1,206 +0,0 @@ -/* gpgconf.c - Configuration utility for GnuPG - * Copyright (C) 2003 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include <config.h> -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "gpgconf.h" -#include "i18n.h" - -/* Constants to identify the commands and options. */ -enum cmd_and_opt_values - { - aNull = 0, - oDryRun = 'n', - oOutput = 'o', - oQuiet = 'q', - oVerbose = 'v', - oRuntime = 'r', - oComponent = 'c', - oNoVerbose = 500, - oHomedir, - - aListComponents, - aListOptions, - aChangeOptions, - - }; - - -/* The list of commands and options. */ -static ARGPARSE_OPTS opts[] = - { - { 300, NULL, 0, N_("@Commands:\n ") }, - - { aListComponents, "list-components", 256, N_("list all components") }, - { aListOptions, "list-options", 256, N_("|COMPONENT|list options") }, - { aChangeOptions, "change-options", 256, N_("|COMPONENT|change options") }, - - { 301, NULL, 0, N_("@\nOptions:\n ") }, - - { oOutput, "output", 2, N_("use as output file") }, - { oVerbose, "verbose", 0, N_("verbose") }, - { oQuiet, "quiet", 0, N_("quiet") }, - { oDryRun, "dry-run", 0, N_("do not make any changes") }, - { oRuntime, "runtime", 0, N_("activate changes at runtime, if possible") }, - - /* hidden options */ - { oNoVerbose, "no-verbose", 0, "@"}, - {0} - }; - - -/* Print usage information and and provide strings for help. */ -static const char * -my_strusage( int level ) -{ - const char *p; - - switch (level) - { - case 11: p = "gpgconf (GnuPG)"; - break; - case 13: p = VERSION; break; - case 17: p = PRINTABLE_OS_NAME; break; - case 19: p = _("Please report bugs to <" PACKAGE_BUGREPORT ">.\n"); - break; - case 1: - case 40: p = _("Usage: gpgconf [options] (-h for help)"); - break; - case 41: - p = _("Syntax: gpgconf [options]\n" - "Manage configuration options for tools of the GnuPG system\n"); - break; - - default: p = NULL; break; - } - return p; -} - - -/* Initialize the gettext system. */ -static void -i18n_init(void) -{ -#ifdef USE_SIMPLE_GETTEXT - set_gettext_file (PACKAGE_GT); -#else -# ifdef ENABLE_NLS -# ifdef HAVE_LC_MESSAGES - setlocale (LC_TIME, ""); - setlocale (LC_MESSAGES, ""); -# else - setlocale (LC_ALL, "" ); -# endif - bindtextdomain (PACKAGE_GT, LOCALEDIR); - textdomain (PACKAGE_GT); -# endif -#endif -} - - -/* gpgconf main. */ -int -main (int argc, char **argv) -{ - ARGPARSE_ARGS pargs; - const char *fname; - int no_more_options = 0; - enum cmd_and_opt_values cmd = 0; - - set_strusage (my_strusage); - log_set_prefix ("gpgconf", 1); - - i18n_init(); - - /* Parse the command line. */ - pargs.argc = &argc; - pargs.argv = &argv; - pargs.flags = 1; /* Do not remove the args. */ - while (!no_more_options && optfile_parse (NULL, NULL, NULL, &pargs, opts)) - { - switch (pargs.r_opt) - { - case oOutput: opt.outfile = pargs.r.ret_str; break; - case oQuiet: opt.quiet = 1; break; - case oDryRun: opt.dry_run = 1; break; - case oRuntime: - opt.runtime = 1; - break; - case oVerbose: opt.verbose++; break; - case oNoVerbose: opt.verbose = 0; break; - - case aListComponents: - case aListOptions: - case aChangeOptions: - cmd = pargs.r_opt; - break; - - default: pargs.err = 2; break; - } - } - - if (log_get_errorcount (0)) - exit (2); - - fname = argc ? *argv : NULL; - - switch (cmd) - { - case aListComponents: - default: - /* List all components. */ - gc_component_list_components (stdout); - break; - - case aListOptions: - case aChangeOptions: - if (!fname) - { - fputs (N_("usage: gpgconf [options] "), stderr); - fputs (N_("Need one component argument"), stderr); - putc ('\n',stderr); - exit (2); - } - else - { - int idx = gc_component_find (fname); - if (idx < 0) - { - fputs (N_("Component not found"), stderr); - putc ('\n', stderr); - exit (1); - } - gc_component_retrieve_options (idx); - if (cmd == aListOptions) - gc_component_list_options (idx, stdout); - else - gc_component_change_options (idx, stdin); - } - } - - return 0; -} - - - diff --git a/tools/gpgconf.h b/tools/gpgconf.h deleted file mode 100644 index 138380b6d..000000000 --- a/tools/gpgconf.h +++ /dev/null @@ -1,58 +0,0 @@ -/* gpgconf.h - Global definitions for gpgconf - * Copyright (C) 2003 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#ifndef GPGCONF_H -#define GPGCONF_H - -#include "../common/util.h" - -/* We keep all global options in the structure OPT. */ -struct -{ - int verbose; /* Verbosity level. */ - int quiet; /* Be extra quiet. */ - int dry_run; /* Don't change any persistent data. */ - int runtime; /* Make changes active at runtime. */ - char *outfile; /* Name of output file. */ - - int component; /* The active component. */ -} opt; - - - -/*-- gpgconf-comp.c --*/ -/* List all components that are available. */ -void gc_component_list_components (FILE *out); - -/* Find the component with the name NAME. Returns -1 if not - found. */ -int gc_component_find (const char *name); - -/* Retrieve the currently active options and their defaults from all - involved backends for this component. */ -void gc_component_retrieve_options (int component); - -/* List all options of the component COMPONENT. */ -void gc_component_list_options (int component, FILE *out); - -/* Read the modifications from IN and apply them. */ -void gc_component_change_options (int component, FILE *in); - -#endif /*GPGCONF_H*/ diff --git a/tools/gpgparsemail.c b/tools/gpgparsemail.c deleted file mode 100644 index fa848c8f6..000000000 --- a/tools/gpgparsemail.c +++ /dev/null @@ -1,705 +0,0 @@ -/* gpgparsemail.c - Standalone crypto mail parser - * 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - - -/* This utility prints an RFC8222, possible MIME structured, message - in an annotated format with the first column having an indicator - for the content of the line.. Several options are available to - scrutinize the message. S/MIME and OpenPGP suuport is included. */ - - -#include <stdio.h> -#include <stdlib.h> -#include <stddef.h> -#include <string.h> -#include <errno.h> -#include <stdarg.h> -#include <assert.h> -#include <time.h> -#include <signal.h> -#include <unistd.h> -#include <fcntl.h> -#include <sys/wait.h> - -#include "rfc822parse.h" - - -#define PGM "gpgparsemail" - -/* Option flags. */ -static int verbose; -static int debug; -static int opt_crypto; /* Decrypt or verify messages. */ -static int opt_no_header; /* Don't output the header lines. */ - -/* Structure used to communicate with the parser callback. */ -struct parse_info_s { - int show_header; /* Show the header lines. */ - int show_data; /* Show the data lines. */ - unsigned int skip_show; /* Temporary disable above for these - number of lines. */ - int show_data_as_note; /* The next data line should be shown - as a note. */ - int show_boundary; - int nesting_level; - - int gpgsm_mime; /* gpgsm shall be used from S/MIME. */ - char *signing_protocol; - int hashing_level; /* The nesting level we are hashing. */ - int hashing; - FILE *hash_file; - FILE *sig_file; - int verify_now; /* Falg set when all signature data is - available. */ -}; - - -/* Print diagnostic message and exit with failure. */ -static void -die (const char *format, ...) -{ - va_list arg_ptr; - - fflush (stdout); - fprintf (stderr, "%s: ", PGM); - - va_start (arg_ptr, format); - vfprintf (stderr, format, arg_ptr); - va_end (arg_ptr); - putc ('\n', stderr); - - exit (1); -} - - -/* Print diagnostic message. */ -static void -err (const char *format, ...) -{ - va_list arg_ptr; - - fflush (stdout); - fprintf (stderr, "%s: ", PGM); - - va_start (arg_ptr, format); - vfprintf (stderr, format, arg_ptr); - va_end (arg_ptr); - putc ('\n', stderr); -} - -static void * -xmalloc (size_t n) -{ - void *p = malloc (n); - if (!p) - die ("out of core: %s", strerror (errno)); - return p; -} - -/* static void * */ -/* xcalloc (size_t n, size_t m) */ -/* { */ -/* void *p = calloc (n, m); */ -/* if (!p) */ -/* die ("out of core: %s", strerror (errno)); */ -/* return p; */ -/* } */ - -/* static void * */ -/* xrealloc (void *old, size_t n) */ -/* { */ -/* void *p = realloc (old, n); */ -/* if (!p) */ -/* die ("out of core: %s", strerror (errno)); */ -/* return p; */ -/* } */ - -static char * -xstrdup (const char *string) -{ - void *p = malloc (strlen (string)+1); - if (!p) - die ("out of core: %s", strerror (errno)); - strcpy (p, string); - return p; -} - -static char * -stpcpy (char *a,const char *b) -{ - while (*b) - *a++ = *b++; - *a = 0; - - return (char*)a; -} - - -static int -run_gnupg (int smime, int sig_fd, int data_fd, int *close_list) -{ - int rp[2]; - pid_t pid; - int i, c, is_status; - unsigned int pos; - char status_buf[10]; - const char *cmd = smime? "gpgsm":"gpg"; - FILE *fp; - - if (pipe (rp) == -1) - die ("error creating a pipe: %s", strerror (errno)); - - pid = fork (); - if (pid == -1) - die ("error forking process: %s", strerror (errno)); - - if (!pid) - { /* Child. */ - char data_fd_buf[50]; - int fd; - - /* Connect our signature fd to stdin. */ - if (sig_fd != 0) - { - if (dup2 (sig_fd, 0) == -1) - die ("dup2 stdin failed: %s", strerror (errno)); - } - - /* Keep our data fd and format it for gpg/gpgsm use. */ - sprintf (data_fd_buf, "-&%d", data_fd); - - /* Send stdout to the bit bucket. */ - fd = open ("/dev/null", O_WRONLY); - if (fd == -1) - die ("can't open `/dev/null': %s", strerror (errno)); - if (fd != 1) - { - if (dup2 (fd, 1) == -1) - die ("dup2 stderr failed: %s", strerror (errno)); - } - - /* Connect stderr to our pipe. */ - if (rp[1] != 2) - { - if (dup2 (rp[1], 2) == -1) - die ("dup2 stderr failed: %s", strerror (errno)); - } - - /* Close other files. */ - for (i=0; (fd=close_list[i]) != -1; i++) - if (fd > 2 && fd != data_fd) - close (fd); - errno = 0; - - execlp (cmd, cmd, - "--enable-special-filenames", - "--status-fd", "2", - "--assume-base64", - "--verify", - "--", - "-", data_fd_buf, - NULL); - - die ("failed to exec the crypto command: %s", strerror (errno)); - } - - /* Parent. */ - close (rp[1]); - - fp = fdopen (rp[0], "r"); - if (!fp) - die ("can't fdopen pipe for reading: %s", strerror (errno)); - - pos = 0; - is_status = 0; - assert (sizeof status_buf > 9); - while ((c=getc (fp)) != EOF) - { - if (pos < 9) - status_buf[pos] = c; - else - { - if (pos == 9) - { - is_status = !memcmp (status_buf, "[GNUPG:] ", 9); - if (is_status) - fputs ( "c ", stdout); - else if (verbose) - fputs ( "# ", stdout); - fwrite (status_buf, 9, 1, stdout); - } - putchar (c); - } - if (c == '\n') - { - if (verbose && pos < 9) - { - fputs ( "# ", stdout); - fwrite (status_buf, pos+1, 1, stdout); - } - pos = 0; - } - else - pos++; - } - if (pos) - { - if (verbose && pos < 9) - { - fputs ( "# ", stdout); - fwrite (status_buf, pos+1, 1, stdout); - } - putchar ('\n'); - } - fclose (fp); - - while ( (i=waitpid (pid, NULL, 0)) == -1 && errno == EINTR) - ; - if (i == -1) - die ("waiting for child failed: %s", strerror (errno)); - - return 0; -} - - - - -/* Verify the signature in the current temp files. */ -static void -verify_signature (struct parse_info_s *info) -{ - int close_list[10]; - - assert (info->hash_file); - assert (info->sig_file); - rewind (info->hash_file); - rewind (info->sig_file); - -/* printf ("# Begin hashed data\n"); */ -/* while ( (c=getc (info->hash_file)) != EOF) */ -/* putchar (c); */ -/* printf ("# End hashed data signature\n"); */ -/* printf ("# Begin signature\n"); */ -/* while ( (c=getc (info->sig_file)) != EOF) */ -/* putchar (c); */ -/* printf ("# End signature\n"); */ -/* rewind (info->hash_file); */ -/* rewind (info->sig_file); */ - - close_list[0] = -1; - run_gnupg (1, fileno (info->sig_file), fileno (info->hash_file), close_list); -} - - - - - -/* Prepare for a multipart/signed. - FIELD_CTX is the parsed context of the content-type header.*/ -static void -mime_signed_begin (struct parse_info_s *info, rfc822parse_t msg, - rfc822parse_field_t field_ctx) -{ - const char *s; - s = rfc822parse_query_parameter (field_ctx, "protocol", 1); - if (s) - { - printf ("h signed.protocol: %s\n", s); - if (!strcmp (s, "application/pkcs7-signature") - || !strcmp (s, "application/x-pkcs7-signature")) - { - if (info->gpgsm_mime) - err ("note: ignoring nested pkcs7-signature"); - else - { - info->gpgsm_mime = 1; - free (info->signing_protocol); - info->signing_protocol = xstrdup (s); - } - } - else if (verbose) - printf ("# this protocol is not supported\n"); - } -} - - -/* Prepare for a multipart/encrypted. - FIELD_CTX is the parsed context of the content-type header.*/ -static void -mime_encrypted_begin (struct parse_info_s *info, rfc822parse_t msg, - rfc822parse_field_t field_ctx) -{ - const char *s; - s = rfc822parse_query_parameter (field_ctx, "protocol", 0); - if (s) - printf ("h encrypted.protocol: %s\n", s); -} - - - -/* Print the event received by the parser for debugging as comment - line. */ -static void -show_event (rfc822parse_event_t event) -{ - const char *s; - - switch (event) - { - case RFC822PARSE_OPEN: s= "Open"; break; - case RFC822PARSE_CLOSE: s= "Close"; break; - case RFC822PARSE_CANCEL: s= "Cancel"; break; - case RFC822PARSE_T2BODY: s= "T2Body"; break; - case RFC822PARSE_FINISH: s= "Finish"; break; - case RFC822PARSE_RCVD_SEEN: s= "Rcvd_Seen"; break; - case RFC822PARSE_LEVEL_DOWN: s= "Level_Down"; break; - case RFC822PARSE_LEVEL_UP: s= "Level_Up"; break; - case RFC822PARSE_BOUNDARY: s= "Boundary"; break; - case RFC822PARSE_LAST_BOUNDARY: s= "Last_Boundary"; break; - case RFC822PARSE_BEGIN_HEADER: s= "Begin_Header"; break; - case RFC822PARSE_PREAMBLE: s= "Preamble"; break; - case RFC822PARSE_EPILOGUE: s= "Epilogue"; break; - default: s= "[unknown event]"; break; - } - printf ("# *** got RFC822 event %s\n", s); -} - -/* This function is called by the parser to communicate events. This - callback comminucates with the main program using a structure - passed in OPAQUE. Should retrun 0 or set errno and return -1. */ -static int -message_cb (void *opaque, rfc822parse_event_t event, rfc822parse_t msg) -{ - struct parse_info_s *info = opaque; - - if (debug) - show_event (event); - if (event == RFC822PARSE_OPEN) - { - /* Initialize for a new message. */ - info->show_header = 1; - } - else if (event == RFC822PARSE_T2BODY) - { - rfc822parse_field_t ctx; - - ctx = rfc822parse_parse_field (msg, "Content-Type", -1); - if (ctx) - { - const char *s1, *s2; - s1 = rfc822parse_query_media_type (ctx, &s2); - if (s1) - { - printf ("h media: %*s%s %s\n", - info->nesting_level*2, "", s1, s2); - if (info->gpgsm_mime == 3) - { - char *buf = xmalloc (strlen (s1) + strlen (s2) + 2); - strcpy (stpcpy (stpcpy (buf, s1), "/"), s2); - assert (info->signing_protocol); - if (strcmp (buf, info->signing_protocol)) - err ("invalid S/MIME structure; expected `%s', found `%s'", - info->signing_protocol, buf); - else - { - printf ("c begin_signature\n"); - info->gpgsm_mime++; - if (opt_crypto) - { - assert (!info->sig_file); - info->sig_file = tmpfile (); - if (!info->sig_file) - die ("error creating temp file: %s", - strerror (errno)); - } - } - free (buf); - } - else if (!strcmp (s1, "multipart")) - { - if (!strcmp (s2, "signed")) - mime_signed_begin (info, msg, ctx); - else if (!strcmp (s2, "encrypted")) - mime_encrypted_begin (info, msg, ctx); - } - } - else - printf ("h media: %*s none\n", info->nesting_level*2, ""); - - rfc822parse_release_field (ctx); - } - else - printf ("h media: %*stext plain [assumed]\n", - info->nesting_level*2, ""); - info->show_header = 0; - info->show_data = 1; - info->skip_show = 1; - } - else if (event == RFC822PARSE_PREAMBLE) - info->show_data_as_note = 1; - else if (event == RFC822PARSE_LEVEL_DOWN) - { - printf ("b down\n"); - info->nesting_level++; - } - else if (event == RFC822PARSE_LEVEL_UP) - { - printf ("b up\n"); - if (info->nesting_level) - info->nesting_level--; - else - err ("invalid structure (bad nesting level)"); - } - else if (event == RFC822PARSE_BOUNDARY || event == RFC822PARSE_LAST_BOUNDARY) - { - info->show_data = 0; - info->show_boundary = 1; - if (event == RFC822PARSE_BOUNDARY) - { - info->show_header = 1; - info->skip_show = 1; - printf ("b part\n"); - } - else - printf ("b last\n"); - - if (info->gpgsm_mime == 2 && info->nesting_level == info->hashing_level) - { - printf ("c end_hash\n"); - info->gpgsm_mime++; - info->hashing = 0; - } - else if (info->gpgsm_mime == 4) - { - printf ("c end_signature\n"); - info->verify_now = 1; - } - } - else if (event == RFC822PARSE_BEGIN_HEADER) - { - if (info->gpgsm_mime == 1) - { - printf ("c begin_hash\n"); - info->hashing = 1; - info->hashing_level = info->nesting_level; - info->gpgsm_mime++; - - if (opt_crypto) - { - assert (!info->hash_file); - info->hash_file = tmpfile (); - if (!info->hash_file) - die ("failed to create temporary file: %s", strerror (errno)); - } - } - } - - return 0; -} - - -/* Read a message from FP and process it according to the global - options. */ -static void -parse_message (FILE *fp) -{ - char line[5000]; - size_t length; - rfc822parse_t msg; - unsigned int lineno = 0; - int no_cr_reported = 0; - struct parse_info_s info; - - memset (&info, 0, sizeof info); - - msg = rfc822parse_open (message_cb, &info); - if (!msg) - die ("can't open parser: %s", strerror (errno)); - - /* Fixme: We should not use fgets becuase it can't cope with - embedded nul characters. */ - while (fgets (line, sizeof (line), fp)) - { - lineno++; - if (lineno == 1 && !strncmp (line, "From ", 5)) - continue; /* We better ignore a leading From line. */ - - length = strlen (line); - if (length && line[length - 1] == '\n') - line[--length] = 0; - else - err ("line number %u too long or last line not terminated", lineno); - if (length && line[length - 1] == '\r') - line[--length] = 0; - else if (verbose && !no_cr_reported) - { - err ("non canonical ended line detected (line %u)", lineno); - no_cr_reported = 1; - } - - - if (rfc822parse_insert (msg, line, length)) - die ("parser failed: %s", strerror (errno)); - - if (info.hashing) - { - /* Delay hashing of the CR/LF because the last line ending - belongs to the next boundary. */ - if (debug) - printf ("# hashing %s`%s'\n", info.hashing==2?"CR,LF+":"", line); - if (opt_crypto) - { - if (info.hashing == 2) - fputs ("\r\n", info.hash_file); - fputs (line, info.hash_file); - if (ferror (info.hash_file)) - die ("error writing to temporary file: %s", strerror (errno)); - } - - info.hashing = 2; - } - - if (info.sig_file && opt_crypto) - { - if (info.verify_now) - { - verify_signature (&info); - fclose (info.hash_file); - info.hash_file = NULL; - fclose (info.sig_file); - info.sig_file = NULL; - info.gpgsm_mime = 0; - } - else - { - fputs (line, info.sig_file); - fputs ("\r\n", info.sig_file); - if (ferror (info.sig_file)) - die ("error writing to temporary file: %s", strerror (errno)); - } - } - - if (info.show_boundary) - { - if (!opt_no_header) - printf (":%s\n", line); - info.show_boundary = 0; - } - - if (info.skip_show) - info.skip_show--; - else if (info.show_data) - { - if (info.show_data_as_note) - { - if (verbose) - printf ("# DATA: %s\n", line); - info.show_data_as_note = 0; - } - else - printf (" %s\n", line); - } - else if (info.show_header && !opt_no_header) - printf (".%s\n", line); - - } - - rfc822parse_close (msg); -} - - -int -main (int argc, char **argv) -{ - int last_argc = -1; - - if (argc) - { - argc--; argv++; - } - while (argc && last_argc != argc ) - { - last_argc = argc; - if (!strcmp (*argv, "--")) - { - argc--; argv++; - break; - } - else if (!strcmp (*argv, "--help")) - { - puts ( - "Usage: " PGM " [OPTION] [FILE]\n" - "Parse a mail message into an annotated format.\n\n" - " --crypto decrypt or verify messages\n" - " --no-header don't output the header lines\n" - " --verbose enable extra informational output\n" - " --debug enable additional debug output\n" - " --help display this help and exit\n\n" - "With no FILE, or when FILE is -, read standard input.\n\n" - "Report bugs to <[email protected]>."); - exit (0); - } - else if (!strcmp (*argv, "--verbose")) - { - verbose = 1; - argc--; argv++; - } - else if (!strcmp (*argv, "--debug")) - { - verbose = debug = 1; - argc--; argv++; - } - else if (!strcmp (*argv, "--crypto")) - { - opt_crypto = 1; - argc--; argv++; - } - else if (!strcmp (*argv, "--no-header")) - { - opt_no_header = 1; - argc--; argv++; - } - } - - if (argc > 1) - die ("usage: " PGM " [OPTION] [FILE] (try --help for more information)\n"); - - signal (SIGPIPE, SIG_IGN); - - if (argc && strcmp (*argv, "-")) - { - FILE *fp = fopen (*argv, "rb"); - if (!fp) - die ("can't open `%s': %s", *argv, strerror (errno)); - parse_message (fp); - fclose (fp); - } - else - parse_message (stdin); - - return 0; -} - - -/* -Local Variables: -compile-command: "gcc -Wall -g -o gpgparsemail rfc822parse.c gpgparsemail.c" -End: -*/ diff --git a/tools/no-libgcrypt.c b/tools/no-libgcrypt.c deleted file mode 100644 index 0fabec90d..000000000 --- a/tools/no-libgcrypt.c +++ /dev/null @@ -1,105 +0,0 @@ -/* no-libgcrypt.c - Replacement functions for libgcrypt. - * Copyright (C) 2003 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include <config.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> - -#include "../common/util.h" -#include "i18n.h" - - -/* Replace libgcrypt's malloc functions which are used by - ../jnlib/libjnlib.a . ../common/util.h defines macros to map them - to xmalloc etc. */ -static void -out_of_core (void) -{ - log_fatal (_("error allocating enough memory: %s\n"), strerror (errno)); -} - - -void * -gcry_malloc (size_t n) -{ - return malloc (n); -} - -void * -gcry_xmalloc (size_t n) -{ - void *p = malloc (n); - if (!p) - out_of_core (); - return p; -} - - -void * -gcry_realloc (void *a, size_t n) -{ - return realloc (a, n); -} - -void * -gcry_xrealloc (void *a, size_t n) -{ - void *p = realloc (a, n); - if (!p) - out_of_core (); - return p; -} - - - -void * -gcry_calloc (size_t n, size_t m) -{ - return calloc (n, m); -} - -void * -gcry_xcalloc (size_t n, size_t m) -{ - void *p = calloc (n, m); - if (!p) - out_of_core (); - return p; -} - - -char * -gcry_xstrdup (const char *string) -{ - void *p = malloc (strlen (string)+1); - if (!p) - out_of_core (); - strcpy( p, string ); - return p; -} - -void -gcry_free (void *a) -{ - if (a) - free (a); -} diff --git a/tools/rfc822parse.c b/tools/rfc822parse.c deleted file mode 100644 index be1cf4a47..000000000 --- a/tools/rfc822parse.c +++ /dev/null @@ -1,1235 +0,0 @@ -/* rfc822parse.c - Simple mail and MIME parser - * Copyright (C) 1999, 2000 Werner Koch, Duesseldorf - * Copyright (C) 2003, g10 Code GmbH - * - * This program 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. - * - * This program is is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - - -/* According to RFC822 binary 0 are allowed at many places. We - * do not handle this correct especially in the field parsing code. It - * should be easy to fix and the API provides a interfcaes which returns - * the length but in addition makes sure that returned strings are always - * ended by a \0. - * - * Furthermore, the case of field names is changed and thus it is not - * always a good idea to use these modified header - * lines (e.g. signatures may break). - * - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <errno.h> -#include <stdarg.h> -#include <assert.h> - -#include "rfc822parse.h" - -enum token_type -{ - tSPACE, - tATOM, - tQUOTED, - tDOMAINLIT, - tSPECIAL -}; - -/* For now we directly use our TOKEN as the parse context */ -typedef struct rfc822parse_field_context *TOKEN; -struct rfc822parse_field_context -{ - TOKEN next; - enum token_type type; - struct { - unsigned int cont:1; - unsigned int lowered:1; - } flags; - /*TOKEN owner_pantry; */ - char data[1]; -}; - -struct hdr_line -{ - struct hdr_line *next; - int cont; /* This is a continuation of the previous line. */ - unsigned char line[1]; -}; - -typedef struct hdr_line *HDR_LINE; - - -struct part -{ - struct part *right; /* The next part. */ - struct part *down; /* A contained part. */ - HDR_LINE hdr_lines; /* Header lines os that part. */ - HDR_LINE *hdr_lines_tail; /* Helper for adding lines. */ - char *boundary; /* Only used in the first part. */ -}; -typedef struct part *part_t; - -struct rfc822parse_context -{ - rfc822parse_cb_t callback; - void *callback_value; - int callback_error; - int in_body; - int in_preamble; /* Wether we are before the first boundary. */ - part_t parts; /* The tree of parts. */ - part_t current_part; /* Whom we are processing (points into parts). */ - const char *boundary; /* Current boundary. */ -}; - -static HDR_LINE find_header (rfc822parse_t msg, const char *name, - int which, HDR_LINE * rprev); - - -static size_t -length_sans_trailing_ws (const unsigned char *line, size_t len) -{ - const unsigned char *p, *mark; - size_t n; - - for (mark=NULL, p=line, n=0; n < len; n++, p++) - { - if (strchr (" \t\r\n", *p )) - { - if( !mark ) - mark = p; - } - else - mark = NULL; - } - - if (mark) - return mark - line; - return len; -} - - -static void -lowercase_string (unsigned char *string) -{ - for (; *string; string++) - if (*string >= 'A' && *string <= 'Z') - *string = *string - 'A' + 'a'; -} - -/* Transform a header name into a standard capitalized format; i.e - "Content-Type". Conversion stops at the colon. As usual we don't - use the localized versions of ctype.h. - */ -static void -capitalize_header_name (unsigned char *name) -{ - int first = 1; - - for (; *name && *name != ':'; name++) - if (*name == '-') - first = 1; - else if (first) - { - if (*name >= 'a' && *name <= 'z') - *name = *name - 'a' + 'A'; - first = 0; - } - else if (*name >= 'A' && *name <= 'Z') - *name = *name - 'A' + 'a'; -} - - -static char * -stpcpy (char *a,const char *b) -{ - while (*b) - *a++ = *b++; - *a = 0; - - return (char*)a; -} - - -/* If a callback has been registerd, call it for the event of type - EVENT. */ -static int -do_callback (rfc822parse_t msg, rfc822parse_event_t event) -{ - int rc; - - if (!msg->callback || msg->callback_error) - return 0; - rc = msg->callback (msg->callback_value, event, msg); - if (rc) - msg->callback_error = rc; - return rc; -} - -static part_t -new_part (void) -{ - part_t part; - - part = calloc (1, sizeof *part); - if (part) - { - part->hdr_lines_tail = &part->hdr_lines; - } - return part; -} - - -static void -release_part (part_t part) -{ - part_t tmp; - HDR_LINE hdr, hdr2; - - for (; part; part = tmp) - { - tmp = part->right; - if (part->down) - release_part (part->down); - for (hdr = part->hdr_lines; hdr; hdr = hdr2) - { - hdr2 = hdr->next; - free (hdr); - } - free (part->boundary); - free (part); - } -} - - -static void -release_handle_data (rfc822parse_t msg) -{ - release_part (msg->parts); - msg->parts = NULL; - msg->current_part = NULL; - msg->boundary = NULL; -} - - -/* Create a new parsing context for an entire rfc822 message and - return it. CB and CB_VALUE may be given to callback for certain - events. NULL is returned on error with errno set appropriately. */ -rfc822parse_t -rfc822parse_open (rfc822parse_cb_t cb, void *cb_value) -{ - rfc822parse_t msg = calloc (1, sizeof *msg); - if (msg) - { - msg->parts = msg->current_part = new_part (); - if (!msg->parts) - { - free (msg); - msg = NULL; - } - else - { - msg->callback = cb; - msg->callback_value = cb_value; - if (do_callback (msg, RFC822PARSE_OPEN)) - { - release_handle_data (msg); - free (msg); - msg = NULL; - } - } - } - return msg; -} - - -void -rfc822parse_cancel (rfc822parse_t msg) -{ - if (msg) - { - do_callback (msg, RFC822PARSE_CANCEL); - release_handle_data (msg); - free (msg); - } -} - - -void -rfc822parse_close (rfc822parse_t msg) -{ - if (msg) - { - do_callback (msg, RFC822PARSE_CLOSE); - release_handle_data (msg); - free (msg); - } -} - -static part_t -find_parent (part_t tree, part_t target) -{ - part_t part; - - for (part = tree->down; part; part = part->right) - { - if (part == target) - return tree; /* Found. */ - if (part->down) - { - part_t tmp = find_parent (part, target); - if (tmp) - return tmp; - } - } - return NULL; -} - -static void -set_current_part_to_parent (rfc822parse_t msg) -{ - part_t parent; - - assert (msg->current_part); - parent = find_parent (msg->parts, msg->current_part); - if (!parent) - return; /* Already at the top. */ - -#ifndef NDEBUG - { - part_t part; - for (part = parent->down; part; part = part->right) - if (part == msg->current_part) - break; - assert (part); - } -#endif - msg->current_part = parent; - - parent = find_parent (msg->parts, parent); - msg->boundary = parent? parent->boundary: NULL; -} - - - -/**************** - * We have read in all header lines and are about to receive the body - * part. The delimiter line has already been processed. - * - * FIXME: we's better return an error in case of memory failures. - */ -static int -transition_to_body (rfc822parse_t msg) -{ - rfc822parse_field_t ctx; - int rc; - - rc = do_callback (msg, RFC822PARSE_T2BODY); - if (!rc) - { - /* Store the boundary if we have multipart type. */ - ctx = rfc822parse_parse_field (msg, "Content-Type", -1); - if (ctx) - { - const char *s; - - s = rfc822parse_query_media_type (ctx, NULL); - if (s && !strcmp (s,"multipart")) - { - s = rfc822parse_query_parameter (ctx, "boundary", 0); - if (s) - { - assert (!msg->current_part->boundary); - msg->current_part->boundary = malloc (strlen (s) + 1); - if (msg->current_part->boundary) - { - part_t part; - - strcpy (msg->current_part->boundary, s); - msg->boundary = msg->current_part->boundary; - part = new_part (); - if (!part) - { - int save_errno = errno; - rfc822parse_release_field (ctx); - errno = save_errno; - return -1; - } - rc = do_callback (msg, RFC822PARSE_LEVEL_DOWN); - assert (!msg->current_part->down); - msg->current_part->down = part; - msg->current_part = part; - msg->in_preamble = 1; - } - } - } - rfc822parse_release_field (ctx); - } - } - - return rc; -} - -/* We have just passed a MIME boundary and need to prepare for new part. - headers. */ -static int -transition_to_header (rfc822parse_t msg) -{ - part_t part; - - assert (msg->current_part); - assert (!msg->current_part->right); - - part = new_part (); - if (!part) - return -1; - - msg->current_part->right = part; - msg->current_part = part; - return 0; -} - - -static int -insert_header (rfc822parse_t msg, const unsigned char *line, size_t length) -{ - HDR_LINE hdr; - - assert (msg->current_part); - if (!length) - { - msg->in_body = 1; - return transition_to_body (msg); - } - - if (!msg->current_part->hdr_lines) - do_callback (msg, RFC822PARSE_BEGIN_HEADER); - - length = length_sans_trailing_ws (line, length); - hdr = malloc (sizeof (*hdr) + length); - if (!hdr) - return -1; - hdr->next = NULL; - hdr->cont = (*line == ' ' || *line == '\t'); - memcpy (hdr->line, line, length); - hdr->line[length] = 0; /* Make it a string. */ - - /* Transform a field name into canonical format. */ - if (!hdr->cont && strchr (line, ':')) - capitalize_header_name (hdr->line); - - *msg->current_part->hdr_lines_tail = hdr; - msg->current_part->hdr_lines_tail = &hdr->next; - - /* Lets help the caller to prevent mail loops and issue an event for - * every Received header. */ - if (length >= 9 && !memcmp (line, "Received:", 9)) - do_callback (msg, RFC822PARSE_RCVD_SEEN); - return 0; -} - - -/**************** - * Note: We handle the body transparent to allow binary zeroes in it. - */ -static int -insert_body (rfc822parse_t msg, const unsigned char *line, size_t length) -{ - int rc = 0; - - if (length > 2 && *line == '-' && line[1] == '-' && msg->boundary) - { - size_t blen = strlen (msg->boundary); - - if (length == blen + 2 - && !memcmp (line+2, msg->boundary, blen)) - { - rc = do_callback (msg, RFC822PARSE_BOUNDARY); - msg->in_body = 0; - if (!rc && !msg->in_preamble) - rc = transition_to_header (msg); - msg->in_preamble = 0; - } - else if (length == blen + 4 - && line[length-2] =='-' && line[length-1] == '-' - && !memcmp (line+2, msg->boundary, blen)) - { - rc = do_callback (msg, RFC822PARSE_LAST_BOUNDARY); - msg->boundary = NULL; /* No current boundary anymore. */ - set_current_part_to_parent (msg); - - /* Fixme: The next should acctually be sent right before the - next boundary, so that we can mark the epilogue. */ - if (!rc) - rc = do_callback (msg, RFC822PARSE_LEVEL_UP); - } - } - if (msg->in_preamble && !rc) - rc = do_callback (msg, RFC822PARSE_PREAMBLE); - - return rc; -} - -/* Insert the next line into the parser. Return 0 on success or true - on error with errno set appropriately. */ -int -rfc822parse_insert (rfc822parse_t msg, const unsigned char *line, size_t length) -{ - return (msg->in_body - ? insert_body (msg, line, length) - : insert_header (msg, line, length)); -} - - -/* Tell the parser that we have finished the message. */ -int -rfc822parse_finish (rfc822parse_t msg) -{ - return do_callback (msg, RFC822PARSE_FINISH); -} - - - -/**************** - * Get a copy of a header line. The line is returned as one long - * string with LF to separate the continuation line. Caller must free - * the return buffer. which may be used to enumerate over all lines. - * Wildcards are allowed. This function works on the current headers; - * i.e. the regular mail headers or the MIME headers of the current - * part. - * - * WHICH gives the mode: - * -1 := Take the last occurence - * n := Take the n-th one. - * - * Returns a newly allocated buffer or NULL on error. errno is set in - * case of a memory failure or set to 0 if the requested field is not - * available. - */ -char * -rfc822parse_get_field (rfc822parse_t msg, const char *name, int which) -{ - HDR_LINE h, h2; - char *buf, *p; - size_t n; - - h = find_header (msg, name, which, NULL); - if (!h) - { - errno = 0; - return NULL; /* no such field */ - } - - n = strlen (h->line) + 1; - for (h2 = h->next; h2 && h2->cont; h2 = h2->next) - n += strlen (h2->line) + 1; - - buf = p = malloc (n); - if (buf) - { - p = stpcpy (p, h->line); - *p++ = '\n'; - for (h2 = h->next; h2 && h2->cont; h2 = h2->next) - { - p = stpcpy (p, h2->line); - *p++ = '\n'; - } - p[-1] = 0; - } - return buf; -} - - -/**************** - * Enumerate all header. Caller has to provide the address of a pointer - * which has to be initialzed to NULL, the caller should then never change this - * pointer until he has closed the enumeration by passing again the address - * of the pointer but with msg set to NULL. - * The function returns pointers to all the header lines or NULL when - * all lines have been enumerated or no headers are available. - */ -const char * -rfc822parse_enum_header_lines (rfc822parse_t msg, void **context) -{ - HDR_LINE l; - - if (!msg) /* Close. */ - return NULL; - - if (*context == msg || !msg->current_part) - return NULL; - - l = *context ? (HDR_LINE) *context : msg->current_part->hdr_lines; - - if (l) - { - *context = l->next ? (void *) (l->next) : (void *) msg; - return l->line; - } - *context = msg; /* Mark end of list. */ - return NULL; -} - - - -/**************** - * Find a header field. If the Name does end in an asterisk this is meant - * to be a wildcard. - * - * which -1 : Retrieve the last field - * >0 : Retrieve the n-th field - - * RPREV may be used to return the predecessor of the returned field; - * which may be NULL for the very first one. It has to be initialzed - * to either NULL in which case the search start at the first header line, - * or it may point to a headerline, where the search should start - */ -static HDR_LINE -find_header (rfc822parse_t msg, const char *name, int which, HDR_LINE *rprev) -{ - HDR_LINE hdr, prev = NULL, mark = NULL; - unsigned char *p; - size_t namelen, n; - int found = 0; - int glob = 0; - - if (!msg->current_part) - return NULL; - - namelen = strlen (name); - if (namelen && name[namelen - 1] == '*') - { - namelen--; - glob = 1; - } - - hdr = msg->current_part->hdr_lines; - if (rprev && *rprev) - { - /* spool forward to the requested starting place. - * we cannot simply set this as we have to return - * the previous list element too */ - for (; hdr && hdr != *rprev; prev = hdr, hdr = hdr->next) - ; - } - - for (; hdr; prev = hdr, hdr = hdr->next) - { - if (hdr->cont) - continue; - if (!(p = strchr (hdr->line, ':'))) - continue; /* invalid header, just skip it. */ - n = p - hdr->line; - if (!n) - continue; /* invalid name */ - if ((glob ? (namelen <= n) : (namelen == n)) - && !memcmp (hdr->line, name, namelen)) - { - found++; - if (which == -1) - mark = hdr; - else if (found == which) - { - if (rprev) - *rprev = prev; - return hdr; - } - } - } - if (mark && rprev) - *rprev = prev; - return mark; -} - - - -static const char * -skip_ws (const char *s) -{ - while (*s == ' ' || *s == '\t' || *s == '\r' || *s == '\n') - s++; - return s; -} - - -static void -release_token_list (TOKEN t) -{ - while (t) - { - TOKEN t2 = t->next; - /* fixme: If we have owner_pantry, put the token back to - * this pantry so that it can be reused later */ - free (t); - t = t2; - } -} - - -static TOKEN -new_token (enum token_type type, const char *buf, size_t length) -{ - TOKEN t; - - /* fixme: look through our pantries to find a suitable - * token for reuse */ - t = malloc (sizeof *t + length); - if (t) - { - t->next = NULL; - t->type = type; - memset (&t->flags, 0, sizeof (t->flags)); - t->data[0] = 0; - if (buf) - { - memcpy (t->data, buf, length); - t->data[length] = 0; /* Make sure it is a C string. */ - } - else - t->data[0] = 0; - } - return t; -} - -static TOKEN -append_to_token (TOKEN old, const char *buf, size_t length) -{ - size_t n = strlen (old->data); - TOKEN t; - - t = malloc (sizeof *t + n + length); - if (t) - { - t->next = old->next; - t->type = old->type; - t->flags = old->flags; - memcpy (t->data, old->data, n); - memcpy (t->data + n, buf, length); - t->data[n + length] = 0; - old->next = NULL; - release_token_list (old); - } - return t; -} - - - -/* - Parse a field into tokens as defined by rfc822. - */ -static TOKEN -parse_field (HDR_LINE hdr) -{ - static const char specials[] = "<>@.,;:\\[]\"()"; - static const char specials2[] = "<>@.,;:"; - static const char tspecials[] = "/?=<>@,;:\\[]\"()"; - static const char tspecials2[] = "/?=<>@.,;:"; - static struct - { - const unsigned char *name; - size_t namelen; - } tspecial_header[] = { - { "Content-Type", 12}, - { "Content-Transfer-Encoding", 25}, - { NULL, 0} - }; - const char *delimiters; - const char *delimiters2; - const unsigned char *line, *s, *s2; - size_t n; - int i, invalid = 0; - TOKEN t, tok, *tok_tail; - - errno = 0; - if (!hdr) - return NULL; - - tok = NULL; - tok_tail = &tok; - - line = hdr->line; - if (!(s = strchr (line, ':'))) - return NULL; /* oops */ - - n = s - line; - if (!n) - return NULL; /* oops: invalid name */ - - delimiters = specials; - delimiters2 = specials2; - for (i = 0; tspecial_header[i].name; i++) - { - if (n == tspecial_header[i].namelen - && !memcmp (line, tspecial_header[i].name, n)) - { - delimiters = tspecials; - delimiters2 = tspecials2; - break; - } - } - - s++; /* Move over the colon. */ - for (;;) - { - if (!*s) - { - if (!hdr->next || !hdr->next->cont) - break; - hdr = hdr->next; - s = hdr->line; - } - - if (*s == '(') - { - int level = 1; - int in_quote = 0; - - invalid = 0; - for (s++;; s++) - { - if (!*s) - { - if (!hdr->next || !hdr->next->cont) - break; - hdr = hdr->next; - s = hdr->line; - } - - if (in_quote) - { - if (*s == '\"') - in_quote = 0; - else if (*s == '\\' && s[1]) /* what about continuation? */ - s++; - } - else if (*s == ')') - { - if (!--level) - break; - } - else if (*s == '(') - level++; - else if (*s == '\"') - in_quote = 1; - } - if (!*s) - ; /* Actually this is an error, but we don't care about it. */ - else - s++; - } - else if (*s == '\"' || *s == '[') - { - /* We do not check for non-allowed nesting of domainliterals */ - int term = *s == '\"' ? '\"' : ']'; - invalid = 0; - s++; - t = NULL; - - for (;;) - { - for (s2 = s; *s2; s2++) - { - if (*s2 == term) - break; - else if (*s2 == '\\' && s2[1]) /* what about continuation? */ - s2++; - } - - t = (t - ? append_to_token (t, s, s2 - s) - : new_token (term == '\"'? tQUOTED : tDOMAINLIT, s, s2 - s)); - if (!t) - goto failure; - - if (*s2 || !hdr->next || !hdr->next->cont) - break; - hdr = hdr->next; - s = hdr->line; - } - *tok_tail = t; - tok_tail = &t->next; - s = s2; - if (*s) - s++; /* skip the delimiter */ - } - else if ((s2 = strchr (delimiters2, *s))) - { /* Special characters which are not handled above. */ - invalid = 0; - t = new_token (tSPECIAL, s, 1); - if (!t) - goto failure; - *tok_tail = t; - tok_tail = &t->next; - s++; - } - else if (*s == ' ' || *s == '\t' || *s == '\r' || *s == '\n') - { - invalid = 0; - s = skip_ws (s + 1); - } - else if (*s > 0x20 && !(*s & 128)) - { /* Atom. */ - invalid = 0; - for (s2 = s + 1; *s2 > 0x20 - && !(*s2 & 128) && !strchr (delimiters, *s2); s2++) - ; - t = new_token (tATOM, s, s2 - s); - if (!t) - goto failure; - *tok_tail = t; - tok_tail = &t->next; - s = s2; - } - else - { /* Invalid character. */ - if (!invalid) - { /* For parsing we assume only one space. */ - t = new_token (tSPACE, NULL, 0); - if (!t) - goto failure; - *tok_tail = t; - tok_tail = &t->next; - invalid = 1; - } - s++; - } - } - - return tok; - - failure: - { - int save = errno; - release_token_list (tok); - errno = save; - } - return NULL; -} - - - - -/**************** - * Find and parse a header field. - * WHICH indicates what to do if there are multiple instance of the same - * field (like "Received"); the following value are defined: - * -1 := Take the last occurence - * 0 := Reserved - * n := Take the n-th one. - * Returns a handle for further operations on the parse context of the field - * or NULL if the field was not found. - */ -rfc822parse_field_t -rfc822parse_parse_field (rfc822parse_t msg, const char *name, int which) -{ - HDR_LINE hdr; - - if (!which) - return NULL; - - hdr = find_header (msg, name, which, NULL); - if (!hdr) - return NULL; - return parse_field (hdr); -} - -void -rfc822parse_release_field (rfc822parse_field_t ctx) -{ - if (ctx) - release_token_list (ctx); -} - - - -/**************** - * Check whether T points to a parameter. - * A parameter starts with a semicolon and it is assumed that t - * points to exactly this one. - */ -static int -is_parameter (TOKEN t) -{ - t = t->next; - if (!t || t->type != tATOM) - return 0; - t = t->next; - if (!t || !(t->type == tSPECIAL && t->data[0] == '=')) - return 0; - t = t->next; - if (!t) - return 1; /* We assume that an non existing value is an empty one. */ - return t->type == tQUOTED || t->type == tATOM; -} - -/* - Some header (Content-type) have a special syntax where attribute=value - pairs are used after a leading semicolon. The parse_field code - knows about these fields and changes the parsing to the one defined - in RFC2045. - Returns a pointer to the value which is valid as long as the - parse context is valid; NULL is returned in case that attr is not - defined in the header, a missing value is reppresented by an empty string. - - With LOWER_VALUE set to true, a matching field valuebe be - lowercased. - - Note, that ATTR should be lowercase. - */ -const char * -rfc822parse_query_parameter (rfc822parse_field_t ctx, const char *attr, - int lower_value) -{ - TOKEN t, a; - - for (t = ctx; t; t = t->next) - { - /* skip to the next semicolon */ - for (; t && !(t->type == tSPECIAL && t->data[0] == ';'); t = t->next) - ; - if (!t) - return NULL; - if (is_parameter (t)) - { /* Look closer. */ - a = t->next; /* We know that this is an atom */ - if ( !a->flags.lowered ) - { - lowercase_string (a->data); - a->flags.lowered = 1; - } - if (!strcmp (a->data, attr)) - { /* found */ - t = a->next->next; - /* Either T is now an atom, a quoted string or NULL in - * which case we return an empty string. */ - - if ( lower_value && t && !t->flags.lowered ) - { - lowercase_string (t->data); - t->flags.lowered = 1; - } - return t ? t->data : ""; - } - } - } - return NULL; -} - -/**************** - * This function may be used for the Content-Type header to figure out - * the media type and subtype. Note, that the returned strings are - * guaranteed to be lowercase as required by MIME. - * - * Returns: a pointer to the media type and if subtype is not NULL, - * a pointer to the subtype. - */ -const char * -rfc822parse_query_media_type (rfc822parse_field_t ctx, const char **subtype) -{ - TOKEN t = ctx; - const char *type; - - if (t->type != tATOM) - return NULL; - if (!t->flags.lowered) - { - lowercase_string (t->data); - t->flags.lowered = 1; - } - type = t->data; - t = t->next; - if (!t || t->type != tSPECIAL || t->data[0] != '/') - return NULL; - t = t->next; - if (!t || t->type != tATOM) - return NULL; - - if (subtype) - { - if (!t->flags.lowered) - { - lowercase_string (t->data); - t->flags.lowered = 1; - } - *subtype = t->data; - } - return type; -} - - - - - -#ifdef TESTING - -/* Internal debug function to print the structure of the message. */ -static void -dump_structure (rfc822parse_t msg, part_t part, int indent) -{ - if (!part) - { - printf ("*** Structure of this message:\n"); - part = msg->parts; - } - - for (; part; part = part->right) - { - rfc822parse_field_t ctx; - part_t save_part; /* ugly hack - we should have a function to - get part inforation. */ - const char *s; - - save_part = msg->current_part; - msg->current_part = part; - ctx = rfc822parse_parse_field (msg, "Content-Type", -1); - msg->current_part = save_part; - if (ctx) - { - const char *s1, *s2; - s1 = rfc822parse_query_media_type (ctx, &s2); - if (s1) - printf ("*** %*s %s/%s", indent*2, "", s1, s2); - else - printf ("*** %*s [not found]", indent*2, ""); - - s = rfc822parse_query_parameter (ctx, "boundary", 0); - if (s) - printf (" (boundary=\"%s\")", s); - rfc822parse_release_field (ctx); - } - else - printf ("*** %*s text/plain [assumed]", indent*2, ""); - putchar('\n'); - - if (part->down) - dump_structure (msg, part->down, indent + 1); - } - -} - - - -static void -show_param (rfc822parse_field_t ctx, const char *name) -{ - const char *s; - - if (!ctx) - return; - s = rfc822parse_query_parameter (ctx, name, 0); - if (s) - printf ("*** %s: `%s'\n", name, s); -} - - - -static void -show_event (rfc822parse_event_t event) -{ - const char *s; - - switch (event) - { - case RFC822PARSE_OPEN: s= "Open"; break; - case RFC822PARSE_CLOSE: s= "Close"; break; - case RFC822PARSE_CANCEL: s= "Cancel"; break; - case RFC822PARSE_T2BODY: s= "T2Body"; break; - case RFC822PARSE_FINISH: s= "Finish"; break; - case RFC822PARSE_RCVD_SEEN: s= "Rcvd_Seen"; break; - case RFC822PARSE_BOUNDARY: s= "Boundary"; break; - case RFC822PARSE_LAST_BOUNDARY: s= "Last_Boundary"; break; - default: s= "***invalid event***"; break; - } - printf ("*** got RFC822 event %s\n", s); -} - -static int -msg_cb (void *dummy_arg, rfc822parse_event_t event, rfc822parse_t msg) -{ - show_event (event); - if (event == RFC822PARSE_T2BODY) - { - rfc822parse_field_t ctx; - void *ectx; - const char *line; - - for (ectx=NULL; (line = rfc822parse_enum_header_lines (msg, &ectx)); ) - { - printf ("*** HDR: %s\n", line); - } - rfc822parse_enum_header_lines (NULL, &ectx); /* Close enumerator. */ - - ctx = rfc822parse_parse_field (msg, "Content-Type", -1); - if (ctx) - { - const char *s1, *s2; - s1 = rfc822parse_query_media_type (ctx, &s2); - if (s1) - printf ("*** media: `%s/%s'\n", s1, s2); - else - printf ("*** media: [not found]\n"); - show_param (ctx, "boundary"); - show_param (ctx, "protocol"); - rfc822parse_release_field (ctx); - } - else - printf ("*** media: text/plain [assumed]\n"); - - } - - - return 0; -} - - - -int -main (int argc, char **argv) -{ - char line[5000]; - size_t length; - rfc822parse_t msg; - - msg = rfc822parse_open (msg_cb, NULL); - if (!msg) - abort (); - - while (fgets (line, sizeof (line), stdin)) - { - length = strlen (line); - if (length && line[length - 1] == '\n') - line[--length] = 0; - if (length && line[length - 1] == '\r') - line[--length] = 0; - if (rfc822parse_insert (msg, line, length)) - abort (); - } - - dump_structure (msg, NULL, 0); - - rfc822parse_close (msg); - return 0; -} -#endif - -/* -Local Variables: -compile-command: "gcc -Wall -g -DTESTING -o rfc822parse rfc822parse.c" -End: -*/ diff --git a/tools/rfc822parse.h b/tools/rfc822parse.h deleted file mode 100644 index 1293117ac..000000000 --- a/tools/rfc822parse.h +++ /dev/null @@ -1,79 +0,0 @@ -/* rfc822parse.h - Simple mail and MIME parser - * Copyright (C) 1999 Werner Koch, Duesseldorf - * Copyright (C) 2003, g10 Code GmbH - * - * This program 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. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#ifndef RFC822PARSE_H -#define RFC822PARSE_H - -struct rfc822parse_context; -typedef struct rfc822parse_context *rfc822parse_t; - -typedef enum - { - RFC822PARSE_OPEN = 1, - RFC822PARSE_CLOSE, - RFC822PARSE_CANCEL, - RFC822PARSE_T2BODY, - RFC822PARSE_FINISH, - RFC822PARSE_RCVD_SEEN, - RFC822PARSE_LEVEL_DOWN, - RFC822PARSE_LEVEL_UP, - RFC822PARSE_BOUNDARY, - RFC822PARSE_LAST_BOUNDARY, - RFC822PARSE_BEGIN_HEADER, - RFC822PARSE_PREAMBLE, - RFC822PARSE_EPILOGUE - } -rfc822parse_event_t; - -struct rfc822parse_field_context; -typedef struct rfc822parse_field_context *rfc822parse_field_t; - - -typedef int (*rfc822parse_cb_t) (void *opaque, - rfc822parse_event_t event, - rfc822parse_t msg); - - -rfc822parse_t rfc822parse_open (rfc822parse_cb_t cb, void *opaque_value); - -void rfc822parse_close (rfc822parse_t msg); - -void rfc822parse_cancel (rfc822parse_t msg); -int rfc822parse_finish (rfc822parse_t msg); - -int rfc822parse_insert (rfc822parse_t msg, - const unsigned char *line, size_t length); - -char *rfc822parse_get_field (rfc822parse_t msg, const char *name, int which); - -const char *rfc822parse_enum_header_lines (rfc822parse_t msg, void **context); - -rfc822parse_field_t rfc822parse_parse_field (rfc822parse_t msg, - const char *name, - int which); - -void rfc822parse_release_field (rfc822parse_field_t field); - -const char *rfc822parse_query_parameter (rfc822parse_field_t ctx, - const char *attr, int lower_value); - -const char *rfc822parse_query_media_type (rfc822parse_field_t ctx, - const char **subtype); - -#endif /*RFC822PARSE_H */ diff --git a/tools/watchgnupg.c b/tools/watchgnupg.c deleted file mode 100644 index 7f79f2f18..000000000 --- a/tools/watchgnupg.c +++ /dev/null @@ -1,389 +0,0 @@ -/* watchgnupg.c - Socket server for GnuPG logs - * Copyright (C) 2003, 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif -#include <stdio.h> -#include <stdlib.h> -#include <stddef.h> -#include <string.h> -#include <errno.h> -#include <stdarg.h> -#include <assert.h> -#include <unistd.h> -#include <sys/socket.h> -#include <sys/un.h> -#include <fcntl.h> -#include <time.h> - -#define PGM "watchgnupg" - -/* Allow for a standalone build. */ -#ifdef VERSION -#define MYVERSION_LINE PGM " (GnuPG) " VERSION -#define BUGREPORT_LINE "\nReport bugs to <[email protected]>.\n" -#else -#define MYVERSION_LINE PGM -#define BUGREPORT_LINE "" -#endif - -static int verbose; - - -static void -die (const char *format, ...) -{ - va_list arg_ptr; - - fflush (stdout); - fprintf (stderr, "%s: ", PGM); - - va_start (arg_ptr, format); - vfprintf (stderr, format, arg_ptr); - va_end (arg_ptr); - putc ('\n', stderr); - - exit (1); -} - - -/* static void */ -/* err (const char *format, ...) */ -/* { */ -/* va_list arg_ptr; */ - -/* fflush (stdout); */ -/* fprintf (stderr, "%s: ", PGM); */ - -/* va_start (arg_ptr, format); */ -/* vfprintf (stderr, format, arg_ptr); */ -/* va_end (arg_ptr); */ -/* putc ('\n', stderr); */ -/* } */ - -static void * -xmalloc (size_t n) -{ - void *p = malloc (n); - if (!p) - die ("out of core"); - return p; -} - -static void * -xcalloc (size_t n, size_t m) -{ - void *p = calloc (n, m); - if (!p) - die ("out of core"); - return p; -} - -static void * -xrealloc (void *old, size_t n) -{ - void *p = realloc (old, n); - if (!p) - die ("out of core"); - return p; -} - - -struct client_s { - struct client_s *next; - int fd; - size_t size; /* Allocated size of buffer. */ - size_t len; /* Current length of buffer. */ - unsigned char *buffer; /* Buffer to with data already read. */ - -}; -typedef struct client_s *client_t; - - - -static void -print_fd_and_time (int fd) -{ - struct tm *tp; - time_t atime = time (NULL); - - tp = localtime (&atime); - printf ("%3d - %04d-%02d-%02d %02d:%02d:%02d ", - fd, - 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday, - tp->tm_hour, tp->tm_min, tp->tm_sec ); -} - - -/* Print LINE for the client identified by C. Calling this function - witgh LINE set to NULL, will flush the internal buffer. */ -static void -print_line (client_t c, const char *line) -{ - const char *s; - size_t n; - - if (!line) - { - if (c->buffer && c->len) - { - print_fd_and_time (c->fd); - fwrite (c->buffer, c->len, 1, stdout); - putc ('\n', stdout); - c->len = 0; - } - return; - } - - while ((s = strchr (line, '\n'))) - { - print_fd_and_time (c->fd); - if (c->buffer && c->len) - { - fwrite (c->buffer, c->len, 1, stdout); - c->len = 0; - } - fwrite (line, s - line + 1, 1, stdout); - line = s + 1; - } - n = strlen (line); - if (n) - { - if (c->len + n >= c->size) - { - c->size += ((n + 255) & ~255); - c->buffer = (c->buffer - ? xrealloc (c->buffer, c->size) - : xmalloc (c->size)); - } - memcpy (c->buffer + c->len, line, n); - c->len += n; - } -} - - -static void -print_version (int with_help) -{ - fputs (MYVERSION_LINE "\n" - "Copyright (C) 2004 Free Software Foundation, Inc.\n" - "This program comes with ABSOLUTELY NO WARRANTY.\n" - "This is free software, and you are welcome to redistribute it\n" - "under certain conditions. See the file COPYING for details.\n", - stdout); - - if (with_help) - fputs ("\n" - "Usage: " PGM " [OPTIONS] SOCKETNAME\n" - "Open the local socket SOCKETNAME and display log messages\n" - "\n" - " --force delete an already existing socket file\n" - " --verbose enable extra informational output\n" - " --version print version of the program and exit\n" - " --help display this help and exit\n" - BUGREPORT_LINE, stdout ); - - exit (0); -} - -int -main (int argc, char **argv) -{ - int last_argc = -1; - int force = 0; - - struct sockaddr_un srvr_addr; - int addrlen; - int server; - int flags; - client_t client_list = NULL; - - if (argc) - { - argc--; argv++; - } - while (argc && last_argc != argc ) - { - last_argc = argc; - if (!strcmp (*argv, "--")) - { - argc--; argv++; - break; - } - else if (!strcmp (*argv, "--version")) - print_version (0); - else if (!strcmp (*argv, "--help")) - print_version (1); - else if (!strcmp (*argv, "--verbose")) - { - verbose = 1; - argc--; argv++; - } - else if (!strcmp (*argv, "--force")) - { - force = 1; - argc--; argv++; - } - } - - if (argc != 1) - { - fprintf (stderr, "usage: " PGM " socketname\n"); - exit (1); - } - - - if (verbose) - fprintf (stderr, "opening socket `%s'\n", *argv); - - setvbuf (stdout, NULL, _IOLBF, 0); - - server = socket (PF_LOCAL, SOCK_STREAM, 0); - if (server == -1) - die ("socket() failed: %s\n", strerror (errno)); - - /* We better set the listening socket to non-blocking so that we - don't get bitten by race conditions in accept. The should not - happen for Unix Domain sockets but well, shit happens. */ - flags = fcntl (server, F_GETFL, 0); - if (flags == -1) - die ("fcntl (F_GETFL) failed: %s\n", strerror (errno)); - if ( fcntl (server, F_SETFL, (flags | O_NONBLOCK)) == -1) - die ("fcntl (F_SETFL) failed: %s\n", strerror (errno)); - - - memset (&srvr_addr, 0, sizeof srvr_addr); - srvr_addr.sun_family = AF_LOCAL; - strncpy (srvr_addr.sun_path, *argv, sizeof (srvr_addr.sun_path) - 1); - srvr_addr.sun_path[sizeof (srvr_addr.sun_path) - 1] = 0; - addrlen = (offsetof (struct sockaddr_un, sun_path) - + strlen (srvr_addr.sun_path) + 1); - - - again: - if (bind (server, (struct sockaddr *) &srvr_addr, addrlen)) - { - if (errno == EADDRINUSE && force) - { - force = 0; - remove (srvr_addr.sun_path); - goto again; - } - die ("bind to `%s' failed: %s\n", *argv, strerror (errno)); - } - - if (listen (server, 5)) - die ("listen failed: %s\n", strerror (errno)); - - for (;;) - { - fd_set rfds; - int max_fd; - client_t client; - - /* Usually we don't have that many connections, thus it is okay - to set them allways from scratch and don't maintain an active - fd_set. */ - FD_ZERO (&rfds); - FD_SET (server, &rfds); - max_fd = server; - for (client = client_list; client; client = client->next) - if (client->fd != -1) - { - FD_SET (client->fd, &rfds); - if (client->fd > max_fd) - max_fd = client->fd; - } - - if (select (max_fd + 1, &rfds, NULL, NULL, NULL) <= 0) - continue; /* Ignore any errors. */ - - if (FD_ISSET (server, &rfds)) /* New connection. */ - { - struct sockaddr_un clnt_addr; - int fd; - - addrlen = sizeof clnt_addr; - fd = accept (server, (struct sockaddr *) &clnt_addr, &addrlen); - if (fd == -1) - { - printf ("[accepting connection failed: %s]\n", strerror (errno)); - } - else if (fd >= FD_SETSIZE) - { - close (fd); - printf ("[connection request denied: too many connections]\n"); - } - else - { - for (client = client_list; client && client->fd != -1; - client = client->next) - ; - if (!client) - { - client = xcalloc (1, sizeof *client); - client->next = client_list; - client_list = client; - } - client->fd = fd; - printf ("[client at fd %d connected]\n", client->fd); - } - } - for (client = client_list; client; client = client->next) - if (client->fd != -1 && FD_ISSET (client->fd, &rfds)) - { - char line[256]; - int n; - - n = read (client->fd, line, sizeof line - 1); - if (n == 1) - { - int save_errno = errno; - print_line (client, NULL); /* flush */ - printf ("[client at fd %d read error: %s]\n", - client->fd, strerror (save_errno)); - close (client->fd); - client->fd = -1; - } - else if (!n) - { - print_line (client, NULL); /* flush */ - close (client->fd); - printf ("[client at fd %d disconnected]\n", client->fd); - client->fd = -1; - } - else - { - line[n] = 0; - print_line (client, line); - } - } - } - - return 0; -} - - -/* -Local Variables: -compile-command: "gcc -Wall -g -o watchgnupg watchgnupg.c" -End: -*/ |