summaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
Diffstat (limited to 'common')
-rw-r--r--common/ChangeLog-20112494
-rw-r--r--common/ChangeLog-2011.include458
-rw-r--r--common/ChangeLog.jnlib783
-rw-r--r--common/Makefile.am235
-rw-r--r--common/Makefile.in3509
-rw-r--r--common/README1
-rw-r--r--common/agent-opt.c106
-rw-r--r--common/all-tests.scm45
-rw-r--r--common/argparse.c2809
-rw-r--r--common/argparse.h281
-rw-r--r--common/asshelp.c685
-rw-r--r--common/asshelp.h104
-rw-r--r--common/asshelp2.c136
-rw-r--r--common/audit-events.h116
-rw-r--r--common/audit.c1324
-rw-r--r--common/audit.h225
-rw-r--r--common/b64dec.c254
-rw-r--r--common/b64enc.c422
-rw-r--r--common/call-gpg.c753
-rw-r--r--common/call-gpg.h54
-rw-r--r--common/ccparray.c148
-rw-r--r--common/ccparray.h51
-rw-r--r--common/common-defs.h54
-rw-r--r--common/compliance.c702
-rw-r--r--common/compliance.h97
-rw-r--r--common/convert.c267
-rw-r--r--common/dotlock.c1443
-rw-r--r--common/dotlock.h113
-rw-r--r--common/dynload.h100
-rw-r--r--common/exaudit.awk43
-rw-r--r--common/exechelp-posix.c909
-rw-r--r--common/exechelp-w32.c1043
-rw-r--r--common/exechelp-w32ce.c886
-rw-r--r--common/exechelp.h207
-rw-r--r--common/exectool.c650
-rw-r--r--common/exectool.h69
-rw-r--r--common/exstatus.awk39
-rw-r--r--common/fwddecl.h39
-rw-r--r--common/gc-opt-flags.h42
-rw-r--r--common/get-passphrase.c255
-rw-r--r--common/get-passphrase.h54
-rw-r--r--common/gettime.c1064
-rw-r--r--common/gettime.h70
-rw-r--r--common/gnupg.icobin0 -> 10134 bytes
-rw-r--r--common/gpgrlhelp.c97
-rw-r--r--common/helpfile.c272
-rw-r--r--common/homedir.c1536
-rw-r--r--common/host2net.h112
-rw-r--r--common/i18n.c237
-rw-r--r--common/i18n.h63
-rw-r--r--common/init.c384
-rw-r--r--common/init.h47
-rw-r--r--common/iobuf.c2698
-rw-r--r--common/iobuf.h615
-rw-r--r--common/ksba-io-support.c762
-rw-r--r--common/ksba-io-support.h66
-rw-r--r--common/localename.c127
-rw-r--r--common/logging.c1110
-rw-r--r--common/logging.h142
-rw-r--r--common/mapstrings.c216
-rw-r--r--common/mbox-util.c282
-rw-r--r--common/mbox-util.h30
-rw-r--r--common/membuf.c233
-rw-r--r--common/membuf.h64
-rw-r--r--common/miscellaneous.c842
-rw-r--r--common/mischelp.c205
-rw-r--r--common/mischelp.h92
-rw-r--r--common/mkdir_p.c187
-rw-r--r--common/mkdir_p.h52
-rw-r--r--common/mkstrtable.awk185
-rw-r--r--common/name-value.c908
-rw-r--r--common/name-value.h132
-rw-r--r--common/openpgp-fpr.c283
-rw-r--r--common/openpgp-oid.c472
-rw-r--r--common/openpgpdefs.h230
-rw-r--r--common/percent.c321
-rw-r--r--common/recsel.c632
-rw-r--r--common/recsel.h43
-rw-r--r--common/server-help.c185
-rw-r--r--common/server-help.h70
-rw-r--r--common/session-env.c406
-rw-r--r--common/session-env.h53
-rw-r--r--common/sexp-parse.h137
-rw-r--r--common/sexputil.c1188
-rw-r--r--common/shareddefs.h61
-rw-r--r--common/signal.c251
-rw-r--r--common/simple-pwquery.c495
-rw-r--r--common/simple-pwquery.h70
-rw-r--r--common/ssh-utils.c354
-rw-r--r--common/ssh-utils.h41
-rw-r--r--common/status-codes.h248
-rw-r--r--common/status.c76
-rw-r--r--common/status.h170
-rw-r--r--common/stringhelp.c1795
-rw-r--r--common/stringhelp.h181
-rw-r--r--common/strlist.c281
-rw-r--r--common/strlist.h69
-rw-r--r--common/sysutils.c1951
-rw-r--r--common/sysutils.h117
-rw-r--r--common/t-b64.c181
-rw-r--r--common/t-ccparray.c93
-rw-r--r--common/t-convert.c463
-rw-r--r--common/t-exechelp.c188
-rw-r--r--common/t-exectool.c237
-rw-r--r--common/t-gettime.c277
-rw-r--r--common/t-helpfile.c66
-rw-r--r--common/t-iobuf.c394
-rw-r--r--common/t-mapstrings.c126
-rw-r--r--common/t-mbox-util.c156
-rw-r--r--common/t-name-value.c593
-rw-r--r--common/t-openpgp-oid.c246
-rw-r--r--common/t-percent.c114
-rw-r--r--common/t-recsel.c438
-rw-r--r--common/t-session-env.c304
-rw-r--r--common/t-sexputil.c511
-rw-r--r--common/t-ssh-utils.c391
-rw-r--r--common/t-stringhelp.c1319
-rw-r--r--common/t-strlist.c84
-rw-r--r--common/t-support.h84
-rw-r--r--common/t-sysutils.c89
-rw-r--r--common/t-timestuff.c175
-rw-r--r--common/t-w32-cmdline.c250
-rw-r--r--common/t-w32-reg.c87
-rw-r--r--common/t-zb32.c305
-rw-r--r--common/tlv-builder.c388
-rw-r--r--common/tlv.c309
-rw-r--r--common/tlv.h143
-rw-r--r--common/ttyio.c751
-rw-r--r--common/ttyio.h73
-rw-r--r--common/types.h116
-rw-r--r--common/userids.c435
-rw-r--r--common/userids.h39
-rw-r--r--common/utf8conv.c857
-rw-r--r--common/utf8conv.h58
-rw-r--r--common/util.h424
-rw-r--r--common/utilproto.h44
-rw-r--r--common/w32-cmdline.c450
-rw-r--r--common/w32-reg.c315
-rw-r--r--common/w32help.h66
-rw-r--r--common/w32info-rc.h.in32
-rw-r--r--common/xasprintf.c123
-rw-r--r--common/xreadline.c127
-rw-r--r--common/yesno.c150
-rw-r--r--common/zb32.c120
-rw-r--r--common/zb32.h38
145 files changed, 57244 insertions, 0 deletions
diff --git a/common/ChangeLog-2011 b/common/ChangeLog-2011
new file mode 100644
index 0000000..4b95b35
--- /dev/null
+++ b/common/ChangeLog-2011
@@ -0,0 +1,2494 @@
+2011-12-01 Werner Koch <wk@g10code.com>
+
+ NB: ChangeLog files are no longer manually maintained. Starting
+ on December 1st, 2011 we put change information only in the GIT
+ commit log, and generate a top-level ChangeLog file from logs at
+ "make dist". See doc/HACKING for details.
+
+2011-11-30 Werner Koch <wk@gnupg.org>
+
+ Rewrite dns-cert.c to not use the gpg-only iobuf stuff.
+ * dns-cert.c: Remove iobuf.h.
+ (get_dns_cert): Rename to _get_dns_cert. Remove MAX_SIZE arg.
+ Change iobuf arg to a estream-t. Rewrite function to make use of
+ estream instead of iobuf. Require all parameters. Return an
+ gpg_error_t error instead of the type. Add arg ERRSOURCE.
+ * dns-cert.h (get_dns_cert): New macro to pass the error source to
+ _gpg_dns_cert.
+ * t-dns-cert.c (main): Adjust for changes in get_dns_cert.
+
+ * estream.c (es_fopenmem_init): New.
+ * estream.h (es_fopenmem_init): New.
+
+2011-11-29 Werner Koch <wk@g10code.com>
+
+ * estream.c (func_mem_create): Don't set FUNC_REALLOC if GROW is
+ not set. Require FUNC_REALLOC if DATA is NULL and FUNC_FREE is
+ given.
+
+ * dns-cert.c: Use new CERTTYPE_ constants for better readability.
+
+2011-11-28 Werner Koch <wk@g10code.com>
+
+ * t-dns-cert.c (main): Increase MAX_SIZE to 64k.
+
+ * dns-cert.c (get_dns_cert): Factor test code out to ...
+ * t-dns-cert.c: new file.
+
+2011-10-24 Werner Koch <wk@g10code.com>
+
+ * dotlock.h, dotlock.c: Add alternative to allow distribution of
+ these files under a modified BSD license
+
+2011-09-30 Werner Koch <wk@g10code.com>
+
+ Change the license of all JNLIB parts from LPGLv3+ to to LGPLv3+
+ or GPLv2+.
+
+ * dotlock.h (DOTLOCK_EXT_SYM_PREFIX): New macro.
+
+2011-09-29 Werner Koch <wk@g10code.com>
+
+ * dotlock.c (DOTLOCK_USE_PTHREAD): New macro.
+ [DOTLOCK_USE_PTHREAD] (all_lockfiles_mutex): New.
+ (LOCK_all_lockfiles, UNLOCK_all_lockfiles): New. Use them to
+ protect access to all_lockfiles.
+ (dotlock_set_fd, dotlock_get_fd): New.
+
+2011-09-28 Werner Koch <wk@g10code.com>
+
+ * dotlock.c (dotlock_take, dotlock_take_unix, dotlock_take_w32):
+ Implement arbitrary timeout values.
+ (dotlock_create): Add arg FLAGS for future extensions.
+
+2011-09-27 Werner Koch <wk@g10code.com>
+
+ * dotlock.c (dotlock_take_unix): Check only the link count and not
+ the error return from link.
+ (use_hardlinks_p): New.
+ (dotlock_create_unix): Test for hardlinks.
+ (dotlock_take_unix): Implement O_EXCL locking.
+
+2011-09-23 Werner Koch <wk@g10code.com>
+
+ * dotlock.c: Factor Unix and W32 specific code out into specific
+ functions. Define HAVE_POSIX_SYSTEM. Rearrange some functions.
+ (disable_dotlock): Rename to dotlock_disable.
+ (create_dotlock): Rename to dotlock_create.
+ (destroy_dotlock): Rename to dotlock_destroy.
+ (make_dotlock): Rename to dotlock_take.
+ (release_dotlock): Rename to dotlock_release.
+
+2011-09-22 Werner Koch <wk@g10code.com>
+
+ * dotlock.c: Remove support for RISCOS.
+
+2011-08-10 Werner Koch <wk@g10code.com>
+
+ * t-exechelp.c (test_close_all_fds): Don't use the DUMMY_FD var.
+
+ * pka.c (get_pka_info): Remove unused var.
+
+ * signal.c (got_fatal_signal): Remove unused var.
+
+ * estream.c (es_fread, es_fwrite): Remove unused var.
+
+2011-07-20 Werner Koch <wk@g10code.com>
+
+ * ssh-utils.c, ssh-utils.h: New.
+ * t-ssh-utils.c: New.
+ * Makefile.am (t_ssh_utils_LDADD): New.
+ (module_tests): Add t-ssh-utils.c
+
+2011-06-01 Marcus Brinkmann <mb@g10code.com>
+
+ * util.h: Undef snprintf before redefining it.
+
+2011-05-20 Werner Koch <wk@g10code.com>
+
+ * util.h: Remove some error code substitutes.
+
+2011-04-25 Werner Koch <wk@g10code.com>
+
+ * userids.c (classify_user_id): Add arg OPENPGP_HACK to fix
+ regression from 2009-12-08.
+
+2011-04-01 Werner Koch <wk@g10code.com>
+
+ * sysutils.c (get_uint_nonce): New.
+
+2011-03-03 Werner Koch <wk@g10code.com>
+
+ * estream.c (struct estream_list): Rename to estream_list_s and
+ simplify. A double linked list is overkill for our purpose.
+ (do_list_add, do_list_remove): Adjust accordingly.
+ (_es_get_std_stream): Ditto.
+ (do_list_iterate, estream_iterator_t): Remove; it is used only at
+ one place.
+ (es_fflush): Replace iteration function. Also lock each stream
+ while flushing all streams.
+
+2011-02-27 Werner Koch <wk@g10code.com>
+
+ * gettime.c (isotime2epoch): Factor check code out to ..
+ (isotime_p): .. new.
+ (isotime_human_p): New.
+ (string2isotime): New.
+ * t-gettime.c (test_string2isotime): New.
+
+2011-02-11 Andrey Jivsov <openpgp@brainhub.org>
+
+ * openpgp-oid.c (openpgp_oid_to_str): Use unsigned int for
+ get_opaque. Fixes a bug on 64 bit platforms.
+
+2011-02-08 Werner Koch <wk@g10code.com>
+
+ * http.c (connect_server): Add arg R_HOST_NOT_FOUND.
+
+2011-02-07 Werner Koch <wk@g10code.com>
+
+ * http.c (my_socket_new, my_socket_ref, my_socket_unref): New.
+ (cookie_close, cookie_read, cookie_write, http_close, _http_open)
+ (send_request): Replace use of an socket integer by the new socket
+ object.
+ (_http_raw_connect): New.
+ (fp_onclose_notification): New.
+ (_http_raw_connect, _http_wait_response, http_close): Register and
+ unregister this notification.
+ * http.h (http_raw_connect): New.
+
+ * http.h (parsed_uri_s): Add field IS_OPAQUE.
+ (http_req_t): Add HTTP_REQ_OPAQUE.
+ * http.c (do_parse_uri): Parse unknown schemes into PATH.
+ (my_socket_new, my_socket_ref, my_socket_unref): New.
+ (send_request): Simplify save_errno stuff.
+
+2011-02-03 Werner Koch <wk@g10code.com>
+
+ * status.h (STATUS_DECRYPTION_INFO): New.
+
+ * argparse.c (strusage): Update copyright year.
+
+2011-01-31 Werner Koch <wk@g10code.com>
+
+ * openpgp-oid.c: New.
+ * t-openpgp-oid.c: New.
+
+2011-01-20 Werner Koch <wk@g10code.com>
+
+ Fix bug#1313.
+
+ * http.c (my_select): New. Define to pth_select if building with Pth.
+ (start_server, write_server, cookie_read, cookie_write): Use it.
+ (my_connect): New. Define to pth_connect if building with Pth.
+ (connect_server): Use it.
+ (my_accept): New. Define to pth_accept if building with Pth.
+ (start_server): Use it.
+
+2011-01-20 Werner Koch <wk@g10code.com>
+
+ * util.h (struct b64state): Add field LASTERR.
+ * b64enc.c (enc_start, b64enc_write, b64enc_finish): Handle
+ LASTERR. This is to make sure that we don't leak strduped data.
+ * b64dec.c (b64dec_start, b64dec_proc, b64dec_finish): Ditto.
+
+ * http.c (escape_data): New.
+ (insert_escapes): Implement using escape_data.
+ (http_escape_data): New.
+
+2011-01-19 Werner Koch <wk@g10code.com>
+
+ * homedir.c (gnupg_module_name): Use NAME_OF_INSTALLED_GPG instead
+ of "gpg2".
+
+2011-01-18 Werner Koch <wk@g10code.com>
+
+ * iobuf.c (file_es_filter_ctx_t): New.
+ (file_es_filter): New.
+ (iobuf_esopen): New.
+
+ * membuf.c (clear_membuf, peek_membuf): New.
+
+ * util.h (GPG_ERR_NO_KEYSERVER): New.
+
+ * keyserver.h (keyserver_spec): Move from ../g10/options.h to here.
+
+ * http.c (do_parse_uri): Add arg NO_SCHEME_CHECK. Change all
+ callers. Support HKP and HKPS.
+ (_http_parse_uri): Do proper error management.
+ * http.h (parsed_uri_s): Add field IS_HTTP.
+ (http_parse_uri): Support NO_SCHEME_CHECK arg.
+
+ * estream.c (es_func_mem_write): Fix computation of NEWSIZE.
+
+2011-01-10 Werner Koch <wk@g10code.com>
+
+ * session-env.c (update_var): Fix same value detection. Fixes
+ bug#1311.
+
+2010-12-17 Werner Koch <wk@g10code.com>
+
+ * asshelp.c (lock_spawning): Add arg VERBOSE. Improve timeout
+ management. Make callers pass a value for VERBOSE.
+ (lock_agent_spawning, unlock_agent_spawning): Remove. Change
+ callers to use lock_spawning and unlock_spawning.
+
+2010-12-17 Marcus Brinkmann <mb@g10code.com>
+
+ * homedir.c (gnupg_cachedir): Create /temp subdirectories.
+
+2010-12-02 Werner Koch <wk@g10code.com>
+
+ * miscellaneous.c (gnupg_cipher_algo_name): New. Replace all
+ users of gcry_cipher_algo_name by this one.
+
+ * logging.c (fun_cookie_s) [W32CE]: Add field USE_WRITEFILE.
+ (fun_writer) [W32CE]: Make use of it.
+ (set_file_fd) [W32CE]: Implement special filename "GPG2:".
+
+2010-11-25 Werner Koch <wk@g10code.com>
+
+ * asshelp.c (start_new_gpg_agent): Change style of startup info.
+ (start_new_dirmngr): Ditto.
+
+2010-11-23 Werner Koch <wk@g10code.com>
+
+ * asshelp.c (SECS_TO_WAIT_FOR_AGENT, SECS_TO_WAIT_FOR_DIRMNGR):
+ Use these constants. For W32CE increase them to 30 seconds.
+ (start_new_gpg_agent): Print time to startup agent.
+ (start_new_dirmngr): Ditto.
+
+2010-11-04 Werner Koch <wk@g10code.com>
+
+ * logging.c (do_logv) [W32]: Don't set a default log stream if the
+ registry entry is empty.
+
+2010-10-27 Werner Koch <wk@g10code.com>
+
+ * gettime.c (gnupg_get_isotime): Compare to (time_t)-1.
+ (epoch2isotime): Ditto.
+ (IS_INVALID_TIME_T): New.
+ (asctimestamp): Use new macro.
+ (strtimestamp, isotimestamp): Ditto. Use snprintf.
+
+2010-10-25 Werner Koch <wk@g10code.com>
+
+ * logging.c (do_log): Rename to log_log and make global.
+
+2010-10-20 Werner Koch <wk@g10code.com>
+
+ * i18n.c (i18n_init) [USE_SIMPLE_GETTEXT]: Call textdomain.
+
+2010-10-14 Werner Koch <wk@g10code.com>
+
+ * asshelp.c (start_new_gpg_agent): Print a notice once the agent
+ has been started.
+ (start_new_dirmngr): Likewise.
+
+2010-10-13 Werner Koch <wk@g10code.com>
+
+ * miscellaneous.c (parse_version_number, parse_version_string)
+ (gnupg_compare_version): New.
+
+2010-10-04 Werner Koch <wk@g10code.com>
+
+ * gettime.c (asctimestamp) [W32CE]: Do not print the timezone.
+
+2010-09-30 Werner Koch <wk@g10code.com>
+
+ * util.h (GPG_ERR_FULLY_CANCELED): Add replacement.
+
+2010-09-17 Werner Koch <wk@g10code.com>
+
+ * http.c (INADDR_NONE): Provide fallback.
+ * logging.c (INADDR_NONE): Ditto.
+
+2010-09-16 Werner Koch <wk@g10code.com>
+
+ * util.h: Add GPG_ERR_MISSING_ISSUER_CERT.
+ * status.c (get_inv_recpsgnr_code): Ditto.
+
+2010-09-13 Werner Koch <wk@g10code.com>
+
+ * homedir.c (gnupg_bindir) [W32CE]: Change to bin/.
+ (gnupg_libexecdir) [W32]: Call gnupg_bindir.
+ (gnupg_libdir, gnupg_datadir, gnupg_localedir) [W32]: Simplify by
+ using xstrconcat.
+ (gnupg_module_name): Ditto.
+ (w32_rootdir): Strip a trailing "bin".
+
+2010-09-02 Werner Koch <wk@g10code.com>
+
+ * util.h (GPG_ERR_NOT_INITIALIZED): Define if not defined.
+
+2010-09-01 Marcus Brinkmann <marcus@g10code.de>
+
+ * estream.c (_es_set_std_fd): Disable debug output.
+
+2010-08-26 Werner Koch <wk@g10code.com>
+
+ * estream.c (es_convert_mode): Rename to parse_mode.
+ (parse_mode): Add arg R_CMODE and parse key value pairs. Use Use
+ 664 as the default mode. Change callers.
+ (ES_DEFAULT_OPEN_MODE): Remove.
+ (es_fopen, do_fpopen, do_w32open, es_freopen): Support a creation
+ mode.
+ (es_func_file_create): Rename to func_file_create and add arg CMODE.
+ (es_func_fd_create): Rename to func_fd_create.
+ (es_func_fp_create): Rename to func_fp_create.
+ (es_list_add): Rename to do_list_add.
+ (es_list_remove): Rename to do_list_remove.
+ (es_list_iterate): Rename to do_list_iterate.
+ (es_pth_read): Rename to do_pth_read.
+ (es_deinit): Rename to do_deinit.
+ (es_init_do): Rename to do_init.
+ (es_func_mem_create): Rename to func_mem_create.
+
+2010-08-23 Werner Koch <wk@g10code.com>
+
+ * exechelp-w32ce.c: Rewrite all spawn stuff.
+
+ * exechelp-w32.c (close_all_fds) [W32]: Make it a dummy function.
+
+ * estream.c (es_onclose): New.
+ (notify_list_t, onclose): New.
+ (struct estream_internal): Add field ONCLOSE.
+ (es_initialize, es_deinitialize): Manage new field.
+ (do_close): Call onclose notify functions.
+
+2010-08-20 Werner Koch <wk@g10code.com>
+
+ * exechelp-w32.c (create_inheritable_pipe): Change arg to HANDLE.
+
+ * estream.h (es_sysopen_t): New.
+ * estream.c (es_func_w32_create, es_func_w32_read)
+ (es_func_w32_write, es_func_w32_seek, es_func_w32_destroy)
+ (estream_functions_w32, estream_cookie_fd): New. Only for W32.
+ (es_sysopen, es_sysopen_nc): New.
+ (do_w32open, do_sysopen): New.
+ (es_syshd, es_syshd_unlocked): New.
+ (struct estream_internal): Replace filed FD by SYSHD.
+ (es_initialize): Clear SYSHD_VALID.
+ (map_w32_to_errno): New.
+ (es_get_fd): Remove.
+ (es_fileno_unlocked): Re-implement using es_syshd.
+ (es_initialize, es_create): Replace arg FD by SYSHD.
+ (es_fopen, es_mopen, es_fopenmem, do_fdopen, do_fpopen)
+ (es_tmpfile): Use SYSHD instead of FD.
+ (es_destroy): Rename to do_close.
+
+2010-08-19 Werner Koch <wk@g10code.com>
+
+ * exechelp-posix.c (create_pipe_and_estream): New.
+ (gnupg_spawn_process): Rework this function and its calling
+ convention; it is not used anyway.
+ * exechelp-w32.c (gnupg_spawn_process): Ditto.
+
+2010-08-18 Werner Koch <wk@g10code.com>
+
+ * logging.c (writen): Add arg IS_SOCKET.
+ (fun_writer): Pass the is_socket flag.
+ (do_logv) [W32]: Allow for a default log stream
+
+ * estream.c (struct estream_internal): Remove obsolete fields
+ PRINT_FP, PRINT_ERRNO, PRINT_ERR and all remaining code cruft.
+
+2010-08-16 Werner Koch <wk@g10code.com>
+
+ * estream.c (es_printf_unlocked, es_printf): New.
+
+ * asshelp.c (lock_agent_t): Rename to lock_spawn_t.
+ (lock_agent_spawning, unlock_agent_spawning): Factor code out to ...
+ (lock_spawning, unlock_spawning): .. new.
+ (start_new_gpg_agent): Make more use of ERRSOURCE.
+ (start_new_dirmngr): New.
+
+2010-08-13 Werner Koch <wk@g10code.com>
+
+ * Makefile.am (audit-events.h, status-codes.h): Fix srcdir problem
+ amd depend on Makefile.am instead of Makefile.
+
+2010-08-12 Werner Koch <wk@g10code.com>
+
+ * sysutils.c (gnupg_remove) [W32CE]: Fix returned error.
+
+2010-08-09 Werner Koch <wk@g10code.com>
+
+ * logging.c (WITH_IPV6): New macro.
+ (parse_portno): New. From libassuan.
+ (fun_writer): Support TCP logging on all platforms.
+ (sock_close): New.
+
+2010-08-06 Werner Koch <wk@g10code.com>
+
+ * homedir.c (dirmngr_socket_name) [W32CE]: Base on default homedir.
+ (gnupg_cachedir) [W32CE]: Drop drive letter.
+
+ * http.c (http_open_document): Rename to _http_open_document and
+ add arg ERRSOURCE. Pass ERRSOURCE to all called funcs.
+ (http_wait_response, http_open, http_parse_uri): Likewise.
+ (do_parse_uri, parse_response, store_header): Change to return an
+ gpg_err_code_t. Change callers.
+ (send_request): Add arg ERRSOURCE. Change callers.
+ * http.h (http_open_document, http_wait_response, http_open)
+ (http_parse_uri): Define as macro.
+
+2010-08-05 Werner Koch <wk@g10code.com>
+
+ * estream.h (es_asprintf, es_vasprintf): Add lost prototyps.
+
+ * http.c: Require estream and make HTTP_USE_ESTREAM obsolete. It
+ make the code unreadable and we require estream anyway for GnuPG.
+ (http_wait_response): Get use of cookies right.
+ (send_request): s/xtryasprintf/es_asprintf/ to allow standalone
+ use of the code.
+ (insert_escapes, connect_server): s/sprintf/snprintf/.
+ (parse_response): s/my_read_line/es_read_line/.
+ (my_read_line): Remove.
+ (write_server): Use pth_write.
+
+2010-07-26 Werner Koch <wk@g10code.com>
+
+ * estream.c (es_func_fp_write) [W32]: Write smaller chunks.
+
+2010-07-25 Werner Koch <wk@g10code.com>
+
+ * argparse.c (initialize): Use ARGPARSE_PRINT_WARNING constant.
+
+2010-07-24 Werner Koch <wk@g10code.com>
+
+ * estream.c (es_set_binary): New.
+
+2010-07-19 Werner Koch <wk@g10code.com>
+
+ * utf8conv.c (utf8_to_wchar): s/malloc/jnlib_malloc/.
+
+2010-07-16 Werner Koch <wk@g10code.com>
+
+ * http.h (HTTP_FLAG_IGNORE_CL): Add flag .
+ * http.c (WITHOUT_GNU_PTH): Test macro for Pth support.
+ (http_parse_uri): s/xcalloc/xtrycalloc/.
+ (send_request): Replace of discrete allocation and sprintf by
+ xtryasprintf.
+ (http_wait_response): Replace HTTP_FLAG_NO_SHUTDOWN by
+ HTTP_FLAG_SHUTDOWN to change the default to no shutdown.
+ (cookie_read) [HAVE_PTH]: Use pth_read.
+ (longcounter_t): New.
+ (struct cookie_s): Add support for content length. Turn flag
+ fields into bit types.
+ (parse_response): Parse content length header.
+ (cookie_read): Take care of the content length.
+
+2010-07-08 Werner Koch <wk@g10code.com>
+
+ * estream.c (estream_functions_file): Remove and replace by
+ identical estream_functions_fd.
+
+2010-07-06 Werner Koch <wk@g10code.com>
+
+ * util.h (b64state): Add field STREAM.
+ * b64enc.c (b64enc_start): Factor code out to ..
+ (enc_start): new.
+ (b64enc_start_es, my_fputs): New.
+ (b64enc_write, b64enc_finish): Support estream.
+
+2010-06-24 Werner Koch <wk@g10code.com>
+
+ * asshelp.c (lock_agent_spawning) [W32]: Use CreateMutexW.
+ (start_new_gpg_agent): Use HANG option for gnupg_wait_progress.
+ Fixes regression from 2010-06-09.
+
+2010-06-21 Werner Koch <wk@g10code.com>
+
+ * util.h (xfree_fnc): New.
+
+2010-06-18 Werner Koch <wk@g10code.com>
+
+ * util.h (GPG_ERR_MISSING_KEY) [!GPG_ERR_MISSING_KEY]: New.
+
+ * sexputil.c (make_canon_sexp_pad): Add arg SECURE.
+
+2010-06-17 Werner Koch <wk@g10code.com>
+
+ * sexputil.c (make_canon_sexp_pad): New.
+
+2010-06-14 Werner Koch <wk@g10code.com>
+
+ * membuf.c (put_membuf): Add shortcut for !LEN.
+
+2010-06-11 Marcus Brinkmann <marcus@g10code.de>
+
+ * sysutils.c (translate_sys2libc_fd): Revert last change.
+ (translate_sys2libc_fd_int): Revert last change.
+
+2010-06-10 Marcus Brinkmann <marcus@g10code.de>
+
+ * sysutils.c (translate_sys2libc_fd) [HAVE_W32CE_SYSTEM]:
+ Implement.
+ (translate_sys2libc_fd_int) [HAVE_W32CE_SYSTEM]: Don't call
+ translate_sys2libc_fd.
+
+ * estream.c (_es_get_std_stream): Fix cut&paste bug.
+
+2010-06-09 Werner Koch <wk@g10code.com>
+
+ * exechelp-posix.c, exechelp-w32.c
+ * exechelp-w32ce.c (gnupg_wait_process): Add new arg HANG. Change
+ all callers.
+ (gnupg_release_process): New. Use it after all calls to
+ gnupg_wait_process.
+
+ * util.h (GNUPG_MODULE_NAME_DIRMNGR_LDAP): New.
+ * homedir.c (gnupg_cachedir): New.
+ (w32_try_mkdir): New.
+ (dirmngr_socket_name): Change standard socket name.
+ (gnupg_module_name): Support GNUPG_MODULE_NAME_DIRMNGR_LDAP.
+
+ * logging.c (log_set_get_tid_callback): Replace by ...
+ (log_set_pid_suffix_cb): .. new.
+ (do_logv): Change accordingly.
+
+2010-06-08 Marcus Brinkmann <marcus@g10code.de>
+
+ * Makefile.am (AM_CFLAGS): Add $(LIBASSUAN_CFLAGS).
+ (t_common_ldadd): Add $(LIBASSUAN_LIBS).
+ * sysutils.c: Include <assuan.h>.
+ (translate_sys2libc_fd_int): Cast to silence gcc warning.
+ * iobuf.c: Include <assuan.h>
+ (translate_file_handle): Fix syntax error.
+
+2010-06-08 Werner Koch <wk@g10code.com>
+
+ * iobuf.c (translate_file_handle) [W32CE]: Handle rendezvous ids.
+
+2010-06-07 Werner Koch <wk@g10code.com>
+
+ * sysutils.c [W32CE]: Finish pipe creation.
+
+ * estream.c (es_fname_get, es_fname_set): New.
+ (fname_set_internal): New.
+ (struct estream_internal): Add fields printable_fname and
+ printable_fname_inuse.
+ (_es_get_std_stream): Set stream name.
+ (es_fopen, es_freopen, es_deinitialize): Set fname.
+
+ * exechelp-posix.c (gnupg_spawn_process): Allow passing INFILE or
+ OUTFILE as NULL.
+ * exechelp-w32.c (gnupg_spawn_process): Ditto.
+ * exechelp-w32ce.c (gnupg_spawn_process): Return an error for
+ INFILE or OUTFILE passed as NULL.
+
+2010-06-01 Werner Koch <wk@g10code.com>
+
+ * logging.c (log_get_stream): Make sture a log stream is available.
+
+2010-05-30 Werner Koch <wk@g10code.com>
+
+ * init.c (writestring_via_estream): New.
+ (init_common_subsystems): Register with argparse.
+
+ * argparse.c (argparse_register_outfnc): New.
+ (writestrings, flushstrings): New. Use them instead of stdout or
+ stderr based functions.
+
+2010-05-04 Werner Koch <wk@g10code.com>
+
+ * estream.c (_es_get_std_stream): Re-use registered standard fds.
+ (IS_INVALID_FD, ESTREAM_SYS_YIELD): New.
+ (es_func_fd_read, es_func_fd_write, es_func_fd_seek)
+ (es_func_fd_destroy): Implement a dummy stream.
+
+ * exechelp-w32ce.c (build_w32_commandline): Add args FD0_ISNULL
+ and FD1_ISNULL. Remove arg PGMNAME. Change callers.
+ (gnupg_spawn_process_detached): Implement.
+ (gnupg_spawn_process_fd): Implement one special case for now.
+
+2010-05-03 Werner Koch <wk@g10code.com>
+
+ * asshelp.c (lock_agent_spawning, unlock_agent_spawning): New.
+ (start_new_gpg_agent): Test for configured standard socket and
+ try to fire up the agent in this case.
+
+ * exechelp-posix.c (gnupg_wait_process): Do not log a message if
+ EXITCODE is given.
+ (gnupg_spawn_process_detached): Do not reuse PID for the second fork.
+
+2010-04-26 Werner Koch <wk@g10code.com>
+
+ * utf8conv.c (load_libiconv) [W32CE]: No libiconv warning
+
+ * init.c (init_common_subsystems) [W32CE]: Register the sleep
+ function before es_init.
+
+2010-04-20 Werner Koch <wk@g10code.com>
+
+ * estream.c (es_deinit): New.
+ (es_init_do): Install atexit handler to flush all streams.
+
+ * Makefile.am (common_sources): Add gettime.h.
+
+2010-04-20 Marcus Brinkmann <marcus@g10code.de>
+
+ * logging.c (do_log_ignore_arg): New helper function.
+ (log_string): Use it to remove ugly volatile hack that causes gcc
+ warning.
+ (log_flush): Likewise.
+ * sysutils.c (gnupg_unsetenv) [!HAVE_W32CE_SYSTEM]: Return something.
+ (gnupg_setenv) [!HAVE_W32CE_SYSTEM]: Likewise.
+ * pka.c (get_pka_info): Solve strict aliasing rule violation.
+ * t-exechelp.c (test_close_all_fds): Use dummy variables to
+ silence gcc warning.
+
+2010-04-15 Werner Koch <wk@g10code.com>
+
+ * util.h: Factor time related functions out to ...
+ * gettime.h: New.
+ (gnupg_copy_time): Move to ...
+ * gettime.c (gnupg_copy_time): New.
+
+ * sysutils.c (gnupg_setenv) [!W32CE]: Add missing return.
+ (gnupg_unsetenv) [!W32CE]: Add missing return.
+
+2010-04-14 Werner Koch <wk@g10code.com>
+
+ * Makefile.am (noinst_LIBRARIES) [W32CE]: Exclude libsimple-pwquery.
+
+ * w32help.h (umask) [W32CE]: New.
+
+ * sysutils.c (_gnupg_isatty): New.
+ * util.h (gnupg_isatty): New.
+
+ * asshelp.c (setup_libassuan_logging): Read ASSUAN_DEBUG envvar.
+ (my_libassuan_log_handler): Use it.
+ * sysutils.c (_gnupg_getenv): Implement ASSUAN_DEBUG.
+
+2010-04-08 Werner Koch <wk@g10code.com>
+
+ * w32help.h (_setmode, setmode) [W32CE]: Provide prototype and
+ macro.
+
+2010-04-07 Werner Koch <wk@g10code.com>
+
+ * mischelp.c (timegm): Replace unsetenv/putenv by gnupg_unsetenv.
+
+ * sysutils.c: Include setenv.h.
+ (gnupg_setenv, gnupg_unsetenv): New.
+
+
+2010-04-06 Werner Koch <wk@g10code.com>
+
+ * sysutils.c (gnupg_mkdir): New.
+
+2010-03-29 Werner Koch <wk@g10code.com>
+
+ * init.c (sleep_on_exit): Change to 400ms.
+
+2010-03-25 Werner Koch <wk@g10code.com>
+
+ * init.c (sleep_on_exit) [W32CE]: New.
+ (init_common_subsystems): Call it.
+
+2010-03-24 Werner Koch <wk@g10code.com>
+
+ * stringhelp.c (change_slashes, compare_filenames): Replace
+ HAVE_DRIVE_LETTERS by HAVE_DOSISH_SYSTEM.
+ (make_basename, make_dirname): Detect backslashes and drive
+ letters separately.
+
+ * dotlock.c (make_dotlock, create_dotlock, release_dotlock): Use
+ LockFileEx and UnlockFileEx to support W32CE.
+
+ * ttyio.c (USE_W32_CONSOLE): Replace all _WIN32 by this.
+ (init_ttyfp) [W32CE]: Use stderr.
+
+ * iobuf.c (FD_FOR_STDIN, FD_FOR_STDOUT) [W32CE]: Use estream.
+ (translate_file_handle) [W32CE]: Remove handle translation.
+
+2010-03-23 Werner Koch <wk@g10code.com>
+
+ * sysutils.c (gnupg_remove): New.
+
+2010-03-22 Werner Koch <wk@g10code.com>
+
+ * exechelp-w32ce.c (build_w32_commandline): Replace by code from
+ libassuan.
+ (create_inheritable_pipe): Use _assuan_w32ce_prepare_pipe.
+ (build_w32_commandline_copy, do_create_pipe): Remove.
+
+ * exechelp-posix.c (gnupg_spawn_process): Change to use estream
+ also for INFILE and STATUSFILE.
+ * exechelp-w32.c (gnupg_spawn_process): Ditto.
+
+2010-03-22 Werner Koch <wk@g10code.com>
+
+ * exechelp.c: Remove after factoring all code out to ...
+ * exechelp-posix.c, exechelp-w32.c, exechelp-w32ce.c: .. new.
+
+ * exechelp.c (create_inheritable_pipe_r)
+ (create_inheritable_pipe_w): Fold both into ...
+ (create_inheritable_pipe): .. New. Change callers to use this.
+ (gnupg_create_inbound_pipe, gnupg_create_outbound_pipe): Factor
+ code out to ...
+ (do_create_pipe): .. New.
+
+ * init.c (parse_std_file_handles): Change to use rendezvous ids.
+
+2010-03-15 Werner Koch <wk@g10code.com>
+
+ * init.c (init_common_subsystems): Add args ARGCP and
+ ARGVP. Change all callers to provide them.
+ (parse_std_file_handles): New.
+
+ * t-sysutils.c (rewind) [W32CE]: Provide a replacement.
+
+ * Makefile.am (module_tests) [W32CE]: Don't build t-exechelp for now.
+
+ * sysutils.c (gnupg_allow_set_foregound_window) [W32CE]: Don't
+ call AllowSetForegroundWindow.
+
+ * logging.c (isatty) [W32CE]: New.
+ (fun_writer, set_file_fd): Use estream even for the internal error
+ messages.
+ (log_string, log_flush): Make DUMMY_ARG_PTR static.
+
+2010-03-15 Werner Koch <wk@g10code.com>
+
+ * asshelp.c (send_pinentry_environment) [!HAVE_SETLOCALE]: Do not
+ define OLD_LC.
+ * http.c (connect_server) [!USE_DNS_SRV]: Mark SRVTAG unused.
+ * dns-cert.c (get_dns_cert) [!USE_DNS_CERT]: Mark args unused.
+ * pka.c (get_pka_info): Ditto.
+
+ * signal.c (pause_on_sigusr): Remove. It was used in ancient gpg
+ version with shared memory IPC. Last caller removed on 2006-04-18.
+ (do_block) [W32]: Mark arg unused.
+
+ * exechelp.c (w32_open_null): Use CreateFileW.
+
+ * init.c (init_common_subsystems): Add args ARGCP and ARGVP.
+ Change all callers to pass them.
+
+ * logging.c (S_IRGRP, S_IROTH, S_IWGRP, S_IWOTH) [W32]: New.
+ (fun_writer, set_file_fd) [W32]: Disable socket code.
+
+ * localename.c: Include gpg-error.h.
+
+ * util.h (GPG_ERR_NOT_ENABLED): Remove this temporary definition.
+
+2010-03-12 Werner Koch <wk@g10code.com>
+
+ * status.h (STATUS_ENTER): New.
+
+ * ttyio.c (tty_fprintf): Change to use estream.
+
+ * miscellaneous.c (print_utf8_string): Rename to print_utf8_buffer
+ and change FP arg to an estream. Change all callers.
+ (print_utf8_string2): Ditto; new name is to print_utf8_buffer2.
+
+2010-03-11 Werner Koch <wk@g10code.com>
+
+ * miscellaneous.c (print_string): Remove.
+
+ * estream.c (es_setvbuf): Fix parameter check.
+ (es_set_buffering): Allow a SIZE of 0.
+ * asshelp.c (setup_libassuan_logging, my_libassuan_log_handler): New.
+ * logging.c (do_logv): Add arg IGNORE_ARG_PTR. Change all callers.
+ (log_string): New.
+ (log_flush): New.
+ (set_file_fd): Simplify by using estreams es_stderr.
+
+ * estream.h (es_stdout, es_stderr, es_stdin): New.
+
+2010-03-10 Werner Koch <wk@g10code.com>
+
+ * estream.c (es_func_fp_read, es_func_fp_write, es_func_fp_seek)
+ (es_func_fp_destroy): Allow a NULL FP to implement a dummy stream.
+ (do_fpopen): Ditto.
+ (es_vfprintf_unlocked): New.
+ (es_fprintf_unlocked): Make public.
+ (es_fputs_unlocked): New.
+
+ * logging.h: Replace FILE* by estream_t.
+ * logging.c: Remove USE_FUNWRITER cpp conditional because we now
+ use estream.
+ (my_funopen_hook_ret_t, my_funopen_hook_size_t): Replace by
+ ssize_t.
+ (log_get_stream): Change to return an estream_t.
+ (set_file_fd): Always close the log stream because it can't be
+ assigned to stderr or stdout directly. Use a dummy estream as
+ last resort log stream.
+ (log_test_fd, log_get_fd): Use es_fileno.
+ (log_get_stream): Assert that we have a log stream.
+ (do_logv): Use estream functions and lock the output.
+
+2010-03-10 Werner Koch <wk@g10code.com>
+
+ * util.h: Replace jnlib path part by common.
+ (snprintf): Use the replacement macro on all platforms.
+
+ * Makefile.am (jnlib_sources): New.
+ (libcommon_a_SOURCES, libcommonpth_a_SOURCES): Add jnlib_sources.
+ (jnlib_tests): New.
+ (noinst_PROGRAMS, TESTS): Add jnlib_tests.
+ (t_common_ldadd): Remove libjnlib.a.
+
+ * README.jnlib, ChangeLog.jnlib, libjnlib-config.h, argparse.c
+ * argparse.h, dotlock.c, dotlock.h, dynload.h, logging.c
+ * logging.h, mischelp.c, mischelp.h, stringhelp.c, stringhelp.h
+ * strlist.c, strlist.h, types.h, utf8conv.c, utf8conv.h
+ * w32-afunix.c, w32-afunix.h, w32-reg.c, w32help.h, xmalloc.c
+ * xmalloc.h, t-stringhelp.c, t-support.c, t-support.h
+ * t-timestuff.c, t-w32-reg.c: Move from jnlib to here.
+
+ * init.c: Remove "estream.h".
+ * util.h: Include "estream.h".
+
+ * xasprintf.c, ttyio.c: Remove "estream-printf.h".
+
+2010-03-08 Werner Koch <wk@g10code.com>
+
+ * exechelp.c [!HAVE_SIGNAL_H]: Do not include signal.h.
+ (DETACHED_PROCESS, CREATE_NEW_PROCESS_GROUP) [W32CE]: Provide stubs.
+
+ * iobuf.h (iobuf_ioctl_t): New. Use the new macros instead of the
+ hard wired values.
+ * iobuf.c (iobuf_append): Remove.
+ (iobuf_fdopen): Factor code out to ...
+ (do_iobuf_fdopen): ... new.
+ (iobuf_fdopen_nc): New.
+ (iobuf_open_fd_or_name): Implement using iobuf_fdopen_nc.
+
+ * iobuf.c (INVALID_FD): Replace by GNUPG_INVALID_FD.
+ (fp_or_fd_t): Replace by gnupg_fd_t.
+ (my_fileno): Replace by the FD2INT macro.
+ (FILEP_OR_FD_FOR_STDIN, FILEP_OR_FD_FOR_STDOUT): Rename to
+ FD_FOR_STDIN, FD_FOR_STDOUT.
+ (file_filter): Make full use of FD_FOR_STDIN.
+ (USE_SETMODE): Remove. Not needed without stdio.
+ (my_fopen_ro, my_fopen): Replace unneeded macros.
+
+ * iobuf.c [FILE_FILTER_USES_STDIO]: Remove all code. It has not
+ been used for a long time.
+
+ * exechelp.h: Include "estream.h".
+
+ * exechelp.c (gnupg_spawn_process): Change OUTFILE to an estream_t.
+
+2010-03-02 Werner Koch <wk@g10code.com>
+
+ * estream.c, estream.h, estream-printf.c, estream-printf.h: Update
+ from libestream.
+
+2010-03-01 Werner Koch <wk@g10code.com>
+
+ * signal.c [!HAVE_SIGNAL_H]: Don't include signal.h.
+
+ * iobuf.c (direct_open) [W32CE]: Make filename to wchar_t.
+ (iobuf_cancel) [W32CE]: Use DeleteFile.
+
+ * gettime.c (dump_isotime): Use "%s" to print "none".
+
+ * homedir.c (standard_homedir) [W32CE]: Use wchar_t to create the
+ directory.
+ (w32_rootdir) [W32CE]: Likewise.
+
+ * sysutils.c (translate_sys2libc_fd) [W32CE]: Add support.
+ (gnupg_tmpfile) [W32CE]: Ditto.
+ (_gnupg_getenv) [W32CE]: New.
+
+ * util.h (getpid, getenv) [W32CE]: New.
+
+ * i18n.c (i18n_switchto_utf8)
+ (i18n_switchback) [USE_SIMPLE_GETTEXT]: Use new function from
+ libgpg-error which supports proper restoring.
+
+ * sysutils.c (get_session_marker): Simplified by using gcrypt.
+
+2009-12-08 Marcus Brinkmann <marcus@g10code.de>
+
+ * Makefile.am (audit-events.h, status.h) [!MAINTAINER_MODE]: No
+ longer include these rules if not in maintainer mode.
+
+2009-12-08 Werner Koch <wk@g10code.com>
+
+ * userids.h, userids.c: New.
+ (classify_user_id): Merged from similar fucntions in sm/ and g10/.
+
+ * dns-cert.c (get_dns_cert): Add support for ADNS.
+
+2009-12-08 Marcus Brinkmann <marcus@g10code.de>
+
+ * asshelp.c (start_new_gpg_agent): Convert posix FD to assuan FD.
+
+ * asshelp.c (start_new_gpg_agent) [HAVE_W32_SYSTEM]: Add missing
+ argument in assuan_socket_connect invocation.
+ * iobuf.c (iobuf_open_fd_or_name): Fix type of FD in function
+ declaration.
+
+2009-12-07 Werner Koch <wk@g10code.com>
+
+ * pka.c (get_pka_info): Add support for ADNS.
+ * src.v (getsrv): Add support for ADNS.
+
+ * srv.c (getsrv): s/xrealloc/xtryrealloc/.
+
+2009-12-04 Werner Koch <wk@g10code.com>
+
+ * Makefile.am (audit-events.h, status-codes.h): Create files in
+ the source dir. Fixes bug#1164.
+
+2009-12-02 Werner Koch <wk@g10code.com>
+
+ * audit.c (proc_type_decrypt, proc_type_sign): Implemented.
+ (proc_type_verify): Print hash algo infos.
+ * audit.h (AUDIT_DATA_CIPHER_ALGO, AUDIT_BAD_DATA_CIPHER_ALSO)
+ (AUDIT_NEW_RECP, AUDIT_DECRYPTION_RESULT, AUDIT_RECP_RESULT)
+ (AUDIT_ATTR_HASH_ALGO, AUDIT_SIGNED_BY, AUDIT_SIGNING_DONE):
+
+2009-11-05 Marcus Brinkmann <marcus@g10code.de>
+
+ * asshelp.c (start_new_gpg_agent): Update use of
+ assuan_socket_connect and assuan_pipe_connect.
+
+2009-11-02 Marcus Brinkmann <marcus@g10code.de>
+
+ * get-passphrase.c (default_inq_cb, membuf_data_cb): Change return
+ type to gpg_error_t.
+
+2009-10-28 Werner Koch <wk@g10code.com>
+
+ * status.h (STATUS_MOUNTPOINT): New.
+
+2009-10-16 Marcus Brinkmann <marcus@g10code.com>
+
+ * Makefile.am (libcommon_a_CFLAGS): Use LIBASSUAN_CFLAGS instead
+ of LIBASSUAN_PTH_CFLAGS.
+
+2009-10-13 Werner Koch <wk@g10code.com>
+
+ * exechelp.c (gnupg_kill_process): New.
+
+2009-09-29 Werner Koch <wk@g10code.com>
+
+ * exechelp.c (create_inheritable_pipe): Rename to
+ create_inheritable_pipe_w.
+ (create_inheritable_pipe_r): New.
+ (gnupg_create_outbound_pipe): New.
+
+ * iobuf.h: Include "sysutils.h"
+
+ * iobuf.c (iobuf_open_fd_or_name): New.
+ (iobuf_get_fname_nonnull): New.
+
+2009-09-23 Marcus Brinkmann <marcus@g10code.de>
+
+ * asshelp.c (start_new_gpg_agent): Allocate assuan context before
+ starting server.
+
+2009-09-03 Werner Koch <wk@g10code.com>
+
+ Update from libestream:
+ * estream-printf.c: Include stdint.h only if HAVE_STDINT_H is
+ defined.
+ * estream-printf.c: Remove all test code. Use macro DEBUG instead
+ of TEST for debugging.
+ * estream-printf.c (pr_float): Make buffer larger for silly high
+ numbers.
+
+2009-08-11 David Shaw <dshaw@jabberwocky.com>
+
+ * ttyio.h, ttyio.c (tty_enable_completion): Some ifdefs around
+ HAVE_LIBREADLINE to allow building when readline isn't available.
+
+2009-08-06 Werner Koch <wk@g10code.com>
+
+ * status.h (STATUS_INV_SGNR, STATUS_NO_SGNR): New.
+ * status.c (get_inv_recpsgnr_code): New.
+
+2009-07-23 David Shaw <dshaw@jabberwocky.com>
+
+ * srv.c (getsrv): Fix type-punning warning.
+
+2009-07-23 Werner Koch <wk@g10code.com>
+
+ * util.h (GPG_ERR_NOT_ENABLED): New.
+ * audit.h (enum): Add AUDIT_CRL_CHECK.
+ * audit.c (proc_type_verify): Show CRL check result.
+
+2009-07-06 Werner Koch <wk@g10code.com>
+
+ * get-passphrase.c (struct agentargs): Add SESSION_ENV and remove
+ obsolete args.
+ (gnupg_prepare_get_passphrase): Ditto.
+
+ * session-env.c, session-env.h: New.
+ * t-session-env.c: New.
+ * Makefile.am (common_sources, module_tests): Add them.
+ * asshelp.h: Include "session-env.h"
+ * asshelp.c (send_one_option): Add arg PUTENV.
+ (send_pinentry_environment): Replace most args by SESSION_ENV and
+ rewrite fucntion.
+ (start_new_gpg_agent): Likewise.
+
+ * t-exechelp.c (test_close_all_fds): Remove debug code.
+
+2009-07-01 Werner Koch <wk@g10code.com>
+
+ * sexputil.c (get_pk_algo_from_canon_sexp): New.
+
+2009-06-29 Werner Koch <wk@g10code.com>
+
+ * estream.c (BUFFER_ROUND_TO_BLOCK): Remove unused macro.
+ (es_func_mem_write): Rewrite reallocation part.
+
+ * estream.c (es_write_sanitized_utf8_buffer): Typo typo fix.
+
+2009-06-25 Werner Koch <wk@g10code.com>
+
+ * estream.c (es_write_sanitized_utf8_buffer): Typo fix.
+
+2009-06-24 Werner Koch <wk@g10code.com>
+
+ * estream.c (es_read_line): In the malloc error case, set
+ MAX_LENGTH to 0 only if requested.
+ * xreadline.c (read_line): Ditto.
+ * estream.c (es_write_sanitized_utf8_buffer): Pass on error from
+ es_fputs.
+ * sexputil.c (get_rsa_pk_from_canon_sexp): Check for error after
+ the loop. Reported by Fabian Keil.
+
+2009-06-22 Werner Koch <wk@g10code.com>
+
+ * estream.c (es_pth_read, es_pth_write) [W32]: New.
+ (ESTREAM_SYS_READ, ESTREAM_SYS_WRITE) [HAVE_PTH]: Use them.
+
+2009-06-03 Werner Koch <wk@g10code.com>
+
+ * estream.c (es_convert_mode): Rewrite and support the "x" flag.
+
+2009-05-28 David Shaw <dshaw@jabberwocky.com>
+
+ From 1.4:
+
+ * http.h, http.c (send_request) Pass in a STRLIST for additional
+ headers. Change all callers.
+
+2009-05-27 David Shaw <dshaw@jabberwocky.com>
+
+ From 1.4:
+
+ * http.h, http.c (send_request): Pass in srvtag and make its
+ presence sufficient to turn the feature on.
+ (http_open): From here.
+ (http_document): And here.
+
+ * srv.c (getsrv): Raise maximum packet size to 2048, as PACKETSZ
+ is too small these days.
+
+2009-05-22 Werner Koch <wk@g10code.com>
+
+ * ttyio.c (tty_cleanup_after_signal): New.
+
+2009-05-19 Werner Koch <wk@g10code.com>
+
+ * simple-pwquery.c (agent_open): Use SUN_LEN
+ (JNLIB_NEED_AFLOCAL): Define and include mischelp.h.
+
+2009-05-07 Werner Koch <wk@g10code.com>
+
+ * sexputil.c (get_rsa_pk_from_canon_sexp): New.
+ * t-sexputil.c (test_make_canon_sexp_from_rsa_pk): Extend the test.
+
+2009-04-28 Werner Koch <wk@g10code.com>
+
+ * sexputil.c (make_canon_sexp_from_rsa_pk): New.
+ * t-sexputil.c (test_make_canon_sexp_from_rsa_pk): New.
+
+2009-04-01 Werner Koch <wk@g10code.com>
+
+ * iobuf.c: Port David's changes from 1.4:
+ (fd_cache_invalidate): Pass return code from close back.
+ (direct_open, iobuf_ioctl): Check that return value.
+ (fd_cache_synchronize): New.
+ (iobuf_ioctl): Add new sub command 4 (fsync).
+
+ * iobuf.c (fd_cache_strcmp): New. Taken from 1.4.
+ (fd_cache_invalidate, fd_cache_close, fd_cache_open): Use it.
+
+ * exechelp.c (gnupg_spawn_process): Implement new flag bit 6.
+ * sysutils.c (gnupg_allow_set_foregound_window): Allow the use of
+ ASFW_ANY.
+
+ * membuf.c (put_membuf, get_membuf): Wipe memory on out of core.
+
+2009-03-31 Werner Koch <wk@g10code.com>
+
+ * percent.c (percent_unescape, percent_plus_unescape): New.
+ (percent_plus_unescape_inplace, percent_unescape_inplace): New.
+ (do_plus_or_plain_unescape, count_unescape, do_unescape): New.
+ (do_unescape_inplace): New.
+ * t-percent.c (test_percent_plus_escape): Test percent_plus_unescape.
+
+ * get-passphrase.c, get-passphrase.h: New.
+ * Makefile.am (without_pth_sources): New.
+
+2009-03-18 Werner Koch <wk@g10code.com>
+
+ * exechelp.c: Include sys/resource.h and sys/stat.h.
+ (get_max_open_fds): New.
+ (do_exec): Use it.
+ (get_all_open_fds): New.
+ (close_all_fds): New.
+ (do_exec): Use close_all_fds.
+ * t-exechelp.c: New.
+
+2009-03-13 David Shaw <dshaw@jabberwocky.com>
+
+ * http.c (do_parse_uri): Properly handle IPv6 literal addresses as
+ per RFC-2732. Adapted from patch by Phil Pennock.
+
+2009-03-12 Werner Koch <wk@g10code.com>
+
+ * gettime.c: Include i18n.h.
+ (dump_isotime): New.
+
+2009-03-06 Werner Koch <wk@g10code.com>
+
+ * sexputil.c (make_canon_sexp): New.
+
+2009-03-03 Werner Koch <wk@g10code.com>
+
+ * exechelp.c (do_exec): Make sure that /dev/null connected FDs are
+ not closed.
+
+2009-01-19 Werner Koch <wk@g10code.com>
+
+ * audit.c (writeout_li): Translate a few more result strings.
+ Fixes bug#970.
+
+ * convert.c (hex2str): Fix optimization to append a nul character.
+
+2008-12-05 Werner Koch <wk@g10code.com>
+
+ * percent.c, t-percent.c: New.
+
+ * exechelp.c (gnupg_spawn_process, gnupg_spawn_process_fd)
+ (gnupg_spawn_process_detached) [W32]: Remove debug output.
+
+2008-11-20 Werner Koch <wk@g10code.com>
+
+ * audit.c (writeout_li): Translate OKTEXT.
+
+2008-11-04 Werner Koch <wk@g10code.com>
+
+ * i18n.c (i18n_init) [USE_SIMPLE_GETTEXT]: Adjust for changed
+ w32-gettext.c.
+ * homedir.c (gnupg_localedir): New.
+
+2008-10-20 Werner Koch <wk@g10code.com>
+
+ * http.c (http_register_tls_callback) [!HTTP_USE_GNUTLS]: Mark
+ unused arg.
+ * localename.c (do_nl_locale_name): Ditto.
+ * audit.c (event2str): Silent gcc warning.
+ * sysutils.c (translate_sys2libc_fd): Mark unused arg.
+ (translate_sys2libc_fd_int): Ditto.
+ * iobuf.c (translate_file_handle): Ditto.
+ * asshelp.c (send_one_option): Ditto.
+ * exechelp.c (gnupg_spawn_process): Ditto.
+ * signal.c (got_usr_signal): Ditto
+ * estream.c (es_func_fd_create) [!W32]: Ditto.
+ (es_func_fp_create) [!W32]: Ditto.
+ (es_write_hexstring): Ditto.
+ (dummy_mutex_call_void, dummy_mutex_call_int) [HAVE_PTH]: New.
+ (ESTREAM_MUTEX_LOCK, ESTREAM_MUTEX_UNLOCK, ESTREAM_MUTEX_TRYLOCK)
+ (ESTREAM_MUTEX_INITIALIZE) [HAVE_PTH]: Use dummy calls so to mark
+ unused arg.
+
+2008-10-19 Werner Koch <wk@g10code.com>
+
+ * estream-printf.c (estream_vsnprintf): Fix return value.
+ (check_snprintf): Add a new test.
+ (one_test) [W32]: Disable test.
+
+2008-10-17 Werner Koch <wk@g10code.com>
+
+ * util.h (snprintf) [W32]: Redefine to estream_snprintf.
+
+2008-09-03 Werner Koch <wk@g10code.com>
+
+ * convert.c (hex2str): New.
+ (hex2str_alloc): New.
+ * t-convert.c (test_hex2str): New.
+
+2008-08-19 Werner Koch <wk@g10code.com>
+
+ * iobuf.c: Avoid passing a NULL (iobuf_t)->desc to the log
+ function. Should in general never be NULL, but well. Reported by
+ M. Heneka.
+
+2008-06-26 Werner Koch <wk@g10code.com>
+
+ * estream.c (es_write_sanitized): Loose check for control
+ characters to better cope with utf-8. The range 0x80..0x9f is
+ nowadays not anymore accidently used for control charaters.
+
+2008-06-25 Marcus Brinkmann <marcus@g10code.de>
+
+ Revert last three changes related to handle translation.
+ * sysutils.c:
+ (FD_TRANSLATE_MAX, fd_translate, fd_translate_len)
+ (translate_table_init, translate_table_lookup): Removed.
+ * iobuf.c (check_special_filename): Do not use
+ translate_table_lookup.
+ * sysutils.h (translate_table_init, translate_table_lookup):
+ Remove prototypes.
+
+2008-06-19 Werner Koch <wk@g10code.com>
+
+ * sysutils.c: Remove <ctype.h>.
+ (fd_translate_max): Use macro for the size.
+ (translate_table_init): Protect read against EINTR and replace
+ isspace by spacep.
+
+2008-06-18 Marcus Brinkmann <marcus@g10code.de>
+
+ * sysutils.c (TRANS_MAX): Bump up to 350 to be on the safe side.
+
+ * sysutils.h (translate_table_init, translate_table_lookup): New
+ prototypes.
+ * sysutils.c: Include <ctype.h>.
+ (FD_TRANSLATE_MAX): New macro.
+ (fd_translate, fd_translate_len): New static variables.
+ (translate_table_init, translate_table_lookup): New functions.
+ (translate_sys2libc_fd_int): Translate file descriptor.
+ * iobuf.c (check_special_filename): Translate handle values from
+ special filenames.
+
+2008-06-16 Werner Koch <wk@g10code.com>
+
+ * homedir.c (w32_commondir): New.
+ (gnupg_sysconfdir): Use it.
+
+2008-06-09 Werner Koch <wk@g10code.com>
+
+ * b64dec.c: New.
+
+2008-06-05 Werner Koch <wk@g10code.com>
+
+ * util.h (gnupg_copy_time): Replace strcpy by memcpy.
+
+2008-05-26 Werner Koch <wk@g10code.com>
+
+ * asshelp.c (send_one_option, send_pinentry_environment): use
+ xfree and xtrystrdup.
+
+ * i18n.c (i18n_switchto_utf8) [USE_SIMPLE_GETTEXT]: Return NULL.
+
+ * homedir.c (gnupg_module_name): Add
+ GNUPG_MODULE_NAME_CONNECT_AGENT and GNUPG_MODULE_NAME_GPGCONF.
+
+2008-04-21 Werner Koch <wk@g10code.com>
+
+ * http.c (http_wait_response) [W32]: Use DuplicateHandle because
+ it is a socket.
+ (cookie_read) [W32]: Use recv in place of read.
+
+2008-04-08 Werner Koch <wk@g10code.com>
+
+ * i18n.c (i18n_switchto_utf8, i18n_switchback)
+ [USE_SIMPLE_GETTEXT]: Implement.
+
+2008-04-07 Werner Koch <wk@g10code.com>
+
+ * b64enc.c (b64enc_start): Detect PGP mode.
+ (b64enc_finish): Write PGP CRC.
+ * util.h (struct b64state): Add field CRC.
+ * t-b64.c: New.
+
+ * pka.c (get_pka_info): Use xtrymalloc and check result.
+
+2008-03-25 Werner Koch <wk@g10code.com>
+
+ * localename.c: Strip all W32 code. Include w32help.h.
+ (gnupg_messages_locale_name) [W32]: Use the gettext_localename.
+
+2008-03-17 Werner Koch <wk@g10code.com>
+
+ * iobuf.c (IOBUF_BUFFER_SIZE): Actually use this macro.
+
+ * simple-pwquery.c (agent_send_all_options): Fix last change.
+
+2008-03-06 Werner Koch <wk@g10code.com>
+
+ * simple-pwquery.c (agent_send_all_options): Add support for
+ XAUTHORITY and PINENTRY_USER_DATA.
+
+2008-02-15 Marcus Brinkmann <marcus@g10code.de>
+
+ * exechelp.c (gnupg_spawn_process_fd): Add flag DETACHED_PROCESS
+ unconditionally (required for all callers at the moment).
+
+2008-02-14 Werner Koch <wk@g10code.com>
+
+ * sysutils.c (gnupg_allow_set_foregound_window): New.
+ (WINVER) [W32]: Define.
+
+2008-01-31 Werner Koch <wk@g10code.com>
+
+ * audit.c (audit_print_result): Make sure that the output is
+ always UTF8.
+
+2008-01-27 Werner Koch <wk@g10code.com>
+
+ * exechelp.c (gnupg_spawn_process): Add arg FLAGS and changed all
+ callers to pass 0 for it.
+
+2007-12-13 Werner Koch <wk@g10code.com>
+
+ * sexputil.c (hash_algo_from_sigval): New.
+ * t-sexputil.c: New.
+ * Makefile.am (module_tests): Add it.
+
+2007-12-11 Werner Koch <wk@g10code.com>
+
+ * asshelp.c (send_pinentry_environment): Allow using of old
+ gpg-agents not capabale of the xauthority and pinentry_user_data
+ options.
+
+2007-12-04 Werner Koch <wk@g10code.com>
+
+ * Makefile.am (t_helpfile_LDADD, module_maint_tests): New.
+ * t-helpfile.c: New.
+ * helpfile.c: New.
+ * membuf.h (is_membuf_ready, MEMBUF_ZERO): New.
+ * localename.c: New. Taken from gettext with modifications as done
+ for GpgOL. Export one new function.
+ * util.h (gnupg_messages_locale_name, gnupg_get_help_string): Added.
+
+ * sysutils.c (gnupg_reopen_std): New. Taken from ../g10/gpg.c.
+
+2007-11-27 Werner Koch <wk@g10code.com>
+
+ * Makefile.am (CLEANFILES): New.
+
+ * homedir.c (dirmngr_socket_name): Use CSIDL_WINDOWS.
+
+2007-11-15 Werner Koch <wk@g10code.com>
+
+ * asshelp.c (send_pinentry_environment): Add args XAUTHORITY and
+ PINENTRY_USER_DATA.
+ (start_new_gpg_agent): Ditto.
+
+2007-11-07 Werner Koch <wk@g10code.com>
+
+ * status.h: New.
+ * errors.h: Remove.
+
+2007-11-05 Werner Koch <wk@g10code.com>
+
+ * audit.c, audit.h: New.
+ * Makefile.am: Add rules to build audit-events.h.
+ * exaudit.awk: New.
+ * mkstrtable.awk: New. Taken from libgpg-error.
+
+2007-10-19 Werner Koch <wk@g10code.com>
+
+ * i18n.c (i18n_switchto_utf8, i18n_switchback): New.
+
+2007-10-01 Werner Koch <wk@g10code.com>
+
+ * sysutils.h (FD2INT, INT2FD): New.
+
+2007-09-21 Werner Koch <wk@g10code.com>
+
+ * homedir.c (default_homedir): Make registry work. Reported by
+ Marc Mutz.
+
+2007-08-29 Werner Koch <wk@g10code.com>
+
+ * exechelp.c (gnupg_wait_process): Add arg EXITCODE. Changed all
+ callers.
+ (gnupg_create_inbound_pipe): New.
+ * util.h (GNUPG_MODULE_NAME_GPGSM, GNUPG_MODULE_NAME_GPG): New.
+ * homedir.c (gnupg_module_name): Add them
+
+2007-08-28 Werner Koch <wk@g10code.com>
+
+ * gettime.c (check_isotime, add_isotime): New. Originally written
+ for DirMngr by me.
+ (add_days_to_isotime): New.
+ (date2jd, jd2date, days_per_month, days_per_year): New. Taken from
+ my ancient (1988) code used in Wedit (time2.c).
+
+2007-08-27 Werner Koch <wk@g10code.com>
+
+ * util.h (GNUPG_MODULE_NAME_CHECK_PATTERN): New.
+ * homedir.c (gnupg_module_name): Add it.
+ * exechelp.c (w32_fd_or_null) [W32]: New.
+ (gnupg_spawn_process_fd): New.
+ (gnupg_wait_process) [W32]: Close the handle after if the process has
+ returned.
+
+2007-08-22 Werner Koch <wk@g10code.com>
+
+ Updated estream from libestream.
+
+ * estream.c (mem_malloc, mem_realloc, mem_free): New. Use them
+ instead of the ES_MEM_foo.
+ * estream.c (estream_cookie_mem): Remove members DONT_FREE,
+ APPEND_ZERO, PTR and SIZE. Add MEMORY_LIMIT. Put GROW into a new
+ FLAGS struct.
+ (es_func_mem_create): Remove APPEND_ZERO, DONT_FREE, PTR and
+ SIZE. Add MEMORY_LIMIT.
+ (es_func_mem_write, es_func_mem_seek, es_func_mem_destroy): Revamp.
+ (es_open_memstream): Change API to just take a memory limit and a
+ mode argument. Rename to ..
+ (es_fopenmem): .. this.
+ (HAVE_W32_SYSTEM) [_WIN32]: Define if not defined.
+ (tmpfd) [W32]: Implement directly using the W32 API.
+ (es_fgets): Rewrite without using doreadline.
+
+2007-08-21 Werner Koch <wk@g10code.com>
+
+ * sysutils.c (gnupg_tmpfile): New.
+ * t-sysutils.c: New.
+ * Makefile.am (module_tests): Add t-sysutils.
+
+2007-08-20 Werner Koch <wk@g10code.com>
+
+ * exechelp.c [W32]: Redefine X_OK to F_OK.
+
+2007-08-16 Werner Koch <wk@g10code.com>
+
+ * Makefile.am (t_convert_DEPENDENCIES): Remove
+ ($(PROGRAMS)): Remove.
+ (t_common_ldadd): Use libcommon.a and not the macro.
+
+2007-08-14 Werner Koch <wk@g10code.com>
+
+ * homedir.c (dirmngr_socket_name): New.
+
+2007-08-07 Werner Koch <wk@g10code.com>
+
+ * tlv.c, tlv.h: Move from ../scd/.
+ * tlv.c (parse_sexp, parse_ber_header): Add ERRSOURCE arg and prefix
+ name with a _.
+ * tlv.h: Use macro to convey ERRSOURCE.
+
+2007-08-02 Werner Koch <wk@g10code.com>
+
+ * gc-opt-flags.h: New.
+
+2007-08-01 Werner Koch <wk@g10code.com>
+
+ * estream-printf.c (read_dummy_value): Removed as it is useless now.
+ (read_values): Remove check on !vaargs which is not anymore needed
+ and anyway not portable. Reported by Peter O'Gorman.
+
+2007-07-16 Werner Koch <wk@g10code.com>
+
+ * estream.c (es_func_file_create): Clear NO_CLOSE flag.
+
+2007-07-12 Werner Koch <wk@g10code.com>
+
+ * sysutils.h (gnupg_fd_t): New.
+ * sysutils.c (translate_sys2libc_fd): Use that type instead of int.
+ (translate_sys2libc_fd_int): New.
+
+2007-07-09 Werner Koch <wk@g10code.com>
+
+ * t-gettime.c (test_isotime2epoch): Use time_t and not u32.
+
+2007-07-05 Werner Koch <wk@g10code.com>
+
+ * t-gettime.c: New.
+ * gettime.c (isotime2epoch, epoch2isotime): New.
+
+2007-07-04 Werner Koch <wk@g10code.com>
+
+ * estream.c (es_init_do): Do not throw an error if pth has already
+ been initialized.
+
+2007-06-26 Werner Koch <wk@g10code.com>
+
+ * Makefile.am ($(PROGRAMS)): New.
+
+ * util.h (init_common_subsystems): Moved to ..
+ * init.h: .. New.
+ * util.h: Include init.h.
+
+ * homedir.c (standard_homedir): New.
+ (default_homedir) [W32]: Reimplemented in terms of
+ standard_homedir. Fixed memory leak.
+
+2007-06-25 Werner Koch <wk@g10code.com>
+
+ * iobuf.c: Add more documentation and slighly restructured macro
+ defintion for better readability.
+ (FILEP_OR_FD): Rename to fp_or_fd_t.
+ (CLOSE_CACHE): Rename to close_cache_t.
+
+ * sysutils.c (translate_sys2libc_fd): New using the code from iobuf.c.
+ * iobuf.c: Include sysutils.h.
+ (iobuf_translate_file_handle): Remove.
+ (translate_file_handle): Use new function.
+
+ * estream-printf.c [TEST]: Header including fixes.
+ (do_format): Do not append a trailing Nul. This avoids spurious
+ Nuls in the es_printf output.
+ (estream_vsnprintf, estream_vasprintf): Take this in account.
+
+ * estream.h (struct es__stream): Change FLAGS to a bit structure.
+ (ES__FLAG_WRITING): Replace by a bit from FLAGS. * estream.c
+ (struct estream_internal): Rename FLAGS to MODEFLAGS so that they
+ are not confused with the estream flags.
+ (es_initialize, es_create): Add arg MODEFLAGS so that we can setup
+ the intial writemode. Changed all callers to pass them.
+ (es_convert_mode): Set O_BINARY.
+ (es_func_fd_create, es_func_fp_create, es_func_file_create) [W32]:
+ Call setmode if requested.
+
+2007-06-24 Werner Koch <wk@g10code.com>
+
+ * estream.c (do_fpopen, es_fpopen, es_fpopen_nc): New.
+ (es_func_fp_create, es_func_fp_read, es_func_fp_write)
+ (es_func_fp_seek, es_func_fp_destroy): New.
+
+2007-06-22 Werner Koch <wk@g10code.com>
+
+ * estream.c (es_fdopen): Factored code out to..
+ (do_fdopen): .. new.
+ (es_fdopen_nc): New.
+ (estream_cookie_fd): Add field NO_CLOSE.
+ (es_func_fd_create): Add arg NO_CLOSE and changed all callers.
+ (es_func_fd_destroy): Handle the new flag.
+
+ * homedir.c (gnupg_libexecdir) [W32]: Factor code out to ..
+ (w32_rootdir): .. new.
+ (gnupg_sysconfdir, gnupg_libdir, gnupg_datadir) [W32]: Return
+ name based on w32_rootdir().
+
+2007-06-21 Werner Koch <wk@g10code.com>
+
+ * membuf.h (get_membuf_len): New.
+
+ * membuf.c (init_membuf_secure): Really allocate in secure memory.
+ (put_membuf_str): New.
+
+ * ttyio.c (tty_getf): New.
+
+ * util.h (ctrl_t): Declare it here.
+
+ * asshelp.c (start_new_gpg_agent): New. Based on code from
+ ../sm/call-agent.c
+
+2007-06-20 Werner Koch <wk@g10code.com>
+
+ * sysutils.c (gnupg_sleep): New.
+ * sysutils.h [W32]: Remove _sleep wrapper. Changed all callers to
+ use gnupg_sleep.
+
+ * exechelp.c (build_w32_commandline_copy): New.
+ (build_w32_commandline): Factored some code out to new function
+ and correctly process a PGMNAME with spaces.
+ (gnupg_spawn_process_detached) [W32]: Implement.
+
+2007-06-14 Werner Koch <wk@g10code.com>
+
+ * simple-pwquery.h (MAP_SPWQ_ERROR_IMPL): New.
+ (SPWQ_NO_PIN_ENTRY): New.
+ * simple-pwquery.c (simple_pw_set_socket): New.
+ (agent_open): Use it if GPG_AGENT_INFO is not set.
+ (simple_pwquery): Extended to allow returning of other error codes.
+
+ * util.h (GNUPG_MODULE_NAME_AGENT, GNUPG_MODULE_NAME_PINENTRY)
+ (GNUPG_MODULE_NAME_SCDAEMON, GNUPG_MODULE_NAME_DIRMNGR)
+ (GNUPG_MODULE_NAME_PROTECT_TOOL): New.
+ * homedir.c (gnupg_module_name): New.
+ (gnupg_bindir): New.
+
+2007-06-12 Werner Koch <wk@g10code.com>
+
+ * homedir.c (gnupg_sysconfdir): New.
+ (gnupg_libexecdir): New. Taken from g10/misc.c:get_libexecdir.
+ (gnupg_datadir): New.
+ (gnupg_libdir): New.
+
+ * http.c (connect_server) [W32]: Do not call init_sockets if
+ HTTP_NO_WSASTARTUP is defined.
+
+ * init.c: New.
+
+ * estream.c (es_init_do): Init stream lock here because we can't
+ use a static initialization with W32pth.
+
+2007-06-11 Werner Koch <wk@g10code.com>
+
+ * Makefile.am (t_common_ldadd): Use libcommonstd macro.
+
+2007-06-06 Werner Koch <wk@g10code.com>
+
+ * Makefile.am: Include am/cmacros.am.
+
+ * sysutils.h [W32]: Remove prototypes for the registry access.
+ * w32reg.c: Move to ../jnlib/w32-reg.c.
+
+ * i18n.c (i18n_init): New.
+
+ * simple-gettext.c: Remove.
+
+ * iobuf.c (iobuf_get_filelength): Rename SIZE to EXSIZE to silent
+ shadowing warning.
+
+2007-06-04 Werner Koch <wk@g10code.com>
+
+ * http.c [W32]: Include unistd.h also in this case.
+ (write_server) [W32]: Fixed error code.
+ (init_sockets): Fixed syntax error.
+ (cookie_close): Replace close by sock_close macro.
+
+ * estream.c [w32]: Do not init Mutex.
+
+ * Makefile.am (common_sources) [USE_SNS_SRV]: Build srv.c only
+ when needed.
+
+ * ttyio.c (init_ttyfp) [W32]: Do not use TTYFP.
+
+ * util.h: Include ../jnlib/dynload.h.
+
+ * dynload.h: Move to ../jnlib.
+
+2007-05-30 Werner Koch <wk@g10code.com>
+
+ * estream.c (MEM_FREE, MEM_ALLOC, MEM_REALLOC): Prefix with ES_ as
+ windows.h also has such definitions,
+
+2007-05-15 Werner Koch <wk@g10code.com>
+
+ * util.h: Do not include gnulib's vasprintf. Redefine asprintf
+ and vasprintf.
+
+ * xasprintf.c (xasprintf, xtryasprintf): Use estream_vasprintf.
+
+ * estream-printf.h, estream-printf.c: New. Taken from current
+ libestream SVN.
+ * Makefile.am (common_sources): Add them.
+
+2007-05-14 Werner Koch <wk@g10code.com>
+
+ * sexp-parse.h (smklen): New.
+ * sexputil.c: Include sexp-parse.h.
+ (make_simple_sexp_from_hexstr): Replace sprintf by smklen.
+
+2007-05-07 Werner Koch <wk@g10code.com>
+
+ * signal.c (got_fatal_signal): Protect SIG from being clobbered by
+ a faulty signal implementaion. Suggested by James Juran.
+
+2007-04-25 Werner Koch <wk@g10code.com>
+
+ * i18n.h (ngettext): New.
+ * simple-gettext.c (ngettext): New.
+
+2007-04-20 Werner Koch <wk@g10code.com>
+
+ * miscellaneous.c (my_gcry_logger, my_gcry_outofcore_handler):
+ Moved from gpg-agent to here.
+ (my_gcry_fatalerror_handler): new.
+ (setup_libgcrypt_logging): New.
+
+2007-03-19 Werner Koch <wk@g10code.com>
+
+ * miscellaneous.c (print_hexstring): New.
+ * estream.c (es_fprintf_unlocked): New.
+ (es_write_sanitized): New.
+ (es_write_hexstring): New.
+ (es_write_sanitized_utf8_buffer) [GNUPG_MAJOR_VERSION]: New.
+
+2007-03-09 David Shaw <dshaw@jabberwocky.com>
+
+ From STABLE-BRANCH-1-4
+
+ * http.c (do_parse_uri): Remove the hkp port 11371 detection. We
+ implement hkp in the keyserver handler, and the support here makes
+ it appear like a bad hkp request actually succeeded.
+
+2007-01-31 Werner Koch <wk@g10code.com>
+
+ * Makefile.am (t_common_ldadd): Add LIBINCONV and LIBINTL.
+
+2007-01-25 Werner Koch <wk@g10code.com>
+
+ * simple-pwquery.c (simple_pwquery): New arg OPT_CHECK.
+
+2006-12-13 David Shaw <dshaw@jabberwocky.com>
+
+ * Makefile.am (AM_CPPFLAGS): Include intl/ so we can reference the
+ built-in headers.
+
+2006-11-23 Werner Koch <wk@g10code.com>
+
+ * http.c: Include i18n.h
+
+2006-11-21 Werner Koch <wk@g10code.com>
+
+ * estream.c: Remove explicit Pth soft mapping diabling becuase it
+ is now done in config.h.
+
+2006-11-15 Werner Koch <wk@g10code.com>
+
+ * estream.c: Disabled Pth soft mapping.
+ (my_funopen_hook_ret_t): New.
+ (print_fun_writer): Use it here.
+
+ * iobuf.c (fd_cache_close): Use %d instead of %p for debug output.
+
+2006-11-03 Werner Koch <wk@g10code.com>
+
+ * Makefile.am (t_convert_DEPENDENCIES): Add libcommon. From
+ Gentoo.
+
+2006-10-24 Marcus Brinkmann <marcus@g10code.de>
+
+ * Makefile.am (libcommon_a_CFLAGS): Add $(LIBASSUAN_CFLAGS).
+ (libsimple_pwquery_a_CFLAGS): New variable.
+
+2006-10-20 Werner Koch <wk@g10code.com>
+
+ * convert.c (hex2bin): New.
+
+2006-10-17 Werner Koch <wk@g10code.com>
+
+ * estream.c (struct estream_internal, es_initialize)
+ (es_deinitialize, print_fun_writer, es_print): New and modified
+ functions to avoid tempfiles for printf style printing.
+
+ * Makefile.am (libcommonpth_a_SOURCES): New. We now build a secon
+ version of the library with explicit Pth support.
+ * exechelp.c, estream.c: Make use of WITHOUT_GNU_PTH.
+
+2006-10-08 Werner Koch <wk@g10code.com>
+
+ * gpgrlhelp.c: Trun all functions into dummies if readline is not
+ available.
+
+2006-10-06 Werner Koch <wk@g10code.com>
+
+ * Makefile.am (AM_CFLAGS): Use PTH version of libassuan.
+
+ * util.h (GNUPG_GCC_A_SENTINEL): Defined for gcc >= 4.
+
+2006-10-04 David Shaw <dshaw@jabberwocky.com>
+
+ * gpgrlhelp.c: readline requires stdio.h.
+
+2006-10-04 Werner Koch <wk@g10code.com>
+
+ * membuf.c (init_membuf_secure): New.
+ (put_membuf): Make sure that ERRNO is set even if the underlying
+ malloc code does not work properly.
+ (get_membuf): Set ERRNO on error.
+ (get_membuf): Allow to pass LEN as NULL.
+
+2006-10-02 Werner Koch <wk@g10code.com>
+
+ * iobuf.c (iobuf_unread): Removed. This code is not required.
+ Also removed the entire unget buffer stuff.
+
+2006-09-27 Werner Koch <wk@g10code.com>
+
+ * util.h: Do not include strsep.h and strpbrk.h.
+ (isascii): Removed as it is now in jnlib.
+
+ * iobuf.c (pop_filter, underflow, iobuf_close): Free the unget
+ buffer.
+
+2006-09-27 Florian Weimer <fweimer@bfk.de> (wk)
+
+ * iobuf.c (iobuf_unread): New.
+
+2006-09-22 Werner Koch <wk@g10code.com>
+
+ * i18n.h: Changed license to an all permissive one.
+
+ * ttyio.c (tty_get): We need to use readline too. Added two more
+ hooks.
+
+2006-09-21 Werner Koch <wk@g10code.com>
+
+ * ttyio.c (tty_private_set_rl_hooks): New.
+ (tty_enable_completion, tty_disable_completion): Use a hook to
+ enable readline support. Now always available.
+ (tty_cleanup_rl_after_signal): New.
+
+ * ttyio.h: Removed readline specific stuff. Included util.h.
+ * common-defs.h: New.
+
+2006-09-15 Werner Koch <wk@g10code.com>
+
+ * convert.c: New.
+ (hexcolon2bin): New.
+ (bin2hex, bin2hexcolon, do_binhex): New.
+ * t-convert.c: New
+
+2006-09-14 Werner Koch <wk@g10code.com>
+
+ * util.h (out_of_core): Use new gpg_error_from_syserror function.
+
+ * http.c (init_sockets): Changed it to require 2.2 unless it is
+ build within gnupg 1 where we require 1.1 (and not anymore allow
+ for 1.0).
+
+2006-09-07 Werner Koch <wk@g10code.com>
+
+ * exechelp.c (gnupg_spawn_process): Factor out post fork code to ..
+ (do_exec): .. new function. Allow passing of -1 for the fds.
+ (gnupg_spawn_process): Terminate gcrypt's secure memory in the child.
+ (gnupg_spawn_process_detached): New.
+
+2006-09-06 Werner Koch <wk@g10code.com>
+
+ * maperror.c: Removed.
+
+ * util.h (out_of_core): New.
+
+2006-09-04 Werner Koch <wk@g10code.com>
+
+ * http.c (http_get_header): New.
+ (capitalize_header_name, store_header): New.
+ (parse_response): Store headers away.
+ (send_request): Return GPG_ERR_NOT_FOUND if connect_server failed.
+ * http.h: New flag HTTP_FLAG_NEED_HEADER.
+
+2006-08-21 Werner Koch <wk@g10code.com>
+
+ * Makefile.am (libcommon_a_SOURCES): Added keyserver.h
+
+ * openpgpdefs.h: New. Stripped from ..g10/packet.h.
+
+2006-08-16 Werner Koch <wk@g10code.com>
+
+ * keyserver.h: Moved from ../include to here.
+
+ * http.c: Include srv.h.
+
+ * srv.c, srv.h: New. Taken from GnuPG 1.4
+
+2006-08-14 Werner Koch <wk@g10code.com>
+
+ * http.h (struct http_context_s): Moved to implementation.
+ * http.c (http_open): Changed call to return a context.
+ (http_open_document): Ditto.
+ (http_get_read_ptr, http_get_read_ptr, http_get_status_code): New.
+ (do_parse_uri): Replaced strlwr by straight code to ease
+ standalone use of this file.
+ (http_wait_response): Removed arg STATUS_CODE as it is available
+ through an accessor function. Adjusted caller.
+ (http_escape_string): New.
+
+ * estream.c (es_read_line): Renamed to ..
+ (doreadline): .. this. Changed all callers.
+ (es_read_line): New. This is theusual limited getline variabnt as
+ used at several places. Here taken and adjusted from xreadline.c
+ (es_free): New.
+
+2006-08-11 Werner Koch <wk@g10code.com>
+
+ * http.c: Major internal changes to optionallly support GNUTLS and
+ ESTREAM.
+ (http_open): Move initialization of the stream ...
+ (send_request): .. here.
+ (http_register_tls_callback): New.
+
+ * estream.c (es_writen): Try to seek only is a seek function has
+ been registered.
+
+2006-08-09 Werner Koch <wk@g10code.com>
+
+ * http.c, http.h: New. Taken from gnupg 1.4.5, merged with
+ changes done for the Dirmngr project (by g10 Code) and cleaned up
+ some stuff.
+ (make_header_line): New. Change all caller to make user of the new
+ * Makefile.am (libcommon_a_SOURCES): Added http.c and http.h.
+
+2006-05-23 Werner Koch <wk@g10code.com>
+
+ * gettime.c (isotimestamp): New.
+
+ * ttyio.c (tty_get_ttyname): Posixly correct usage of ctermid.
+
+ * dns-cert.c: New. Taken from 1.4.3's util/cert.c.
+ * dns-cert.h: New.
+
+2006-05-22 Werner Koch <wk@g10code.com>
+
+ * pka.c: New. Taked from 1.4.3.
+ * pka.h: New.
+ * Makefile.am: Added pka.
+
+2006-05-19 Werner Koch <wk@g10code.com>
+
+ * yesno.c (answer_is_yes_no_default, answer_is_yes_no_quit):
+ Updated from 1.4.3.
+ (answer_is_okay_cancel): new. From 1.4.3.
+
+ * miscellaneous.c (match_multistr): New. Taken from 1.4.3.
+
+ * ttyio.c (tty_enable_completion, tty_disable_completion): New
+ dummy functions.
+ * ttyio.h: Add prototypes and stubs.
+
+2006-04-19 Werner Koch <wk@g10code.com>
+
+ * iobuf.c (iobuf_get_fd): New. Taken from 1.4.3.
+ (iobuf_is_pipe_filename): New.
+ (pop_filter): Made static.
+ (iobuf_skip_rest): New. Orginal patch by Florian
+ Weimer. Added new argument PARTIAL.
+ (block_filter): Remove the old gpg indeterminate length mode.
+ (block_filter): Properly handle a partial body stream
+ that ends with a 5-byte length that happens to be zero.
+ (iobuf_set_block_mode, iobuf_in_block_mode): Removed as
+ superfluous.
+ (iobuf_get_filelength): New arg OVERFLOW.
+ (iobuf_get_filelength) [W32]: Use GetFileSizeEx if available
+ * miscellaneous.c (is_file_compressed): Take care of OVERFLOW.
+
+2006-04-18 Werner Koch <wk@g10code.com>
+
+ * homedir.c (w32_shgetfolderpath): New. Taken from gpg 1.4.3.
+ (default_homedir): Use it.
+
+2005-10-08 Marcus Brinkmann <marcus@g10code.de>
+
+ * signal.c (get_signal_name): Check value of HAVE_DECL_SYS_SIGLIST
+ instead of just if it is defined.
+
+2005-09-28 Marcus Brinkmann <marcus@g10code.de>
+
+ * Makefile.am (AM_CFLAGS): Add $(LIBASSUAN_CFLAGS).
+
+2005-07-04 Marcus Brinkmann <marcus@g10code.de>
+
+ * simple-pwquery.h (simple_pwclear): New prototype.
+ * simple-pwquery.c (simple_pwclear): New function.
+
+2005-06-15 Werner Koch <wk@g10code.com>
+
+ * miscellaneous.c (make_printable_string): Made P a void*.
+
+ * sexputil.c (keygrip_from_canon_sexp, cmp_simple_canon_sexp):
+ Fixed signed/unsigned pointer mismatch.
+ (make_simple_sexp_from_hexstr): Ditto. This is all too ugly; I
+ wonder why gcc-4's default is to warn about them and forcing us to
+ use cast the warning away.
+ * iobuf.c (block_filter): Ditto.
+ (iobuf_flush): Ditto.
+ (iobuf_read_line): Ditto.
+ (iobuf_read): Make BUFFER a void *.
+ (iobuf_write): Make BUFFER a const void *.
+ * ttyio.c (tty_print_utf8_string2): Ditto.
+ * estream.c (estream_cookie_mem): Make MEMORY unsigned char*.
+ (es_write): Make BUFFER a void *.
+ (es_writen): Ditto.
+ (es_func_fd_read, es_func_fd_write, es_func_mem_read)
+ (es_func_mem_write): Ditto.
+ (es_read, es_readn): Ditto.
+ (es_func_mem_write): Made MEMORY_NEW an unsigned char *.
+ * estream.h (es_cookie_read_function_t)
+ (es_cookie_write_function_t): Changed buffer arg to void*.
+
+2005-06-03 Werner Koch <wk@g10code.com>
+
+ * estream.c: Use HAVE_CONFIG_H and not USE_CONFIG_H!
+ (es_func_fd_read, es_func_fd_write): Protect against EINTR.
+
+2005-06-01 Werner Koch <wk@g10code.com>
+
+ * Makefile.am (AM_CPPFLAGS): Added.
+
+ * util.h: Add some includes for gnulib.
+ (ttyname, isascii): Define them inline.
+ * fseeko.c, ftello.c: Removed.
+ * strsep.c, mkdtemp.c: Removed.
+ * ttyname.c, isascii.c: Removed.
+
+2005-05-31 Werner Koch <wk@g10code.com>
+
+ * dynload.h: s/__inline__/inline/.
+
+2005-05-13 Werner Koch <wk@g10code.com>
+
+ * signal.c (got_fatal_signal): Print the signal number if we can't
+ get a name for it.
+ (get_signal_name): Return NULL if no name is available. Fixed
+ conditional for sys_siglist to the correct one.
+
+2005-04-17 Werner Koch <wk@g10code.com>
+
+ * sexputil.c (cmp_simple_canon_sexp): New.
+ (make_simple_sexp_from_hexstr): New.
+
+2005-04-07 Werner Koch <wk@g10code.com>
+
+ * sexputil.c: New.
+
+2005-04-11 Marcus Brinkmann <marcus@g10code.de>
+
+ * simple-pwquery.c (simple_pwquery): Use spwq_secure_free.
+
+2005-03-03 Werner Koch <wk@g10code.com>
+
+ * Makefile.am (AM_CFLAGS): Added PTH_CFLAGS. Noted by Kazu Yamamoto.
+
+2005-02-25 Werner Koch <wk@g10code.com>
+
+ * xasprintf.c (xtryasprintf): New.
+
+2005-01-26 Moritz Schulte <moritz@g10code.com>
+
+ * Makefile.am (libcommon_a_SOURCES): New source files: estream.c,
+ estream.h.
+ * estream.c, estream.h: New files.
+
+2005-01-03 Werner Koch <wk@g10code.com>
+
+ * asshelp.c (send_pinentry_environment): Fixed changed from
+ 2004-12-18; cut+paste error for lc-messages.
+
+2004-12-21 Werner Koch <wk@g10code.com>
+
+ * simple-pwquery.c (agent_open) [W32]: Implement for W32.
+ (readline) [W32]: Use recv instead of read.
+ (writen) [W32]: Use send instead of write.
+ (my_stpcpy): Define a stpcpy replacement so that this file
+ continues to be self-contained.
+ (agent_send_all_options) [W32]: Don't call ttyname.
+
+2004-12-21 Marcus Brinkmann <marcus@g10code.de>
+
+ * simple-pwquery.h (simple_query): Add prototype.
+ * simple-pwquery.c (simple_query): New function.
+
+2004-12-21 Werner Koch <wk@g10code.com>
+
+ * signal.c (got_fatal_signal, got_usr_signal)
+ (got_fatal_signal) [DOSISH]: Don't build.
+ * simple-gettext.c: Include sysutils.h
+
+ * homedir.c: New. Use CSIDL_APPDATA for W32 as the default home
+ directory.
+ * Makefile.am (libcommon_a_SOURCES): Add it.
+ (EXTRA_DIST): Removed mkerror and mkerrtok.
+
+2004-12-20 Werner Koch <wk@g10code.com>
+
+ * sysutils.h [W32]: Define sleep.
+ * util.h: Add prototype for mkdtemp.
+
+ * membuf.c (put_membuf): Wipe out buffer after a failed realloc.
+
+2004-12-19 Werner Koch <wk@g10code.com>
+
+ * maperror.c (map_assuan_err_with_source): Oops, args were swapped.
+
+2004-12-18 Werner Koch <wk@g10code.com>
+
+ * maperror.c (map_assuan_err): Renamed to ..
+ (map_assuan_err_with_source): .. this and add arg SOURCE.c
+ * asshelp.c (send_pinentry_environment, send_one_option): Add arg
+ ERRSOURCE.
+
+2004-12-15 Werner Koch <wk@g10code.com>
+
+ * sysutils.h [W32]: Prototypes for registry functions.
+ * w32reg.c: Include sysutils.h
+
+ * simple-pwquery.c [W32]: Dummy code to allow a build.
+
+ * exechelp.c [W32]: Implemented for W32 .
+
+ * ttyname.c: New.
+
+ * asshelp.c (send_one_option): New.
+ (send_pinentry_environment): Cleaned up and made sure that empty
+ values are not send.
+
+2004-12-07 Werner Koch <wk@g10code.com>
+
+ * asshelp.c (send_pinentry_environment) [W32]: Do not use ttyname.
+
+2004-12-06 Werner Koch <wk@g10code.com>
+
+ * exechelp.h, exechelp.c: New. Based on code from ../sm/import.c.
+
+2004-12-03 Werner Koch <wk@g10code.com>
+
+ * strsep.c: Fixed copyright comments.
+
+2004-11-26 Werner Koch <wk@g10code.com>
+
+ * simple-gettext.c: New taken from gnupg 1.3.x
+
+ * simple-pwquery.c [_WIN32]: Include winsock2.h.
+ (agent_open): Disable it until we have our AF_UNIX implementation
+ ready.
+ * fseeko.c, ftello.c: Include sys/types for the sake of W32.
+
+2004-11-23 Werner Koch <wk@g10code.com>
+
+ * b64enc.c: Include stdio.h and string.h
+
+2004-08-18 Werner Koch <wk@g10code.de>
+
+ * simple-pwquery.c (simple_pwquery): Handle gpg-error style return
+ code for canceled.
+
+2004-07-20 Werner Koch <wk@g10code.de>
+
+ * maperror.c: Removed header ksba.h. Not required anymore.
+
+2004-06-14 Werner Koch <wk@gnupg.org>
+
+ * xreadline.c: New. Based on the iobuf_read_line function.
+
+2004-05-12 Werner Koch <wk@gnupg.org>
+
+ * util.h (xtrycalloc_secure,xtrymalloc_secure): New.
+
+2004-05-11 Werner Koch <wk@gnupg.org>
+
+ * sysutils.c (disable_core_dumps): Only set the current limit.
+ (enable_core_dumps): New.
+
+2004-04-13 Werner Koch <wk@gnupg.org>
+
+ * simple-pwquery.c (copy_and_escape): Relaxed quoting.
+
+2004-04-05 Werner Koch <wk@gnupg.org>
+
+ * errors.h (STATUS_NEWSIG): New.
+
+2004-03-11 Werner Koch <wk@gnupg.org>
+
+ * dynload.h [__MINGW32__]: Define RTLD_LAZY.
+
+2004-03-09 Werner Koch <wk@gnupg.org>
+
+ * maperror.c (map_assuan_err): Map the Locale_Problem item.
+
+2004-03-03 Werner Koch <wk@gnupg.org>
+
+ * asshelp.c, asshelp.h: New.
+ (send_pinentry_environment): New. Code taken from ../sm/call-agent.c.
+
+2004-02-19 Werner Koch <wk@gnupg.org>
+
+ * simple-pwquery.c (agent_open): Don't mangle INFOSTR.
+
+2004-02-17 Werner Koch <wk@gnupg.org>
+
+ * simple-pwquery.c (agent_open): Ignore an empty GPG_AGENT_INFO.
+
+ * errors.h: Added STATUS_IMPORT_OK.
+
+2004-02-10 Werner Koch <wk@gnupg.org>
+
+ * b64enc.c: New. Based on code from ../sm/base64.c.
+
+2004-01-30 Marcus Brinkmann <marcus@g10code.de>
+
+ * Makefile.am (libcommon_a_SOURCES): Add xasprintf.c.
+ * miscellaneous.c (xasprintf): Moved to ...
+ * xasprintf (xasprintf): ... here. New file.
+ This allows to use xasprintf without sucking in gpg-error.
+
+2004-01-27 Werner Koch <wk@gnupg.org>
+
+ * sexp-parse.h: New; moved from../agent.
+
+ * util.h (xtoi_4): New.
+
+2003-12-23 Werner Koch <wk@gnupg.org>
+
+ * maperror.c (map_assuan_err): Prepared for a new error code.
+
+2003-12-17 Werner Koch <wk@gnupg.org>
+
+ * gettime.c (asctimestamp): Add a note on a non-avoidable gcc warning.
+
+ * util.h [!HAVE_VASPRINTF]: Add printf format attribute to the
+ replacement function.
+
+ * miscellaneous.c (xasprintf): New.
+
+2003-11-14 Werner Koch <wk@gnupg.org>
+
+ * mkdtemp.c (mkdtemp): Use gcry_create_nonce.
+
+ * cryptmiss.c: Removed.
+
+2003-11-13 Werner Koch <wk@gnupg.org>
+
+ * util.h (vasprintf): Also fixed the prototype.
+
+ * vasprintf.c (vasprintf): ARGS should not be a pointer. Fixed
+ segv on Solaris. Reported by Andrew J. Schorr.
+
+2003-11-12 Werner Koch <wk@gnupg.org>
+
+ * maperror.c (map_ksba_err, map_gcry_err, map_kbx_err): Removed.
+
+2003-10-31 Werner Koch <wk@gnupg.org>
+
+ * util.h (gnupg_isotime_t): New.
+ (gnupg_copy_time): New.
+
+ * gettime.c (gnupg_get_isotime): New.
+
+2003-09-23 Werner Koch <wk@gnupg.org>
+
+ * iobuf.c (check_special_filename): Replaced is isdigit by digitp
+ to avoid passing negative values and potential locale problems.
+ Problem noted by Christian Biere.
+
+ * util.h (ascii_isspace): New.
+
+2003-09-18 Werner Koch <wk@gnupg.org>
+
+ * ttyio.c (tty_fprintf): New.
+ (tty_print_string, tty_print_utf8_string2)
+ (tty_print_utf8_string): Made P argument const byte*.
+
+2003-08-20 Marcus Brinkmann <marcus@g10code.de>
+
+ * maperror.c (map_ksba_err): Map -1. Use gpg_err_make to set
+ the error source.
+
+2003-08-14 Timo Schulz <twoaday@freakmail.de>
+
+ * dynload.h. New. W32 wrapper around the dynload mechanism.
+
+2003-07-15 Werner Koch <wk@gnupg.org>
+
+ * simple-pwquery.c, simple-pwquery.h: New; moved from ../agent.
+ * Makefile.am (libsimple_pwquery_a_LIBADD): New.
+
+2003-06-25 Werner Koch <wk@gnupg.org>
+
+ * maperror.c (map_to_assuan_status): Directly map 0 to 0.
+
+2003-06-17 Werner Koch <wk@gnupg.org>
+
+ * gettime.c (scan_isodatestr,add_days_to_timestamp,strtimevalue)
+ (strtimestamp,asctimestamp): New. Code taken from gnupg 1.3.2
+ mischelp.c.
+
+ * yesno.c: New. Code taken from gnupg 1.3.2 mischelp.c
+
+ * miscellaneous.c: New.
+
+ * util.h: Include utf8conf.h
+
+2003-06-16 Werner Koch <wk@gnupg.org>
+
+ * gettime.c (make_timestamp): New.
+
+ * ttyio.c: New. Taken from gnupg 1.2.
+ * ttyio.h: Move from ../include.
+
+2003-06-13 Werner Koch <wk@gnupg.org>
+
+ * util.h (seterr): Removed macro.
+ (xmalloc_secure,xcalloc_secure): New.
+
+2003-06-11 Werner Koch <wk@gnupg.org>
+
+ * iobuf.c (iobuf_writebyte,iobuf_write): Return error code from
+ iobuf_flush.
+ (iobuf_writestr): Ditto.
+
+2003-06-10 Werner Koch <wk@gnupg.org>
+
+ * iobuf.c, iobuf.h: New. Taken from current gnupg 1.3 CVS. Run
+ indent on it and adjusted error handling to libgpg-error style.
+ Replaced IOBUF by iobuf_t. Renamed malloc functions.
+
+2003-06-04 Werner Koch <wk@gnupg.org>
+
+ * errors.h: Removed all error codes. We keep the status codes for
+ now.
+ * Makefile.am: Do not create errors.c anymore; remove it from the
+ sources.
+
+ * maperror.c: Don't include error.h. Change all error codes to
+ libgpg-error style.
+ (map_assuan_err): Changed to new Assuan error code convention.
+ (map_to_assuan_status): Likewise.
+ (map_gcry_err,map_kbx_err): Not needed. For now dummy functions.
+
+ * membuf.c, membuf.h: New. Code taken from ../sm/call-agent.h.
+ * Makefile.am: Added above.
+
+2003-04-29 Werner Koch <wk@gnupg.org>
+
+ * util.h (fopencokokie): Removed prototype and struct.
+
+ * fopencookie.c: Removed.
+
+ * maperror.c: Use system assuan.h
+
+2002-10-31 Neal H. Walfield <neal@g10code.de>
+
+ * isascii.c: New file.
+ * putc_unlocked.c: Likewise.
+
+2002-10-28 Neal H. Walfield <neal@g10code.de>
+
+ * signal.c (caught_fatal_sig): Remove superfluous zero
+ initializer.
+ (caught_sigusr1): Likewise.
+
+2002-09-04 Neal H. Walfield <neal@g10code.de>
+
+ * vasprintf.c (vasprintf) [va_copy]: Use va_copy.
+ [!va_copy && __va_copy]: Use __va_copy.
+ [!va_copy && !__va_copy]: Only now fall back to using memcpy.
+
+2002-08-21 Werner Koch <wk@gnupg.org>
+
+ * errors.h: Added STATUS_IMPORT_PROBLEM.
+
+2002-08-20 Werner Koch <wk@gnupg.org>
+
+ * vasprintf.c: Hack to handle NULL for %s.
+
+2002-08-09 Werner Koch <wk@gnupg.org>
+
+ * signal.c: New. Taken from GnuPG 1.1.91.
+
+2002-07-23 Werner Koch <wk@gnupg.org>
+
+ * util.h (_IO_cookie_io_functions_t): Fixed typo. Noted by
+ Richard Lefebvre.
+
+2002-07-22 Werner Koch <wk@gnupg.org>
+
+ * fseeko.c, ftello.c: New.
+
+2002-06-28 Werner Koch <wk@gnupg.org>
+
+ * maperror.c (map_to_assuan_status): Map more errorcodes to Bad
+ Certificate.
+
+2002-06-26 Werner Koch <wk@gnupg.org>
+
+ * maperror.c (map_to_assuan_status): Map EOF to No_Data_Available.
+
+2002-06-10 Werner Koch <wk@gnupg.org>
+
+ * errors.h (gnupg_error_token): Add new prototype.
+ (STATUS_ERROR): New.
+
+ * mkerrtok: New.
+ * Makefile.am: Use it to create the new error token function.
+
+2002-06-04 Werner Koch <wk@gnupg.org>
+
+ * maperror.c (map_to_assuan_status): Map Bad_CA_Certificate.
+
+2002-05-23 Werner Koch <wk@gnupg.org>
+
+ * no-pth.c, Makefile.am: Removed.
+
+2002-05-22 Werner Koch <wk@gnupg.org>
+
+ * mkdtemp.c: Replaced byte by unsigned char because it is no longer
+ defined in gcrypt.h.
+
+2002-05-21 Werner Koch <wk@gnupg.org>
+
+ * maperror.c (map_gcry_err): Add libgcrypt's new S-expression errors.
+ (map_ksba_err): Add a few mappings.
+
+2002-05-14 Werner Koch <wk@gnupg.org>
+
+ * gettime.c: New.
+
+2002-05-03 Werner Koch <wk@gnupg.org>
+
+ * errors.h: Added STARUS_EXPSIG and STATUS_EXPKEYSIG.
+
+2002-04-15 Werner Koch <wk@gnupg.org>
+
+ * cryptmiss.c: New.
+
+2002-02-14 Werner Koch <wk@gnupg.org>
+
+ * maperror.c: Add more assuan<->gnupg mappings.
+
+2002-02-12 Werner Koch <wk@gnupg.org>
+
+ * fopencookie.c: Dummy function.
+
+ * vasprintf.c: New. Taken from binutils-2.9.1 and dropped all non
+ ANSI-C stuff. Merged with asprintf version.
+
+ * no-pth.c: New.
+
+2002-01-23 Werner Koch <wk@gnupg.org>
+
+ * mkdtemp.c: Copied from gnupg-1.0.6c and changed to use libgcrypt.
+
+2002-01-19 Werner Koch <wk@gnupg.org>
+
+ * sysutils.c: New. This is the misc.c file from gnupg 1.0.6 with
+ the OpenPGP stuff removed.
+ * sysutils.h: New.
+
+2002-01-15 Werner Koch <wk@gnupg.org>
+
+ * maperror.c: Add mapping for Not_Trusted.
+
+2002-01-11 Werner Koch <wk@gnupg.org>
+
+ * maperror.c (map_assuan_err): Codes for CRL
+
+2002-01-08 Werner Koch <wk@gnupg.org>
+
+ * util.h (spacep): New.
+
+2002-01-02 Werner Koch <wk@gnupg.org>
+
+ * maperror.c (map_to_assuan_status): New. Merged from ../agent
+ and ../sm.
+
+2001-12-20 Werner Koch <wk@gnupg.org>
+
+ * maperror.c (map_gcry_err): Add some mappings.
+
+2001-12-18 Werner Koch <wk@gnupg.org>
+
+ * Makefile.am (AM_CPPFLAGS): Include flags for gcrypt and ksba
+
+2001-12-14 Werner Koch <wk@gnupg.org>
+
+ * util.h (digitp, hexdigitp): New ctype like macros.
+ (atoi_1,atoi_2,atoi_4,xtoi_1,xtoi_2): New.
+
+
+ Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+ 2009, 2010, 2011 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.
+
+Local Variables:
+buffer-read-only: t
+End:
diff --git a/common/ChangeLog-2011.include b/common/ChangeLog-2011.include
new file mode 100644
index 0000000..b9ca861
--- /dev/null
+++ b/common/ChangeLog-2011.include
@@ -0,0 +1,458 @@
+# This is the ChangeLog-2011 from the former ../include directory. It
+# was moved to here after the removal of the directory on 2014-01-29.
+
+2011-12-01 Werner Koch <wk@g10code.com>
+
+ NB: ChangeLog files are no longer manually maintained. Starting
+ on December 1st, 2011 we put change information only in the GIT
+ commit log, and generate a top-level ChangeLog file from logs at
+ "make dist". See doc/HACKING for details.
+
+2011-02-01 Werner Koch <wk@g10code.com>
+
+ * cipher.h (PUBKEY_MAX_NPKEY, PUBKEY_MAX_NSKEY): Bump up to
+ accommodate gcrypt ECC keys.
+
+2011-01-21 Werner Koch <wk@g10code.com>
+
+ * cipher.h (GCRY_PK_USAGE_CERT): Remove compatibility macros
+ because we now require libgcrypt 1.4.6.
+ (GCRY_PK_ECDH): Add replacement.
+
+2009-08-20 Daiki Ueno <ueno@unixuser.org> (wk)
+
+ * cipher.h (struct DEK): Add field S2K_CACHEID.
+
+2008-04-18 Werner Koch <wk@g10code.com>
+
+ * cipher.h (CIPHER_ALGO_CAMELLIA256): Change ID to 13.
+ (CIPHER_ALGO_CAMELLIA192): New.
+
+2007-12-12 Werner Koch <wk@g10code.com>
+
+ * cipher.h (CIPHER_ALGO_CAMELLIA128, CIPHER_ALGO_CAMELLIA256): New.
+
+2006-09-20 Werner Koch <wk@g10code.com>
+
+ * errors.h, http.h, memory.h, mpi.h, util.h, i18n.h: Removed.
+ * Makefile.am: New.
+ * distfiles: Removed.
+
+2006-08-16 Werner Koch <wk@g10code.com>
+
+ * keyserver.h: Moved to ../common.
+ * http.h: Retired.
+
+2006-04-28 Werner Koch <wk@g10code.com>
+
+ * cipher.h (DIGEST_ALGO_SHA224): Define it.
+
+2006-04-18 Werner Koch <wk@g10code.com>
+
+ * keyserver.h, i18n.h, http.h, cipher.h: Updated to gpg 1.4.3.
+
+2003-09-04 David Shaw <dshaw@jabberwocky.com>
+
+ * cipher.h: Drop TIGER/192 support.
+
+ * types.h: Prefer using uint64_t when creating a 64-bit unsigned
+ type. This avoids a warning on compilers that support but complain
+ about unsigned long long.
+
+ * util.h: Make sure that only ascii is passed to isfoo
+ functions. (From Werner on stable branch).
+
+2003-09-04 Werner Koch <wk@gnupg.org>
+
+ * cipher.h (PUBKEY_USAGE_AUTH): Added.
+
+2003-07-03 Werner Koch <wk@gnupg.org>
+
+ * cipher.h (DBG_CIPHER,g10c_debug_mode): Removed.
+
+2003-06-11 Werner Koch <wk@gnupg.org>
+
+ * cipher.h: Include gcrypt.h and mapped cipher algo names to
+ gcrypt ones. Removed twofish_old and skipjack. Removed all
+ handle definitions and other raerely used stuff. This file will
+ eventually be entirely removed.
+
+2003-06-10 Werner Koch <wk@gnupg.org>
+
+ * types.h (struct strlist): Removed.
+
+2003-05-24 David Shaw <dshaw@jabberwocky.com>
+
+ * cipher.h, i18n.h, iobuf.h, memory.h, mpi.h, types.h, util.h:
+ Edit all preprocessor instructions to remove whitespace before the
+ '#'. This is not required by C89, but there are some compilers
+ out there that don't like it.
+
+2003-05-14 David Shaw <dshaw@jabberwocky.com>
+
+ * types.h: Add initializer macros for 64-bit unsigned type.
+
+2003-05-02 David Shaw <dshaw@jabberwocky.com>
+
+ * cipher.h: Add constants for compression algorithms.
+
+2003-03-11 David Shaw <dshaw@jabberwocky.com>
+
+ * http.h: Add HTTP_FLAG_TRY_SRV.
+
+2003-02-11 David Shaw <dshaw@jabberwocky.com>
+
+ * types.h: Try and use uint64_t for a 64-bit type.
+
+2003-02-04 David Shaw <dshaw@jabberwocky.com>
+
+ * cipher.h: Add constants for new SHAs.
+
+2002-11-13 David Shaw <dshaw@jabberwocky.com>
+
+ * util.h [__CYGWIN32__]: Don't need the registry prototypes. From
+ Werner on stable branch.
+
+2002-11-06 David Shaw <dshaw@jabberwocky.com>
+
+ * util.h: Add wipememory2() macro (same as wipememory, but can
+ specify the byte to wipe with).
+
+2002-10-31 Stefan Bellon <sbellon@sbellon.de>
+
+ * util.h [__riscos__]: Prefixed all RISC OS prototypes with
+ riscos_*
+
+ * zlib-riscos.h: New. This is macro magic in order to make the
+ zlib library calls indeed call the RISC OS ZLib module.
+
+2002-10-31 David Shaw <dshaw@jabberwocky.com>
+
+ * util.h: Add wipememory() macro.
+
+2002-10-29 Stefan Bellon <sbellon@sbellon.de>
+
+ * util.h: Added parameter argument to make_basename() needed for
+ filetype support.
+ [__riscos__]: Added prototype.
+
+2002-10-28 Stefan Bellon <sbellon@sbellon.de>
+
+ * util.h [__riscos__]: Added prototypes for new filetype support.
+
+2002-10-19 David Shaw <dshaw@jabberwocky.com>
+
+ * distfiles, _regex.h: Add _regex.h from glibc 2.3.1.
+
+2002-10-14 David Shaw <dshaw@jabberwocky.com>
+
+ * keyserver.h: Go to KEYSERVER_PROTO_VERSION 1.
+
+2002-10-08 David Shaw <dshaw@jabberwocky.com>
+
+ * keyserver.h: Add new error code KEYSERVER_UNREACHABLE.
+
+2002-10-03 David Shaw <dshaw@jabberwocky.com>
+
+ * util.h: Add new log_warning logger command which can be switched
+ between log_info and log_error via log_set_strict.
+
+2002-09-24 David Shaw <dshaw@jabberwocky.com>
+
+ * keyserver.h: Add some new error codes for better GPA support.
+
+2002-09-10 Werner Koch <wk@gnupg.org>
+
+ * mpi.h (mpi_is_protected, mpi_set_protect_flag)
+ (mpi_clear_protect_flag): Removed.
+ (mpi_get_nbit_info, mpi_set_nbit_info): Removed.
+
+2002-08-13 David Shaw <dshaw@jabberwocky.com>
+
+ * cipher.h: Add AES aliases for RIJNDAEL algo numbers.
+
+2002-08-07 David Shaw <dshaw@jabberwocky.com>
+
+ * cipher.h: Add md_algo_present().
+
+2002-08-06 Stefan Bellon <sbellon@sbellon.de>
+
+ * util.h [__riscos__]: Added riscos_getchar().
+
+2002-06-21 Stefan Bellon <sbellon@sbellon.de>
+
+ * util.h [__riscos__]: Further moving away of RISC OS specific
+ stuff from general code.
+
+2002-06-20 Stefan Bellon <sbellon@sbellon.de>
+
+ * util.h [__riscos__]: Added riscos_set_filetype().
+
+2002-06-14 David Shaw <dshaw@jabberwocky.com>
+
+ * util.h: Add pop_strlist() from strgutil.c.
+
+2002-06-07 Stefan Bellon <sbellon@sbellon.de>
+
+ * util.h [__riscos__]: RISC OS needs strings.h for strcasecmp()
+ and strncasecmp().
+
+2002-05-22 Werner Koch <wk@gnupg.org>
+
+ * util.h: Add strncasecmp. Removed stricmp and memicmp.
+
+2002-05-10 Stefan Bellon <sbellon@sbellon.de>
+
+ * mpi.h: New function mpi_debug_alloc_like for M_DEBUG.
+
+ * util.h [__riscos__]: Make use of __func__ that later
+ Norcroft compiler provides.
+
+ * memory.h: Fixed wrong definition of m_alloc_secure_clear.
+
+2002-04-23 David Shaw <dshaw@jabberwocky.com>
+
+ * util.h: New function answer_is_yes_no_default() to give a
+ default answer.
+
+2002-04-22 Stefan Bellon <sbellon@sbellon.de>
+
+ * util.h [__riscos__]: Removed riscos_open, riscos_fopen and
+ riscos_fstat as those special versions aren't needed anymore.
+
+2002-02-19 David Shaw <dshaw@jabberwocky.com>
+
+ * keyserver.h: Add KEYSERVER_NOT_SUPPORTED for unsupported actions
+ (say, a keyserver that has no way to search, or a readonly
+ keyserver that has no way to add).
+
+2002-01-02 Stefan Bellon <sbellon@sbellon.de>
+
+ * util.h [__riscos__]: Updated prototype list.
+
+ * types.h [__riscos__]: Changed comment wording.
+
+2001-12-27 David Shaw <dshaw@jabberwocky.com>
+
+ * KEYSERVER_SCHEME_NOT_FOUND should be 127 to match the POSIX
+ system() (via /bin/sh) way of signaling this.
+
+ * Added G10ERR_KEYSERVER
+
+2001-12-27 Werner Koch <wk@gnupg.org>
+
+ * util.h [MINGW32]: Fixed name of include file.
+
+2001-12-22 Timo Schulz <ts@winpt.org>
+
+ * util.h (is_file_compressed): New.
+
+2001-12-19 Werner Koch <wk@gnupg.org>
+
+ * util.h [CYGWIN32]: Allow this as an alias for MINGW32. Include
+ stdarg.h because we use the va_list type. By Disastry.
+
+2001-09-28 Werner Koch <wk@gnupg.org>
+
+ * cipher.h (PUBKEY_USAGE_CERT): New.
+
+2001-09-07 Werner Koch <wk@gnupg.org>
+
+ * util.h: Add strsep().
+
+2001-08-30 Werner Koch <wk@gnupg.org>
+
+ * cipher.h (DEK): Added use_mdc.
+
+2001-08-24 Werner Koch <wk@gnupg.org>
+
+ * cipher.h (md_write): Made buf arg const.
+
+2001-08-20 Werner Koch <wk@gnupg.org>
+
+ * cipher.h (DEK): Added algo_info_printed;
+
+ * util.h [__riscos__]: Added prototypes and made sure that we
+ never use __attribute__.
+ * cipher.h, iobuf.h, memory.h, mpi.h [__riscos__]: extern hack.
+ * i18n.h [__riscos__]: Use another include file
+
+2001-05-30 Werner Koch <wk@gnupg.org>
+
+ * ttyio.h (tty_printf): Add missing parenthesis for non gcc.
+ * http.h: Removed trailing comma to make old ccs happy. Both are
+ by Albert Chin.
+
+2001-05-25 Werner Koch <wk@gnupg.org>
+
+ * ttyio.h (tty_printf): Add printf attribute.
+
+2001-04-23 Werner Koch <wk@gnupg.org>
+
+ * http.h: New flag HTTP_FLAG_NO_SHUTDOWN.
+
+2001-04-13 Werner Koch <wk@gnupg.org>
+
+ * iobuf.h: Removed iobuf_fopen.
+
+2001-03-01 Werner Koch <wk@gnupg.org>
+
+ * errors.h (G10ERR_UNU_SECKEY,G10ERR_UNU_PUBKEY): New
+
+2000-11-30 Werner Koch <wk@gnupg.org>
+
+ * iobuf.h (iobuf_translate_file_handle): Add prototype.
+
+2000-11-11 Paul Eggert <eggert@twinsun.com>
+
+ * iobuf.h (iobuf_get_filelength): Now returns off_t, not u32.
+ (struct iobuf_struct, iobuf_set_limit,
+ iobuf_tell, iobuf_seek): Use off_t, not ulong, for file offsets.
+
+2000-10-12 Werner Koch <wk@gnupg.org>
+
+ * mpi.h: Changed the way mpi_limb_t is defined.
+
+Wed Sep 6 17:55:47 CEST 2000 Werner Koch <wk@openit.de>
+
+ * iobuf.c (IOBUF_FILELENGTH_LIMIT): New.
+
+2000-03-14 14:03:43 Werner Koch (wk@habibti.openit.de)
+
+ * types.h (HAVE_U64_TYPEDEF): Defined depending on configure test.
+
+Thu Jan 13 19:31:58 CET 2000 Werner Koch <wk@gnupg.de>
+
+ * types.h (HAVE_U64_TYPEDEF): Add a test for _LONGLONG which fixes
+ this long living SGI bug. Reported by Alec Habig.
+
+Sat Dec 4 12:30:28 CET 1999 Werner Koch <wk@gnupg.de>
+
+ * iobuf.h (IOBUFCTRL_CANCEL): Nww.
+
+Mon Oct 4 21:23:04 CEST 1999 Werner Koch <wk@gnupg.de>
+
+ * errors.h (G10ERR_NOT_PROCESSED): New.
+
+Wed Sep 15 16:22:17 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
+
+
+ * i18n.h: Add support for simple-gettext.
+
+Tue Jun 29 21:44:25 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
+
+
+ * util.h (stricmp): Use strcasecmp as replacement.
+
+Sat Jun 26 12:15:59 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
+
+
+ * cipher.h (MD_HANDLE): Assigned a structure name.
+
+Fri Apr 9 12:26:25 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
+
+ * cipher.h (BLOWFISH160): Removed.
+
+Tue Apr 6 19:58:12 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
+
+ * cipher.h (DEK): increased max. key length to 32 bytes
+
+
+Sat Feb 20 21:40:49 CET 1999 Werner Koch <wk@isil.d.shuttle.de>
+
+ * g10lib.h: Removed file and changed all files that includes this.
+
+Tue Feb 16 14:10:02 CET 1999 Werner Koch <wk@isil.d.shuttle.de>
+
+ * types.h (STRLIST): Add field flags.
+
+Wed Feb 10 17:15:39 CET 1999 Werner Koch <wk@isil.d.shuttle.de>
+
+ * cipher.h (CIPHER_ALGO_TWOFISH): Chnaged ID to 10 and renamed
+ the old experimenatl algorithm to xx_OLD.
+
+Thu Jan 7 18:00:58 CET 1999 Werner Koch <wk@isil.d.shuttle.de>
+
+ * cipher.h (MD_BUFFER_SIZE): Removed.
+
+Mon Dec 14 21:18:49 CET 1998 Werner Koch <wk@isil.d.shuttle.de>
+
+ * types.h: fix for SUNPRO_C
+
+Tue Dec 8 13:15:16 CET 1998 Werner Koch <wk@isil.d.shuttle.de>
+
+ * mpi.h (MPI): Changed the structure name to gcry_mpi and
+ changed all users.
+
+Tue Oct 20 11:40:00 1998 Werner Koch (wk@isil.d.shuttle.de)
+
+ * iobuf.h (iobuf_get_temp_buffer): New.
+
+Tue Oct 13 12:40:48 1998 Werner Koch (wk@isil.d.shuttle.de)
+
+ * iobuf.h (iobuf_get): Now uses .nofast
+ (iobuf_get2): Removed.
+
+Mon Sep 14 09:17:22 1998 Werner Koch (wk@(none))
+
+ * util.h (HAVE_ATEXIT): New.
+ (HAVE_RAISE): New.
+
+Mon Jul 6 10:41:55 1998 Werner Koch (wk@isil.d.shuttle.de)
+
+ * cipher.h (PUBKEY_USAGE_): New.
+
+Mon Jul 6 09:49:51 1998 Werner Koch (wk@isil.d.shuttle.de)
+
+ * iobuf.h (iobuf_set_error): New.
+ (iobuf_error): New.
+
+Sat Jun 13 17:31:32 1998 Werner Koch (wk@isil.d.shuttle.de)
+
+ * g10lib.h: New as interface for the g10lib.
+
+Mon Jun 8 22:14:48 1998 Werner Koch (wk@isil.d.shuttle.de)
+
+ * cipher.h (CIPHER_ALGO_CAST5): Changed name from .. CAST
+
+Thu May 21 13:25:51 1998 Werner Koch (wk@isil.d.shuttle.de)
+
+ * cipher.h: removed ROT 5 and changed one id and add dummy
+
+Tue May 19 18:09:05 1998 Werner Koch (wk@isil.d.shuttle.de)
+
+ * cipher.h (DIGEST_ALGO_TIGER): Chnaged id from 101 to 6.
+
+Mon May 4 16:37:17 1998 Werner Koch (wk@isil.d.shuttle.de)
+
+ * cipher.h (PUBKEY_ALGO_ELGAMAL_E): New, with value of the
+ old one.
+ * (is_ELGAMAL, is_RSA): New macros
+
+Sun Apr 26 14:35:24 1998 Werner Koch (wk@isil.d.shuttle.de)
+
+ * types.h: New type u64
+
+Mon Mar 9 12:59:55 1998 Werner Koch (wk@isil.d.shuttle.de)
+
+ * cipher.h: Included dsa.h.
+
+Tue Mar 3 15:11:21 1998 Werner Koch (wk@isil.d.shuttle.de)
+
+ * cipher.h (random.h): Add new header and move all relevalt
+ functions to this header.
+
+
+ Copyright 1998, 1999, 2000, 2001 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.
+
+Local Variables:
+buffer-read-only: t
+End:
diff --git a/common/ChangeLog.jnlib b/common/ChangeLog.jnlib
new file mode 100644
index 0000000..6c0db13
--- /dev/null
+++ b/common/ChangeLog.jnlib
@@ -0,0 +1,783 @@
+2011-12-01 Werner Koch <wk@g10code.com>
+
+ NB: ChangeLog files are no longer manually maintained. Starting
+ on December 1st, 2011 we put change information only in the GIT
+ commit log, and generate a top-level ChangeLog file from logs at
+ "make dist". See doc/HACKING for details.
+
+ [Update 2015-04-24: README.jnlib has been removed and all
+ references to JNLIB, except for this file, have been removed.]
+
+2010-03-10 Werner Koch <wk@g10code.com>
+
+ See gnupg/common/ChangeLog for newer changes.
+
+ JNLIB has been merged into GnuPG's common directory. README.jnlib
+ list the files making up JNLIB.
+
+ * README: Rename to README.jnlib
+ * ChangeLog: Rename to ChangeLog.jnlib.
+ * Makefile.am: Remove.
+
+2010-03-01 Werner Koch <wk@g10code.com>
+
+ * t-w32-reg.c: New.
+
+ * w32-reg.c (read_w32_registry_string)
+ (write_w32_registry_string): Support W32CE.
+
+2010-02-26 Werner Koch <wk@g10code.com>
+
+ * t-timestuff.c: New.
+
+ * dynload.h (dlopen, dlsym) [W32CE]: Map to wchar_t.
+
+ * mischelp.c (_jnlib_free): New.
+ (same_file_p) [W32CE]: Map to wchar_t.
+
+ * utf8conv.c (set_native_charset) [W32CE]: Do not use
+ GetConsoleOutputCP.
+ (wchar_to_utf8, utf8_to_wchar) [W32]: New.
+
+ * Makefile.am (t_jnlib_ldadd) [W32CE]: Add gpg-error.
+
+ * t-support.h (getenv) [HAVE_GETENV]: Add getenv stub.
+ [W32CE]: Include gpg-error.h
+ * t-support.c (gpg_err_code_from_errno)
+ (gpg_err_code_from_syserror) [GPG_ERROR_H]: Do not build.
+
+ * t-stringhelp.c (gethome) [!HAVE_GETPWUID]: Keep result of getenv.
+
+ * dotlock.c [!HAVE_SIGNAL_H]: Don't include signal.h.
+ (create_dotlock) [W32CE]: Map filename top wchar_t.
+
+ * libjnlib-config.h [USE_SIMPLE_GETTEXT]: Include gpg-error.h and
+ remove w32help.h.
+ (jnlib_set_errno): New. Use it everywhere to set ERRNO.
+ (getenv) [!HAVE_GETENV]: New.
+ (getpid) [W32E]: New.
+
+ * stringhelp.c (get_pwdir) [!HAVE_PWD_H]: Mark unused args.
+ (w32_strerror) [W32CE]: Use a simple implementation.
+
+ * w32help.h [USE_SIMPLE_GETTEXT]: Remove all definitions; we are
+ now using the gpg-error included implementation.
+ * w32-gettext.c: Remove.
+
+ * mischelp.c (same_file_p): Fix bug in case the second file can't
+ be opened.
+
+2009-10-19 Werner Koch <wk@g10code.com>
+
+ * strlist.c (add_to_strlist_try): New.
+
+2009-09-22 Werner Koch <wk@g10code.com>
+
+ * dotlock.h (DOTLOCK): Rename to dotlock_t. Change all users.
+
+2009-08-26 Werner Koch <wk@g10code.com>
+
+ * stringhelp.c (do_make_filename): Factor some code out to ..
+ (get_pwdir): .. new.
+
+2009-08-26 Werner Koch <wk@g10code.com>
+
+ * stringhelp.c [HAVE_PWD_H]: Include pwd.h.
+ (do_make_filename): New.
+ (make_filename, make_filename_try): Implement using the new
+ function.
+ * t-stringhelp.c (test_make_filename_try): New.
+ * t-support.c (gcry_strdup): Fix.
+
+ * stringhelp.h (make_filename, make_filename_try): Add sentinel
+ attribute.
+
+2009-08-25 Werner Koch <wk@g10code.com>
+
+ * stringhelp.c: Include errno.h.
+ (do_strconcat): New.
+ (strconcat, xstrconcat): New.
+ * types.h (GNUPG_GCC_A_SENTINEL): New.
+ * t-stringhelp.c (test_strconcat, test_xstrconcat): New.
+ (main): Run them.
+
+2009-07-07 Werner Koch <wk@g10code.com>
+
+ * stringhelp.c (make_filename_try): Use jnlib_malloc.
+
+ * dotlock.c (read_lockfile): Replace jnlib_xmalloc by jnlib_malloc.
+
+2009-06-04 Werner Koch <wk@g10code.com>
+
+ * mischelp.h: Include SUN_LEN etc also for W32.
+
+2009-05-19 Werner Koch <wk@g10code.com>
+
+ * mischelp.h: Define PF_LOCAL, AF_LOCAL and SUN_LEN if requested.
+ * logging.c (fun_writer): Use SUN_LEN to fix a Mac OS X freeze.
+
+2009-03-25 Werner Koch <wk@g10code.com>
+
+ * logging.c (fun_closer): Never close fd 2.
+ (set_file_fd): Close logstream early.
+
+2009-02-25 Werner Koch <wk@g10code.com>
+
+ * logging.c (get_tid_callback): New.
+ (do_logv): Use it.
+ (log_set_get_tid_callback): New.
+
+2009-01-22 Werner Koch <wk@g10code.com>
+
+ * t-support.c (gpg_err_code_from_errno)
+ (gpg_err_code_from_syserror): New.
+
+2008-11-20 Werner Koch <wk@g10code.com>
+
+ * argparse.c (arg_parse): Fix last change.
+
+2008-11-11 Werner Koch <wk@g10code.com>
+
+ * argparse.h: Add a bunch of macros and constants.
+ * argparse.c: Use the new macros. Re-indent the code. Change
+ license back to LGPL 2.1.
+
+2008-11-04 Werner Koch <wk@g10code.com>
+
+ * w32-gettext.c: Merged with code from libgpg-error and rewrote
+ most parts.
+
+ * Makefile.am (AM_CFLAGS): Add -DJNLIB_IN_JNLIB.
+
+2008-10-29 Werner Koch <wk@g10code.com>
+
+ * stringhelp.c (make_filename): Implement using macros. Factor some
+ code out to ..
+ (change_slashes): New.
+ (make_filename_try): New.
+
+ * w32-gettext.c (gettext): Return if no domain is loaded.
+ Reported by Tom Pegios.
+
+2008-10-28 Werner Koch <wk@g10code.com>
+
+ * w32-gettext.c (gettext): Try the binary search if the string was
+ not found in the hash table.
+
+2008-10-20 Werner Koch <wk@g10code.com>
+
+ * w32-afunix.c (_w32_sock_connect): Mark ADDRLEN as unused.
+
+ * dotlock.c (release_dotlock): Do not mix declaration and code.
+
+ * stringhelp.c (make_basename): Silent gcc warning about unused arg.
+ * argparse.c (store_alias): Ditto.
+ (find_long_option):
+
+2008-10-15 Werner Koch <wk@g10code.com>
+
+ * logging.c (do_logv) [W32]: Flush the log stream.
+
+2008-09-29 Werner Koch <wk@g10code.com>
+
+ * argparse.c (ARGERR_): Use constants for error values.
+ (optfile_parse): Prettify. Replace xmalloc and xrealloc by malloc
+ and realloc.
+ * libjnlib-config.h (jnlib_strdup, jnlib_realloc): New.
+
+2008-06-26 Werner Koch <wk@g10code.com>
+
+ * stringhelp.c (print_sanitized_buffer2): Loose check for control
+ characters to better cope with utf-8. The range 0x80..0x9f is
+ nowadays not anymore accidently used for control charaters.
+
+2008-06-13 Werner Koch <wk@g10code.com>
+
+ * dotlock.c: Reformat code and implement locking for W32.
+ (create_dotlock): Use snprintf.
+
+2008-06-11 Werner Koch <wk@g10code.com>
+
+ * utf8conv.c: Remove useless variable ACTIVE_CHARSET. Suggested
+ by Petr Uzel.
+
+2008-05-26 Werner Koch <wk@g10code.com>
+
+ * argparse.c (usage): Make sure to print a trailing LF for usage(1).
+
+2008-04-08 Werner Koch <wk@g10code.com>
+
+ * w32-gettext.c (gettext_select_utf8): New.
+ (get_string): Support switching encodings.
+ (load_domain): Allocate space for DATA_NATIVE.
+
+2008-03-25 Werner Koch <wk@g10code.com>
+
+ * w32-gettext.c (_nl_locale_name): New. Taken from
+ ../common/localename and GNU gettext's localename.c.
+ (set_gettext_file): Rewritten.
+ (gettext_localename): New.
+
+2008-03-17 Werner Koch <wk@g10code.com>
+
+ * logging.c (my_funopen_hook_size_t): New.
+ (fun_writer): Use it to cope with fopencookie/funopen differences.
+ * dotlock.c (read_lockfile): Initialize PID. Reported by Stéphane
+ Corthésy.
+
+2008-02-22 Werner Koch <wk@g10code.com>
+
+ * argparse.c (strusage): Set copyright year to 2008.
+
+2007-11-19 Werner Koch <wk@g10code.com>
+
+ * stringhelp.c (percent_escape): Factor code out to
+ (do_percent_escape): .. new.
+ (try_percent_escape): New.
+
+2007-10-01 Werner Koch <wk@g10code.com>
+
+ * w32-afunix.c: Only keep the client related code.
+ (read_port_and_nonce): New. Taken from Assuan.
+ (_w32_sock_connect): Rewritten.
+
+2007-08-29 Werner Koch <wk@g10code.com>
+
+ * argparse.c (initialize): Make strings translatable and remove
+ extra LF.
+
+2007-08-24 Werner Koch <wk@g10code.com>
+
+ * mischelp.c (same_file_p): New.
+ (libjnlib_dummy_mischelp_func): Remove as we now always have one
+ function.
+
+2007-08-09 Werner Koch <wk@g10code.com>
+
+ * argparse.c (show_help): Expand the @EMAIL@ macro in the package
+ bug reporting address.
+
+2007-08-02 Werner Koch <wk@g10code.com>
+
+ * t-stringhelp.c (test_compare_filenames): New.
+
+ * stringhelp.c (compare_filenames) [HAVE_DRIVE_LETTERS]: Fixed
+ comparison to take slash and backslash in account.
+ (make_filename): Avoid mixing / and \.
+
+2007-07-04 Werner Koch <wk@g10code.com>
+
+ * utf8conv.c (load_libiconv): Remove URL from translatble string.
+
+ Switched JNLIB from LGPLv2.1 to LGPLv3.
+
+2007-07-01 Werner Koch <wk@g10code.com>
+
+ * argparse.c (strusage): Use id 10 for the license string;
+ default to GPL3+. Change long note to version 3 or later.
+ (show_version): Print the license info.
+
+2007-06-19 Werner Koch <wk@g10code.com>
+
+ * Makefile.am: Add support for regression tests.
+ * t-support.h, t-support.c: New.
+ * t-stringhelp.c: New.
+
+ * stringhelp.c (percent_escape): Add arg EXTRA to make it a more
+ general function. Changed all callers.
+
+2007-06-18 Werner Koch <wk@g10code.com>
+
+ * w32-afunix.c (_w32_sock_bind): Changed to properly detect an
+ already used socket.
+
+2007-06-18 Marcus Brinkmann <marcus@g10code.de>
+
+ * stringhelp.h (percent_escape): New prototype.
+ * stringhelp.c (percent_escape): New function.
+
+2007-06-11 Werner Koch <wk@g10code.com>
+
+ * utf8conv.c (jnlib_iconv_open, jnlib_iconv, jnlib_iconv_close): New.
+
+2007-06-06 Werner Koch <wk@g10code.com>
+
+ * w32help.h: New.
+ * w32-gettext.c: New. Taken from gnupg 1.4, added ngettext,
+ changed to use jnlib malloc functions and put under the LGPL.
+ * w32-reg.c: New. Taken from../common/w32reg.c and changed to
+ LGPL. Changed API to use the jnlib malloc functions.
+ * Makefile.am (libjnlib_a_SOURCES) [!W32]: Do not build the w32
+ specific modules.
+
+ * dotlock.c: Include stringhelp.h for stpcpy prototype.
+
+2007-06-04 Werner Koch <wk@g10code.com>
+
+ * dynload.h: New. Taken from ../common and changed to LGPL.
+
+ * utf8conv.c (load_libiconv): New. Taken from GnuPG 1.4
+
+2007-05-30 Werner Koch <wk@g10code.com>
+
+ * w32-pth.h, w32-pth.c: Remove.
+
+2007-04-25 Werner Koch <wk@g10code.com>
+
+ * argparse.c (long_opt_strlen): Fixed for utf-8.
+
+2007-03-07 Werner Koch <wk@g10code.com>
+
+ * argparse.c (strusage): Set copyright year to 2007.
+
+2007-01-25 Werner Koch <wk@g10code.com>
+
+ * stringhelp.c (utf8_charcount): New.
+
+2006-11-29 Werner Koch <wk@g10code.com>
+
+ * utf8conv.c (set_native_charset) [HAVE_W32_SYSTEM]: Fixed typo in
+ macro name.
+
+2006-11-15 Werner Koch <wk@g10code.com>
+
+ * logging.c (my_funopen_hook_ret_t): New.
+ (fun_writer): Use it.
+
+2006-10-19 Werner Koch <wk@g10code.com>
+
+ * stringhelp.c (memrchr) [!HAVE_MEMRCHR]: Provide a replacement.
+
+2006-09-27 Werner Koch <wk@g10code.com>
+
+ * mischelp.c: New.
+ (timegm): Copied from gnupg 1.4, changed from GPL to LGPL. Fixed
+ a memory leak.
+
+ * stringhelp.h (isascii): New.
+
+ * stringhelp.c (strsep): New. Copied from gnupg 1.4.5
+ util/strgutil.c.
+
+ * strlist.h (STRLIST): Removed deprecated typedef.
+
+ * types.h: Made cpp commands work with old compilers. Also shows
+ up nicer with Emacs' font locking.
+
+ * w32-afunix.c (_w32_sock_connect): Set ERRNO for an invalid port.
+
+ Changed license from GPL to LGPL. Note that all code has either
+ been written by me, David, employees of g10 Code or taken from
+ glibc.
+
+ * libjnlib-config.h, stringhelp.c, stringhelp.h:
+ * strlist.c, strlist.h, utf8conv.c, utf8conv.h:
+ * argparse.c, argparse.h, logging.c, logging.h:
+ * dotlock.c, dotlock.h, types.h, mischelp.h:
+ * xmalloc.c, xmalloc.h, w32-pth.c, w32-pth.h:
+ * w32-afunix.c, w32-afunix.h: Tagged them to be long to jnlib
+ which is a part of GnuPG but also used by other projetcs.
+
+2006-09-22 Werner Koch <wk@g10code.com>
+
+ * utf8conv.c: Reworked to match the gnupg 1.4.5 code. This now
+ requires iconv support but this is reasonable for all modern
+ systems.
+
+2006-08-29 Werner Koch <wk@g10code.com>
+
+ * logging.c (do_logv): Emit a missing LF for fatal errors.
+
+2006-06-28 Werner Koch <wk@g10code.com>
+
+ * dotlock.c (make_dotlock, release_dotlock, read_lockfile)
+ (maybe_deadlock, destroy_dotlock, create_dotlock): Re-indented.
+ (create_dotlock): Repalces some log_fatal by log_error as it was
+ not intended that they should terminate. Write the nodename to
+ the locking file. Code cleanups.
+ (read_lockfile): Reworked to read the node name.
+ (make_dotlock): Test for identical node name and delete lock stale
+ file.
+ (release_dotlock): Likewise.
+
+2006-05-23 Werner Koch <wk@g10code.com>
+
+ * libjnlib-config.h (JNLIB_NEED_UTF8CONV): Fixed typo in name.
+
+ * dotlock.c (release_dotlock): Don't act if we don't have any
+ locks at all.
+ (destroy_dotlock): New. From 1.4.3.
+ (dotlock_remove_lockfiles): Make use of destroy function.
+
+2006-05-19 Werner Koch <wk@g10code.com>
+
+ * strlist.c (append_to_strlist2): Enabled.
+
+ * stringhelp.c (print_sanitized_buffer2): New. Changed the rules
+ to match the behaviour of print_string2 from gnupg 1.4.3.
+ (print_sanitized_buffer): Use the new function.
+ (print_sanitized_string2): New.
+ (hextobyte): New. Taken from gpg 1.4.3.
+
+2006-04-28 Werner Koch <wk@g10code.com>
+
+ * stringhelp.c (print_sanitized_buffer): Fix bug where the count
+ got wrong for the \xNN representation.
+ (sanitize_buffer): Fix bug where some control characters lose part
+ of their \xNN representation.
+
+2006-04-20 Werner Koch <wk@g10code.com>
+
+ * stringhelp.c (make_basename): New arg INPUTPATH for future
+ riscos compatibility.
+
+2006-04-18 Werner Koch <wk@g10code.com>
+
+ * libjnlib-config.h (JNLIB_NEED_UTF8CONF): Defined.
+ * strlist.c (add_to_strlist2) [JNLIB_NEED_UTF8CONV]: Enabled.
+
+2005-06-15 Werner Koch <wk@g10code.com>
+
+ * stringhelp.c (sanitize_buffer): Make P a void*.
+ (ascii_memistr, memistr): Ditto.
+ (ascii_memcasecmp): Ditto.
+ * logging.c (writen): Use void * for arg BUFFER.
+ * stringhelp.c (memistr): Fixed unsigned/signed pointer conflict.
+ (ascii_memistr): Ditto.
+ (ascii_memcasemem): Ditto.
+ * utf8conv.c (utf8_to_native): Ditto.
+ (utf8_to_native): Ditto.
+ * argparse.c (show_version): Removed non-required cast.
+
+2005-01-19 Werner Koch <wk@g10code.com>
+
+ * logging.c (fun_writer): Don't fallback to stderr. Print to
+ stderr only if connected to a tty.
+
+2004-12-20 Werner Koch <wk@g10code.com>
+
+ * w32-pth.c (do_pth_event_free): The events are hold in a ring
+ buffer. Adjust for that.
+ (do_pth_event_body): Ditto.
+ (pth_event_isolate): Ditto.
+ (do_pth_wait): Ditto.
+ (_pth_event_count): Renamed to ..
+ (event_count): .. and adjusted as above.
+ (pth_init): Define 3 debug levels and change all debug calls to
+ make use of them. This makes the moule now silent.
+
+2004-12-19 Werner Koch <wk@g10code.com>
+
+ * w32-pth.c (pth_init): Enable debugging depending on env var.
+ (pth_self): New.
+ (pth_mutex_release, pth_mutex_acquire): Implemented directly using
+ the W32 API.
+
+2004-12-18 Werner Koch <wk@g10code.com>
+
+ * w32-pth.c (pth_init): Reverse return values. Use TRUE and FALSE
+ constants.
+ (pth_kill, pth_mutex_acquire, pth_attr_set, pth_join, pth_cancel):
+ Ditto.
+
+2004-12-15 Werner Koch <wk@g10code.com>
+
+ * logging.c [W32]: Don't include unavailable headers.
+
+2004-12-14 Werner Koch <wk@g10code.com>
+
+ * w32-pth.c (_pth_strerror): Renamed to ...
+ (w32_strerror): .. this. And let callers provide a buffer.
+ (spawn_helper_thread): Removed HD arg and hardwire the stack size
+ to 32k.
+ (do_pth_wait): Removed use of ATTR; not needed for the helper
+ threads.
+ (helper_thread): Renamed to ..
+ (launch_thread): .. this. Release handle if not joinable.
+ (struct pth_priv_hd_s): Renamed to ...
+ (struct thread_info_s): .. this. Add member JOINABLE and TH.
+
+2004-12-14 Timo Schulz <twoaday@g10code.com>
+
+ * w32-pth.c (pth_kill): Just release the crit section if
+ pth_init was really called. And set all handles to NULL.
+ (_pth_strerror): New.
+ (do_pth_wait): Before we enter the loop we check if there
+ are too much events in the ring.
+
+2004-12-14 Werner Koch <wk@g10code.com>
+
+ * w32-pth.h (pth_event_occured): Removed macro.
+ * w32-pth.c: Fixed license statement; its under the LGPL.
+ (enter_pth, leave_pth): Use them to bracket almost all public
+ functions.
+
+2004-12-13 Timo Schulz <twoaday@g10code.com>
+
+ * w32-pth.c (enter_pth, leave_pth): New.
+ (pth_init): Initialize global mutex section.
+ (pth_kill): Release global mutex section.
+ (helper_thread): New.
+ (pth_spawn): Make sure only one thread is running.
+
+2004-12-13 Werner Koch <wk@g10code.com>
+
+ * stringhelp.c (w32_strerror) [W32]: New.
+
+ * w32-pth.c, w32-pth.h: Added real code written by Timo Schulz.
+ Not finished, though.
+
+2004-12-07 Werner Koch <wk@g10code.com>
+
+ * w32-pth.c, w32-pth.h: New.
+
+2004-11-26 Werner Koch <wk@g10code.com>
+
+ * logging.c [_WIN32]: Don't include socket headers.
+
+2004-11-30 Timo Schulz <ts@g10code.com>
+
+ * w32-afunix.c: New. AF_UNIX emulation for W32.
+ * w32-afunix.h: Likewise.
+
+2004-11-22 Werner Koch <wk@g10code.com>
+
+ * logging.c (log_test_fd): Add test on LOGSTREAM. Reported by
+ Barry Schwartz.
+
+2004-11-18 Werner Koch <wk@g10code.com>
+
+ * logging.c: Explicitly include sys/stat.h for the S_I* constants.
+
+2004-10-21 Werner Koch <wk@g10code.com>
+
+ * logging.c (do_logv): Use set_log_stream to setup a default.
+ (log_set_file): Factored code out to ..
+ (set_file_fd): .. New function to allow using a file descriptor.
+ (log_set_fd): Make use of new fucntion.
+ (fun_writer): Reworked.
+
+2004-08-18 Werner Koch <wk@g10code.de>
+
+ * stringhelp.c (print_sanitized_utf8_string): Actually implement
+ it.
+
+2004-06-21 Werner Koch <wk@g10code.com>
+
+ * logging.c (log_set_file): Do not close an old logstream if it
+ used to be stderr or stdout.
+
+2004-05-05 Werner Koch <wk@gnupg.org>
+
+ * logging.c (log_set_file): Oops, don't close if LOGSTREAM is NULL.
+
+2004-04-30 Werner Koch <wk@gnupg.org>
+
+ * logging.c (log_set_file): Make sure the log stream will be
+ closed even if the stderr fileno will be assigned to a new socket.
+
+2004-04-16 Werner Koch <wk@gnupg.org>
+
+ * logging.h (JNLIB_LOG_WITH_PREFIX): Add constants for the flag
+ values.
+ * logging.c (log_set_prefix): New flag DETACHED.
+ (fun_writer): Take care of this flag.
+ (log_test_fd): New.
+
+2004-02-18 Werner Koch <wk@gnupg.org>
+
+ * stringhelp.c (print_sanitized_buffer): Don't care about
+ non-ASCII characaters.
+ (sanitize_buffer): Ditto.
+
+2004-02-12 Werner Koch <wk@gnupg.org>
+
+ * Makefile.am: Replaced INCLUDES by AM_CPPFLAGS.
+
+2004-01-05 Werner Koch <wk@gnupg.org>
+
+ * argparse.c (strusage): Changed default copyright year to 2004.
+
+2003-12-17 Werner Koch <wk@gnupg.org>
+
+ * argparse.c (initialize): Replaced use of non-literal format
+ args. Suggested by Florian Weimer.
+
+2003-12-16 Werner Koch <wk@gnupg.org>
+
+ * logging.c (writen, fun_writer, fun_closer): New.
+ (log_set_file): Add feature to log to a socket.
+ (log_set_file, do_logv): Force printing with prefix and pid.
+
+2003-11-13 Werner Koch <wk@gnupg.org>
+
+ * strlist.c (strlist_copy): New.
+
+ * dotlock.c: Define DIRSEP_C et al. if not defined.
+
+2003-11-06 Werner Koch <wk@gnupg.org>
+
+ * strlist.h (strlist_t): New. STRLIST is now deprecated.
+
+2003-06-18 Werner Koch <wk@gnupg.org>
+
+ * strlist.c (strlist_pop): New.
+
+ * dotlock.c (dotlock_remove_lockfiles): Prefixed with dotlock_ and
+ made global.
+
+2003-06-17 Werner Koch <wk@gnupg.org>
+
+ * stringhelp.c (length_sans_trailing_chars)
+ (length_sans_trailing_ws): New.
+
+ * logging.c (log_inc_errorcount): New.
+
+ * stringhelp.c (print_sanitized_utf8_buffer): Implement utf8
+ conversion.
+ (sanitize_buffer): New. Based on gnupg 1.3.2 make_printable_string.
+
+ * dotlock.c: Updated to match the version from 1.3.2
+ * utf8conv.c: New. Code taken from strgutil.c of gnupg 1.3.2.
+ * utf8conv.h: New.
+
+2003-06-16 Werner Koch <wk@gnupg.org>
+
+ * logging.c (do_logv): Hack to optionally suppress a leading space.
+
+ * stringhelp.c (ascii_strncasecmp): New. Taken from gnupg 1.3.
+ (ascii_memistr): New. Taken from gnupg 1.3
+
+2003-06-13 Werner Koch <wk@gnupg.org>
+
+ * mischelp.h (wipememory2,wipememory): New. Taken from GnuPG 1.3.2.
+
+2002-06-04 Werner Koch <wk@gnupg.org>
+
+ * stringhelp.c (print_sanitized_utf8_string): New. No real
+ implementation for now.
+ (print_sanitized_utf8_buffer): Ditto.
+
+2002-04-04 Werner Koch <wk@gnupg.org>
+
+ * logging.c (log_get_prefix): New.
+
+2002-03-15 Werner Koch <wk@gnupg.org>
+
+ * argparse.c (optfile_parse): Fixed missing argument handling.
+
+2002-02-25 Werner Koch <wk@gnupg.org>
+
+ * stringhelp.c (ascii_memcasemem): New.
+
+2002-02-14 Werner Koch <wk@gnupg.org>
+
+ * Makefile.am (INCLUDES): Add cflags for libgcrypt.
+
+2002-02-07 Werner Koch <wk@gnupg.org>
+
+ * logging.c (log_set_fd): New.
+
+ * stringhelp.c (print_sanitized_buffer): New.
+ (print_sanitized_string): New.
+
+2002-01-24 Werner Koch <wk@gnupg.org>
+
+ * argparse.c (strusage): Set default copyright notice year to 2002.
+
+ Fixed the copyright notice of this file, as it has always been
+ part of GnuPG and therefore belongs to the FSF.
+
+2001-11-01 Marcus Brinkmann <marcus@g10code.de>
+
+ * logging.c (log_printf): Do not initialize ARG_PTR with 0, we
+ don't know the correct type. Instead, run va_start and va_end
+ unconditionally.
+ Reported by Jose Carlos Garcia Sogo <jsogo@debian.org>.
+
+2002-01-19 Werner Koch <wk@gnupg.org>
+
+ * logging.c (log_get_stream): New.
+
+2001-12-05 Werner Koch <wk@gnupg.org>
+
+ * logging.c (log_set_prefix): New.
+ (do_logv): Include prefix and pid only if enabled. Print time only
+ when explicitly enabled.
+ (log_logv): New.
+ * logging.h: Include log_logv() only when requested.
+
+2001-11-06 Werner Koch <wk@gnupg.org>
+
+ * strlist.c, strlist.h: New. Taken from pgnupg/util/strgutil.c
+
+2001-08-30 Werner Koch <wk@gnupg.org>
+
+ * logging.c (log_printf): Don't pass NULL instead of arg_ptr.
+
+2001-07-19 Werner Koch <wk@gnupg.org>
+
+ * stringhelp.c (ascii_memistr,ascii_isupper,ascii_islower,
+ ascii_toupper,ascii_tolower, ascii_strcasecmp, ascii_memcasecmp): New.
+
+2000-07-26 10:02:51 Werner Koch (wk@habibti.openit.de)
+
+ * stringhelp.c.: Add stdarg.h
+ * argparse.h: s/ulong/unsigned long/ although this should be defined
+ by types.h.
+
+2000-06-28 19:40:23 Werner Koch (wk@habibti.openit.de)
+
+ * Makefile.am: Replaced second logging.c by .h
+
+2000-05-24 08:58:15 Werner Koch (wk@habibti.openit.de)
+
+ * logging.c (log_get_errorcount): New.
+
+2000-05-24 08:44:47 Werner Koch (wk@habibti.openit.de)
+
+ * stringhelp.c: Added a few filename related helper functions.
+
+2000-05-11 18:04:43 Werner Koch (wk@habibti.openit.de)
+
+ * xmalloc.c (xstrcat2): Replaced stpcpy to quickly address W32
+ problems.
+
+2000-05-02 19:43:38 Werner Koch (wk@habibti.openit.de)
+
+ * xmalloc.c (xstrcat2): New.
+
+Mon Jan 24 13:04:28 CET 2000 Werner Koch <wk@gnupg.de>
+
+ * README: New.
+ * Makefile.am: new.
+ * argparse.c, argparse.h, logging.c, logging.h:
+ * mischelp.h, stringhelp.c, stringhelp.h, xmalloc.c:
+ * xmalloc.h, dotlock.c: Moved from ../util to here.
+ * dotlock.h: New.
+ * libjnlib-config.h: New.
+
+ * logging.c (log_set_file): New.
+ (log_printf): New.
+ (do_logv): Add kludge to insert LFs.
+
+
+ ***********************************************************
+ * Please note that JNLIB is maintained as part of GnuPG. *
+ * You may find it source-copied in other packages. *
+ ***********************************************************
+
+ Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+ 2010 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.
+
+Local Variables:
+buffer-read-only: t
+End:
diff --git a/common/Makefile.am b/common/Makefile.am
new file mode 100644
index 0000000..bd281d6
--- /dev/null
+++ b/common/Makefile.am
@@ -0,0 +1,235 @@
+# Makefile for common gnupg modules
+# Copyright (C) 2001, 2003, 2007, 2010 Free Software Foundation, Inc.
+#
+# This file is part of GnuPG.
+#
+# GnuPG is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# GnuPG is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <https://www.gnu.org/licenses/>.
+
+## Process this file with automake to produce Makefile.in
+
+EXTRA_DIST = mkstrtable.awk exaudit.awk exstatus.awk ChangeLog-2011 \
+ audit-events.h status-codes.h ChangeLog.jnlib \
+ ChangeLog-2011.include w32info-rc.h.in gnupg.ico \
+ all-tests.scm
+
+noinst_LIBRARIES = libcommon.a libcommonpth.a libgpgrl.a
+if !HAVE_W32CE_SYSTEM
+noinst_LIBRARIES += libsimple-pwquery.a
+endif
+noinst_PROGRAMS = $(module_tests) $(module_maint_tests)
+if DISABLE_TESTS
+TESTS =
+else
+TESTS = $(module_tests)
+endif
+
+BUILT_SOURCES = audit-events.h status-codes.h
+
+MAINTAINERCLEANFILES = audit-events.h status-codes.h
+
+AM_CPPFLAGS =
+
+AM_CFLAGS = $(LIBGCRYPT_CFLAGS) $(LIBASSUAN_CFLAGS) $(KSBA_CFLAGS)
+
+include $(top_srcdir)/am/cmacros.am
+
+
+common_sources = \
+ common-defs.h \
+ util.h utilproto.h fwddecl.h i18n.c i18n.h \
+ types.h host2net.h dynload.h w32help.h \
+ mapstrings.c stringhelp.c stringhelp.h \
+ strlist.c strlist.h \
+ utf8conv.c utf8conv.h \
+ argparse.c argparse.h \
+ logging.c logging.h \
+ dotlock.c dotlock.h \
+ mischelp.c mischelp.h \
+ status.c status.h\
+ shareddefs.h \
+ openpgpdefs.h \
+ gc-opt-flags.h \
+ sexp-parse.h \
+ tlv.c tlv.h tlv-builder.c \
+ init.c init.h \
+ sexputil.c \
+ sysutils.c sysutils.h \
+ homedir.c \
+ gettime.c gettime.h \
+ yesno.c \
+ b64enc.c b64dec.c zb32.c zb32.h \
+ convert.c \
+ percent.c \
+ mbox-util.c mbox-util.h \
+ miscellaneous.c \
+ xasprintf.c \
+ xreadline.c \
+ membuf.c membuf.h \
+ ccparray.c ccparray.h \
+ iobuf.c iobuf.h \
+ ttyio.c ttyio.h \
+ asshelp.c asshelp2.c asshelp.h \
+ exechelp.h \
+ signal.c \
+ audit.c audit.h \
+ localename.c \
+ session-env.c session-env.h \
+ userids.c userids.h \
+ openpgp-oid.c \
+ ssh-utils.c ssh-utils.h \
+ agent-opt.c \
+ helpfile.c \
+ mkdir_p.c mkdir_p.h \
+ strlist.c strlist.h \
+ exectool.c exectool.h \
+ server-help.c server-help.h \
+ name-value.c name-value.h \
+ recsel.c recsel.h \
+ ksba-io-support.c ksba-io-support.h \
+ openpgp-fpr.c \
+ compliance.c compliance.h
+
+
+if HAVE_W32_SYSTEM
+common_sources += w32-reg.c w32-cmdline.c
+endif
+
+# To make the code easier to read we have split home some code into
+# separate source files.
+if HAVE_W32_SYSTEM
+if HAVE_W32CE_SYSTEM
+common_sources += exechelp-w32ce.c
+else
+common_sources += exechelp-w32.c
+endif
+else
+common_sources += exechelp-posix.c
+endif
+
+# Sources only useful without NPTH.
+without_npth_sources = \
+ get-passphrase.c get-passphrase.h
+
+# Sources only useful with NPTH.
+with_npth_sources = \
+ call-gpg.c call-gpg.h
+
+libcommon_a_SOURCES = $(common_sources) $(without_npth_sources)
+libcommon_a_CFLAGS = $(AM_CFLAGS) $(LIBASSUAN_CFLAGS) -DWITHOUT_NPTH=1
+
+libcommonpth_a_SOURCES = $(common_sources) $(with_npth_sources)
+libcommonpth_a_CFLAGS = $(AM_CFLAGS) $(LIBASSUAN_CFLAGS) $(NPTH_CFLAGS)
+
+if !HAVE_W32CE_SYSTEM
+libsimple_pwquery_a_SOURCES = \
+ simple-pwquery.c simple-pwquery.h asshelp.c asshelp.h
+libsimple_pwquery_a_CFLAGS = $(AM_CFLAGS) $(LIBASSUAN_CFLAGS)
+endif
+
+libgpgrl_a_SOURCES = \
+ gpgrlhelp.c
+
+if MAINTAINER_MODE
+# Note: Due to the dependency on Makefile, the file will always be
+# rebuilt, so we allow this only in maintainer mode.
+
+# Create the audit-events.h include file from audit.h
+# Note: We create the target file in the source directory because it
+# is a distributed built source. If we would not do that we may end
+# up with two files and then it is not clear which version of the
+# files will be picked up.
+audit-events.h: Makefile.am mkstrtable.awk exaudit.awk audit.h
+ $(AWK) -f $(srcdir)/exaudit.awk $(srcdir)/audit.h \
+ | $(AWK) -f $(srcdir)/mkstrtable.awk -v textidx=3 -v nogettext=1 \
+ -v pkg_namespace=eventstr_ > $(srcdir)/audit-events.h
+
+# Create the status-codes.h include file from status.h
+status-codes.h: Makefile.am mkstrtable.awk exstatus.awk status.h
+ $(AWK) -f $(srcdir)/exstatus.awk $(srcdir)/status.h \
+ | $(AWK) -f $(srcdir)/mkstrtable.awk -v textidx=3 -v nogettext=1 \
+ -v pkg_namespace=statusstr_ > $(srcdir)/status-codes.h
+endif
+
+#
+# Module tests
+#
+module_tests = t-stringhelp t-timestuff \
+ t-convert t-percent t-gettime t-sysutils t-sexputil \
+ t-session-env t-openpgp-oid t-ssh-utils \
+ t-mapstrings t-zb32 t-mbox-util t-iobuf t-strlist \
+ t-name-value t-ccparray t-recsel t-w32-cmdline
+if !HAVE_W32CE_SYSTEM
+module_tests += t-exechelp t-exectool
+endif
+if HAVE_W32_SYSTEM
+module_tests += t-w32-reg
+endif
+
+if MAINTAINER_MODE
+module_maint_tests = t-helpfile t-b64
+else
+module_maint_tests =
+endif
+
+t_extra_src = t-support.h
+
+t_common_cflags = $(KSBA_CFLAGS) $(LIBGCRYPT_CFLAGS) \
+ $(LIBASSUAN_CFLAGS) $(GPG_ERROR_CFLAGS) $(INCICONV)
+t_common_ldadd = libcommon.a \
+ $(LIBGCRYPT_LIBS) $(LIBASSUAN_LIBS) $(GPG_ERROR_LIBS) \
+ $(LIBINTL) $(LIBICONV) $(NETLIBS)
+
+
+# Common tests
+t_stringhelp_SOURCES = t-stringhelp.c $(t_extra_src)
+t_stringhelp_LDADD = $(t_common_ldadd)
+
+t_timestuff_SOURCES = t-timestuff.c $(t_extra_src)
+t_timestuff_LDADD = $(t_common_ldadd)
+
+t_convert_LDADD = $(t_common_ldadd)
+t_percent_LDADD = $(t_common_ldadd)
+t_gettime_LDADD = $(t_common_ldadd)
+t_sysutils_LDADD = $(t_common_ldadd)
+t_helpfile_LDADD = $(t_common_ldadd)
+t_sexputil_LDADD = $(t_common_ldadd)
+t_b64_LDADD = $(t_common_ldadd)
+t_exechelp_LDADD = $(t_common_ldadd)
+t_exectool_LDADD = $(t_common_ldadd)
+t_session_env_LDADD = $(t_common_ldadd)
+t_openpgp_oid_LDADD = $(t_common_ldadd)
+t_ssh_utils_LDADD = $(t_common_ldadd)
+t_mapstrings_LDADD = $(t_common_ldadd)
+
+t_zb32_SOURCES = t-zb32.c $(t_extra_src)
+t_zb32_LDADD = $(t_common_ldadd)
+
+t_mbox_util_LDADD = $(t_common_ldadd)
+t_iobuf_LDADD = $(t_common_ldadd)
+t_strlist_LDADD = $(t_common_ldadd)
+t_name_value_LDADD = $(t_common_ldadd)
+t_ccparray_LDADD = $(t_common_ldadd)
+t_recsel_LDADD = $(t_common_ldadd)
+
+t_w32_cmdline_SOURCES = t-w32-cmdline.c w32-cmdline.c $(t_extra_src)
+t_w32_cmdline_LDADD = $(t_common_ldadd)
+
+# System specific test
+if HAVE_W32_SYSTEM
+t_w32_reg_SOURCES = t-w32-reg.c $(t_extra_src)
+t_w32_reg_LDADD = $(t_common_ldadd)
+endif
+
+# All programs should depend on the created libs.
+$(PROGRAMS) : libcommon.a libcommonpth.a
diff --git a/common/Makefile.in b/common/Makefile.in
new file mode 100644
index 0000000..d78f9c0
--- /dev/null
+++ b/common/Makefile.in
@@ -0,0 +1,3509 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# 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.
+
+@SET_MAKE@
+
+# Makefile for common gnupg modules
+# Copyright (C) 2001, 2003, 2007, 2010 Free Software Foundation, Inc.
+#
+# This file is part of GnuPG.
+#
+# GnuPG is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# GnuPG is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <https://www.gnu.org/licenses/>.
+
+# cmacros.am - C macro definitions
+# 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 3 of the License, or
+# (at your option) any later version.
+#
+# GnuPG is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <https://www.gnu.org/licenses/>.
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@HAVE_W32CE_SYSTEM_FALSE@am__append_1 = libsimple-pwquery.a
+noinst_PROGRAMS = $(am__EXEEXT_3) $(am__EXEEXT_4)
+@DISABLE_TESTS_FALSE@TESTS = $(am__EXEEXT_3)
+@HAVE_DOSISH_SYSTEM_FALSE@am__append_2 = -DGNUPG_BINDIR="\"$(bindir)\"" \
+@HAVE_DOSISH_SYSTEM_FALSE@ -DGNUPG_LIBEXECDIR="\"$(libexecdir)\"" \
+@HAVE_DOSISH_SYSTEM_FALSE@ -DGNUPG_LIBDIR="\"$(libdir)/@PACKAGE@\"" \
+@HAVE_DOSISH_SYSTEM_FALSE@ -DGNUPG_DATADIR="\"$(datadir)/@PACKAGE@\"" \
+@HAVE_DOSISH_SYSTEM_FALSE@ -DGNUPG_SYSCONFDIR="\"$(sysconfdir)/@PACKAGE@\"" \
+@HAVE_DOSISH_SYSTEM_FALSE@ -DGNUPG_LOCALSTATEDIR="\"$(localstatedir)\""
+
+
+# If a specific protect tool program has been defined, pass its name
+# to cc. Note that these macros should not be used directly but via
+# the gnupg_module_name function.
+@GNUPG_AGENT_PGM_TRUE@am__append_3 = -DGNUPG_DEFAULT_AGENT="\"@GNUPG_AGENT_PGM@\""
+@GNUPG_PINENTRY_PGM_TRUE@am__append_4 = -DGNUPG_DEFAULT_PINENTRY="\"@GNUPG_PINENTRY_PGM@\""
+@GNUPG_SCDAEMON_PGM_TRUE@am__append_5 = -DGNUPG_DEFAULT_SCDAEMON="\"@GNUPG_SCDAEMON_PGM@\""
+@GNUPG_DIRMNGR_PGM_TRUE@am__append_6 = -DGNUPG_DEFAULT_DIRMNGR="\"@GNUPG_DIRMNGR_PGM@\""
+@GNUPG_PROTECT_TOOL_PGM_TRUE@am__append_7 = -DGNUPG_DEFAULT_PROTECT_TOOL="\"@GNUPG_PROTECT_TOOL_PGM@\""
+@GNUPG_DIRMNGR_LDAP_PGM_TRUE@am__append_8 = -DGNUPG_DEFAULT_DIRMNGR_LDAP="\"@GNUPG_DIRMNGR_LDAP_PGM@\""
+@HAVE_W32_SYSTEM_TRUE@am__append_9 = w32-reg.c w32-cmdline.c
+
+# To make the code easier to read we have split home some code into
+# separate source files.
+@HAVE_W32CE_SYSTEM_TRUE@@HAVE_W32_SYSTEM_TRUE@am__append_10 = exechelp-w32ce.c
+@HAVE_W32CE_SYSTEM_FALSE@@HAVE_W32_SYSTEM_TRUE@am__append_11 = exechelp-w32.c
+@HAVE_W32_SYSTEM_FALSE@am__append_12 = exechelp-posix.c
+@HAVE_W32CE_SYSTEM_FALSE@am__append_13 = t-exechelp t-exectool
+@HAVE_W32_SYSTEM_TRUE@am__append_14 = t-w32-reg
+subdir = common
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/autobuild.m4 \
+ $(top_srcdir)/m4/codeset.m4 $(top_srcdir)/m4/gettext.m4 \
+ $(top_srcdir)/m4/gpg-error.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/isc-posix.m4 $(top_srcdir)/m4/ksba.m4 \
+ $(top_srcdir)/m4/lcmessage.m4 $(top_srcdir)/m4/ldap.m4 \
+ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \
+ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libassuan.m4 \
+ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/nls.m4 \
+ $(top_srcdir)/m4/npth.m4 $(top_srcdir)/m4/ntbtls.m4 \
+ $(top_srcdir)/m4/pkg.m4 $(top_srcdir)/m4/po.m4 \
+ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/readline.m4 \
+ $(top_srcdir)/m4/socklen.m4 $(top_srcdir)/m4/sys_socket_h.m4 \
+ $(top_srcdir)/m4/tar-ustar.m4 $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(SHELL) $(top_srcdir)/build-aux/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES = w32info-rc.h
+CONFIG_CLEAN_VPATH_FILES =
+@HAVE_W32CE_SYSTEM_FALSE@am__EXEEXT_1 = t-exechelp$(EXEEXT) \
+@HAVE_W32CE_SYSTEM_FALSE@ t-exectool$(EXEEXT)
+@HAVE_W32_SYSTEM_TRUE@am__EXEEXT_2 = t-w32-reg$(EXEEXT)
+am__EXEEXT_3 = t-stringhelp$(EXEEXT) t-timestuff$(EXEEXT) \
+ t-convert$(EXEEXT) t-percent$(EXEEXT) t-gettime$(EXEEXT) \
+ t-sysutils$(EXEEXT) t-sexputil$(EXEEXT) t-session-env$(EXEEXT) \
+ t-openpgp-oid$(EXEEXT) t-ssh-utils$(EXEEXT) \
+ t-mapstrings$(EXEEXT) t-zb32$(EXEEXT) t-mbox-util$(EXEEXT) \
+ t-iobuf$(EXEEXT) t-strlist$(EXEEXT) t-name-value$(EXEEXT) \
+ t-ccparray$(EXEEXT) t-recsel$(EXEEXT) t-w32-cmdline$(EXEEXT) \
+ $(am__EXEEXT_1) $(am__EXEEXT_2)
+@MAINTAINER_MODE_TRUE@am__EXEEXT_4 = t-helpfile$(EXEEXT) \
+@MAINTAINER_MODE_TRUE@ t-b64$(EXEEXT)
+PROGRAMS = $(noinst_PROGRAMS)
+LIBRARIES = $(noinst_LIBRARIES)
+ARFLAGS = cru
+AM_V_AR = $(am__v_AR_@AM_V@)
+am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@)
+am__v_AR_0 = @echo " AR " $@;
+am__v_AR_1 =
+libcommon_a_AR = $(AR) $(ARFLAGS)
+libcommon_a_LIBADD =
+am__libcommon_a_SOURCES_DIST = common-defs.h util.h utilproto.h \
+ fwddecl.h i18n.c i18n.h types.h host2net.h dynload.h w32help.h \
+ mapstrings.c stringhelp.c stringhelp.h strlist.c strlist.h \
+ utf8conv.c utf8conv.h argparse.c argparse.h logging.c \
+ logging.h dotlock.c dotlock.h mischelp.c mischelp.h status.c \
+ status.h shareddefs.h openpgpdefs.h gc-opt-flags.h \
+ sexp-parse.h tlv.c tlv.h tlv-builder.c init.c init.h \
+ sexputil.c sysutils.c sysutils.h homedir.c gettime.c gettime.h \
+ yesno.c b64enc.c b64dec.c zb32.c zb32.h convert.c percent.c \
+ mbox-util.c mbox-util.h miscellaneous.c xasprintf.c \
+ xreadline.c membuf.c membuf.h ccparray.c ccparray.h iobuf.c \
+ iobuf.h ttyio.c ttyio.h asshelp.c asshelp2.c asshelp.h \
+ exechelp.h signal.c audit.c audit.h localename.c session-env.c \
+ session-env.h userids.c userids.h openpgp-oid.c ssh-utils.c \
+ ssh-utils.h agent-opt.c helpfile.c mkdir_p.c mkdir_p.h \
+ exectool.c exectool.h server-help.c server-help.h name-value.c \
+ name-value.h recsel.c recsel.h ksba-io-support.c \
+ ksba-io-support.h openpgp-fpr.c compliance.c compliance.h \
+ w32-reg.c w32-cmdline.c exechelp-w32ce.c exechelp-w32.c \
+ exechelp-posix.c get-passphrase.c get-passphrase.h
+@HAVE_W32_SYSTEM_TRUE@am__objects_1 = libcommon_a-w32-reg.$(OBJEXT) \
+@HAVE_W32_SYSTEM_TRUE@ libcommon_a-w32-cmdline.$(OBJEXT)
+@HAVE_W32CE_SYSTEM_TRUE@@HAVE_W32_SYSTEM_TRUE@am__objects_2 = libcommon_a-exechelp-w32ce.$(OBJEXT)
+@HAVE_W32CE_SYSTEM_FALSE@@HAVE_W32_SYSTEM_TRUE@am__objects_3 = libcommon_a-exechelp-w32.$(OBJEXT)
+@HAVE_W32_SYSTEM_FALSE@am__objects_4 = \
+@HAVE_W32_SYSTEM_FALSE@ libcommon_a-exechelp-posix.$(OBJEXT)
+am__objects_5 = libcommon_a-i18n.$(OBJEXT) \
+ libcommon_a-mapstrings.$(OBJEXT) \
+ libcommon_a-stringhelp.$(OBJEXT) libcommon_a-strlist.$(OBJEXT) \
+ libcommon_a-utf8conv.$(OBJEXT) libcommon_a-argparse.$(OBJEXT) \
+ libcommon_a-logging.$(OBJEXT) libcommon_a-dotlock.$(OBJEXT) \
+ libcommon_a-mischelp.$(OBJEXT) libcommon_a-status.$(OBJEXT) \
+ libcommon_a-tlv.$(OBJEXT) libcommon_a-tlv-builder.$(OBJEXT) \
+ libcommon_a-init.$(OBJEXT) libcommon_a-sexputil.$(OBJEXT) \
+ libcommon_a-sysutils.$(OBJEXT) libcommon_a-homedir.$(OBJEXT) \
+ libcommon_a-gettime.$(OBJEXT) libcommon_a-yesno.$(OBJEXT) \
+ libcommon_a-b64enc.$(OBJEXT) libcommon_a-b64dec.$(OBJEXT) \
+ libcommon_a-zb32.$(OBJEXT) libcommon_a-convert.$(OBJEXT) \
+ libcommon_a-percent.$(OBJEXT) libcommon_a-mbox-util.$(OBJEXT) \
+ libcommon_a-miscellaneous.$(OBJEXT) \
+ libcommon_a-xasprintf.$(OBJEXT) \
+ libcommon_a-xreadline.$(OBJEXT) libcommon_a-membuf.$(OBJEXT) \
+ libcommon_a-ccparray.$(OBJEXT) libcommon_a-iobuf.$(OBJEXT) \
+ libcommon_a-ttyio.$(OBJEXT) libcommon_a-asshelp.$(OBJEXT) \
+ libcommon_a-asshelp2.$(OBJEXT) libcommon_a-signal.$(OBJEXT) \
+ libcommon_a-audit.$(OBJEXT) libcommon_a-localename.$(OBJEXT) \
+ libcommon_a-session-env.$(OBJEXT) \
+ libcommon_a-userids.$(OBJEXT) \
+ libcommon_a-openpgp-oid.$(OBJEXT) \
+ libcommon_a-ssh-utils.$(OBJEXT) \
+ libcommon_a-agent-opt.$(OBJEXT) libcommon_a-helpfile.$(OBJEXT) \
+ libcommon_a-mkdir_p.$(OBJEXT) libcommon_a-strlist.$(OBJEXT) \
+ libcommon_a-exectool.$(OBJEXT) \
+ libcommon_a-server-help.$(OBJEXT) \
+ libcommon_a-name-value.$(OBJEXT) libcommon_a-recsel.$(OBJEXT) \
+ libcommon_a-ksba-io-support.$(OBJEXT) \
+ libcommon_a-openpgp-fpr.$(OBJEXT) \
+ libcommon_a-compliance.$(OBJEXT) $(am__objects_1) \
+ $(am__objects_2) $(am__objects_3) $(am__objects_4)
+am__objects_6 = libcommon_a-get-passphrase.$(OBJEXT)
+am_libcommon_a_OBJECTS = $(am__objects_5) $(am__objects_6)
+libcommon_a_OBJECTS = $(am_libcommon_a_OBJECTS)
+libcommonpth_a_AR = $(AR) $(ARFLAGS)
+libcommonpth_a_LIBADD =
+am__libcommonpth_a_SOURCES_DIST = common-defs.h util.h utilproto.h \
+ fwddecl.h i18n.c i18n.h types.h host2net.h dynload.h w32help.h \
+ mapstrings.c stringhelp.c stringhelp.h strlist.c strlist.h \
+ utf8conv.c utf8conv.h argparse.c argparse.h logging.c \
+ logging.h dotlock.c dotlock.h mischelp.c mischelp.h status.c \
+ status.h shareddefs.h openpgpdefs.h gc-opt-flags.h \
+ sexp-parse.h tlv.c tlv.h tlv-builder.c init.c init.h \
+ sexputil.c sysutils.c sysutils.h homedir.c gettime.c gettime.h \
+ yesno.c b64enc.c b64dec.c zb32.c zb32.h convert.c percent.c \
+ mbox-util.c mbox-util.h miscellaneous.c xasprintf.c \
+ xreadline.c membuf.c membuf.h ccparray.c ccparray.h iobuf.c \
+ iobuf.h ttyio.c ttyio.h asshelp.c asshelp2.c asshelp.h \
+ exechelp.h signal.c audit.c audit.h localename.c session-env.c \
+ session-env.h userids.c userids.h openpgp-oid.c ssh-utils.c \
+ ssh-utils.h agent-opt.c helpfile.c mkdir_p.c mkdir_p.h \
+ exectool.c exectool.h server-help.c server-help.h name-value.c \
+ name-value.h recsel.c recsel.h ksba-io-support.c \
+ ksba-io-support.h openpgp-fpr.c compliance.c compliance.h \
+ w32-reg.c w32-cmdline.c exechelp-w32ce.c exechelp-w32.c \
+ exechelp-posix.c call-gpg.c call-gpg.h
+@HAVE_W32_SYSTEM_TRUE@am__objects_7 = \
+@HAVE_W32_SYSTEM_TRUE@ libcommonpth_a-w32-reg.$(OBJEXT) \
+@HAVE_W32_SYSTEM_TRUE@ libcommonpth_a-w32-cmdline.$(OBJEXT)
+@HAVE_W32CE_SYSTEM_TRUE@@HAVE_W32_SYSTEM_TRUE@am__objects_8 = libcommonpth_a-exechelp-w32ce.$(OBJEXT)
+@HAVE_W32CE_SYSTEM_FALSE@@HAVE_W32_SYSTEM_TRUE@am__objects_9 = libcommonpth_a-exechelp-w32.$(OBJEXT)
+@HAVE_W32_SYSTEM_FALSE@am__objects_10 = libcommonpth_a-exechelp-posix.$(OBJEXT)
+am__objects_11 = libcommonpth_a-i18n.$(OBJEXT) \
+ libcommonpth_a-mapstrings.$(OBJEXT) \
+ libcommonpth_a-stringhelp.$(OBJEXT) \
+ libcommonpth_a-strlist.$(OBJEXT) \
+ libcommonpth_a-utf8conv.$(OBJEXT) \
+ libcommonpth_a-argparse.$(OBJEXT) \
+ libcommonpth_a-logging.$(OBJEXT) \
+ libcommonpth_a-dotlock.$(OBJEXT) \
+ libcommonpth_a-mischelp.$(OBJEXT) \
+ libcommonpth_a-status.$(OBJEXT) libcommonpth_a-tlv.$(OBJEXT) \
+ libcommonpth_a-tlv-builder.$(OBJEXT) \
+ libcommonpth_a-init.$(OBJEXT) \
+ libcommonpth_a-sexputil.$(OBJEXT) \
+ libcommonpth_a-sysutils.$(OBJEXT) \
+ libcommonpth_a-homedir.$(OBJEXT) \
+ libcommonpth_a-gettime.$(OBJEXT) \
+ libcommonpth_a-yesno.$(OBJEXT) libcommonpth_a-b64enc.$(OBJEXT) \
+ libcommonpth_a-b64dec.$(OBJEXT) libcommonpth_a-zb32.$(OBJEXT) \
+ libcommonpth_a-convert.$(OBJEXT) \
+ libcommonpth_a-percent.$(OBJEXT) \
+ libcommonpth_a-mbox-util.$(OBJEXT) \
+ libcommonpth_a-miscellaneous.$(OBJEXT) \
+ libcommonpth_a-xasprintf.$(OBJEXT) \
+ libcommonpth_a-xreadline.$(OBJEXT) \
+ libcommonpth_a-membuf.$(OBJEXT) \
+ libcommonpth_a-ccparray.$(OBJEXT) \
+ libcommonpth_a-iobuf.$(OBJEXT) libcommonpth_a-ttyio.$(OBJEXT) \
+ libcommonpth_a-asshelp.$(OBJEXT) \
+ libcommonpth_a-asshelp2.$(OBJEXT) \
+ libcommonpth_a-signal.$(OBJEXT) libcommonpth_a-audit.$(OBJEXT) \
+ libcommonpth_a-localename.$(OBJEXT) \
+ libcommonpth_a-session-env.$(OBJEXT) \
+ libcommonpth_a-userids.$(OBJEXT) \
+ libcommonpth_a-openpgp-oid.$(OBJEXT) \
+ libcommonpth_a-ssh-utils.$(OBJEXT) \
+ libcommonpth_a-agent-opt.$(OBJEXT) \
+ libcommonpth_a-helpfile.$(OBJEXT) \
+ libcommonpth_a-mkdir_p.$(OBJEXT) \
+ libcommonpth_a-strlist.$(OBJEXT) \
+ libcommonpth_a-exectool.$(OBJEXT) \
+ libcommonpth_a-server-help.$(OBJEXT) \
+ libcommonpth_a-name-value.$(OBJEXT) \
+ libcommonpth_a-recsel.$(OBJEXT) \
+ libcommonpth_a-ksba-io-support.$(OBJEXT) \
+ libcommonpth_a-openpgp-fpr.$(OBJEXT) \
+ libcommonpth_a-compliance.$(OBJEXT) $(am__objects_7) \
+ $(am__objects_8) $(am__objects_9) $(am__objects_10)
+am__objects_12 = libcommonpth_a-call-gpg.$(OBJEXT)
+am_libcommonpth_a_OBJECTS = $(am__objects_11) $(am__objects_12)
+libcommonpth_a_OBJECTS = $(am_libcommonpth_a_OBJECTS)
+libgpgrl_a_AR = $(AR) $(ARFLAGS)
+libgpgrl_a_LIBADD =
+am_libgpgrl_a_OBJECTS = gpgrlhelp.$(OBJEXT)
+libgpgrl_a_OBJECTS = $(am_libgpgrl_a_OBJECTS)
+libsimple_pwquery_a_AR = $(AR) $(ARFLAGS)
+libsimple_pwquery_a_LIBADD =
+am__libsimple_pwquery_a_SOURCES_DIST = simple-pwquery.c \
+ simple-pwquery.h asshelp.c asshelp.h
+@HAVE_W32CE_SYSTEM_FALSE@am_libsimple_pwquery_a_OBJECTS = libsimple_pwquery_a-simple-pwquery.$(OBJEXT) \
+@HAVE_W32CE_SYSTEM_FALSE@ libsimple_pwquery_a-asshelp.$(OBJEXT)
+libsimple_pwquery_a_OBJECTS = $(am_libsimple_pwquery_a_OBJECTS)
+t_b64_SOURCES = t-b64.c
+t_b64_OBJECTS = t-b64.$(OBJEXT)
+am__DEPENDENCIES_1 =
+am__DEPENDENCIES_2 = libcommon.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
+t_b64_DEPENDENCIES = $(am__DEPENDENCIES_2)
+t_ccparray_SOURCES = t-ccparray.c
+t_ccparray_OBJECTS = t-ccparray.$(OBJEXT)
+t_ccparray_DEPENDENCIES = $(am__DEPENDENCIES_2)
+t_convert_SOURCES = t-convert.c
+t_convert_OBJECTS = t-convert.$(OBJEXT)
+t_convert_DEPENDENCIES = $(am__DEPENDENCIES_2)
+t_exechelp_SOURCES = t-exechelp.c
+t_exechelp_OBJECTS = t-exechelp.$(OBJEXT)
+t_exechelp_DEPENDENCIES = $(am__DEPENDENCIES_2)
+t_exectool_SOURCES = t-exectool.c
+t_exectool_OBJECTS = t-exectool.$(OBJEXT)
+t_exectool_DEPENDENCIES = $(am__DEPENDENCIES_2)
+t_gettime_SOURCES = t-gettime.c
+t_gettime_OBJECTS = t-gettime.$(OBJEXT)
+t_gettime_DEPENDENCIES = $(am__DEPENDENCIES_2)
+t_helpfile_SOURCES = t-helpfile.c
+t_helpfile_OBJECTS = t-helpfile.$(OBJEXT)
+t_helpfile_DEPENDENCIES = $(am__DEPENDENCIES_2)
+t_iobuf_SOURCES = t-iobuf.c
+t_iobuf_OBJECTS = t-iobuf.$(OBJEXT)
+t_iobuf_DEPENDENCIES = $(am__DEPENDENCIES_2)
+t_mapstrings_SOURCES = t-mapstrings.c
+t_mapstrings_OBJECTS = t-mapstrings.$(OBJEXT)
+t_mapstrings_DEPENDENCIES = $(am__DEPENDENCIES_2)
+t_mbox_util_SOURCES = t-mbox-util.c
+t_mbox_util_OBJECTS = t-mbox-util.$(OBJEXT)
+t_mbox_util_DEPENDENCIES = $(am__DEPENDENCIES_2)
+t_name_value_SOURCES = t-name-value.c
+t_name_value_OBJECTS = t-name-value.$(OBJEXT)
+t_name_value_DEPENDENCIES = $(am__DEPENDENCIES_2)
+t_openpgp_oid_SOURCES = t-openpgp-oid.c
+t_openpgp_oid_OBJECTS = t-openpgp-oid.$(OBJEXT)
+t_openpgp_oid_DEPENDENCIES = $(am__DEPENDENCIES_2)
+t_percent_SOURCES = t-percent.c
+t_percent_OBJECTS = t-percent.$(OBJEXT)
+t_percent_DEPENDENCIES = $(am__DEPENDENCIES_2)
+t_recsel_SOURCES = t-recsel.c
+t_recsel_OBJECTS = t-recsel.$(OBJEXT)
+t_recsel_DEPENDENCIES = $(am__DEPENDENCIES_2)
+t_session_env_SOURCES = t-session-env.c
+t_session_env_OBJECTS = t-session-env.$(OBJEXT)
+t_session_env_DEPENDENCIES = $(am__DEPENDENCIES_2)
+t_sexputil_SOURCES = t-sexputil.c
+t_sexputil_OBJECTS = t-sexputil.$(OBJEXT)
+t_sexputil_DEPENDENCIES = $(am__DEPENDENCIES_2)
+t_ssh_utils_SOURCES = t-ssh-utils.c
+t_ssh_utils_OBJECTS = t-ssh-utils.$(OBJEXT)
+t_ssh_utils_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am__objects_13 =
+am_t_stringhelp_OBJECTS = t-stringhelp.$(OBJEXT) $(am__objects_13)
+t_stringhelp_OBJECTS = $(am_t_stringhelp_OBJECTS)
+t_stringhelp_DEPENDENCIES = $(am__DEPENDENCIES_2)
+t_strlist_SOURCES = t-strlist.c
+t_strlist_OBJECTS = t-strlist.$(OBJEXT)
+t_strlist_DEPENDENCIES = $(am__DEPENDENCIES_2)
+t_sysutils_SOURCES = t-sysutils.c
+t_sysutils_OBJECTS = t-sysutils.$(OBJEXT)
+t_sysutils_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_t_timestuff_OBJECTS = t-timestuff.$(OBJEXT) $(am__objects_13)
+t_timestuff_OBJECTS = $(am_t_timestuff_OBJECTS)
+t_timestuff_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_t_w32_cmdline_OBJECTS = t-w32-cmdline.$(OBJEXT) \
+ w32-cmdline.$(OBJEXT) $(am__objects_13)
+t_w32_cmdline_OBJECTS = $(am_t_w32_cmdline_OBJECTS)
+t_w32_cmdline_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am__t_w32_reg_SOURCES_DIST = t-w32-reg.c t-support.h
+@HAVE_W32_SYSTEM_TRUE@am_t_w32_reg_OBJECTS = t-w32-reg.$(OBJEXT) \
+@HAVE_W32_SYSTEM_TRUE@ $(am__objects_13)
+t_w32_reg_OBJECTS = $(am_t_w32_reg_OBJECTS)
+@HAVE_W32_SYSTEM_TRUE@t_w32_reg_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_t_zb32_OBJECTS = t-zb32.$(OBJEXT) $(am__objects_13)
+t_zb32_OBJECTS = $(am_t_zb32_OBJECTS)
+t_zb32_DEPENDENCIES = $(am__DEPENDENCIES_2)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/gpgrlhelp.Po \
+ ./$(DEPDIR)/libcommon_a-agent-opt.Po \
+ ./$(DEPDIR)/libcommon_a-argparse.Po \
+ ./$(DEPDIR)/libcommon_a-asshelp.Po \
+ ./$(DEPDIR)/libcommon_a-asshelp2.Po \
+ ./$(DEPDIR)/libcommon_a-audit.Po \
+ ./$(DEPDIR)/libcommon_a-b64dec.Po \
+ ./$(DEPDIR)/libcommon_a-b64enc.Po \
+ ./$(DEPDIR)/libcommon_a-ccparray.Po \
+ ./$(DEPDIR)/libcommon_a-compliance.Po \
+ ./$(DEPDIR)/libcommon_a-convert.Po \
+ ./$(DEPDIR)/libcommon_a-dotlock.Po \
+ ./$(DEPDIR)/libcommon_a-exechelp-posix.Po \
+ ./$(DEPDIR)/libcommon_a-exechelp-w32.Po \
+ ./$(DEPDIR)/libcommon_a-exechelp-w32ce.Po \
+ ./$(DEPDIR)/libcommon_a-exectool.Po \
+ ./$(DEPDIR)/libcommon_a-get-passphrase.Po \
+ ./$(DEPDIR)/libcommon_a-gettime.Po \
+ ./$(DEPDIR)/libcommon_a-helpfile.Po \
+ ./$(DEPDIR)/libcommon_a-homedir.Po \
+ ./$(DEPDIR)/libcommon_a-i18n.Po \
+ ./$(DEPDIR)/libcommon_a-init.Po \
+ ./$(DEPDIR)/libcommon_a-iobuf.Po \
+ ./$(DEPDIR)/libcommon_a-ksba-io-support.Po \
+ ./$(DEPDIR)/libcommon_a-localename.Po \
+ ./$(DEPDIR)/libcommon_a-logging.Po \
+ ./$(DEPDIR)/libcommon_a-mapstrings.Po \
+ ./$(DEPDIR)/libcommon_a-mbox-util.Po \
+ ./$(DEPDIR)/libcommon_a-membuf.Po \
+ ./$(DEPDIR)/libcommon_a-miscellaneous.Po \
+ ./$(DEPDIR)/libcommon_a-mischelp.Po \
+ ./$(DEPDIR)/libcommon_a-mkdir_p.Po \
+ ./$(DEPDIR)/libcommon_a-name-value.Po \
+ ./$(DEPDIR)/libcommon_a-openpgp-fpr.Po \
+ ./$(DEPDIR)/libcommon_a-openpgp-oid.Po \
+ ./$(DEPDIR)/libcommon_a-percent.Po \
+ ./$(DEPDIR)/libcommon_a-recsel.Po \
+ ./$(DEPDIR)/libcommon_a-server-help.Po \
+ ./$(DEPDIR)/libcommon_a-session-env.Po \
+ ./$(DEPDIR)/libcommon_a-sexputil.Po \
+ ./$(DEPDIR)/libcommon_a-signal.Po \
+ ./$(DEPDIR)/libcommon_a-ssh-utils.Po \
+ ./$(DEPDIR)/libcommon_a-status.Po \
+ ./$(DEPDIR)/libcommon_a-stringhelp.Po \
+ ./$(DEPDIR)/libcommon_a-strlist.Po \
+ ./$(DEPDIR)/libcommon_a-sysutils.Po \
+ ./$(DEPDIR)/libcommon_a-tlv-builder.Po \
+ ./$(DEPDIR)/libcommon_a-tlv.Po \
+ ./$(DEPDIR)/libcommon_a-ttyio.Po \
+ ./$(DEPDIR)/libcommon_a-userids.Po \
+ ./$(DEPDIR)/libcommon_a-utf8conv.Po \
+ ./$(DEPDIR)/libcommon_a-w32-cmdline.Po \
+ ./$(DEPDIR)/libcommon_a-w32-reg.Po \
+ ./$(DEPDIR)/libcommon_a-xasprintf.Po \
+ ./$(DEPDIR)/libcommon_a-xreadline.Po \
+ ./$(DEPDIR)/libcommon_a-yesno.Po \
+ ./$(DEPDIR)/libcommon_a-zb32.Po \
+ ./$(DEPDIR)/libcommonpth_a-agent-opt.Po \
+ ./$(DEPDIR)/libcommonpth_a-argparse.Po \
+ ./$(DEPDIR)/libcommonpth_a-asshelp.Po \
+ ./$(DEPDIR)/libcommonpth_a-asshelp2.Po \
+ ./$(DEPDIR)/libcommonpth_a-audit.Po \
+ ./$(DEPDIR)/libcommonpth_a-b64dec.Po \
+ ./$(DEPDIR)/libcommonpth_a-b64enc.Po \
+ ./$(DEPDIR)/libcommonpth_a-call-gpg.Po \
+ ./$(DEPDIR)/libcommonpth_a-ccparray.Po \
+ ./$(DEPDIR)/libcommonpth_a-compliance.Po \
+ ./$(DEPDIR)/libcommonpth_a-convert.Po \
+ ./$(DEPDIR)/libcommonpth_a-dotlock.Po \
+ ./$(DEPDIR)/libcommonpth_a-exechelp-posix.Po \
+ ./$(DEPDIR)/libcommonpth_a-exechelp-w32.Po \
+ ./$(DEPDIR)/libcommonpth_a-exechelp-w32ce.Po \
+ ./$(DEPDIR)/libcommonpth_a-exectool.Po \
+ ./$(DEPDIR)/libcommonpth_a-gettime.Po \
+ ./$(DEPDIR)/libcommonpth_a-helpfile.Po \
+ ./$(DEPDIR)/libcommonpth_a-homedir.Po \
+ ./$(DEPDIR)/libcommonpth_a-i18n.Po \
+ ./$(DEPDIR)/libcommonpth_a-init.Po \
+ ./$(DEPDIR)/libcommonpth_a-iobuf.Po \
+ ./$(DEPDIR)/libcommonpth_a-ksba-io-support.Po \
+ ./$(DEPDIR)/libcommonpth_a-localename.Po \
+ ./$(DEPDIR)/libcommonpth_a-logging.Po \
+ ./$(DEPDIR)/libcommonpth_a-mapstrings.Po \
+ ./$(DEPDIR)/libcommonpth_a-mbox-util.Po \
+ ./$(DEPDIR)/libcommonpth_a-membuf.Po \
+ ./$(DEPDIR)/libcommonpth_a-miscellaneous.Po \
+ ./$(DEPDIR)/libcommonpth_a-mischelp.Po \
+ ./$(DEPDIR)/libcommonpth_a-mkdir_p.Po \
+ ./$(DEPDIR)/libcommonpth_a-name-value.Po \
+ ./$(DEPDIR)/libcommonpth_a-openpgp-fpr.Po \
+ ./$(DEPDIR)/libcommonpth_a-openpgp-oid.Po \
+ ./$(DEPDIR)/libcommonpth_a-percent.Po \
+ ./$(DEPDIR)/libcommonpth_a-recsel.Po \
+ ./$(DEPDIR)/libcommonpth_a-server-help.Po \
+ ./$(DEPDIR)/libcommonpth_a-session-env.Po \
+ ./$(DEPDIR)/libcommonpth_a-sexputil.Po \
+ ./$(DEPDIR)/libcommonpth_a-signal.Po \
+ ./$(DEPDIR)/libcommonpth_a-ssh-utils.Po \
+ ./$(DEPDIR)/libcommonpth_a-status.Po \
+ ./$(DEPDIR)/libcommonpth_a-stringhelp.Po \
+ ./$(DEPDIR)/libcommonpth_a-strlist.Po \
+ ./$(DEPDIR)/libcommonpth_a-sysutils.Po \
+ ./$(DEPDIR)/libcommonpth_a-tlv-builder.Po \
+ ./$(DEPDIR)/libcommonpth_a-tlv.Po \
+ ./$(DEPDIR)/libcommonpth_a-ttyio.Po \
+ ./$(DEPDIR)/libcommonpth_a-userids.Po \
+ ./$(DEPDIR)/libcommonpth_a-utf8conv.Po \
+ ./$(DEPDIR)/libcommonpth_a-w32-cmdline.Po \
+ ./$(DEPDIR)/libcommonpth_a-w32-reg.Po \
+ ./$(DEPDIR)/libcommonpth_a-xasprintf.Po \
+ ./$(DEPDIR)/libcommonpth_a-xreadline.Po \
+ ./$(DEPDIR)/libcommonpth_a-yesno.Po \
+ ./$(DEPDIR)/libcommonpth_a-zb32.Po \
+ ./$(DEPDIR)/libsimple_pwquery_a-asshelp.Po \
+ ./$(DEPDIR)/libsimple_pwquery_a-simple-pwquery.Po \
+ ./$(DEPDIR)/t-b64.Po ./$(DEPDIR)/t-ccparray.Po \
+ ./$(DEPDIR)/t-convert.Po ./$(DEPDIR)/t-exechelp.Po \
+ ./$(DEPDIR)/t-exectool.Po ./$(DEPDIR)/t-gettime.Po \
+ ./$(DEPDIR)/t-helpfile.Po ./$(DEPDIR)/t-iobuf.Po \
+ ./$(DEPDIR)/t-mapstrings.Po ./$(DEPDIR)/t-mbox-util.Po \
+ ./$(DEPDIR)/t-name-value.Po ./$(DEPDIR)/t-openpgp-oid.Po \
+ ./$(DEPDIR)/t-percent.Po ./$(DEPDIR)/t-recsel.Po \
+ ./$(DEPDIR)/t-session-env.Po ./$(DEPDIR)/t-sexputil.Po \
+ ./$(DEPDIR)/t-ssh-utils.Po ./$(DEPDIR)/t-stringhelp.Po \
+ ./$(DEPDIR)/t-strlist.Po ./$(DEPDIR)/t-sysutils.Po \
+ ./$(DEPDIR)/t-timestuff.Po ./$(DEPDIR)/t-w32-cmdline.Po \
+ ./$(DEPDIR)/t-w32-reg.Po ./$(DEPDIR)/t-zb32.Po \
+ ./$(DEPDIR)/w32-cmdline.Po
+am__mv = mv -f
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libcommon_a_SOURCES) $(libcommonpth_a_SOURCES) \
+ $(libgpgrl_a_SOURCES) $(libsimple_pwquery_a_SOURCES) t-b64.c \
+ t-ccparray.c t-convert.c t-exechelp.c t-exectool.c t-gettime.c \
+ t-helpfile.c t-iobuf.c t-mapstrings.c t-mbox-util.c \
+ t-name-value.c t-openpgp-oid.c t-percent.c t-recsel.c \
+ t-session-env.c t-sexputil.c t-ssh-utils.c \
+ $(t_stringhelp_SOURCES) t-strlist.c t-sysutils.c \
+ $(t_timestuff_SOURCES) $(t_w32_cmdline_SOURCES) \
+ $(t_w32_reg_SOURCES) $(t_zb32_SOURCES)
+DIST_SOURCES = $(am__libcommon_a_SOURCES_DIST) \
+ $(am__libcommonpth_a_SOURCES_DIST) $(libgpgrl_a_SOURCES) \
+ $(am__libsimple_pwquery_a_SOURCES_DIST) t-b64.c t-ccparray.c \
+ t-convert.c t-exechelp.c t-exectool.c t-gettime.c t-helpfile.c \
+ t-iobuf.c t-mapstrings.c t-mbox-util.c t-name-value.c \
+ t-openpgp-oid.c t-percent.c t-recsel.c t-session-env.c \
+ t-sexputil.c t-ssh-utils.c $(t_stringhelp_SOURCES) t-strlist.c \
+ t-sysutils.c $(t_timestuff_SOURCES) $(t_w32_cmdline_SOURCES) \
+ $(am__t_w32_reg_SOURCES_DIST) $(t_zb32_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__tty_colors_dummy = \
+ mgn= red= grn= lgn= blu= brg= std=; \
+ am__color_tests=no
+am__tty_colors = { \
+ $(am__tty_colors_dummy); \
+ if test "X$(AM_COLOR_TESTS)" = Xno; then \
+ am__color_tests=no; \
+ elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
+ am__color_tests=yes; \
+ elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
+ am__color_tests=yes; \
+ fi; \
+ if test $$am__color_tests = yes; then \
+ red=''; \
+ grn=''; \
+ lgn=''; \
+ blu=''; \
+ mgn=''; \
+ brg=''; \
+ std=''; \
+ fi; \
+}
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/w32info-rc.h.in \
+ $(top_srcdir)/am/cmacros.am $(top_srcdir)/build-aux/depcomp \
+ $(top_srcdir)/build-aux/mkinstalldirs README
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+AWK_HEX_NUMBER_OPTION = @AWK_HEX_NUMBER_OPTION@
+BUILD_FILEVERSION = @BUILD_FILEVERSION@
+BUILD_HOSTNAME = @BUILD_HOSTNAME@
+BUILD_INCLUDED_LIBINTL = @BUILD_INCLUDED_LIBINTL@
+BUILD_REVISION = @BUILD_REVISION@
+BUILD_TIMESTAMP = @BUILD_TIMESTAMP@
+BUILD_VERSION = @BUILD_VERSION@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DL_LIBS = @DL_LIBS@
+DNSLIBS = @DNSLIBS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENCFS = @ENCFS@
+EXEEXT = @EXEEXT@
+FUSERMOUNT = @FUSERMOUNT@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GNUPG_AGENT_PGM = @GNUPG_AGENT_PGM@
+GNUPG_DIRMNGR_LDAP_PGM = @GNUPG_DIRMNGR_LDAP_PGM@
+GNUPG_DIRMNGR_PGM = @GNUPG_DIRMNGR_PGM@
+GNUPG_PINENTRY_PGM = @GNUPG_PINENTRY_PGM@
+GNUPG_PROTECT_TOOL_PGM = @GNUPG_PROTECT_TOOL_PGM@
+GNUPG_SCDAEMON_PGM = @GNUPG_SCDAEMON_PGM@
+GPGKEYS_LDAP = @GPGKEYS_LDAP@
+GPGRT_CONFIG = @GPGRT_CONFIG@
+GPG_ERROR_CFLAGS = @GPG_ERROR_CFLAGS@
+GPG_ERROR_CONFIG = @GPG_ERROR_CONFIG@
+GPG_ERROR_LIBS = @GPG_ERROR_LIBS@
+GPG_ERROR_MT_CFLAGS = @GPG_ERROR_MT_CFLAGS@
+GPG_ERROR_MT_LIBS = @GPG_ERROR_MT_LIBS@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+KSBA_CFLAGS = @KSBA_CFLAGS@
+KSBA_CONFIG = @KSBA_CONFIG@
+KSBA_LIBS = @KSBA_LIBS@
+LBER_LIBS = @LBER_LIBS@
+LDAPLIBS = @LDAPLIBS@
+LDAP_CPPFLAGS = @LDAP_CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBASSUAN_CFLAGS = @LIBASSUAN_CFLAGS@
+LIBASSUAN_CONFIG = @LIBASSUAN_CONFIG@
+LIBASSUAN_LIBS = @LIBASSUAN_LIBS@
+LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@
+LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@
+LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
+LIBGNUTLS_CFLAGS = @LIBGNUTLS_CFLAGS@
+LIBGNUTLS_LIBS = @LIBGNUTLS_LIBS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBOBJS = @LIBOBJS@
+LIBREADLINE = @LIBREADLINE@
+LIBS = @LIBS@
+LIBUSB_CPPFLAGS = @LIBUSB_CPPFLAGS@
+LIBUSB_LIBS = @LIBUSB_LIBS@
+LIBUTIL_LIBS = @LIBUTIL_LIBS@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+NETLIBS = @NETLIBS@
+NPTH_CFLAGS = @NPTH_CFLAGS@
+NPTH_CONFIG = @NPTH_CONFIG@
+NPTH_LIBS = @NPTH_LIBS@
+NTBTLS_CFLAGS = @NTBTLS_CFLAGS@
+NTBTLS_CONFIG = @NTBTLS_CONFIG@
+NTBTLS_LIBS = @NTBTLS_LIBS@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_GT = @PACKAGE_GT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+POSUB = @POSUB@
+RANLIB = @RANLIB@
+SENDMAIL = @SENDMAIL@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SHRED = @SHRED@
+SQLITE3_CFLAGS = @SQLITE3_CFLAGS@
+SQLITE3_LIBS = @SQLITE3_LIBS@
+STRIP = @STRIP@
+SYSROOT = @SYSROOT@
+SYS_SOCKET_H = @SYS_SOCKET_H@
+TAR = @TAR@
+USE_C99_CFLAGS = @USE_C99_CFLAGS@
+USE_INCLUDED_LIBINTL = @USE_INCLUDED_LIBINTL@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+W32SOCKLIBS = @W32SOCKLIBS@
+WINDRES = @WINDRES@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+YAT2M = @YAT2M@
+ZLIBS = @ZLIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = $(datadir)/locale
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+EXTRA_DIST = mkstrtable.awk exaudit.awk exstatus.awk ChangeLog-2011 \
+ audit-events.h status-codes.h ChangeLog.jnlib \
+ ChangeLog-2011.include w32info-rc.h.in gnupg.ico \
+ all-tests.scm
+
+noinst_LIBRARIES = libcommon.a libcommonpth.a libgpgrl.a \
+ $(am__append_1)
+BUILT_SOURCES = audit-events.h status-codes.h
+MAINTAINERCLEANFILES = audit-events.h status-codes.h
+
+# NB: AM_CFLAGS may also be used by tools running on the build
+# platform to create source files.
+AM_CPPFLAGS = -DLOCALEDIR=\"$(localedir)\" $(am__append_2) \
+ $(am__append_3) $(am__append_4) $(am__append_5) \
+ $(am__append_6) $(am__append_7) $(am__append_8)
+AM_CFLAGS = $(LIBGCRYPT_CFLAGS) $(LIBASSUAN_CFLAGS) $(KSBA_CFLAGS)
+@HAVE_W32CE_SYSTEM_FALSE@extra_sys_libs =
+
+# Under Windows we use LockFileEx. WindowsCE provides this only on
+# the WindowsMobile 6 platform and thus we need to use the coredll6
+# import library. We also want to use a stacksize of 256k instead of
+# the 2MB which is the default with cegcc. 256k is the largest stack
+# we use with pth.
+@HAVE_W32CE_SYSTEM_TRUE@extra_sys_libs = -lcoredll6
+@HAVE_W32CE_SYSTEM_FALSE@extra_bin_ldflags =
+@HAVE_W32CE_SYSTEM_TRUE@extra_bin_ldflags = -Wl,--stack=0x40000
+resource_objs =
+
+# Convenience macros
+libcommon = ../common/libcommon.a
+libcommonpth = ../common/libcommonpth.a
+libcommontls = ../common/libcommontls.a
+libcommontlsnpth = ../common/libcommontlsnpth.a
+common_sources = common-defs.h util.h utilproto.h fwddecl.h i18n.c \
+ i18n.h types.h host2net.h dynload.h w32help.h mapstrings.c \
+ stringhelp.c stringhelp.h strlist.c strlist.h utf8conv.c \
+ utf8conv.h argparse.c argparse.h logging.c logging.h dotlock.c \
+ dotlock.h mischelp.c mischelp.h status.c status.h shareddefs.h \
+ openpgpdefs.h gc-opt-flags.h sexp-parse.h tlv.c tlv.h \
+ tlv-builder.c init.c init.h sexputil.c sysutils.c sysutils.h \
+ homedir.c gettime.c gettime.h yesno.c b64enc.c b64dec.c zb32.c \
+ zb32.h convert.c percent.c mbox-util.c mbox-util.h \
+ miscellaneous.c xasprintf.c xreadline.c membuf.c membuf.h \
+ ccparray.c ccparray.h iobuf.c iobuf.h ttyio.c ttyio.h \
+ asshelp.c asshelp2.c asshelp.h exechelp.h signal.c audit.c \
+ audit.h localename.c session-env.c session-env.h userids.c \
+ userids.h openpgp-oid.c ssh-utils.c ssh-utils.h agent-opt.c \
+ helpfile.c mkdir_p.c mkdir_p.h strlist.c strlist.h exectool.c \
+ exectool.h server-help.c server-help.h name-value.c \
+ name-value.h recsel.c recsel.h ksba-io-support.c \
+ ksba-io-support.h openpgp-fpr.c compliance.c compliance.h \
+ $(am__append_9) $(am__append_10) $(am__append_11) \
+ $(am__append_12)
+
+# Sources only useful without NPTH.
+without_npth_sources = \
+ get-passphrase.c get-passphrase.h
+
+
+# Sources only useful with NPTH.
+with_npth_sources = \
+ call-gpg.c call-gpg.h
+
+libcommon_a_SOURCES = $(common_sources) $(without_npth_sources)
+libcommon_a_CFLAGS = $(AM_CFLAGS) $(LIBASSUAN_CFLAGS) -DWITHOUT_NPTH=1
+libcommonpth_a_SOURCES = $(common_sources) $(with_npth_sources)
+libcommonpth_a_CFLAGS = $(AM_CFLAGS) $(LIBASSUAN_CFLAGS) $(NPTH_CFLAGS)
+@HAVE_W32CE_SYSTEM_FALSE@libsimple_pwquery_a_SOURCES = \
+@HAVE_W32CE_SYSTEM_FALSE@ simple-pwquery.c simple-pwquery.h asshelp.c asshelp.h
+
+@HAVE_W32CE_SYSTEM_FALSE@libsimple_pwquery_a_CFLAGS = $(AM_CFLAGS) $(LIBASSUAN_CFLAGS)
+libgpgrl_a_SOURCES = \
+ gpgrlhelp.c
+
+
+#
+# Module tests
+#
+module_tests = t-stringhelp t-timestuff t-convert t-percent t-gettime \
+ t-sysutils t-sexputil t-session-env t-openpgp-oid t-ssh-utils \
+ t-mapstrings t-zb32 t-mbox-util t-iobuf t-strlist t-name-value \
+ t-ccparray t-recsel t-w32-cmdline $(am__append_13) \
+ $(am__append_14)
+@MAINTAINER_MODE_FALSE@module_maint_tests =
+@MAINTAINER_MODE_TRUE@module_maint_tests = t-helpfile t-b64
+t_extra_src = t-support.h
+t_common_cflags = $(KSBA_CFLAGS) $(LIBGCRYPT_CFLAGS) \
+ $(LIBASSUAN_CFLAGS) $(GPG_ERROR_CFLAGS) $(INCICONV)
+
+t_common_ldadd = libcommon.a \
+ $(LIBGCRYPT_LIBS) $(LIBASSUAN_LIBS) $(GPG_ERROR_LIBS) \
+ $(LIBINTL) $(LIBICONV) $(NETLIBS)
+
+
+# Common tests
+t_stringhelp_SOURCES = t-stringhelp.c $(t_extra_src)
+t_stringhelp_LDADD = $(t_common_ldadd)
+t_timestuff_SOURCES = t-timestuff.c $(t_extra_src)
+t_timestuff_LDADD = $(t_common_ldadd)
+t_convert_LDADD = $(t_common_ldadd)
+t_percent_LDADD = $(t_common_ldadd)
+t_gettime_LDADD = $(t_common_ldadd)
+t_sysutils_LDADD = $(t_common_ldadd)
+t_helpfile_LDADD = $(t_common_ldadd)
+t_sexputil_LDADD = $(t_common_ldadd)
+t_b64_LDADD = $(t_common_ldadd)
+t_exechelp_LDADD = $(t_common_ldadd)
+t_exectool_LDADD = $(t_common_ldadd)
+t_session_env_LDADD = $(t_common_ldadd)
+t_openpgp_oid_LDADD = $(t_common_ldadd)
+t_ssh_utils_LDADD = $(t_common_ldadd)
+t_mapstrings_LDADD = $(t_common_ldadd)
+t_zb32_SOURCES = t-zb32.c $(t_extra_src)
+t_zb32_LDADD = $(t_common_ldadd)
+t_mbox_util_LDADD = $(t_common_ldadd)
+t_iobuf_LDADD = $(t_common_ldadd)
+t_strlist_LDADD = $(t_common_ldadd)
+t_name_value_LDADD = $(t_common_ldadd)
+t_ccparray_LDADD = $(t_common_ldadd)
+t_recsel_LDADD = $(t_common_ldadd)
+t_w32_cmdline_SOURCES = t-w32-cmdline.c w32-cmdline.c $(t_extra_src)
+t_w32_cmdline_LDADD = $(t_common_ldadd)
+
+# System specific test
+@HAVE_W32_SYSTEM_TRUE@t_w32_reg_SOURCES = t-w32-reg.c $(t_extra_src)
+@HAVE_W32_SYSTEM_TRUE@t_w32_reg_LDADD = $(t_common_ldadd)
+all: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .o .obj .rc
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/am/cmacros.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu common/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu common/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+$(top_srcdir)/am/cmacros.am $(am__empty):
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+w32info-rc.h: $(top_builddir)/config.status $(srcdir)/w32info-rc.h.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+
+clean-noinstPROGRAMS:
+ -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS)
+
+clean-noinstLIBRARIES:
+ -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+
+libcommon.a: $(libcommon_a_OBJECTS) $(libcommon_a_DEPENDENCIES) $(EXTRA_libcommon_a_DEPENDENCIES)
+ $(AM_V_at)-rm -f libcommon.a
+ $(AM_V_AR)$(libcommon_a_AR) libcommon.a $(libcommon_a_OBJECTS) $(libcommon_a_LIBADD)
+ $(AM_V_at)$(RANLIB) libcommon.a
+
+libcommonpth.a: $(libcommonpth_a_OBJECTS) $(libcommonpth_a_DEPENDENCIES) $(EXTRA_libcommonpth_a_DEPENDENCIES)
+ $(AM_V_at)-rm -f libcommonpth.a
+ $(AM_V_AR)$(libcommonpth_a_AR) libcommonpth.a $(libcommonpth_a_OBJECTS) $(libcommonpth_a_LIBADD)
+ $(AM_V_at)$(RANLIB) libcommonpth.a
+
+libgpgrl.a: $(libgpgrl_a_OBJECTS) $(libgpgrl_a_DEPENDENCIES) $(EXTRA_libgpgrl_a_DEPENDENCIES)
+ $(AM_V_at)-rm -f libgpgrl.a
+ $(AM_V_AR)$(libgpgrl_a_AR) libgpgrl.a $(libgpgrl_a_OBJECTS) $(libgpgrl_a_LIBADD)
+ $(AM_V_at)$(RANLIB) libgpgrl.a
+
+libsimple-pwquery.a: $(libsimple_pwquery_a_OBJECTS) $(libsimple_pwquery_a_DEPENDENCIES) $(EXTRA_libsimple_pwquery_a_DEPENDENCIES)
+ $(AM_V_at)-rm -f libsimple-pwquery.a
+ $(AM_V_AR)$(libsimple_pwquery_a_AR) libsimple-pwquery.a $(libsimple_pwquery_a_OBJECTS) $(libsimple_pwquery_a_LIBADD)
+ $(AM_V_at)$(RANLIB) libsimple-pwquery.a
+
+t-b64$(EXEEXT): $(t_b64_OBJECTS) $(t_b64_DEPENDENCIES) $(EXTRA_t_b64_DEPENDENCIES)
+ @rm -f t-b64$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(t_b64_OBJECTS) $(t_b64_LDADD) $(LIBS)
+
+t-ccparray$(EXEEXT): $(t_ccparray_OBJECTS) $(t_ccparray_DEPENDENCIES) $(EXTRA_t_ccparray_DEPENDENCIES)
+ @rm -f t-ccparray$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(t_ccparray_OBJECTS) $(t_ccparray_LDADD) $(LIBS)
+
+t-convert$(EXEEXT): $(t_convert_OBJECTS) $(t_convert_DEPENDENCIES) $(EXTRA_t_convert_DEPENDENCIES)
+ @rm -f t-convert$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(t_convert_OBJECTS) $(t_convert_LDADD) $(LIBS)
+
+t-exechelp$(EXEEXT): $(t_exechelp_OBJECTS) $(t_exechelp_DEPENDENCIES) $(EXTRA_t_exechelp_DEPENDENCIES)
+ @rm -f t-exechelp$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(t_exechelp_OBJECTS) $(t_exechelp_LDADD) $(LIBS)
+
+t-exectool$(EXEEXT): $(t_exectool_OBJECTS) $(t_exectool_DEPENDENCIES) $(EXTRA_t_exectool_DEPENDENCIES)
+ @rm -f t-exectool$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(t_exectool_OBJECTS) $(t_exectool_LDADD) $(LIBS)
+
+t-gettime$(EXEEXT): $(t_gettime_OBJECTS) $(t_gettime_DEPENDENCIES) $(EXTRA_t_gettime_DEPENDENCIES)
+ @rm -f t-gettime$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(t_gettime_OBJECTS) $(t_gettime_LDADD) $(LIBS)
+
+t-helpfile$(EXEEXT): $(t_helpfile_OBJECTS) $(t_helpfile_DEPENDENCIES) $(EXTRA_t_helpfile_DEPENDENCIES)
+ @rm -f t-helpfile$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(t_helpfile_OBJECTS) $(t_helpfile_LDADD) $(LIBS)
+
+t-iobuf$(EXEEXT): $(t_iobuf_OBJECTS) $(t_iobuf_DEPENDENCIES) $(EXTRA_t_iobuf_DEPENDENCIES)
+ @rm -f t-iobuf$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(t_iobuf_OBJECTS) $(t_iobuf_LDADD) $(LIBS)
+
+t-mapstrings$(EXEEXT): $(t_mapstrings_OBJECTS) $(t_mapstrings_DEPENDENCIES) $(EXTRA_t_mapstrings_DEPENDENCIES)
+ @rm -f t-mapstrings$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(t_mapstrings_OBJECTS) $(t_mapstrings_LDADD) $(LIBS)
+
+t-mbox-util$(EXEEXT): $(t_mbox_util_OBJECTS) $(t_mbox_util_DEPENDENCIES) $(EXTRA_t_mbox_util_DEPENDENCIES)
+ @rm -f t-mbox-util$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(t_mbox_util_OBJECTS) $(t_mbox_util_LDADD) $(LIBS)
+
+t-name-value$(EXEEXT): $(t_name_value_OBJECTS) $(t_name_value_DEPENDENCIES) $(EXTRA_t_name_value_DEPENDENCIES)
+ @rm -f t-name-value$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(t_name_value_OBJECTS) $(t_name_value_LDADD) $(LIBS)
+
+t-openpgp-oid$(EXEEXT): $(t_openpgp_oid_OBJECTS) $(t_openpgp_oid_DEPENDENCIES) $(EXTRA_t_openpgp_oid_DEPENDENCIES)
+ @rm -f t-openpgp-oid$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(t_openpgp_oid_OBJECTS) $(t_openpgp_oid_LDADD) $(LIBS)
+
+t-percent$(EXEEXT): $(t_percent_OBJECTS) $(t_percent_DEPENDENCIES) $(EXTRA_t_percent_DEPENDENCIES)
+ @rm -f t-percent$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(t_percent_OBJECTS) $(t_percent_LDADD) $(LIBS)
+
+t-recsel$(EXEEXT): $(t_recsel_OBJECTS) $(t_recsel_DEPENDENCIES) $(EXTRA_t_recsel_DEPENDENCIES)
+ @rm -f t-recsel$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(t_recsel_OBJECTS) $(t_recsel_LDADD) $(LIBS)
+
+t-session-env$(EXEEXT): $(t_session_env_OBJECTS) $(t_session_env_DEPENDENCIES) $(EXTRA_t_session_env_DEPENDENCIES)
+ @rm -f t-session-env$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(t_session_env_OBJECTS) $(t_session_env_LDADD) $(LIBS)
+
+t-sexputil$(EXEEXT): $(t_sexputil_OBJECTS) $(t_sexputil_DEPENDENCIES) $(EXTRA_t_sexputil_DEPENDENCIES)
+ @rm -f t-sexputil$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(t_sexputil_OBJECTS) $(t_sexputil_LDADD) $(LIBS)
+
+t-ssh-utils$(EXEEXT): $(t_ssh_utils_OBJECTS) $(t_ssh_utils_DEPENDENCIES) $(EXTRA_t_ssh_utils_DEPENDENCIES)
+ @rm -f t-ssh-utils$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(t_ssh_utils_OBJECTS) $(t_ssh_utils_LDADD) $(LIBS)
+
+t-stringhelp$(EXEEXT): $(t_stringhelp_OBJECTS) $(t_stringhelp_DEPENDENCIES) $(EXTRA_t_stringhelp_DEPENDENCIES)
+ @rm -f t-stringhelp$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(t_stringhelp_OBJECTS) $(t_stringhelp_LDADD) $(LIBS)
+
+t-strlist$(EXEEXT): $(t_strlist_OBJECTS) $(t_strlist_DEPENDENCIES) $(EXTRA_t_strlist_DEPENDENCIES)
+ @rm -f t-strlist$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(t_strlist_OBJECTS) $(t_strlist_LDADD) $(LIBS)
+
+t-sysutils$(EXEEXT): $(t_sysutils_OBJECTS) $(t_sysutils_DEPENDENCIES) $(EXTRA_t_sysutils_DEPENDENCIES)
+ @rm -f t-sysutils$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(t_sysutils_OBJECTS) $(t_sysutils_LDADD) $(LIBS)
+
+t-timestuff$(EXEEXT): $(t_timestuff_OBJECTS) $(t_timestuff_DEPENDENCIES) $(EXTRA_t_timestuff_DEPENDENCIES)
+ @rm -f t-timestuff$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(t_timestuff_OBJECTS) $(t_timestuff_LDADD) $(LIBS)
+
+t-w32-cmdline$(EXEEXT): $(t_w32_cmdline_OBJECTS) $(t_w32_cmdline_DEPENDENCIES) $(EXTRA_t_w32_cmdline_DEPENDENCIES)
+ @rm -f t-w32-cmdline$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(t_w32_cmdline_OBJECTS) $(t_w32_cmdline_LDADD) $(LIBS)
+
+t-w32-reg$(EXEEXT): $(t_w32_reg_OBJECTS) $(t_w32_reg_DEPENDENCIES) $(EXTRA_t_w32_reg_DEPENDENCIES)
+ @rm -f t-w32-reg$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(t_w32_reg_OBJECTS) $(t_w32_reg_LDADD) $(LIBS)
+
+t-zb32$(EXEEXT): $(t_zb32_OBJECTS) $(t_zb32_DEPENDENCIES) $(EXTRA_t_zb32_DEPENDENCIES)
+ @rm -f t-zb32$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(t_zb32_OBJECTS) $(t_zb32_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpgrlhelp.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-agent-opt.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-argparse.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-asshelp.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-asshelp2.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-audit.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-b64dec.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-b64enc.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-ccparray.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-compliance.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-convert.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-dotlock.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-exechelp-posix.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-exechelp-w32.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-exechelp-w32ce.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-exectool.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-get-passphrase.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-gettime.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-helpfile.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-homedir.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-i18n.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-init.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-iobuf.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-ksba-io-support.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-localename.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-logging.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-mapstrings.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-mbox-util.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-membuf.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-miscellaneous.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-mischelp.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-mkdir_p.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-name-value.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-openpgp-fpr.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-openpgp-oid.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-percent.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-recsel.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-server-help.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-session-env.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-sexputil.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-signal.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-ssh-utils.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-status.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-stringhelp.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-strlist.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-sysutils.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-tlv-builder.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-tlv.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-ttyio.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-userids.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-utf8conv.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-w32-cmdline.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-w32-reg.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-xasprintf.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-xreadline.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-yesno.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_a-zb32.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-agent-opt.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-argparse.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-asshelp.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-asshelp2.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-audit.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-b64dec.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-b64enc.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-call-gpg.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-ccparray.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-compliance.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-convert.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-dotlock.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-exechelp-posix.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-exechelp-w32.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-exechelp-w32ce.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-exectool.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-gettime.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-helpfile.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-homedir.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-i18n.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-init.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-iobuf.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-ksba-io-support.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-localename.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-logging.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-mapstrings.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-mbox-util.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-membuf.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-miscellaneous.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-mischelp.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-mkdir_p.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-name-value.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-openpgp-fpr.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-openpgp-oid.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-percent.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-recsel.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-server-help.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-session-env.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-sexputil.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-signal.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-ssh-utils.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-status.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-stringhelp.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-strlist.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-sysutils.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-tlv-builder.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-tlv.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-ttyio.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-userids.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-utf8conv.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-w32-cmdline.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-w32-reg.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-xasprintf.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-xreadline.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-yesno.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonpth_a-zb32.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsimple_pwquery_a-asshelp.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsimple_pwquery_a-simple-pwquery.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t-b64.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t-ccparray.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t-convert.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t-exechelp.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t-exectool.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t-gettime.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t-helpfile.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t-iobuf.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t-mapstrings.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t-mbox-util.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t-name-value.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t-openpgp-oid.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t-percent.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t-recsel.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t-session-env.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t-sexputil.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t-ssh-utils.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t-stringhelp.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t-strlist.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t-sysutils.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t-timestuff.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t-w32-cmdline.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t-w32-reg.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t-zb32.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/w32-cmdline.Po@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+libcommon_a-i18n.o: i18n.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-i18n.o -MD -MP -MF $(DEPDIR)/libcommon_a-i18n.Tpo -c -o libcommon_a-i18n.o `test -f 'i18n.c' || echo '$(srcdir)/'`i18n.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-i18n.Tpo $(DEPDIR)/libcommon_a-i18n.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='i18n.c' object='libcommon_a-i18n.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-i18n.o `test -f 'i18n.c' || echo '$(srcdir)/'`i18n.c
+
+libcommon_a-i18n.obj: i18n.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-i18n.obj -MD -MP -MF $(DEPDIR)/libcommon_a-i18n.Tpo -c -o libcommon_a-i18n.obj `if test -f 'i18n.c'; then $(CYGPATH_W) 'i18n.c'; else $(CYGPATH_W) '$(srcdir)/i18n.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-i18n.Tpo $(DEPDIR)/libcommon_a-i18n.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='i18n.c' object='libcommon_a-i18n.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-i18n.obj `if test -f 'i18n.c'; then $(CYGPATH_W) 'i18n.c'; else $(CYGPATH_W) '$(srcdir)/i18n.c'; fi`
+
+libcommon_a-mapstrings.o: mapstrings.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-mapstrings.o -MD -MP -MF $(DEPDIR)/libcommon_a-mapstrings.Tpo -c -o libcommon_a-mapstrings.o `test -f 'mapstrings.c' || echo '$(srcdir)/'`mapstrings.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-mapstrings.Tpo $(DEPDIR)/libcommon_a-mapstrings.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mapstrings.c' object='libcommon_a-mapstrings.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-mapstrings.o `test -f 'mapstrings.c' || echo '$(srcdir)/'`mapstrings.c
+
+libcommon_a-mapstrings.obj: mapstrings.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-mapstrings.obj -MD -MP -MF $(DEPDIR)/libcommon_a-mapstrings.Tpo -c -o libcommon_a-mapstrings.obj `if test -f 'mapstrings.c'; then $(CYGPATH_W) 'mapstrings.c'; else $(CYGPATH_W) '$(srcdir)/mapstrings.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-mapstrings.Tpo $(DEPDIR)/libcommon_a-mapstrings.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mapstrings.c' object='libcommon_a-mapstrings.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-mapstrings.obj `if test -f 'mapstrings.c'; then $(CYGPATH_W) 'mapstrings.c'; else $(CYGPATH_W) '$(srcdir)/mapstrings.c'; fi`
+
+libcommon_a-stringhelp.o: stringhelp.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-stringhelp.o -MD -MP -MF $(DEPDIR)/libcommon_a-stringhelp.Tpo -c -o libcommon_a-stringhelp.o `test -f 'stringhelp.c' || echo '$(srcdir)/'`stringhelp.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-stringhelp.Tpo $(DEPDIR)/libcommon_a-stringhelp.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='stringhelp.c' object='libcommon_a-stringhelp.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-stringhelp.o `test -f 'stringhelp.c' || echo '$(srcdir)/'`stringhelp.c
+
+libcommon_a-stringhelp.obj: stringhelp.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-stringhelp.obj -MD -MP -MF $(DEPDIR)/libcommon_a-stringhelp.Tpo -c -o libcommon_a-stringhelp.obj `if test -f 'stringhelp.c'; then $(CYGPATH_W) 'stringhelp.c'; else $(CYGPATH_W) '$(srcdir)/stringhelp.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-stringhelp.Tpo $(DEPDIR)/libcommon_a-stringhelp.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='stringhelp.c' object='libcommon_a-stringhelp.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-stringhelp.obj `if test -f 'stringhelp.c'; then $(CYGPATH_W) 'stringhelp.c'; else $(CYGPATH_W) '$(srcdir)/stringhelp.c'; fi`
+
+libcommon_a-strlist.o: strlist.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-strlist.o -MD -MP -MF $(DEPDIR)/libcommon_a-strlist.Tpo -c -o libcommon_a-strlist.o `test -f 'strlist.c' || echo '$(srcdir)/'`strlist.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-strlist.Tpo $(DEPDIR)/libcommon_a-strlist.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='strlist.c' object='libcommon_a-strlist.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-strlist.o `test -f 'strlist.c' || echo '$(srcdir)/'`strlist.c
+
+libcommon_a-strlist.obj: strlist.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-strlist.obj -MD -MP -MF $(DEPDIR)/libcommon_a-strlist.Tpo -c -o libcommon_a-strlist.obj `if test -f 'strlist.c'; then $(CYGPATH_W) 'strlist.c'; else $(CYGPATH_W) '$(srcdir)/strlist.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-strlist.Tpo $(DEPDIR)/libcommon_a-strlist.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='strlist.c' object='libcommon_a-strlist.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-strlist.obj `if test -f 'strlist.c'; then $(CYGPATH_W) 'strlist.c'; else $(CYGPATH_W) '$(srcdir)/strlist.c'; fi`
+
+libcommon_a-utf8conv.o: utf8conv.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-utf8conv.o -MD -MP -MF $(DEPDIR)/libcommon_a-utf8conv.Tpo -c -o libcommon_a-utf8conv.o `test -f 'utf8conv.c' || echo '$(srcdir)/'`utf8conv.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-utf8conv.Tpo $(DEPDIR)/libcommon_a-utf8conv.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utf8conv.c' object='libcommon_a-utf8conv.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-utf8conv.o `test -f 'utf8conv.c' || echo '$(srcdir)/'`utf8conv.c
+
+libcommon_a-utf8conv.obj: utf8conv.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-utf8conv.obj -MD -MP -MF $(DEPDIR)/libcommon_a-utf8conv.Tpo -c -o libcommon_a-utf8conv.obj `if test -f 'utf8conv.c'; then $(CYGPATH_W) 'utf8conv.c'; else $(CYGPATH_W) '$(srcdir)/utf8conv.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-utf8conv.Tpo $(DEPDIR)/libcommon_a-utf8conv.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utf8conv.c' object='libcommon_a-utf8conv.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-utf8conv.obj `if test -f 'utf8conv.c'; then $(CYGPATH_W) 'utf8conv.c'; else $(CYGPATH_W) '$(srcdir)/utf8conv.c'; fi`
+
+libcommon_a-argparse.o: argparse.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-argparse.o -MD -MP -MF $(DEPDIR)/libcommon_a-argparse.Tpo -c -o libcommon_a-argparse.o `test -f 'argparse.c' || echo '$(srcdir)/'`argparse.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-argparse.Tpo $(DEPDIR)/libcommon_a-argparse.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='argparse.c' object='libcommon_a-argparse.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-argparse.o `test -f 'argparse.c' || echo '$(srcdir)/'`argparse.c
+
+libcommon_a-argparse.obj: argparse.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-argparse.obj -MD -MP -MF $(DEPDIR)/libcommon_a-argparse.Tpo -c -o libcommon_a-argparse.obj `if test -f 'argparse.c'; then $(CYGPATH_W) 'argparse.c'; else $(CYGPATH_W) '$(srcdir)/argparse.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-argparse.Tpo $(DEPDIR)/libcommon_a-argparse.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='argparse.c' object='libcommon_a-argparse.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-argparse.obj `if test -f 'argparse.c'; then $(CYGPATH_W) 'argparse.c'; else $(CYGPATH_W) '$(srcdir)/argparse.c'; fi`
+
+libcommon_a-logging.o: logging.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-logging.o -MD -MP -MF $(DEPDIR)/libcommon_a-logging.Tpo -c -o libcommon_a-logging.o `test -f 'logging.c' || echo '$(srcdir)/'`logging.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-logging.Tpo $(DEPDIR)/libcommon_a-logging.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='logging.c' object='libcommon_a-logging.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-logging.o `test -f 'logging.c' || echo '$(srcdir)/'`logging.c
+
+libcommon_a-logging.obj: logging.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-logging.obj -MD -MP -MF $(DEPDIR)/libcommon_a-logging.Tpo -c -o libcommon_a-logging.obj `if test -f 'logging.c'; then $(CYGPATH_W) 'logging.c'; else $(CYGPATH_W) '$(srcdir)/logging.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-logging.Tpo $(DEPDIR)/libcommon_a-logging.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='logging.c' object='libcommon_a-logging.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-logging.obj `if test -f 'logging.c'; then $(CYGPATH_W) 'logging.c'; else $(CYGPATH_W) '$(srcdir)/logging.c'; fi`
+
+libcommon_a-dotlock.o: dotlock.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-dotlock.o -MD -MP -MF $(DEPDIR)/libcommon_a-dotlock.Tpo -c -o libcommon_a-dotlock.o `test -f 'dotlock.c' || echo '$(srcdir)/'`dotlock.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-dotlock.Tpo $(DEPDIR)/libcommon_a-dotlock.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dotlock.c' object='libcommon_a-dotlock.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-dotlock.o `test -f 'dotlock.c' || echo '$(srcdir)/'`dotlock.c
+
+libcommon_a-dotlock.obj: dotlock.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-dotlock.obj -MD -MP -MF $(DEPDIR)/libcommon_a-dotlock.Tpo -c -o libcommon_a-dotlock.obj `if test -f 'dotlock.c'; then $(CYGPATH_W) 'dotlock.c'; else $(CYGPATH_W) '$(srcdir)/dotlock.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-dotlock.Tpo $(DEPDIR)/libcommon_a-dotlock.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dotlock.c' object='libcommon_a-dotlock.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-dotlock.obj `if test -f 'dotlock.c'; then $(CYGPATH_W) 'dotlock.c'; else $(CYGPATH_W) '$(srcdir)/dotlock.c'; fi`
+
+libcommon_a-mischelp.o: mischelp.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-mischelp.o -MD -MP -MF $(DEPDIR)/libcommon_a-mischelp.Tpo -c -o libcommon_a-mischelp.o `test -f 'mischelp.c' || echo '$(srcdir)/'`mischelp.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-mischelp.Tpo $(DEPDIR)/libcommon_a-mischelp.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mischelp.c' object='libcommon_a-mischelp.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-mischelp.o `test -f 'mischelp.c' || echo '$(srcdir)/'`mischelp.c
+
+libcommon_a-mischelp.obj: mischelp.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-mischelp.obj -MD -MP -MF $(DEPDIR)/libcommon_a-mischelp.Tpo -c -o libcommon_a-mischelp.obj `if test -f 'mischelp.c'; then $(CYGPATH_W) 'mischelp.c'; else $(CYGPATH_W) '$(srcdir)/mischelp.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-mischelp.Tpo $(DEPDIR)/libcommon_a-mischelp.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mischelp.c' object='libcommon_a-mischelp.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-mischelp.obj `if test -f 'mischelp.c'; then $(CYGPATH_W) 'mischelp.c'; else $(CYGPATH_W) '$(srcdir)/mischelp.c'; fi`
+
+libcommon_a-status.o: status.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-status.o -MD -MP -MF $(DEPDIR)/libcommon_a-status.Tpo -c -o libcommon_a-status.o `test -f 'status.c' || echo '$(srcdir)/'`status.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-status.Tpo $(DEPDIR)/libcommon_a-status.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='status.c' object='libcommon_a-status.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-status.o `test -f 'status.c' || echo '$(srcdir)/'`status.c
+
+libcommon_a-status.obj: status.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-status.obj -MD -MP -MF $(DEPDIR)/libcommon_a-status.Tpo -c -o libcommon_a-status.obj `if test -f 'status.c'; then $(CYGPATH_W) 'status.c'; else $(CYGPATH_W) '$(srcdir)/status.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-status.Tpo $(DEPDIR)/libcommon_a-status.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='status.c' object='libcommon_a-status.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-status.obj `if test -f 'status.c'; then $(CYGPATH_W) 'status.c'; else $(CYGPATH_W) '$(srcdir)/status.c'; fi`
+
+libcommon_a-tlv.o: tlv.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-tlv.o -MD -MP -MF $(DEPDIR)/libcommon_a-tlv.Tpo -c -o libcommon_a-tlv.o `test -f 'tlv.c' || echo '$(srcdir)/'`tlv.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-tlv.Tpo $(DEPDIR)/libcommon_a-tlv.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tlv.c' object='libcommon_a-tlv.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-tlv.o `test -f 'tlv.c' || echo '$(srcdir)/'`tlv.c
+
+libcommon_a-tlv.obj: tlv.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-tlv.obj -MD -MP -MF $(DEPDIR)/libcommon_a-tlv.Tpo -c -o libcommon_a-tlv.obj `if test -f 'tlv.c'; then $(CYGPATH_W) 'tlv.c'; else $(CYGPATH_W) '$(srcdir)/tlv.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-tlv.Tpo $(DEPDIR)/libcommon_a-tlv.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tlv.c' object='libcommon_a-tlv.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-tlv.obj `if test -f 'tlv.c'; then $(CYGPATH_W) 'tlv.c'; else $(CYGPATH_W) '$(srcdir)/tlv.c'; fi`
+
+libcommon_a-tlv-builder.o: tlv-builder.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-tlv-builder.o -MD -MP -MF $(DEPDIR)/libcommon_a-tlv-builder.Tpo -c -o libcommon_a-tlv-builder.o `test -f 'tlv-builder.c' || echo '$(srcdir)/'`tlv-builder.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-tlv-builder.Tpo $(DEPDIR)/libcommon_a-tlv-builder.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tlv-builder.c' object='libcommon_a-tlv-builder.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-tlv-builder.o `test -f 'tlv-builder.c' || echo '$(srcdir)/'`tlv-builder.c
+
+libcommon_a-tlv-builder.obj: tlv-builder.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-tlv-builder.obj -MD -MP -MF $(DEPDIR)/libcommon_a-tlv-builder.Tpo -c -o libcommon_a-tlv-builder.obj `if test -f 'tlv-builder.c'; then $(CYGPATH_W) 'tlv-builder.c'; else $(CYGPATH_W) '$(srcdir)/tlv-builder.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-tlv-builder.Tpo $(DEPDIR)/libcommon_a-tlv-builder.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tlv-builder.c' object='libcommon_a-tlv-builder.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-tlv-builder.obj `if test -f 'tlv-builder.c'; then $(CYGPATH_W) 'tlv-builder.c'; else $(CYGPATH_W) '$(srcdir)/tlv-builder.c'; fi`
+
+libcommon_a-init.o: init.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-init.o -MD -MP -MF $(DEPDIR)/libcommon_a-init.Tpo -c -o libcommon_a-init.o `test -f 'init.c' || echo '$(srcdir)/'`init.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-init.Tpo $(DEPDIR)/libcommon_a-init.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='init.c' object='libcommon_a-init.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-init.o `test -f 'init.c' || echo '$(srcdir)/'`init.c
+
+libcommon_a-init.obj: init.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-init.obj -MD -MP -MF $(DEPDIR)/libcommon_a-init.Tpo -c -o libcommon_a-init.obj `if test -f 'init.c'; then $(CYGPATH_W) 'init.c'; else $(CYGPATH_W) '$(srcdir)/init.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-init.Tpo $(DEPDIR)/libcommon_a-init.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='init.c' object='libcommon_a-init.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-init.obj `if test -f 'init.c'; then $(CYGPATH_W) 'init.c'; else $(CYGPATH_W) '$(srcdir)/init.c'; fi`
+
+libcommon_a-sexputil.o: sexputil.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-sexputil.o -MD -MP -MF $(DEPDIR)/libcommon_a-sexputil.Tpo -c -o libcommon_a-sexputil.o `test -f 'sexputil.c' || echo '$(srcdir)/'`sexputil.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-sexputil.Tpo $(DEPDIR)/libcommon_a-sexputil.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sexputil.c' object='libcommon_a-sexputil.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-sexputil.o `test -f 'sexputil.c' || echo '$(srcdir)/'`sexputil.c
+
+libcommon_a-sexputil.obj: sexputil.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-sexputil.obj -MD -MP -MF $(DEPDIR)/libcommon_a-sexputil.Tpo -c -o libcommon_a-sexputil.obj `if test -f 'sexputil.c'; then $(CYGPATH_W) 'sexputil.c'; else $(CYGPATH_W) '$(srcdir)/sexputil.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-sexputil.Tpo $(DEPDIR)/libcommon_a-sexputil.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sexputil.c' object='libcommon_a-sexputil.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-sexputil.obj `if test -f 'sexputil.c'; then $(CYGPATH_W) 'sexputil.c'; else $(CYGPATH_W) '$(srcdir)/sexputil.c'; fi`
+
+libcommon_a-sysutils.o: sysutils.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-sysutils.o -MD -MP -MF $(DEPDIR)/libcommon_a-sysutils.Tpo -c -o libcommon_a-sysutils.o `test -f 'sysutils.c' || echo '$(srcdir)/'`sysutils.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-sysutils.Tpo $(DEPDIR)/libcommon_a-sysutils.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sysutils.c' object='libcommon_a-sysutils.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-sysutils.o `test -f 'sysutils.c' || echo '$(srcdir)/'`sysutils.c
+
+libcommon_a-sysutils.obj: sysutils.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-sysutils.obj -MD -MP -MF $(DEPDIR)/libcommon_a-sysutils.Tpo -c -o libcommon_a-sysutils.obj `if test -f 'sysutils.c'; then $(CYGPATH_W) 'sysutils.c'; else $(CYGPATH_W) '$(srcdir)/sysutils.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-sysutils.Tpo $(DEPDIR)/libcommon_a-sysutils.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sysutils.c' object='libcommon_a-sysutils.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-sysutils.obj `if test -f 'sysutils.c'; then $(CYGPATH_W) 'sysutils.c'; else $(CYGPATH_W) '$(srcdir)/sysutils.c'; fi`
+
+libcommon_a-homedir.o: homedir.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-homedir.o -MD -MP -MF $(DEPDIR)/libcommon_a-homedir.Tpo -c -o libcommon_a-homedir.o `test -f 'homedir.c' || echo '$(srcdir)/'`homedir.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-homedir.Tpo $(DEPDIR)/libcommon_a-homedir.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='homedir.c' object='libcommon_a-homedir.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-homedir.o `test -f 'homedir.c' || echo '$(srcdir)/'`homedir.c
+
+libcommon_a-homedir.obj: homedir.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-homedir.obj -MD -MP -MF $(DEPDIR)/libcommon_a-homedir.Tpo -c -o libcommon_a-homedir.obj `if test -f 'homedir.c'; then $(CYGPATH_W) 'homedir.c'; else $(CYGPATH_W) '$(srcdir)/homedir.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-homedir.Tpo $(DEPDIR)/libcommon_a-homedir.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='homedir.c' object='libcommon_a-homedir.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-homedir.obj `if test -f 'homedir.c'; then $(CYGPATH_W) 'homedir.c'; else $(CYGPATH_W) '$(srcdir)/homedir.c'; fi`
+
+libcommon_a-gettime.o: gettime.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-gettime.o -MD -MP -MF $(DEPDIR)/libcommon_a-gettime.Tpo -c -o libcommon_a-gettime.o `test -f 'gettime.c' || echo '$(srcdir)/'`gettime.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-gettime.Tpo $(DEPDIR)/libcommon_a-gettime.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gettime.c' object='libcommon_a-gettime.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-gettime.o `test -f 'gettime.c' || echo '$(srcdir)/'`gettime.c
+
+libcommon_a-gettime.obj: gettime.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-gettime.obj -MD -MP -MF $(DEPDIR)/libcommon_a-gettime.Tpo -c -o libcommon_a-gettime.obj `if test -f 'gettime.c'; then $(CYGPATH_W) 'gettime.c'; else $(CYGPATH_W) '$(srcdir)/gettime.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-gettime.Tpo $(DEPDIR)/libcommon_a-gettime.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gettime.c' object='libcommon_a-gettime.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-gettime.obj `if test -f 'gettime.c'; then $(CYGPATH_W) 'gettime.c'; else $(CYGPATH_W) '$(srcdir)/gettime.c'; fi`
+
+libcommon_a-yesno.o: yesno.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-yesno.o -MD -MP -MF $(DEPDIR)/libcommon_a-yesno.Tpo -c -o libcommon_a-yesno.o `test -f 'yesno.c' || echo '$(srcdir)/'`yesno.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-yesno.Tpo $(DEPDIR)/libcommon_a-yesno.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='yesno.c' object='libcommon_a-yesno.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-yesno.o `test -f 'yesno.c' || echo '$(srcdir)/'`yesno.c
+
+libcommon_a-yesno.obj: yesno.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-yesno.obj -MD -MP -MF $(DEPDIR)/libcommon_a-yesno.Tpo -c -o libcommon_a-yesno.obj `if test -f 'yesno.c'; then $(CYGPATH_W) 'yesno.c'; else $(CYGPATH_W) '$(srcdir)/yesno.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-yesno.Tpo $(DEPDIR)/libcommon_a-yesno.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='yesno.c' object='libcommon_a-yesno.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-yesno.obj `if test -f 'yesno.c'; then $(CYGPATH_W) 'yesno.c'; else $(CYGPATH_W) '$(srcdir)/yesno.c'; fi`
+
+libcommon_a-b64enc.o: b64enc.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-b64enc.o -MD -MP -MF $(DEPDIR)/libcommon_a-b64enc.Tpo -c -o libcommon_a-b64enc.o `test -f 'b64enc.c' || echo '$(srcdir)/'`b64enc.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-b64enc.Tpo $(DEPDIR)/libcommon_a-b64enc.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='b64enc.c' object='libcommon_a-b64enc.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-b64enc.o `test -f 'b64enc.c' || echo '$(srcdir)/'`b64enc.c
+
+libcommon_a-b64enc.obj: b64enc.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-b64enc.obj -MD -MP -MF $(DEPDIR)/libcommon_a-b64enc.Tpo -c -o libcommon_a-b64enc.obj `if test -f 'b64enc.c'; then $(CYGPATH_W) 'b64enc.c'; else $(CYGPATH_W) '$(srcdir)/b64enc.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-b64enc.Tpo $(DEPDIR)/libcommon_a-b64enc.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='b64enc.c' object='libcommon_a-b64enc.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-b64enc.obj `if test -f 'b64enc.c'; then $(CYGPATH_W) 'b64enc.c'; else $(CYGPATH_W) '$(srcdir)/b64enc.c'; fi`
+
+libcommon_a-b64dec.o: b64dec.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-b64dec.o -MD -MP -MF $(DEPDIR)/libcommon_a-b64dec.Tpo -c -o libcommon_a-b64dec.o `test -f 'b64dec.c' || echo '$(srcdir)/'`b64dec.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-b64dec.Tpo $(DEPDIR)/libcommon_a-b64dec.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='b64dec.c' object='libcommon_a-b64dec.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-b64dec.o `test -f 'b64dec.c' || echo '$(srcdir)/'`b64dec.c
+
+libcommon_a-b64dec.obj: b64dec.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-b64dec.obj -MD -MP -MF $(DEPDIR)/libcommon_a-b64dec.Tpo -c -o libcommon_a-b64dec.obj `if test -f 'b64dec.c'; then $(CYGPATH_W) 'b64dec.c'; else $(CYGPATH_W) '$(srcdir)/b64dec.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-b64dec.Tpo $(DEPDIR)/libcommon_a-b64dec.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='b64dec.c' object='libcommon_a-b64dec.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-b64dec.obj `if test -f 'b64dec.c'; then $(CYGPATH_W) 'b64dec.c'; else $(CYGPATH_W) '$(srcdir)/b64dec.c'; fi`
+
+libcommon_a-zb32.o: zb32.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-zb32.o -MD -MP -MF $(DEPDIR)/libcommon_a-zb32.Tpo -c -o libcommon_a-zb32.o `test -f 'zb32.c' || echo '$(srcdir)/'`zb32.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-zb32.Tpo $(DEPDIR)/libcommon_a-zb32.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='zb32.c' object='libcommon_a-zb32.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-zb32.o `test -f 'zb32.c' || echo '$(srcdir)/'`zb32.c
+
+libcommon_a-zb32.obj: zb32.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-zb32.obj -MD -MP -MF $(DEPDIR)/libcommon_a-zb32.Tpo -c -o libcommon_a-zb32.obj `if test -f 'zb32.c'; then $(CYGPATH_W) 'zb32.c'; else $(CYGPATH_W) '$(srcdir)/zb32.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-zb32.Tpo $(DEPDIR)/libcommon_a-zb32.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='zb32.c' object='libcommon_a-zb32.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-zb32.obj `if test -f 'zb32.c'; then $(CYGPATH_W) 'zb32.c'; else $(CYGPATH_W) '$(srcdir)/zb32.c'; fi`
+
+libcommon_a-convert.o: convert.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-convert.o -MD -MP -MF $(DEPDIR)/libcommon_a-convert.Tpo -c -o libcommon_a-convert.o `test -f 'convert.c' || echo '$(srcdir)/'`convert.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-convert.Tpo $(DEPDIR)/libcommon_a-convert.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='convert.c' object='libcommon_a-convert.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-convert.o `test -f 'convert.c' || echo '$(srcdir)/'`convert.c
+
+libcommon_a-convert.obj: convert.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-convert.obj -MD -MP -MF $(DEPDIR)/libcommon_a-convert.Tpo -c -o libcommon_a-convert.obj `if test -f 'convert.c'; then $(CYGPATH_W) 'convert.c'; else $(CYGPATH_W) '$(srcdir)/convert.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-convert.Tpo $(DEPDIR)/libcommon_a-convert.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='convert.c' object='libcommon_a-convert.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-convert.obj `if test -f 'convert.c'; then $(CYGPATH_W) 'convert.c'; else $(CYGPATH_W) '$(srcdir)/convert.c'; fi`
+
+libcommon_a-percent.o: percent.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-percent.o -MD -MP -MF $(DEPDIR)/libcommon_a-percent.Tpo -c -o libcommon_a-percent.o `test -f 'percent.c' || echo '$(srcdir)/'`percent.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-percent.Tpo $(DEPDIR)/libcommon_a-percent.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='percent.c' object='libcommon_a-percent.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-percent.o `test -f 'percent.c' || echo '$(srcdir)/'`percent.c
+
+libcommon_a-percent.obj: percent.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-percent.obj -MD -MP -MF $(DEPDIR)/libcommon_a-percent.Tpo -c -o libcommon_a-percent.obj `if test -f 'percent.c'; then $(CYGPATH_W) 'percent.c'; else $(CYGPATH_W) '$(srcdir)/percent.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-percent.Tpo $(DEPDIR)/libcommon_a-percent.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='percent.c' object='libcommon_a-percent.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-percent.obj `if test -f 'percent.c'; then $(CYGPATH_W) 'percent.c'; else $(CYGPATH_W) '$(srcdir)/percent.c'; fi`
+
+libcommon_a-mbox-util.o: mbox-util.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-mbox-util.o -MD -MP -MF $(DEPDIR)/libcommon_a-mbox-util.Tpo -c -o libcommon_a-mbox-util.o `test -f 'mbox-util.c' || echo '$(srcdir)/'`mbox-util.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-mbox-util.Tpo $(DEPDIR)/libcommon_a-mbox-util.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mbox-util.c' object='libcommon_a-mbox-util.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-mbox-util.o `test -f 'mbox-util.c' || echo '$(srcdir)/'`mbox-util.c
+
+libcommon_a-mbox-util.obj: mbox-util.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-mbox-util.obj -MD -MP -MF $(DEPDIR)/libcommon_a-mbox-util.Tpo -c -o libcommon_a-mbox-util.obj `if test -f 'mbox-util.c'; then $(CYGPATH_W) 'mbox-util.c'; else $(CYGPATH_W) '$(srcdir)/mbox-util.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-mbox-util.Tpo $(DEPDIR)/libcommon_a-mbox-util.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mbox-util.c' object='libcommon_a-mbox-util.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-mbox-util.obj `if test -f 'mbox-util.c'; then $(CYGPATH_W) 'mbox-util.c'; else $(CYGPATH_W) '$(srcdir)/mbox-util.c'; fi`
+
+libcommon_a-miscellaneous.o: miscellaneous.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-miscellaneous.o -MD -MP -MF $(DEPDIR)/libcommon_a-miscellaneous.Tpo -c -o libcommon_a-miscellaneous.o `test -f 'miscellaneous.c' || echo '$(srcdir)/'`miscellaneous.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-miscellaneous.Tpo $(DEPDIR)/libcommon_a-miscellaneous.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='miscellaneous.c' object='libcommon_a-miscellaneous.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-miscellaneous.o `test -f 'miscellaneous.c' || echo '$(srcdir)/'`miscellaneous.c
+
+libcommon_a-miscellaneous.obj: miscellaneous.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-miscellaneous.obj -MD -MP -MF $(DEPDIR)/libcommon_a-miscellaneous.Tpo -c -o libcommon_a-miscellaneous.obj `if test -f 'miscellaneous.c'; then $(CYGPATH_W) 'miscellaneous.c'; else $(CYGPATH_W) '$(srcdir)/miscellaneous.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-miscellaneous.Tpo $(DEPDIR)/libcommon_a-miscellaneous.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='miscellaneous.c' object='libcommon_a-miscellaneous.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-miscellaneous.obj `if test -f 'miscellaneous.c'; then $(CYGPATH_W) 'miscellaneous.c'; else $(CYGPATH_W) '$(srcdir)/miscellaneous.c'; fi`
+
+libcommon_a-xasprintf.o: xasprintf.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-xasprintf.o -MD -MP -MF $(DEPDIR)/libcommon_a-xasprintf.Tpo -c -o libcommon_a-xasprintf.o `test -f 'xasprintf.c' || echo '$(srcdir)/'`xasprintf.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-xasprintf.Tpo $(DEPDIR)/libcommon_a-xasprintf.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xasprintf.c' object='libcommon_a-xasprintf.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-xasprintf.o `test -f 'xasprintf.c' || echo '$(srcdir)/'`xasprintf.c
+
+libcommon_a-xasprintf.obj: xasprintf.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-xasprintf.obj -MD -MP -MF $(DEPDIR)/libcommon_a-xasprintf.Tpo -c -o libcommon_a-xasprintf.obj `if test -f 'xasprintf.c'; then $(CYGPATH_W) 'xasprintf.c'; else $(CYGPATH_W) '$(srcdir)/xasprintf.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-xasprintf.Tpo $(DEPDIR)/libcommon_a-xasprintf.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xasprintf.c' object='libcommon_a-xasprintf.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-xasprintf.obj `if test -f 'xasprintf.c'; then $(CYGPATH_W) 'xasprintf.c'; else $(CYGPATH_W) '$(srcdir)/xasprintf.c'; fi`
+
+libcommon_a-xreadline.o: xreadline.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-xreadline.o -MD -MP -MF $(DEPDIR)/libcommon_a-xreadline.Tpo -c -o libcommon_a-xreadline.o `test -f 'xreadline.c' || echo '$(srcdir)/'`xreadline.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-xreadline.Tpo $(DEPDIR)/libcommon_a-xreadline.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xreadline.c' object='libcommon_a-xreadline.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-xreadline.o `test -f 'xreadline.c' || echo '$(srcdir)/'`xreadline.c
+
+libcommon_a-xreadline.obj: xreadline.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-xreadline.obj -MD -MP -MF $(DEPDIR)/libcommon_a-xreadline.Tpo -c -o libcommon_a-xreadline.obj `if test -f 'xreadline.c'; then $(CYGPATH_W) 'xreadline.c'; else $(CYGPATH_W) '$(srcdir)/xreadline.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-xreadline.Tpo $(DEPDIR)/libcommon_a-xreadline.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xreadline.c' object='libcommon_a-xreadline.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-xreadline.obj `if test -f 'xreadline.c'; then $(CYGPATH_W) 'xreadline.c'; else $(CYGPATH_W) '$(srcdir)/xreadline.c'; fi`
+
+libcommon_a-membuf.o: membuf.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-membuf.o -MD -MP -MF $(DEPDIR)/libcommon_a-membuf.Tpo -c -o libcommon_a-membuf.o `test -f 'membuf.c' || echo '$(srcdir)/'`membuf.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-membuf.Tpo $(DEPDIR)/libcommon_a-membuf.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='membuf.c' object='libcommon_a-membuf.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-membuf.o `test -f 'membuf.c' || echo '$(srcdir)/'`membuf.c
+
+libcommon_a-membuf.obj: membuf.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-membuf.obj -MD -MP -MF $(DEPDIR)/libcommon_a-membuf.Tpo -c -o libcommon_a-membuf.obj `if test -f 'membuf.c'; then $(CYGPATH_W) 'membuf.c'; else $(CYGPATH_W) '$(srcdir)/membuf.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-membuf.Tpo $(DEPDIR)/libcommon_a-membuf.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='membuf.c' object='libcommon_a-membuf.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-membuf.obj `if test -f 'membuf.c'; then $(CYGPATH_W) 'membuf.c'; else $(CYGPATH_W) '$(srcdir)/membuf.c'; fi`
+
+libcommon_a-ccparray.o: ccparray.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-ccparray.o -MD -MP -MF $(DEPDIR)/libcommon_a-ccparray.Tpo -c -o libcommon_a-ccparray.o `test -f 'ccparray.c' || echo '$(srcdir)/'`ccparray.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-ccparray.Tpo $(DEPDIR)/libcommon_a-ccparray.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ccparray.c' object='libcommon_a-ccparray.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-ccparray.o `test -f 'ccparray.c' || echo '$(srcdir)/'`ccparray.c
+
+libcommon_a-ccparray.obj: ccparray.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-ccparray.obj -MD -MP -MF $(DEPDIR)/libcommon_a-ccparray.Tpo -c -o libcommon_a-ccparray.obj `if test -f 'ccparray.c'; then $(CYGPATH_W) 'ccparray.c'; else $(CYGPATH_W) '$(srcdir)/ccparray.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-ccparray.Tpo $(DEPDIR)/libcommon_a-ccparray.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ccparray.c' object='libcommon_a-ccparray.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-ccparray.obj `if test -f 'ccparray.c'; then $(CYGPATH_W) 'ccparray.c'; else $(CYGPATH_W) '$(srcdir)/ccparray.c'; fi`
+
+libcommon_a-iobuf.o: iobuf.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-iobuf.o -MD -MP -MF $(DEPDIR)/libcommon_a-iobuf.Tpo -c -o libcommon_a-iobuf.o `test -f 'iobuf.c' || echo '$(srcdir)/'`iobuf.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-iobuf.Tpo $(DEPDIR)/libcommon_a-iobuf.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='iobuf.c' object='libcommon_a-iobuf.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-iobuf.o `test -f 'iobuf.c' || echo '$(srcdir)/'`iobuf.c
+
+libcommon_a-iobuf.obj: iobuf.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-iobuf.obj -MD -MP -MF $(DEPDIR)/libcommon_a-iobuf.Tpo -c -o libcommon_a-iobuf.obj `if test -f 'iobuf.c'; then $(CYGPATH_W) 'iobuf.c'; else $(CYGPATH_W) '$(srcdir)/iobuf.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-iobuf.Tpo $(DEPDIR)/libcommon_a-iobuf.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='iobuf.c' object='libcommon_a-iobuf.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-iobuf.obj `if test -f 'iobuf.c'; then $(CYGPATH_W) 'iobuf.c'; else $(CYGPATH_W) '$(srcdir)/iobuf.c'; fi`
+
+libcommon_a-ttyio.o: ttyio.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-ttyio.o -MD -MP -MF $(DEPDIR)/libcommon_a-ttyio.Tpo -c -o libcommon_a-ttyio.o `test -f 'ttyio.c' || echo '$(srcdir)/'`ttyio.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-ttyio.Tpo $(DEPDIR)/libcommon_a-ttyio.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ttyio.c' object='libcommon_a-ttyio.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-ttyio.o `test -f 'ttyio.c' || echo '$(srcdir)/'`ttyio.c
+
+libcommon_a-ttyio.obj: ttyio.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-ttyio.obj -MD -MP -MF $(DEPDIR)/libcommon_a-ttyio.Tpo -c -o libcommon_a-ttyio.obj `if test -f 'ttyio.c'; then $(CYGPATH_W) 'ttyio.c'; else $(CYGPATH_W) '$(srcdir)/ttyio.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-ttyio.Tpo $(DEPDIR)/libcommon_a-ttyio.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ttyio.c' object='libcommon_a-ttyio.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-ttyio.obj `if test -f 'ttyio.c'; then $(CYGPATH_W) 'ttyio.c'; else $(CYGPATH_W) '$(srcdir)/ttyio.c'; fi`
+
+libcommon_a-asshelp.o: asshelp.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-asshelp.o -MD -MP -MF $(DEPDIR)/libcommon_a-asshelp.Tpo -c -o libcommon_a-asshelp.o `test -f 'asshelp.c' || echo '$(srcdir)/'`asshelp.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-asshelp.Tpo $(DEPDIR)/libcommon_a-asshelp.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='asshelp.c' object='libcommon_a-asshelp.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-asshelp.o `test -f 'asshelp.c' || echo '$(srcdir)/'`asshelp.c
+
+libcommon_a-asshelp.obj: asshelp.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-asshelp.obj -MD -MP -MF $(DEPDIR)/libcommon_a-asshelp.Tpo -c -o libcommon_a-asshelp.obj `if test -f 'asshelp.c'; then $(CYGPATH_W) 'asshelp.c'; else $(CYGPATH_W) '$(srcdir)/asshelp.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-asshelp.Tpo $(DEPDIR)/libcommon_a-asshelp.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='asshelp.c' object='libcommon_a-asshelp.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-asshelp.obj `if test -f 'asshelp.c'; then $(CYGPATH_W) 'asshelp.c'; else $(CYGPATH_W) '$(srcdir)/asshelp.c'; fi`
+
+libcommon_a-asshelp2.o: asshelp2.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-asshelp2.o -MD -MP -MF $(DEPDIR)/libcommon_a-asshelp2.Tpo -c -o libcommon_a-asshelp2.o `test -f 'asshelp2.c' || echo '$(srcdir)/'`asshelp2.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-asshelp2.Tpo $(DEPDIR)/libcommon_a-asshelp2.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='asshelp2.c' object='libcommon_a-asshelp2.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-asshelp2.o `test -f 'asshelp2.c' || echo '$(srcdir)/'`asshelp2.c
+
+libcommon_a-asshelp2.obj: asshelp2.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-asshelp2.obj -MD -MP -MF $(DEPDIR)/libcommon_a-asshelp2.Tpo -c -o libcommon_a-asshelp2.obj `if test -f 'asshelp2.c'; then $(CYGPATH_W) 'asshelp2.c'; else $(CYGPATH_W) '$(srcdir)/asshelp2.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-asshelp2.Tpo $(DEPDIR)/libcommon_a-asshelp2.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='asshelp2.c' object='libcommon_a-asshelp2.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-asshelp2.obj `if test -f 'asshelp2.c'; then $(CYGPATH_W) 'asshelp2.c'; else $(CYGPATH_W) '$(srcdir)/asshelp2.c'; fi`
+
+libcommon_a-signal.o: signal.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-signal.o -MD -MP -MF $(DEPDIR)/libcommon_a-signal.Tpo -c -o libcommon_a-signal.o `test -f 'signal.c' || echo '$(srcdir)/'`signal.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-signal.Tpo $(DEPDIR)/libcommon_a-signal.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='signal.c' object='libcommon_a-signal.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-signal.o `test -f 'signal.c' || echo '$(srcdir)/'`signal.c
+
+libcommon_a-signal.obj: signal.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-signal.obj -MD -MP -MF $(DEPDIR)/libcommon_a-signal.Tpo -c -o libcommon_a-signal.obj `if test -f 'signal.c'; then $(CYGPATH_W) 'signal.c'; else $(CYGPATH_W) '$(srcdir)/signal.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-signal.Tpo $(DEPDIR)/libcommon_a-signal.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='signal.c' object='libcommon_a-signal.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-signal.obj `if test -f 'signal.c'; then $(CYGPATH_W) 'signal.c'; else $(CYGPATH_W) '$(srcdir)/signal.c'; fi`
+
+libcommon_a-audit.o: audit.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-audit.o -MD -MP -MF $(DEPDIR)/libcommon_a-audit.Tpo -c -o libcommon_a-audit.o `test -f 'audit.c' || echo '$(srcdir)/'`audit.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-audit.Tpo $(DEPDIR)/libcommon_a-audit.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audit.c' object='libcommon_a-audit.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-audit.o `test -f 'audit.c' || echo '$(srcdir)/'`audit.c
+
+libcommon_a-audit.obj: audit.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-audit.obj -MD -MP -MF $(DEPDIR)/libcommon_a-audit.Tpo -c -o libcommon_a-audit.obj `if test -f 'audit.c'; then $(CYGPATH_W) 'audit.c'; else $(CYGPATH_W) '$(srcdir)/audit.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-audit.Tpo $(DEPDIR)/libcommon_a-audit.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audit.c' object='libcommon_a-audit.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-audit.obj `if test -f 'audit.c'; then $(CYGPATH_W) 'audit.c'; else $(CYGPATH_W) '$(srcdir)/audit.c'; fi`
+
+libcommon_a-localename.o: localename.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-localename.o -MD -MP -MF $(DEPDIR)/libcommon_a-localename.Tpo -c -o libcommon_a-localename.o `test -f 'localename.c' || echo '$(srcdir)/'`localename.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-localename.Tpo $(DEPDIR)/libcommon_a-localename.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='localename.c' object='libcommon_a-localename.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-localename.o `test -f 'localename.c' || echo '$(srcdir)/'`localename.c
+
+libcommon_a-localename.obj: localename.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-localename.obj -MD -MP -MF $(DEPDIR)/libcommon_a-localename.Tpo -c -o libcommon_a-localename.obj `if test -f 'localename.c'; then $(CYGPATH_W) 'localename.c'; else $(CYGPATH_W) '$(srcdir)/localename.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-localename.Tpo $(DEPDIR)/libcommon_a-localename.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='localename.c' object='libcommon_a-localename.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-localename.obj `if test -f 'localename.c'; then $(CYGPATH_W) 'localename.c'; else $(CYGPATH_W) '$(srcdir)/localename.c'; fi`
+
+libcommon_a-session-env.o: session-env.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-session-env.o -MD -MP -MF $(DEPDIR)/libcommon_a-session-env.Tpo -c -o libcommon_a-session-env.o `test -f 'session-env.c' || echo '$(srcdir)/'`session-env.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-session-env.Tpo $(DEPDIR)/libcommon_a-session-env.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='session-env.c' object='libcommon_a-session-env.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-session-env.o `test -f 'session-env.c' || echo '$(srcdir)/'`session-env.c
+
+libcommon_a-session-env.obj: session-env.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-session-env.obj -MD -MP -MF $(DEPDIR)/libcommon_a-session-env.Tpo -c -o libcommon_a-session-env.obj `if test -f 'session-env.c'; then $(CYGPATH_W) 'session-env.c'; else $(CYGPATH_W) '$(srcdir)/session-env.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-session-env.Tpo $(DEPDIR)/libcommon_a-session-env.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='session-env.c' object='libcommon_a-session-env.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-session-env.obj `if test -f 'session-env.c'; then $(CYGPATH_W) 'session-env.c'; else $(CYGPATH_W) '$(srcdir)/session-env.c'; fi`
+
+libcommon_a-userids.o: userids.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-userids.o -MD -MP -MF $(DEPDIR)/libcommon_a-userids.Tpo -c -o libcommon_a-userids.o `test -f 'userids.c' || echo '$(srcdir)/'`userids.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-userids.Tpo $(DEPDIR)/libcommon_a-userids.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='userids.c' object='libcommon_a-userids.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-userids.o `test -f 'userids.c' || echo '$(srcdir)/'`userids.c
+
+libcommon_a-userids.obj: userids.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-userids.obj -MD -MP -MF $(DEPDIR)/libcommon_a-userids.Tpo -c -o libcommon_a-userids.obj `if test -f 'userids.c'; then $(CYGPATH_W) 'userids.c'; else $(CYGPATH_W) '$(srcdir)/userids.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-userids.Tpo $(DEPDIR)/libcommon_a-userids.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='userids.c' object='libcommon_a-userids.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-userids.obj `if test -f 'userids.c'; then $(CYGPATH_W) 'userids.c'; else $(CYGPATH_W) '$(srcdir)/userids.c'; fi`
+
+libcommon_a-openpgp-oid.o: openpgp-oid.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-openpgp-oid.o -MD -MP -MF $(DEPDIR)/libcommon_a-openpgp-oid.Tpo -c -o libcommon_a-openpgp-oid.o `test -f 'openpgp-oid.c' || echo '$(srcdir)/'`openpgp-oid.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-openpgp-oid.Tpo $(DEPDIR)/libcommon_a-openpgp-oid.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='openpgp-oid.c' object='libcommon_a-openpgp-oid.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-openpgp-oid.o `test -f 'openpgp-oid.c' || echo '$(srcdir)/'`openpgp-oid.c
+
+libcommon_a-openpgp-oid.obj: openpgp-oid.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-openpgp-oid.obj -MD -MP -MF $(DEPDIR)/libcommon_a-openpgp-oid.Tpo -c -o libcommon_a-openpgp-oid.obj `if test -f 'openpgp-oid.c'; then $(CYGPATH_W) 'openpgp-oid.c'; else $(CYGPATH_W) '$(srcdir)/openpgp-oid.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-openpgp-oid.Tpo $(DEPDIR)/libcommon_a-openpgp-oid.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='openpgp-oid.c' object='libcommon_a-openpgp-oid.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-openpgp-oid.obj `if test -f 'openpgp-oid.c'; then $(CYGPATH_W) 'openpgp-oid.c'; else $(CYGPATH_W) '$(srcdir)/openpgp-oid.c'; fi`
+
+libcommon_a-ssh-utils.o: ssh-utils.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-ssh-utils.o -MD -MP -MF $(DEPDIR)/libcommon_a-ssh-utils.Tpo -c -o libcommon_a-ssh-utils.o `test -f 'ssh-utils.c' || echo '$(srcdir)/'`ssh-utils.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-ssh-utils.Tpo $(DEPDIR)/libcommon_a-ssh-utils.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ssh-utils.c' object='libcommon_a-ssh-utils.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-ssh-utils.o `test -f 'ssh-utils.c' || echo '$(srcdir)/'`ssh-utils.c
+
+libcommon_a-ssh-utils.obj: ssh-utils.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-ssh-utils.obj -MD -MP -MF $(DEPDIR)/libcommon_a-ssh-utils.Tpo -c -o libcommon_a-ssh-utils.obj `if test -f 'ssh-utils.c'; then $(CYGPATH_W) 'ssh-utils.c'; else $(CYGPATH_W) '$(srcdir)/ssh-utils.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-ssh-utils.Tpo $(DEPDIR)/libcommon_a-ssh-utils.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ssh-utils.c' object='libcommon_a-ssh-utils.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-ssh-utils.obj `if test -f 'ssh-utils.c'; then $(CYGPATH_W) 'ssh-utils.c'; else $(CYGPATH_W) '$(srcdir)/ssh-utils.c'; fi`
+
+libcommon_a-agent-opt.o: agent-opt.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-agent-opt.o -MD -MP -MF $(DEPDIR)/libcommon_a-agent-opt.Tpo -c -o libcommon_a-agent-opt.o `test -f 'agent-opt.c' || echo '$(srcdir)/'`agent-opt.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-agent-opt.Tpo $(DEPDIR)/libcommon_a-agent-opt.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='agent-opt.c' object='libcommon_a-agent-opt.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-agent-opt.o `test -f 'agent-opt.c' || echo '$(srcdir)/'`agent-opt.c
+
+libcommon_a-agent-opt.obj: agent-opt.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-agent-opt.obj -MD -MP -MF $(DEPDIR)/libcommon_a-agent-opt.Tpo -c -o libcommon_a-agent-opt.obj `if test -f 'agent-opt.c'; then $(CYGPATH_W) 'agent-opt.c'; else $(CYGPATH_W) '$(srcdir)/agent-opt.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-agent-opt.Tpo $(DEPDIR)/libcommon_a-agent-opt.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='agent-opt.c' object='libcommon_a-agent-opt.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-agent-opt.obj `if test -f 'agent-opt.c'; then $(CYGPATH_W) 'agent-opt.c'; else $(CYGPATH_W) '$(srcdir)/agent-opt.c'; fi`
+
+libcommon_a-helpfile.o: helpfile.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-helpfile.o -MD -MP -MF $(DEPDIR)/libcommon_a-helpfile.Tpo -c -o libcommon_a-helpfile.o `test -f 'helpfile.c' || echo '$(srcdir)/'`helpfile.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-helpfile.Tpo $(DEPDIR)/libcommon_a-helpfile.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='helpfile.c' object='libcommon_a-helpfile.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-helpfile.o `test -f 'helpfile.c' || echo '$(srcdir)/'`helpfile.c
+
+libcommon_a-helpfile.obj: helpfile.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-helpfile.obj -MD -MP -MF $(DEPDIR)/libcommon_a-helpfile.Tpo -c -o libcommon_a-helpfile.obj `if test -f 'helpfile.c'; then $(CYGPATH_W) 'helpfile.c'; else $(CYGPATH_W) '$(srcdir)/helpfile.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-helpfile.Tpo $(DEPDIR)/libcommon_a-helpfile.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='helpfile.c' object='libcommon_a-helpfile.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-helpfile.obj `if test -f 'helpfile.c'; then $(CYGPATH_W) 'helpfile.c'; else $(CYGPATH_W) '$(srcdir)/helpfile.c'; fi`
+
+libcommon_a-mkdir_p.o: mkdir_p.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-mkdir_p.o -MD -MP -MF $(DEPDIR)/libcommon_a-mkdir_p.Tpo -c -o libcommon_a-mkdir_p.o `test -f 'mkdir_p.c' || echo '$(srcdir)/'`mkdir_p.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-mkdir_p.Tpo $(DEPDIR)/libcommon_a-mkdir_p.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mkdir_p.c' object='libcommon_a-mkdir_p.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-mkdir_p.o `test -f 'mkdir_p.c' || echo '$(srcdir)/'`mkdir_p.c
+
+libcommon_a-mkdir_p.obj: mkdir_p.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-mkdir_p.obj -MD -MP -MF $(DEPDIR)/libcommon_a-mkdir_p.Tpo -c -o libcommon_a-mkdir_p.obj `if test -f 'mkdir_p.c'; then $(CYGPATH_W) 'mkdir_p.c'; else $(CYGPATH_W) '$(srcdir)/mkdir_p.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-mkdir_p.Tpo $(DEPDIR)/libcommon_a-mkdir_p.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mkdir_p.c' object='libcommon_a-mkdir_p.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-mkdir_p.obj `if test -f 'mkdir_p.c'; then $(CYGPATH_W) 'mkdir_p.c'; else $(CYGPATH_W) '$(srcdir)/mkdir_p.c'; fi`
+
+libcommon_a-exectool.o: exectool.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-exectool.o -MD -MP -MF $(DEPDIR)/libcommon_a-exectool.Tpo -c -o libcommon_a-exectool.o `test -f 'exectool.c' || echo '$(srcdir)/'`exectool.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-exectool.Tpo $(DEPDIR)/libcommon_a-exectool.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='exectool.c' object='libcommon_a-exectool.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-exectool.o `test -f 'exectool.c' || echo '$(srcdir)/'`exectool.c
+
+libcommon_a-exectool.obj: exectool.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-exectool.obj -MD -MP -MF $(DEPDIR)/libcommon_a-exectool.Tpo -c -o libcommon_a-exectool.obj `if test -f 'exectool.c'; then $(CYGPATH_W) 'exectool.c'; else $(CYGPATH_W) '$(srcdir)/exectool.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-exectool.Tpo $(DEPDIR)/libcommon_a-exectool.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='exectool.c' object='libcommon_a-exectool.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-exectool.obj `if test -f 'exectool.c'; then $(CYGPATH_W) 'exectool.c'; else $(CYGPATH_W) '$(srcdir)/exectool.c'; fi`
+
+libcommon_a-server-help.o: server-help.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-server-help.o -MD -MP -MF $(DEPDIR)/libcommon_a-server-help.Tpo -c -o libcommon_a-server-help.o `test -f 'server-help.c' || echo '$(srcdir)/'`server-help.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-server-help.Tpo $(DEPDIR)/libcommon_a-server-help.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='server-help.c' object='libcommon_a-server-help.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-server-help.o `test -f 'server-help.c' || echo '$(srcdir)/'`server-help.c
+
+libcommon_a-server-help.obj: server-help.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-server-help.obj -MD -MP -MF $(DEPDIR)/libcommon_a-server-help.Tpo -c -o libcommon_a-server-help.obj `if test -f 'server-help.c'; then $(CYGPATH_W) 'server-help.c'; else $(CYGPATH_W) '$(srcdir)/server-help.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-server-help.Tpo $(DEPDIR)/libcommon_a-server-help.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='server-help.c' object='libcommon_a-server-help.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-server-help.obj `if test -f 'server-help.c'; then $(CYGPATH_W) 'server-help.c'; else $(CYGPATH_W) '$(srcdir)/server-help.c'; fi`
+
+libcommon_a-name-value.o: name-value.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-name-value.o -MD -MP -MF $(DEPDIR)/libcommon_a-name-value.Tpo -c -o libcommon_a-name-value.o `test -f 'name-value.c' || echo '$(srcdir)/'`name-value.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-name-value.Tpo $(DEPDIR)/libcommon_a-name-value.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='name-value.c' object='libcommon_a-name-value.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-name-value.o `test -f 'name-value.c' || echo '$(srcdir)/'`name-value.c
+
+libcommon_a-name-value.obj: name-value.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-name-value.obj -MD -MP -MF $(DEPDIR)/libcommon_a-name-value.Tpo -c -o libcommon_a-name-value.obj `if test -f 'name-value.c'; then $(CYGPATH_W) 'name-value.c'; else $(CYGPATH_W) '$(srcdir)/name-value.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-name-value.Tpo $(DEPDIR)/libcommon_a-name-value.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='name-value.c' object='libcommon_a-name-value.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-name-value.obj `if test -f 'name-value.c'; then $(CYGPATH_W) 'name-value.c'; else $(CYGPATH_W) '$(srcdir)/name-value.c'; fi`
+
+libcommon_a-recsel.o: recsel.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-recsel.o -MD -MP -MF $(DEPDIR)/libcommon_a-recsel.Tpo -c -o libcommon_a-recsel.o `test -f 'recsel.c' || echo '$(srcdir)/'`recsel.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-recsel.Tpo $(DEPDIR)/libcommon_a-recsel.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='recsel.c' object='libcommon_a-recsel.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-recsel.o `test -f 'recsel.c' || echo '$(srcdir)/'`recsel.c
+
+libcommon_a-recsel.obj: recsel.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-recsel.obj -MD -MP -MF $(DEPDIR)/libcommon_a-recsel.Tpo -c -o libcommon_a-recsel.obj `if test -f 'recsel.c'; then $(CYGPATH_W) 'recsel.c'; else $(CYGPATH_W) '$(srcdir)/recsel.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-recsel.Tpo $(DEPDIR)/libcommon_a-recsel.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='recsel.c' object='libcommon_a-recsel.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-recsel.obj `if test -f 'recsel.c'; then $(CYGPATH_W) 'recsel.c'; else $(CYGPATH_W) '$(srcdir)/recsel.c'; fi`
+
+libcommon_a-ksba-io-support.o: ksba-io-support.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-ksba-io-support.o -MD -MP -MF $(DEPDIR)/libcommon_a-ksba-io-support.Tpo -c -o libcommon_a-ksba-io-support.o `test -f 'ksba-io-support.c' || echo '$(srcdir)/'`ksba-io-support.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-ksba-io-support.Tpo $(DEPDIR)/libcommon_a-ksba-io-support.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ksba-io-support.c' object='libcommon_a-ksba-io-support.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-ksba-io-support.o `test -f 'ksba-io-support.c' || echo '$(srcdir)/'`ksba-io-support.c
+
+libcommon_a-ksba-io-support.obj: ksba-io-support.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-ksba-io-support.obj -MD -MP -MF $(DEPDIR)/libcommon_a-ksba-io-support.Tpo -c -o libcommon_a-ksba-io-support.obj `if test -f 'ksba-io-support.c'; then $(CYGPATH_W) 'ksba-io-support.c'; else $(CYGPATH_W) '$(srcdir)/ksba-io-support.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-ksba-io-support.Tpo $(DEPDIR)/libcommon_a-ksba-io-support.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ksba-io-support.c' object='libcommon_a-ksba-io-support.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-ksba-io-support.obj `if test -f 'ksba-io-support.c'; then $(CYGPATH_W) 'ksba-io-support.c'; else $(CYGPATH_W) '$(srcdir)/ksba-io-support.c'; fi`
+
+libcommon_a-openpgp-fpr.o: openpgp-fpr.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-openpgp-fpr.o -MD -MP -MF $(DEPDIR)/libcommon_a-openpgp-fpr.Tpo -c -o libcommon_a-openpgp-fpr.o `test -f 'openpgp-fpr.c' || echo '$(srcdir)/'`openpgp-fpr.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-openpgp-fpr.Tpo $(DEPDIR)/libcommon_a-openpgp-fpr.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='openpgp-fpr.c' object='libcommon_a-openpgp-fpr.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-openpgp-fpr.o `test -f 'openpgp-fpr.c' || echo '$(srcdir)/'`openpgp-fpr.c
+
+libcommon_a-openpgp-fpr.obj: openpgp-fpr.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-openpgp-fpr.obj -MD -MP -MF $(DEPDIR)/libcommon_a-openpgp-fpr.Tpo -c -o libcommon_a-openpgp-fpr.obj `if test -f 'openpgp-fpr.c'; then $(CYGPATH_W) 'openpgp-fpr.c'; else $(CYGPATH_W) '$(srcdir)/openpgp-fpr.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-openpgp-fpr.Tpo $(DEPDIR)/libcommon_a-openpgp-fpr.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='openpgp-fpr.c' object='libcommon_a-openpgp-fpr.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-openpgp-fpr.obj `if test -f 'openpgp-fpr.c'; then $(CYGPATH_W) 'openpgp-fpr.c'; else $(CYGPATH_W) '$(srcdir)/openpgp-fpr.c'; fi`
+
+libcommon_a-compliance.o: compliance.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-compliance.o -MD -MP -MF $(DEPDIR)/libcommon_a-compliance.Tpo -c -o libcommon_a-compliance.o `test -f 'compliance.c' || echo '$(srcdir)/'`compliance.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-compliance.Tpo $(DEPDIR)/libcommon_a-compliance.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='compliance.c' object='libcommon_a-compliance.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-compliance.o `test -f 'compliance.c' || echo '$(srcdir)/'`compliance.c
+
+libcommon_a-compliance.obj: compliance.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-compliance.obj -MD -MP -MF $(DEPDIR)/libcommon_a-compliance.Tpo -c -o libcommon_a-compliance.obj `if test -f 'compliance.c'; then $(CYGPATH_W) 'compliance.c'; else $(CYGPATH_W) '$(srcdir)/compliance.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-compliance.Tpo $(DEPDIR)/libcommon_a-compliance.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='compliance.c' object='libcommon_a-compliance.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-compliance.obj `if test -f 'compliance.c'; then $(CYGPATH_W) 'compliance.c'; else $(CYGPATH_W) '$(srcdir)/compliance.c'; fi`
+
+libcommon_a-w32-reg.o: w32-reg.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-w32-reg.o -MD -MP -MF $(DEPDIR)/libcommon_a-w32-reg.Tpo -c -o libcommon_a-w32-reg.o `test -f 'w32-reg.c' || echo '$(srcdir)/'`w32-reg.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-w32-reg.Tpo $(DEPDIR)/libcommon_a-w32-reg.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='w32-reg.c' object='libcommon_a-w32-reg.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-w32-reg.o `test -f 'w32-reg.c' || echo '$(srcdir)/'`w32-reg.c
+
+libcommon_a-w32-reg.obj: w32-reg.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-w32-reg.obj -MD -MP -MF $(DEPDIR)/libcommon_a-w32-reg.Tpo -c -o libcommon_a-w32-reg.obj `if test -f 'w32-reg.c'; then $(CYGPATH_W) 'w32-reg.c'; else $(CYGPATH_W) '$(srcdir)/w32-reg.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-w32-reg.Tpo $(DEPDIR)/libcommon_a-w32-reg.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='w32-reg.c' object='libcommon_a-w32-reg.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-w32-reg.obj `if test -f 'w32-reg.c'; then $(CYGPATH_W) 'w32-reg.c'; else $(CYGPATH_W) '$(srcdir)/w32-reg.c'; fi`
+
+libcommon_a-w32-cmdline.o: w32-cmdline.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-w32-cmdline.o -MD -MP -MF $(DEPDIR)/libcommon_a-w32-cmdline.Tpo -c -o libcommon_a-w32-cmdline.o `test -f 'w32-cmdline.c' || echo '$(srcdir)/'`w32-cmdline.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-w32-cmdline.Tpo $(DEPDIR)/libcommon_a-w32-cmdline.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='w32-cmdline.c' object='libcommon_a-w32-cmdline.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-w32-cmdline.o `test -f 'w32-cmdline.c' || echo '$(srcdir)/'`w32-cmdline.c
+
+libcommon_a-w32-cmdline.obj: w32-cmdline.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-w32-cmdline.obj -MD -MP -MF $(DEPDIR)/libcommon_a-w32-cmdline.Tpo -c -o libcommon_a-w32-cmdline.obj `if test -f 'w32-cmdline.c'; then $(CYGPATH_W) 'w32-cmdline.c'; else $(CYGPATH_W) '$(srcdir)/w32-cmdline.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-w32-cmdline.Tpo $(DEPDIR)/libcommon_a-w32-cmdline.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='w32-cmdline.c' object='libcommon_a-w32-cmdline.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-w32-cmdline.obj `if test -f 'w32-cmdline.c'; then $(CYGPATH_W) 'w32-cmdline.c'; else $(CYGPATH_W) '$(srcdir)/w32-cmdline.c'; fi`
+
+libcommon_a-exechelp-w32ce.o: exechelp-w32ce.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-exechelp-w32ce.o -MD -MP -MF $(DEPDIR)/libcommon_a-exechelp-w32ce.Tpo -c -o libcommon_a-exechelp-w32ce.o `test -f 'exechelp-w32ce.c' || echo '$(srcdir)/'`exechelp-w32ce.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-exechelp-w32ce.Tpo $(DEPDIR)/libcommon_a-exechelp-w32ce.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='exechelp-w32ce.c' object='libcommon_a-exechelp-w32ce.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-exechelp-w32ce.o `test -f 'exechelp-w32ce.c' || echo '$(srcdir)/'`exechelp-w32ce.c
+
+libcommon_a-exechelp-w32ce.obj: exechelp-w32ce.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-exechelp-w32ce.obj -MD -MP -MF $(DEPDIR)/libcommon_a-exechelp-w32ce.Tpo -c -o libcommon_a-exechelp-w32ce.obj `if test -f 'exechelp-w32ce.c'; then $(CYGPATH_W) 'exechelp-w32ce.c'; else $(CYGPATH_W) '$(srcdir)/exechelp-w32ce.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-exechelp-w32ce.Tpo $(DEPDIR)/libcommon_a-exechelp-w32ce.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='exechelp-w32ce.c' object='libcommon_a-exechelp-w32ce.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-exechelp-w32ce.obj `if test -f 'exechelp-w32ce.c'; then $(CYGPATH_W) 'exechelp-w32ce.c'; else $(CYGPATH_W) '$(srcdir)/exechelp-w32ce.c'; fi`
+
+libcommon_a-exechelp-w32.o: exechelp-w32.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-exechelp-w32.o -MD -MP -MF $(DEPDIR)/libcommon_a-exechelp-w32.Tpo -c -o libcommon_a-exechelp-w32.o `test -f 'exechelp-w32.c' || echo '$(srcdir)/'`exechelp-w32.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-exechelp-w32.Tpo $(DEPDIR)/libcommon_a-exechelp-w32.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='exechelp-w32.c' object='libcommon_a-exechelp-w32.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-exechelp-w32.o `test -f 'exechelp-w32.c' || echo '$(srcdir)/'`exechelp-w32.c
+
+libcommon_a-exechelp-w32.obj: exechelp-w32.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-exechelp-w32.obj -MD -MP -MF $(DEPDIR)/libcommon_a-exechelp-w32.Tpo -c -o libcommon_a-exechelp-w32.obj `if test -f 'exechelp-w32.c'; then $(CYGPATH_W) 'exechelp-w32.c'; else $(CYGPATH_W) '$(srcdir)/exechelp-w32.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-exechelp-w32.Tpo $(DEPDIR)/libcommon_a-exechelp-w32.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='exechelp-w32.c' object='libcommon_a-exechelp-w32.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-exechelp-w32.obj `if test -f 'exechelp-w32.c'; then $(CYGPATH_W) 'exechelp-w32.c'; else $(CYGPATH_W) '$(srcdir)/exechelp-w32.c'; fi`
+
+libcommon_a-exechelp-posix.o: exechelp-posix.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-exechelp-posix.o -MD -MP -MF $(DEPDIR)/libcommon_a-exechelp-posix.Tpo -c -o libcommon_a-exechelp-posix.o `test -f 'exechelp-posix.c' || echo '$(srcdir)/'`exechelp-posix.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-exechelp-posix.Tpo $(DEPDIR)/libcommon_a-exechelp-posix.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='exechelp-posix.c' object='libcommon_a-exechelp-posix.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-exechelp-posix.o `test -f 'exechelp-posix.c' || echo '$(srcdir)/'`exechelp-posix.c
+
+libcommon_a-exechelp-posix.obj: exechelp-posix.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-exechelp-posix.obj -MD -MP -MF $(DEPDIR)/libcommon_a-exechelp-posix.Tpo -c -o libcommon_a-exechelp-posix.obj `if test -f 'exechelp-posix.c'; then $(CYGPATH_W) 'exechelp-posix.c'; else $(CYGPATH_W) '$(srcdir)/exechelp-posix.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-exechelp-posix.Tpo $(DEPDIR)/libcommon_a-exechelp-posix.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='exechelp-posix.c' object='libcommon_a-exechelp-posix.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-exechelp-posix.obj `if test -f 'exechelp-posix.c'; then $(CYGPATH_W) 'exechelp-posix.c'; else $(CYGPATH_W) '$(srcdir)/exechelp-posix.c'; fi`
+
+libcommon_a-get-passphrase.o: get-passphrase.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-get-passphrase.o -MD -MP -MF $(DEPDIR)/libcommon_a-get-passphrase.Tpo -c -o libcommon_a-get-passphrase.o `test -f 'get-passphrase.c' || echo '$(srcdir)/'`get-passphrase.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-get-passphrase.Tpo $(DEPDIR)/libcommon_a-get-passphrase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='get-passphrase.c' object='libcommon_a-get-passphrase.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-get-passphrase.o `test -f 'get-passphrase.c' || echo '$(srcdir)/'`get-passphrase.c
+
+libcommon_a-get-passphrase.obj: get-passphrase.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -MT libcommon_a-get-passphrase.obj -MD -MP -MF $(DEPDIR)/libcommon_a-get-passphrase.Tpo -c -o libcommon_a-get-passphrase.obj `if test -f 'get-passphrase.c'; then $(CYGPATH_W) 'get-passphrase.c'; else $(CYGPATH_W) '$(srcdir)/get-passphrase.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_a-get-passphrase.Tpo $(DEPDIR)/libcommon_a-get-passphrase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='get-passphrase.c' object='libcommon_a-get-passphrase.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_a_CFLAGS) $(CFLAGS) -c -o libcommon_a-get-passphrase.obj `if test -f 'get-passphrase.c'; then $(CYGPATH_W) 'get-passphrase.c'; else $(CYGPATH_W) '$(srcdir)/get-passphrase.c'; fi`
+
+libcommonpth_a-i18n.o: i18n.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-i18n.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-i18n.Tpo -c -o libcommonpth_a-i18n.o `test -f 'i18n.c' || echo '$(srcdir)/'`i18n.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-i18n.Tpo $(DEPDIR)/libcommonpth_a-i18n.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='i18n.c' object='libcommonpth_a-i18n.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-i18n.o `test -f 'i18n.c' || echo '$(srcdir)/'`i18n.c
+
+libcommonpth_a-i18n.obj: i18n.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-i18n.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-i18n.Tpo -c -o libcommonpth_a-i18n.obj `if test -f 'i18n.c'; then $(CYGPATH_W) 'i18n.c'; else $(CYGPATH_W) '$(srcdir)/i18n.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-i18n.Tpo $(DEPDIR)/libcommonpth_a-i18n.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='i18n.c' object='libcommonpth_a-i18n.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-i18n.obj `if test -f 'i18n.c'; then $(CYGPATH_W) 'i18n.c'; else $(CYGPATH_W) '$(srcdir)/i18n.c'; fi`
+
+libcommonpth_a-mapstrings.o: mapstrings.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-mapstrings.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-mapstrings.Tpo -c -o libcommonpth_a-mapstrings.o `test -f 'mapstrings.c' || echo '$(srcdir)/'`mapstrings.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-mapstrings.Tpo $(DEPDIR)/libcommonpth_a-mapstrings.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mapstrings.c' object='libcommonpth_a-mapstrings.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-mapstrings.o `test -f 'mapstrings.c' || echo '$(srcdir)/'`mapstrings.c
+
+libcommonpth_a-mapstrings.obj: mapstrings.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-mapstrings.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-mapstrings.Tpo -c -o libcommonpth_a-mapstrings.obj `if test -f 'mapstrings.c'; then $(CYGPATH_W) 'mapstrings.c'; else $(CYGPATH_W) '$(srcdir)/mapstrings.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-mapstrings.Tpo $(DEPDIR)/libcommonpth_a-mapstrings.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mapstrings.c' object='libcommonpth_a-mapstrings.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-mapstrings.obj `if test -f 'mapstrings.c'; then $(CYGPATH_W) 'mapstrings.c'; else $(CYGPATH_W) '$(srcdir)/mapstrings.c'; fi`
+
+libcommonpth_a-stringhelp.o: stringhelp.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-stringhelp.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-stringhelp.Tpo -c -o libcommonpth_a-stringhelp.o `test -f 'stringhelp.c' || echo '$(srcdir)/'`stringhelp.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-stringhelp.Tpo $(DEPDIR)/libcommonpth_a-stringhelp.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='stringhelp.c' object='libcommonpth_a-stringhelp.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-stringhelp.o `test -f 'stringhelp.c' || echo '$(srcdir)/'`stringhelp.c
+
+libcommonpth_a-stringhelp.obj: stringhelp.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-stringhelp.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-stringhelp.Tpo -c -o libcommonpth_a-stringhelp.obj `if test -f 'stringhelp.c'; then $(CYGPATH_W) 'stringhelp.c'; else $(CYGPATH_W) '$(srcdir)/stringhelp.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-stringhelp.Tpo $(DEPDIR)/libcommonpth_a-stringhelp.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='stringhelp.c' object='libcommonpth_a-stringhelp.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-stringhelp.obj `if test -f 'stringhelp.c'; then $(CYGPATH_W) 'stringhelp.c'; else $(CYGPATH_W) '$(srcdir)/stringhelp.c'; fi`
+
+libcommonpth_a-strlist.o: strlist.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-strlist.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-strlist.Tpo -c -o libcommonpth_a-strlist.o `test -f 'strlist.c' || echo '$(srcdir)/'`strlist.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-strlist.Tpo $(DEPDIR)/libcommonpth_a-strlist.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='strlist.c' object='libcommonpth_a-strlist.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-strlist.o `test -f 'strlist.c' || echo '$(srcdir)/'`strlist.c
+
+libcommonpth_a-strlist.obj: strlist.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-strlist.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-strlist.Tpo -c -o libcommonpth_a-strlist.obj `if test -f 'strlist.c'; then $(CYGPATH_W) 'strlist.c'; else $(CYGPATH_W) '$(srcdir)/strlist.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-strlist.Tpo $(DEPDIR)/libcommonpth_a-strlist.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='strlist.c' object='libcommonpth_a-strlist.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-strlist.obj `if test -f 'strlist.c'; then $(CYGPATH_W) 'strlist.c'; else $(CYGPATH_W) '$(srcdir)/strlist.c'; fi`
+
+libcommonpth_a-utf8conv.o: utf8conv.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-utf8conv.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-utf8conv.Tpo -c -o libcommonpth_a-utf8conv.o `test -f 'utf8conv.c' || echo '$(srcdir)/'`utf8conv.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-utf8conv.Tpo $(DEPDIR)/libcommonpth_a-utf8conv.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utf8conv.c' object='libcommonpth_a-utf8conv.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-utf8conv.o `test -f 'utf8conv.c' || echo '$(srcdir)/'`utf8conv.c
+
+libcommonpth_a-utf8conv.obj: utf8conv.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-utf8conv.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-utf8conv.Tpo -c -o libcommonpth_a-utf8conv.obj `if test -f 'utf8conv.c'; then $(CYGPATH_W) 'utf8conv.c'; else $(CYGPATH_W) '$(srcdir)/utf8conv.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-utf8conv.Tpo $(DEPDIR)/libcommonpth_a-utf8conv.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utf8conv.c' object='libcommonpth_a-utf8conv.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-utf8conv.obj `if test -f 'utf8conv.c'; then $(CYGPATH_W) 'utf8conv.c'; else $(CYGPATH_W) '$(srcdir)/utf8conv.c'; fi`
+
+libcommonpth_a-argparse.o: argparse.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-argparse.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-argparse.Tpo -c -o libcommonpth_a-argparse.o `test -f 'argparse.c' || echo '$(srcdir)/'`argparse.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-argparse.Tpo $(DEPDIR)/libcommonpth_a-argparse.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='argparse.c' object='libcommonpth_a-argparse.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-argparse.o `test -f 'argparse.c' || echo '$(srcdir)/'`argparse.c
+
+libcommonpth_a-argparse.obj: argparse.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-argparse.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-argparse.Tpo -c -o libcommonpth_a-argparse.obj `if test -f 'argparse.c'; then $(CYGPATH_W) 'argparse.c'; else $(CYGPATH_W) '$(srcdir)/argparse.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-argparse.Tpo $(DEPDIR)/libcommonpth_a-argparse.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='argparse.c' object='libcommonpth_a-argparse.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-argparse.obj `if test -f 'argparse.c'; then $(CYGPATH_W) 'argparse.c'; else $(CYGPATH_W) '$(srcdir)/argparse.c'; fi`
+
+libcommonpth_a-logging.o: logging.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-logging.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-logging.Tpo -c -o libcommonpth_a-logging.o `test -f 'logging.c' || echo '$(srcdir)/'`logging.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-logging.Tpo $(DEPDIR)/libcommonpth_a-logging.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='logging.c' object='libcommonpth_a-logging.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-logging.o `test -f 'logging.c' || echo '$(srcdir)/'`logging.c
+
+libcommonpth_a-logging.obj: logging.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-logging.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-logging.Tpo -c -o libcommonpth_a-logging.obj `if test -f 'logging.c'; then $(CYGPATH_W) 'logging.c'; else $(CYGPATH_W) '$(srcdir)/logging.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-logging.Tpo $(DEPDIR)/libcommonpth_a-logging.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='logging.c' object='libcommonpth_a-logging.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-logging.obj `if test -f 'logging.c'; then $(CYGPATH_W) 'logging.c'; else $(CYGPATH_W) '$(srcdir)/logging.c'; fi`
+
+libcommonpth_a-dotlock.o: dotlock.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-dotlock.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-dotlock.Tpo -c -o libcommonpth_a-dotlock.o `test -f 'dotlock.c' || echo '$(srcdir)/'`dotlock.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-dotlock.Tpo $(DEPDIR)/libcommonpth_a-dotlock.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dotlock.c' object='libcommonpth_a-dotlock.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-dotlock.o `test -f 'dotlock.c' || echo '$(srcdir)/'`dotlock.c
+
+libcommonpth_a-dotlock.obj: dotlock.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-dotlock.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-dotlock.Tpo -c -o libcommonpth_a-dotlock.obj `if test -f 'dotlock.c'; then $(CYGPATH_W) 'dotlock.c'; else $(CYGPATH_W) '$(srcdir)/dotlock.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-dotlock.Tpo $(DEPDIR)/libcommonpth_a-dotlock.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dotlock.c' object='libcommonpth_a-dotlock.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-dotlock.obj `if test -f 'dotlock.c'; then $(CYGPATH_W) 'dotlock.c'; else $(CYGPATH_W) '$(srcdir)/dotlock.c'; fi`
+
+libcommonpth_a-mischelp.o: mischelp.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-mischelp.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-mischelp.Tpo -c -o libcommonpth_a-mischelp.o `test -f 'mischelp.c' || echo '$(srcdir)/'`mischelp.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-mischelp.Tpo $(DEPDIR)/libcommonpth_a-mischelp.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mischelp.c' object='libcommonpth_a-mischelp.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-mischelp.o `test -f 'mischelp.c' || echo '$(srcdir)/'`mischelp.c
+
+libcommonpth_a-mischelp.obj: mischelp.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-mischelp.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-mischelp.Tpo -c -o libcommonpth_a-mischelp.obj `if test -f 'mischelp.c'; then $(CYGPATH_W) 'mischelp.c'; else $(CYGPATH_W) '$(srcdir)/mischelp.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-mischelp.Tpo $(DEPDIR)/libcommonpth_a-mischelp.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mischelp.c' object='libcommonpth_a-mischelp.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-mischelp.obj `if test -f 'mischelp.c'; then $(CYGPATH_W) 'mischelp.c'; else $(CYGPATH_W) '$(srcdir)/mischelp.c'; fi`
+
+libcommonpth_a-status.o: status.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-status.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-status.Tpo -c -o libcommonpth_a-status.o `test -f 'status.c' || echo '$(srcdir)/'`status.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-status.Tpo $(DEPDIR)/libcommonpth_a-status.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='status.c' object='libcommonpth_a-status.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-status.o `test -f 'status.c' || echo '$(srcdir)/'`status.c
+
+libcommonpth_a-status.obj: status.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-status.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-status.Tpo -c -o libcommonpth_a-status.obj `if test -f 'status.c'; then $(CYGPATH_W) 'status.c'; else $(CYGPATH_W) '$(srcdir)/status.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-status.Tpo $(DEPDIR)/libcommonpth_a-status.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='status.c' object='libcommonpth_a-status.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-status.obj `if test -f 'status.c'; then $(CYGPATH_W) 'status.c'; else $(CYGPATH_W) '$(srcdir)/status.c'; fi`
+
+libcommonpth_a-tlv.o: tlv.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-tlv.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-tlv.Tpo -c -o libcommonpth_a-tlv.o `test -f 'tlv.c' || echo '$(srcdir)/'`tlv.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-tlv.Tpo $(DEPDIR)/libcommonpth_a-tlv.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tlv.c' object='libcommonpth_a-tlv.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-tlv.o `test -f 'tlv.c' || echo '$(srcdir)/'`tlv.c
+
+libcommonpth_a-tlv.obj: tlv.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-tlv.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-tlv.Tpo -c -o libcommonpth_a-tlv.obj `if test -f 'tlv.c'; then $(CYGPATH_W) 'tlv.c'; else $(CYGPATH_W) '$(srcdir)/tlv.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-tlv.Tpo $(DEPDIR)/libcommonpth_a-tlv.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tlv.c' object='libcommonpth_a-tlv.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-tlv.obj `if test -f 'tlv.c'; then $(CYGPATH_W) 'tlv.c'; else $(CYGPATH_W) '$(srcdir)/tlv.c'; fi`
+
+libcommonpth_a-tlv-builder.o: tlv-builder.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-tlv-builder.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-tlv-builder.Tpo -c -o libcommonpth_a-tlv-builder.o `test -f 'tlv-builder.c' || echo '$(srcdir)/'`tlv-builder.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-tlv-builder.Tpo $(DEPDIR)/libcommonpth_a-tlv-builder.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tlv-builder.c' object='libcommonpth_a-tlv-builder.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-tlv-builder.o `test -f 'tlv-builder.c' || echo '$(srcdir)/'`tlv-builder.c
+
+libcommonpth_a-tlv-builder.obj: tlv-builder.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-tlv-builder.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-tlv-builder.Tpo -c -o libcommonpth_a-tlv-builder.obj `if test -f 'tlv-builder.c'; then $(CYGPATH_W) 'tlv-builder.c'; else $(CYGPATH_W) '$(srcdir)/tlv-builder.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-tlv-builder.Tpo $(DEPDIR)/libcommonpth_a-tlv-builder.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tlv-builder.c' object='libcommonpth_a-tlv-builder.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-tlv-builder.obj `if test -f 'tlv-builder.c'; then $(CYGPATH_W) 'tlv-builder.c'; else $(CYGPATH_W) '$(srcdir)/tlv-builder.c'; fi`
+
+libcommonpth_a-init.o: init.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-init.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-init.Tpo -c -o libcommonpth_a-init.o `test -f 'init.c' || echo '$(srcdir)/'`init.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-init.Tpo $(DEPDIR)/libcommonpth_a-init.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='init.c' object='libcommonpth_a-init.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-init.o `test -f 'init.c' || echo '$(srcdir)/'`init.c
+
+libcommonpth_a-init.obj: init.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-init.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-init.Tpo -c -o libcommonpth_a-init.obj `if test -f 'init.c'; then $(CYGPATH_W) 'init.c'; else $(CYGPATH_W) '$(srcdir)/init.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-init.Tpo $(DEPDIR)/libcommonpth_a-init.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='init.c' object='libcommonpth_a-init.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-init.obj `if test -f 'init.c'; then $(CYGPATH_W) 'init.c'; else $(CYGPATH_W) '$(srcdir)/init.c'; fi`
+
+libcommonpth_a-sexputil.o: sexputil.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-sexputil.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-sexputil.Tpo -c -o libcommonpth_a-sexputil.o `test -f 'sexputil.c' || echo '$(srcdir)/'`sexputil.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-sexputil.Tpo $(DEPDIR)/libcommonpth_a-sexputil.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sexputil.c' object='libcommonpth_a-sexputil.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-sexputil.o `test -f 'sexputil.c' || echo '$(srcdir)/'`sexputil.c
+
+libcommonpth_a-sexputil.obj: sexputil.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-sexputil.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-sexputil.Tpo -c -o libcommonpth_a-sexputil.obj `if test -f 'sexputil.c'; then $(CYGPATH_W) 'sexputil.c'; else $(CYGPATH_W) '$(srcdir)/sexputil.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-sexputil.Tpo $(DEPDIR)/libcommonpth_a-sexputil.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sexputil.c' object='libcommonpth_a-sexputil.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-sexputil.obj `if test -f 'sexputil.c'; then $(CYGPATH_W) 'sexputil.c'; else $(CYGPATH_W) '$(srcdir)/sexputil.c'; fi`
+
+libcommonpth_a-sysutils.o: sysutils.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-sysutils.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-sysutils.Tpo -c -o libcommonpth_a-sysutils.o `test -f 'sysutils.c' || echo '$(srcdir)/'`sysutils.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-sysutils.Tpo $(DEPDIR)/libcommonpth_a-sysutils.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sysutils.c' object='libcommonpth_a-sysutils.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-sysutils.o `test -f 'sysutils.c' || echo '$(srcdir)/'`sysutils.c
+
+libcommonpth_a-sysutils.obj: sysutils.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-sysutils.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-sysutils.Tpo -c -o libcommonpth_a-sysutils.obj `if test -f 'sysutils.c'; then $(CYGPATH_W) 'sysutils.c'; else $(CYGPATH_W) '$(srcdir)/sysutils.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-sysutils.Tpo $(DEPDIR)/libcommonpth_a-sysutils.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sysutils.c' object='libcommonpth_a-sysutils.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-sysutils.obj `if test -f 'sysutils.c'; then $(CYGPATH_W) 'sysutils.c'; else $(CYGPATH_W) '$(srcdir)/sysutils.c'; fi`
+
+libcommonpth_a-homedir.o: homedir.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-homedir.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-homedir.Tpo -c -o libcommonpth_a-homedir.o `test -f 'homedir.c' || echo '$(srcdir)/'`homedir.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-homedir.Tpo $(DEPDIR)/libcommonpth_a-homedir.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='homedir.c' object='libcommonpth_a-homedir.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-homedir.o `test -f 'homedir.c' || echo '$(srcdir)/'`homedir.c
+
+libcommonpth_a-homedir.obj: homedir.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-homedir.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-homedir.Tpo -c -o libcommonpth_a-homedir.obj `if test -f 'homedir.c'; then $(CYGPATH_W) 'homedir.c'; else $(CYGPATH_W) '$(srcdir)/homedir.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-homedir.Tpo $(DEPDIR)/libcommonpth_a-homedir.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='homedir.c' object='libcommonpth_a-homedir.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-homedir.obj `if test -f 'homedir.c'; then $(CYGPATH_W) 'homedir.c'; else $(CYGPATH_W) '$(srcdir)/homedir.c'; fi`
+
+libcommonpth_a-gettime.o: gettime.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-gettime.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-gettime.Tpo -c -o libcommonpth_a-gettime.o `test -f 'gettime.c' || echo '$(srcdir)/'`gettime.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-gettime.Tpo $(DEPDIR)/libcommonpth_a-gettime.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gettime.c' object='libcommonpth_a-gettime.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-gettime.o `test -f 'gettime.c' || echo '$(srcdir)/'`gettime.c
+
+libcommonpth_a-gettime.obj: gettime.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-gettime.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-gettime.Tpo -c -o libcommonpth_a-gettime.obj `if test -f 'gettime.c'; then $(CYGPATH_W) 'gettime.c'; else $(CYGPATH_W) '$(srcdir)/gettime.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-gettime.Tpo $(DEPDIR)/libcommonpth_a-gettime.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gettime.c' object='libcommonpth_a-gettime.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-gettime.obj `if test -f 'gettime.c'; then $(CYGPATH_W) 'gettime.c'; else $(CYGPATH_W) '$(srcdir)/gettime.c'; fi`
+
+libcommonpth_a-yesno.o: yesno.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-yesno.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-yesno.Tpo -c -o libcommonpth_a-yesno.o `test -f 'yesno.c' || echo '$(srcdir)/'`yesno.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-yesno.Tpo $(DEPDIR)/libcommonpth_a-yesno.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='yesno.c' object='libcommonpth_a-yesno.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-yesno.o `test -f 'yesno.c' || echo '$(srcdir)/'`yesno.c
+
+libcommonpth_a-yesno.obj: yesno.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-yesno.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-yesno.Tpo -c -o libcommonpth_a-yesno.obj `if test -f 'yesno.c'; then $(CYGPATH_W) 'yesno.c'; else $(CYGPATH_W) '$(srcdir)/yesno.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-yesno.Tpo $(DEPDIR)/libcommonpth_a-yesno.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='yesno.c' object='libcommonpth_a-yesno.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-yesno.obj `if test -f 'yesno.c'; then $(CYGPATH_W) 'yesno.c'; else $(CYGPATH_W) '$(srcdir)/yesno.c'; fi`
+
+libcommonpth_a-b64enc.o: b64enc.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-b64enc.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-b64enc.Tpo -c -o libcommonpth_a-b64enc.o `test -f 'b64enc.c' || echo '$(srcdir)/'`b64enc.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-b64enc.Tpo $(DEPDIR)/libcommonpth_a-b64enc.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='b64enc.c' object='libcommonpth_a-b64enc.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-b64enc.o `test -f 'b64enc.c' || echo '$(srcdir)/'`b64enc.c
+
+libcommonpth_a-b64enc.obj: b64enc.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-b64enc.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-b64enc.Tpo -c -o libcommonpth_a-b64enc.obj `if test -f 'b64enc.c'; then $(CYGPATH_W) 'b64enc.c'; else $(CYGPATH_W) '$(srcdir)/b64enc.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-b64enc.Tpo $(DEPDIR)/libcommonpth_a-b64enc.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='b64enc.c' object='libcommonpth_a-b64enc.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-b64enc.obj `if test -f 'b64enc.c'; then $(CYGPATH_W) 'b64enc.c'; else $(CYGPATH_W) '$(srcdir)/b64enc.c'; fi`
+
+libcommonpth_a-b64dec.o: b64dec.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-b64dec.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-b64dec.Tpo -c -o libcommonpth_a-b64dec.o `test -f 'b64dec.c' || echo '$(srcdir)/'`b64dec.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-b64dec.Tpo $(DEPDIR)/libcommonpth_a-b64dec.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='b64dec.c' object='libcommonpth_a-b64dec.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-b64dec.o `test -f 'b64dec.c' || echo '$(srcdir)/'`b64dec.c
+
+libcommonpth_a-b64dec.obj: b64dec.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-b64dec.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-b64dec.Tpo -c -o libcommonpth_a-b64dec.obj `if test -f 'b64dec.c'; then $(CYGPATH_W) 'b64dec.c'; else $(CYGPATH_W) '$(srcdir)/b64dec.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-b64dec.Tpo $(DEPDIR)/libcommonpth_a-b64dec.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='b64dec.c' object='libcommonpth_a-b64dec.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-b64dec.obj `if test -f 'b64dec.c'; then $(CYGPATH_W) 'b64dec.c'; else $(CYGPATH_W) '$(srcdir)/b64dec.c'; fi`
+
+libcommonpth_a-zb32.o: zb32.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-zb32.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-zb32.Tpo -c -o libcommonpth_a-zb32.o `test -f 'zb32.c' || echo '$(srcdir)/'`zb32.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-zb32.Tpo $(DEPDIR)/libcommonpth_a-zb32.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='zb32.c' object='libcommonpth_a-zb32.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-zb32.o `test -f 'zb32.c' || echo '$(srcdir)/'`zb32.c
+
+libcommonpth_a-zb32.obj: zb32.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-zb32.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-zb32.Tpo -c -o libcommonpth_a-zb32.obj `if test -f 'zb32.c'; then $(CYGPATH_W) 'zb32.c'; else $(CYGPATH_W) '$(srcdir)/zb32.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-zb32.Tpo $(DEPDIR)/libcommonpth_a-zb32.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='zb32.c' object='libcommonpth_a-zb32.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-zb32.obj `if test -f 'zb32.c'; then $(CYGPATH_W) 'zb32.c'; else $(CYGPATH_W) '$(srcdir)/zb32.c'; fi`
+
+libcommonpth_a-convert.o: convert.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-convert.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-convert.Tpo -c -o libcommonpth_a-convert.o `test -f 'convert.c' || echo '$(srcdir)/'`convert.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-convert.Tpo $(DEPDIR)/libcommonpth_a-convert.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='convert.c' object='libcommonpth_a-convert.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-convert.o `test -f 'convert.c' || echo '$(srcdir)/'`convert.c
+
+libcommonpth_a-convert.obj: convert.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-convert.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-convert.Tpo -c -o libcommonpth_a-convert.obj `if test -f 'convert.c'; then $(CYGPATH_W) 'convert.c'; else $(CYGPATH_W) '$(srcdir)/convert.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-convert.Tpo $(DEPDIR)/libcommonpth_a-convert.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='convert.c' object='libcommonpth_a-convert.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-convert.obj `if test -f 'convert.c'; then $(CYGPATH_W) 'convert.c'; else $(CYGPATH_W) '$(srcdir)/convert.c'; fi`
+
+libcommonpth_a-percent.o: percent.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-percent.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-percent.Tpo -c -o libcommonpth_a-percent.o `test -f 'percent.c' || echo '$(srcdir)/'`percent.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-percent.Tpo $(DEPDIR)/libcommonpth_a-percent.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='percent.c' object='libcommonpth_a-percent.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-percent.o `test -f 'percent.c' || echo '$(srcdir)/'`percent.c
+
+libcommonpth_a-percent.obj: percent.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-percent.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-percent.Tpo -c -o libcommonpth_a-percent.obj `if test -f 'percent.c'; then $(CYGPATH_W) 'percent.c'; else $(CYGPATH_W) '$(srcdir)/percent.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-percent.Tpo $(DEPDIR)/libcommonpth_a-percent.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='percent.c' object='libcommonpth_a-percent.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-percent.obj `if test -f 'percent.c'; then $(CYGPATH_W) 'percent.c'; else $(CYGPATH_W) '$(srcdir)/percent.c'; fi`
+
+libcommonpth_a-mbox-util.o: mbox-util.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-mbox-util.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-mbox-util.Tpo -c -o libcommonpth_a-mbox-util.o `test -f 'mbox-util.c' || echo '$(srcdir)/'`mbox-util.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-mbox-util.Tpo $(DEPDIR)/libcommonpth_a-mbox-util.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mbox-util.c' object='libcommonpth_a-mbox-util.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-mbox-util.o `test -f 'mbox-util.c' || echo '$(srcdir)/'`mbox-util.c
+
+libcommonpth_a-mbox-util.obj: mbox-util.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-mbox-util.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-mbox-util.Tpo -c -o libcommonpth_a-mbox-util.obj `if test -f 'mbox-util.c'; then $(CYGPATH_W) 'mbox-util.c'; else $(CYGPATH_W) '$(srcdir)/mbox-util.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-mbox-util.Tpo $(DEPDIR)/libcommonpth_a-mbox-util.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mbox-util.c' object='libcommonpth_a-mbox-util.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-mbox-util.obj `if test -f 'mbox-util.c'; then $(CYGPATH_W) 'mbox-util.c'; else $(CYGPATH_W) '$(srcdir)/mbox-util.c'; fi`
+
+libcommonpth_a-miscellaneous.o: miscellaneous.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-miscellaneous.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-miscellaneous.Tpo -c -o libcommonpth_a-miscellaneous.o `test -f 'miscellaneous.c' || echo '$(srcdir)/'`miscellaneous.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-miscellaneous.Tpo $(DEPDIR)/libcommonpth_a-miscellaneous.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='miscellaneous.c' object='libcommonpth_a-miscellaneous.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-miscellaneous.o `test -f 'miscellaneous.c' || echo '$(srcdir)/'`miscellaneous.c
+
+libcommonpth_a-miscellaneous.obj: miscellaneous.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-miscellaneous.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-miscellaneous.Tpo -c -o libcommonpth_a-miscellaneous.obj `if test -f 'miscellaneous.c'; then $(CYGPATH_W) 'miscellaneous.c'; else $(CYGPATH_W) '$(srcdir)/miscellaneous.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-miscellaneous.Tpo $(DEPDIR)/libcommonpth_a-miscellaneous.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='miscellaneous.c' object='libcommonpth_a-miscellaneous.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-miscellaneous.obj `if test -f 'miscellaneous.c'; then $(CYGPATH_W) 'miscellaneous.c'; else $(CYGPATH_W) '$(srcdir)/miscellaneous.c'; fi`
+
+libcommonpth_a-xasprintf.o: xasprintf.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-xasprintf.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-xasprintf.Tpo -c -o libcommonpth_a-xasprintf.o `test -f 'xasprintf.c' || echo '$(srcdir)/'`xasprintf.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-xasprintf.Tpo $(DEPDIR)/libcommonpth_a-xasprintf.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xasprintf.c' object='libcommonpth_a-xasprintf.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-xasprintf.o `test -f 'xasprintf.c' || echo '$(srcdir)/'`xasprintf.c
+
+libcommonpth_a-xasprintf.obj: xasprintf.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-xasprintf.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-xasprintf.Tpo -c -o libcommonpth_a-xasprintf.obj `if test -f 'xasprintf.c'; then $(CYGPATH_W) 'xasprintf.c'; else $(CYGPATH_W) '$(srcdir)/xasprintf.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-xasprintf.Tpo $(DEPDIR)/libcommonpth_a-xasprintf.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xasprintf.c' object='libcommonpth_a-xasprintf.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-xasprintf.obj `if test -f 'xasprintf.c'; then $(CYGPATH_W) 'xasprintf.c'; else $(CYGPATH_W) '$(srcdir)/xasprintf.c'; fi`
+
+libcommonpth_a-xreadline.o: xreadline.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-xreadline.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-xreadline.Tpo -c -o libcommonpth_a-xreadline.o `test -f 'xreadline.c' || echo '$(srcdir)/'`xreadline.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-xreadline.Tpo $(DEPDIR)/libcommonpth_a-xreadline.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xreadline.c' object='libcommonpth_a-xreadline.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-xreadline.o `test -f 'xreadline.c' || echo '$(srcdir)/'`xreadline.c
+
+libcommonpth_a-xreadline.obj: xreadline.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-xreadline.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-xreadline.Tpo -c -o libcommonpth_a-xreadline.obj `if test -f 'xreadline.c'; then $(CYGPATH_W) 'xreadline.c'; else $(CYGPATH_W) '$(srcdir)/xreadline.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-xreadline.Tpo $(DEPDIR)/libcommonpth_a-xreadline.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xreadline.c' object='libcommonpth_a-xreadline.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-xreadline.obj `if test -f 'xreadline.c'; then $(CYGPATH_W) 'xreadline.c'; else $(CYGPATH_W) '$(srcdir)/xreadline.c'; fi`
+
+libcommonpth_a-membuf.o: membuf.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-membuf.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-membuf.Tpo -c -o libcommonpth_a-membuf.o `test -f 'membuf.c' || echo '$(srcdir)/'`membuf.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-membuf.Tpo $(DEPDIR)/libcommonpth_a-membuf.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='membuf.c' object='libcommonpth_a-membuf.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-membuf.o `test -f 'membuf.c' || echo '$(srcdir)/'`membuf.c
+
+libcommonpth_a-membuf.obj: membuf.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-membuf.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-membuf.Tpo -c -o libcommonpth_a-membuf.obj `if test -f 'membuf.c'; then $(CYGPATH_W) 'membuf.c'; else $(CYGPATH_W) '$(srcdir)/membuf.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-membuf.Tpo $(DEPDIR)/libcommonpth_a-membuf.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='membuf.c' object='libcommonpth_a-membuf.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-membuf.obj `if test -f 'membuf.c'; then $(CYGPATH_W) 'membuf.c'; else $(CYGPATH_W) '$(srcdir)/membuf.c'; fi`
+
+libcommonpth_a-ccparray.o: ccparray.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-ccparray.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-ccparray.Tpo -c -o libcommonpth_a-ccparray.o `test -f 'ccparray.c' || echo '$(srcdir)/'`ccparray.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-ccparray.Tpo $(DEPDIR)/libcommonpth_a-ccparray.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ccparray.c' object='libcommonpth_a-ccparray.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-ccparray.o `test -f 'ccparray.c' || echo '$(srcdir)/'`ccparray.c
+
+libcommonpth_a-ccparray.obj: ccparray.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-ccparray.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-ccparray.Tpo -c -o libcommonpth_a-ccparray.obj `if test -f 'ccparray.c'; then $(CYGPATH_W) 'ccparray.c'; else $(CYGPATH_W) '$(srcdir)/ccparray.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-ccparray.Tpo $(DEPDIR)/libcommonpth_a-ccparray.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ccparray.c' object='libcommonpth_a-ccparray.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-ccparray.obj `if test -f 'ccparray.c'; then $(CYGPATH_W) 'ccparray.c'; else $(CYGPATH_W) '$(srcdir)/ccparray.c'; fi`
+
+libcommonpth_a-iobuf.o: iobuf.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-iobuf.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-iobuf.Tpo -c -o libcommonpth_a-iobuf.o `test -f 'iobuf.c' || echo '$(srcdir)/'`iobuf.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-iobuf.Tpo $(DEPDIR)/libcommonpth_a-iobuf.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='iobuf.c' object='libcommonpth_a-iobuf.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-iobuf.o `test -f 'iobuf.c' || echo '$(srcdir)/'`iobuf.c
+
+libcommonpth_a-iobuf.obj: iobuf.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-iobuf.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-iobuf.Tpo -c -o libcommonpth_a-iobuf.obj `if test -f 'iobuf.c'; then $(CYGPATH_W) 'iobuf.c'; else $(CYGPATH_W) '$(srcdir)/iobuf.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-iobuf.Tpo $(DEPDIR)/libcommonpth_a-iobuf.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='iobuf.c' object='libcommonpth_a-iobuf.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-iobuf.obj `if test -f 'iobuf.c'; then $(CYGPATH_W) 'iobuf.c'; else $(CYGPATH_W) '$(srcdir)/iobuf.c'; fi`
+
+libcommonpth_a-ttyio.o: ttyio.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-ttyio.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-ttyio.Tpo -c -o libcommonpth_a-ttyio.o `test -f 'ttyio.c' || echo '$(srcdir)/'`ttyio.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-ttyio.Tpo $(DEPDIR)/libcommonpth_a-ttyio.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ttyio.c' object='libcommonpth_a-ttyio.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-ttyio.o `test -f 'ttyio.c' || echo '$(srcdir)/'`ttyio.c
+
+libcommonpth_a-ttyio.obj: ttyio.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-ttyio.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-ttyio.Tpo -c -o libcommonpth_a-ttyio.obj `if test -f 'ttyio.c'; then $(CYGPATH_W) 'ttyio.c'; else $(CYGPATH_W) '$(srcdir)/ttyio.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-ttyio.Tpo $(DEPDIR)/libcommonpth_a-ttyio.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ttyio.c' object='libcommonpth_a-ttyio.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-ttyio.obj `if test -f 'ttyio.c'; then $(CYGPATH_W) 'ttyio.c'; else $(CYGPATH_W) '$(srcdir)/ttyio.c'; fi`
+
+libcommonpth_a-asshelp.o: asshelp.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-asshelp.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-asshelp.Tpo -c -o libcommonpth_a-asshelp.o `test -f 'asshelp.c' || echo '$(srcdir)/'`asshelp.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-asshelp.Tpo $(DEPDIR)/libcommonpth_a-asshelp.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='asshelp.c' object='libcommonpth_a-asshelp.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-asshelp.o `test -f 'asshelp.c' || echo '$(srcdir)/'`asshelp.c
+
+libcommonpth_a-asshelp.obj: asshelp.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-asshelp.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-asshelp.Tpo -c -o libcommonpth_a-asshelp.obj `if test -f 'asshelp.c'; then $(CYGPATH_W) 'asshelp.c'; else $(CYGPATH_W) '$(srcdir)/asshelp.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-asshelp.Tpo $(DEPDIR)/libcommonpth_a-asshelp.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='asshelp.c' object='libcommonpth_a-asshelp.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-asshelp.obj `if test -f 'asshelp.c'; then $(CYGPATH_W) 'asshelp.c'; else $(CYGPATH_W) '$(srcdir)/asshelp.c'; fi`
+
+libcommonpth_a-asshelp2.o: asshelp2.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-asshelp2.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-asshelp2.Tpo -c -o libcommonpth_a-asshelp2.o `test -f 'asshelp2.c' || echo '$(srcdir)/'`asshelp2.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-asshelp2.Tpo $(DEPDIR)/libcommonpth_a-asshelp2.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='asshelp2.c' object='libcommonpth_a-asshelp2.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-asshelp2.o `test -f 'asshelp2.c' || echo '$(srcdir)/'`asshelp2.c
+
+libcommonpth_a-asshelp2.obj: asshelp2.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-asshelp2.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-asshelp2.Tpo -c -o libcommonpth_a-asshelp2.obj `if test -f 'asshelp2.c'; then $(CYGPATH_W) 'asshelp2.c'; else $(CYGPATH_W) '$(srcdir)/asshelp2.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-asshelp2.Tpo $(DEPDIR)/libcommonpth_a-asshelp2.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='asshelp2.c' object='libcommonpth_a-asshelp2.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-asshelp2.obj `if test -f 'asshelp2.c'; then $(CYGPATH_W) 'asshelp2.c'; else $(CYGPATH_W) '$(srcdir)/asshelp2.c'; fi`
+
+libcommonpth_a-signal.o: signal.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-signal.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-signal.Tpo -c -o libcommonpth_a-signal.o `test -f 'signal.c' || echo '$(srcdir)/'`signal.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-signal.Tpo $(DEPDIR)/libcommonpth_a-signal.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='signal.c' object='libcommonpth_a-signal.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-signal.o `test -f 'signal.c' || echo '$(srcdir)/'`signal.c
+
+libcommonpth_a-signal.obj: signal.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-signal.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-signal.Tpo -c -o libcommonpth_a-signal.obj `if test -f 'signal.c'; then $(CYGPATH_W) 'signal.c'; else $(CYGPATH_W) '$(srcdir)/signal.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-signal.Tpo $(DEPDIR)/libcommonpth_a-signal.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='signal.c' object='libcommonpth_a-signal.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-signal.obj `if test -f 'signal.c'; then $(CYGPATH_W) 'signal.c'; else $(CYGPATH_W) '$(srcdir)/signal.c'; fi`
+
+libcommonpth_a-audit.o: audit.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-audit.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-audit.Tpo -c -o libcommonpth_a-audit.o `test -f 'audit.c' || echo '$(srcdir)/'`audit.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-audit.Tpo $(DEPDIR)/libcommonpth_a-audit.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audit.c' object='libcommonpth_a-audit.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-audit.o `test -f 'audit.c' || echo '$(srcdir)/'`audit.c
+
+libcommonpth_a-audit.obj: audit.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-audit.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-audit.Tpo -c -o libcommonpth_a-audit.obj `if test -f 'audit.c'; then $(CYGPATH_W) 'audit.c'; else $(CYGPATH_W) '$(srcdir)/audit.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-audit.Tpo $(DEPDIR)/libcommonpth_a-audit.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audit.c' object='libcommonpth_a-audit.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-audit.obj `if test -f 'audit.c'; then $(CYGPATH_W) 'audit.c'; else $(CYGPATH_W) '$(srcdir)/audit.c'; fi`
+
+libcommonpth_a-localename.o: localename.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-localename.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-localename.Tpo -c -o libcommonpth_a-localename.o `test -f 'localename.c' || echo '$(srcdir)/'`localename.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-localename.Tpo $(DEPDIR)/libcommonpth_a-localename.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='localename.c' object='libcommonpth_a-localename.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-localename.o `test -f 'localename.c' || echo '$(srcdir)/'`localename.c
+
+libcommonpth_a-localename.obj: localename.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-localename.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-localename.Tpo -c -o libcommonpth_a-localename.obj `if test -f 'localename.c'; then $(CYGPATH_W) 'localename.c'; else $(CYGPATH_W) '$(srcdir)/localename.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-localename.Tpo $(DEPDIR)/libcommonpth_a-localename.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='localename.c' object='libcommonpth_a-localename.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-localename.obj `if test -f 'localename.c'; then $(CYGPATH_W) 'localename.c'; else $(CYGPATH_W) '$(srcdir)/localename.c'; fi`
+
+libcommonpth_a-session-env.o: session-env.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-session-env.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-session-env.Tpo -c -o libcommonpth_a-session-env.o `test -f 'session-env.c' || echo '$(srcdir)/'`session-env.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-session-env.Tpo $(DEPDIR)/libcommonpth_a-session-env.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='session-env.c' object='libcommonpth_a-session-env.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-session-env.o `test -f 'session-env.c' || echo '$(srcdir)/'`session-env.c
+
+libcommonpth_a-session-env.obj: session-env.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-session-env.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-session-env.Tpo -c -o libcommonpth_a-session-env.obj `if test -f 'session-env.c'; then $(CYGPATH_W) 'session-env.c'; else $(CYGPATH_W) '$(srcdir)/session-env.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-session-env.Tpo $(DEPDIR)/libcommonpth_a-session-env.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='session-env.c' object='libcommonpth_a-session-env.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-session-env.obj `if test -f 'session-env.c'; then $(CYGPATH_W) 'session-env.c'; else $(CYGPATH_W) '$(srcdir)/session-env.c'; fi`
+
+libcommonpth_a-userids.o: userids.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-userids.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-userids.Tpo -c -o libcommonpth_a-userids.o `test -f 'userids.c' || echo '$(srcdir)/'`userids.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-userids.Tpo $(DEPDIR)/libcommonpth_a-userids.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='userids.c' object='libcommonpth_a-userids.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-userids.o `test -f 'userids.c' || echo '$(srcdir)/'`userids.c
+
+libcommonpth_a-userids.obj: userids.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-userids.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-userids.Tpo -c -o libcommonpth_a-userids.obj `if test -f 'userids.c'; then $(CYGPATH_W) 'userids.c'; else $(CYGPATH_W) '$(srcdir)/userids.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-userids.Tpo $(DEPDIR)/libcommonpth_a-userids.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='userids.c' object='libcommonpth_a-userids.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-userids.obj `if test -f 'userids.c'; then $(CYGPATH_W) 'userids.c'; else $(CYGPATH_W) '$(srcdir)/userids.c'; fi`
+
+libcommonpth_a-openpgp-oid.o: openpgp-oid.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-openpgp-oid.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-openpgp-oid.Tpo -c -o libcommonpth_a-openpgp-oid.o `test -f 'openpgp-oid.c' || echo '$(srcdir)/'`openpgp-oid.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-openpgp-oid.Tpo $(DEPDIR)/libcommonpth_a-openpgp-oid.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='openpgp-oid.c' object='libcommonpth_a-openpgp-oid.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-openpgp-oid.o `test -f 'openpgp-oid.c' || echo '$(srcdir)/'`openpgp-oid.c
+
+libcommonpth_a-openpgp-oid.obj: openpgp-oid.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-openpgp-oid.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-openpgp-oid.Tpo -c -o libcommonpth_a-openpgp-oid.obj `if test -f 'openpgp-oid.c'; then $(CYGPATH_W) 'openpgp-oid.c'; else $(CYGPATH_W) '$(srcdir)/openpgp-oid.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-openpgp-oid.Tpo $(DEPDIR)/libcommonpth_a-openpgp-oid.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='openpgp-oid.c' object='libcommonpth_a-openpgp-oid.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-openpgp-oid.obj `if test -f 'openpgp-oid.c'; then $(CYGPATH_W) 'openpgp-oid.c'; else $(CYGPATH_W) '$(srcdir)/openpgp-oid.c'; fi`
+
+libcommonpth_a-ssh-utils.o: ssh-utils.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-ssh-utils.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-ssh-utils.Tpo -c -o libcommonpth_a-ssh-utils.o `test -f 'ssh-utils.c' || echo '$(srcdir)/'`ssh-utils.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-ssh-utils.Tpo $(DEPDIR)/libcommonpth_a-ssh-utils.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ssh-utils.c' object='libcommonpth_a-ssh-utils.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-ssh-utils.o `test -f 'ssh-utils.c' || echo '$(srcdir)/'`ssh-utils.c
+
+libcommonpth_a-ssh-utils.obj: ssh-utils.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-ssh-utils.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-ssh-utils.Tpo -c -o libcommonpth_a-ssh-utils.obj `if test -f 'ssh-utils.c'; then $(CYGPATH_W) 'ssh-utils.c'; else $(CYGPATH_W) '$(srcdir)/ssh-utils.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-ssh-utils.Tpo $(DEPDIR)/libcommonpth_a-ssh-utils.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ssh-utils.c' object='libcommonpth_a-ssh-utils.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-ssh-utils.obj `if test -f 'ssh-utils.c'; then $(CYGPATH_W) 'ssh-utils.c'; else $(CYGPATH_W) '$(srcdir)/ssh-utils.c'; fi`
+
+libcommonpth_a-agent-opt.o: agent-opt.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-agent-opt.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-agent-opt.Tpo -c -o libcommonpth_a-agent-opt.o `test -f 'agent-opt.c' || echo '$(srcdir)/'`agent-opt.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-agent-opt.Tpo $(DEPDIR)/libcommonpth_a-agent-opt.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='agent-opt.c' object='libcommonpth_a-agent-opt.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-agent-opt.o `test -f 'agent-opt.c' || echo '$(srcdir)/'`agent-opt.c
+
+libcommonpth_a-agent-opt.obj: agent-opt.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-agent-opt.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-agent-opt.Tpo -c -o libcommonpth_a-agent-opt.obj `if test -f 'agent-opt.c'; then $(CYGPATH_W) 'agent-opt.c'; else $(CYGPATH_W) '$(srcdir)/agent-opt.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-agent-opt.Tpo $(DEPDIR)/libcommonpth_a-agent-opt.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='agent-opt.c' object='libcommonpth_a-agent-opt.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-agent-opt.obj `if test -f 'agent-opt.c'; then $(CYGPATH_W) 'agent-opt.c'; else $(CYGPATH_W) '$(srcdir)/agent-opt.c'; fi`
+
+libcommonpth_a-helpfile.o: helpfile.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-helpfile.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-helpfile.Tpo -c -o libcommonpth_a-helpfile.o `test -f 'helpfile.c' || echo '$(srcdir)/'`helpfile.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-helpfile.Tpo $(DEPDIR)/libcommonpth_a-helpfile.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='helpfile.c' object='libcommonpth_a-helpfile.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-helpfile.o `test -f 'helpfile.c' || echo '$(srcdir)/'`helpfile.c
+
+libcommonpth_a-helpfile.obj: helpfile.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-helpfile.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-helpfile.Tpo -c -o libcommonpth_a-helpfile.obj `if test -f 'helpfile.c'; then $(CYGPATH_W) 'helpfile.c'; else $(CYGPATH_W) '$(srcdir)/helpfile.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-helpfile.Tpo $(DEPDIR)/libcommonpth_a-helpfile.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='helpfile.c' object='libcommonpth_a-helpfile.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-helpfile.obj `if test -f 'helpfile.c'; then $(CYGPATH_W) 'helpfile.c'; else $(CYGPATH_W) '$(srcdir)/helpfile.c'; fi`
+
+libcommonpth_a-mkdir_p.o: mkdir_p.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-mkdir_p.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-mkdir_p.Tpo -c -o libcommonpth_a-mkdir_p.o `test -f 'mkdir_p.c' || echo '$(srcdir)/'`mkdir_p.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-mkdir_p.Tpo $(DEPDIR)/libcommonpth_a-mkdir_p.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mkdir_p.c' object='libcommonpth_a-mkdir_p.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-mkdir_p.o `test -f 'mkdir_p.c' || echo '$(srcdir)/'`mkdir_p.c
+
+libcommonpth_a-mkdir_p.obj: mkdir_p.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-mkdir_p.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-mkdir_p.Tpo -c -o libcommonpth_a-mkdir_p.obj `if test -f 'mkdir_p.c'; then $(CYGPATH_W) 'mkdir_p.c'; else $(CYGPATH_W) '$(srcdir)/mkdir_p.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-mkdir_p.Tpo $(DEPDIR)/libcommonpth_a-mkdir_p.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mkdir_p.c' object='libcommonpth_a-mkdir_p.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-mkdir_p.obj `if test -f 'mkdir_p.c'; then $(CYGPATH_W) 'mkdir_p.c'; else $(CYGPATH_W) '$(srcdir)/mkdir_p.c'; fi`
+
+libcommonpth_a-exectool.o: exectool.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-exectool.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-exectool.Tpo -c -o libcommonpth_a-exectool.o `test -f 'exectool.c' || echo '$(srcdir)/'`exectool.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-exectool.Tpo $(DEPDIR)/libcommonpth_a-exectool.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='exectool.c' object='libcommonpth_a-exectool.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-exectool.o `test -f 'exectool.c' || echo '$(srcdir)/'`exectool.c
+
+libcommonpth_a-exectool.obj: exectool.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-exectool.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-exectool.Tpo -c -o libcommonpth_a-exectool.obj `if test -f 'exectool.c'; then $(CYGPATH_W) 'exectool.c'; else $(CYGPATH_W) '$(srcdir)/exectool.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-exectool.Tpo $(DEPDIR)/libcommonpth_a-exectool.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='exectool.c' object='libcommonpth_a-exectool.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-exectool.obj `if test -f 'exectool.c'; then $(CYGPATH_W) 'exectool.c'; else $(CYGPATH_W) '$(srcdir)/exectool.c'; fi`
+
+libcommonpth_a-server-help.o: server-help.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-server-help.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-server-help.Tpo -c -o libcommonpth_a-server-help.o `test -f 'server-help.c' || echo '$(srcdir)/'`server-help.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-server-help.Tpo $(DEPDIR)/libcommonpth_a-server-help.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='server-help.c' object='libcommonpth_a-server-help.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-server-help.o `test -f 'server-help.c' || echo '$(srcdir)/'`server-help.c
+
+libcommonpth_a-server-help.obj: server-help.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-server-help.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-server-help.Tpo -c -o libcommonpth_a-server-help.obj `if test -f 'server-help.c'; then $(CYGPATH_W) 'server-help.c'; else $(CYGPATH_W) '$(srcdir)/server-help.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-server-help.Tpo $(DEPDIR)/libcommonpth_a-server-help.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='server-help.c' object='libcommonpth_a-server-help.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-server-help.obj `if test -f 'server-help.c'; then $(CYGPATH_W) 'server-help.c'; else $(CYGPATH_W) '$(srcdir)/server-help.c'; fi`
+
+libcommonpth_a-name-value.o: name-value.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-name-value.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-name-value.Tpo -c -o libcommonpth_a-name-value.o `test -f 'name-value.c' || echo '$(srcdir)/'`name-value.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-name-value.Tpo $(DEPDIR)/libcommonpth_a-name-value.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='name-value.c' object='libcommonpth_a-name-value.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-name-value.o `test -f 'name-value.c' || echo '$(srcdir)/'`name-value.c
+
+libcommonpth_a-name-value.obj: name-value.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-name-value.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-name-value.Tpo -c -o libcommonpth_a-name-value.obj `if test -f 'name-value.c'; then $(CYGPATH_W) 'name-value.c'; else $(CYGPATH_W) '$(srcdir)/name-value.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-name-value.Tpo $(DEPDIR)/libcommonpth_a-name-value.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='name-value.c' object='libcommonpth_a-name-value.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-name-value.obj `if test -f 'name-value.c'; then $(CYGPATH_W) 'name-value.c'; else $(CYGPATH_W) '$(srcdir)/name-value.c'; fi`
+
+libcommonpth_a-recsel.o: recsel.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-recsel.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-recsel.Tpo -c -o libcommonpth_a-recsel.o `test -f 'recsel.c' || echo '$(srcdir)/'`recsel.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-recsel.Tpo $(DEPDIR)/libcommonpth_a-recsel.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='recsel.c' object='libcommonpth_a-recsel.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-recsel.o `test -f 'recsel.c' || echo '$(srcdir)/'`recsel.c
+
+libcommonpth_a-recsel.obj: recsel.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-recsel.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-recsel.Tpo -c -o libcommonpth_a-recsel.obj `if test -f 'recsel.c'; then $(CYGPATH_W) 'recsel.c'; else $(CYGPATH_W) '$(srcdir)/recsel.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-recsel.Tpo $(DEPDIR)/libcommonpth_a-recsel.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='recsel.c' object='libcommonpth_a-recsel.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-recsel.obj `if test -f 'recsel.c'; then $(CYGPATH_W) 'recsel.c'; else $(CYGPATH_W) '$(srcdir)/recsel.c'; fi`
+
+libcommonpth_a-ksba-io-support.o: ksba-io-support.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-ksba-io-support.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-ksba-io-support.Tpo -c -o libcommonpth_a-ksba-io-support.o `test -f 'ksba-io-support.c' || echo '$(srcdir)/'`ksba-io-support.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-ksba-io-support.Tpo $(DEPDIR)/libcommonpth_a-ksba-io-support.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ksba-io-support.c' object='libcommonpth_a-ksba-io-support.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-ksba-io-support.o `test -f 'ksba-io-support.c' || echo '$(srcdir)/'`ksba-io-support.c
+
+libcommonpth_a-ksba-io-support.obj: ksba-io-support.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-ksba-io-support.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-ksba-io-support.Tpo -c -o libcommonpth_a-ksba-io-support.obj `if test -f 'ksba-io-support.c'; then $(CYGPATH_W) 'ksba-io-support.c'; else $(CYGPATH_W) '$(srcdir)/ksba-io-support.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-ksba-io-support.Tpo $(DEPDIR)/libcommonpth_a-ksba-io-support.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ksba-io-support.c' object='libcommonpth_a-ksba-io-support.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-ksba-io-support.obj `if test -f 'ksba-io-support.c'; then $(CYGPATH_W) 'ksba-io-support.c'; else $(CYGPATH_W) '$(srcdir)/ksba-io-support.c'; fi`
+
+libcommonpth_a-openpgp-fpr.o: openpgp-fpr.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-openpgp-fpr.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-openpgp-fpr.Tpo -c -o libcommonpth_a-openpgp-fpr.o `test -f 'openpgp-fpr.c' || echo '$(srcdir)/'`openpgp-fpr.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-openpgp-fpr.Tpo $(DEPDIR)/libcommonpth_a-openpgp-fpr.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='openpgp-fpr.c' object='libcommonpth_a-openpgp-fpr.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-openpgp-fpr.o `test -f 'openpgp-fpr.c' || echo '$(srcdir)/'`openpgp-fpr.c
+
+libcommonpth_a-openpgp-fpr.obj: openpgp-fpr.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-openpgp-fpr.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-openpgp-fpr.Tpo -c -o libcommonpth_a-openpgp-fpr.obj `if test -f 'openpgp-fpr.c'; then $(CYGPATH_W) 'openpgp-fpr.c'; else $(CYGPATH_W) '$(srcdir)/openpgp-fpr.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-openpgp-fpr.Tpo $(DEPDIR)/libcommonpth_a-openpgp-fpr.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='openpgp-fpr.c' object='libcommonpth_a-openpgp-fpr.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-openpgp-fpr.obj `if test -f 'openpgp-fpr.c'; then $(CYGPATH_W) 'openpgp-fpr.c'; else $(CYGPATH_W) '$(srcdir)/openpgp-fpr.c'; fi`
+
+libcommonpth_a-compliance.o: compliance.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-compliance.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-compliance.Tpo -c -o libcommonpth_a-compliance.o `test -f 'compliance.c' || echo '$(srcdir)/'`compliance.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-compliance.Tpo $(DEPDIR)/libcommonpth_a-compliance.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='compliance.c' object='libcommonpth_a-compliance.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-compliance.o `test -f 'compliance.c' || echo '$(srcdir)/'`compliance.c
+
+libcommonpth_a-compliance.obj: compliance.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-compliance.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-compliance.Tpo -c -o libcommonpth_a-compliance.obj `if test -f 'compliance.c'; then $(CYGPATH_W) 'compliance.c'; else $(CYGPATH_W) '$(srcdir)/compliance.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-compliance.Tpo $(DEPDIR)/libcommonpth_a-compliance.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='compliance.c' object='libcommonpth_a-compliance.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-compliance.obj `if test -f 'compliance.c'; then $(CYGPATH_W) 'compliance.c'; else $(CYGPATH_W) '$(srcdir)/compliance.c'; fi`
+
+libcommonpth_a-w32-reg.o: w32-reg.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-w32-reg.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-w32-reg.Tpo -c -o libcommonpth_a-w32-reg.o `test -f 'w32-reg.c' || echo '$(srcdir)/'`w32-reg.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-w32-reg.Tpo $(DEPDIR)/libcommonpth_a-w32-reg.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='w32-reg.c' object='libcommonpth_a-w32-reg.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-w32-reg.o `test -f 'w32-reg.c' || echo '$(srcdir)/'`w32-reg.c
+
+libcommonpth_a-w32-reg.obj: w32-reg.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-w32-reg.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-w32-reg.Tpo -c -o libcommonpth_a-w32-reg.obj `if test -f 'w32-reg.c'; then $(CYGPATH_W) 'w32-reg.c'; else $(CYGPATH_W) '$(srcdir)/w32-reg.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-w32-reg.Tpo $(DEPDIR)/libcommonpth_a-w32-reg.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='w32-reg.c' object='libcommonpth_a-w32-reg.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-w32-reg.obj `if test -f 'w32-reg.c'; then $(CYGPATH_W) 'w32-reg.c'; else $(CYGPATH_W) '$(srcdir)/w32-reg.c'; fi`
+
+libcommonpth_a-w32-cmdline.o: w32-cmdline.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-w32-cmdline.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-w32-cmdline.Tpo -c -o libcommonpth_a-w32-cmdline.o `test -f 'w32-cmdline.c' || echo '$(srcdir)/'`w32-cmdline.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-w32-cmdline.Tpo $(DEPDIR)/libcommonpth_a-w32-cmdline.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='w32-cmdline.c' object='libcommonpth_a-w32-cmdline.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-w32-cmdline.o `test -f 'w32-cmdline.c' || echo '$(srcdir)/'`w32-cmdline.c
+
+libcommonpth_a-w32-cmdline.obj: w32-cmdline.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-w32-cmdline.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-w32-cmdline.Tpo -c -o libcommonpth_a-w32-cmdline.obj `if test -f 'w32-cmdline.c'; then $(CYGPATH_W) 'w32-cmdline.c'; else $(CYGPATH_W) '$(srcdir)/w32-cmdline.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-w32-cmdline.Tpo $(DEPDIR)/libcommonpth_a-w32-cmdline.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='w32-cmdline.c' object='libcommonpth_a-w32-cmdline.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-w32-cmdline.obj `if test -f 'w32-cmdline.c'; then $(CYGPATH_W) 'w32-cmdline.c'; else $(CYGPATH_W) '$(srcdir)/w32-cmdline.c'; fi`
+
+libcommonpth_a-exechelp-w32ce.o: exechelp-w32ce.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-exechelp-w32ce.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-exechelp-w32ce.Tpo -c -o libcommonpth_a-exechelp-w32ce.o `test -f 'exechelp-w32ce.c' || echo '$(srcdir)/'`exechelp-w32ce.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-exechelp-w32ce.Tpo $(DEPDIR)/libcommonpth_a-exechelp-w32ce.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='exechelp-w32ce.c' object='libcommonpth_a-exechelp-w32ce.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-exechelp-w32ce.o `test -f 'exechelp-w32ce.c' || echo '$(srcdir)/'`exechelp-w32ce.c
+
+libcommonpth_a-exechelp-w32ce.obj: exechelp-w32ce.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-exechelp-w32ce.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-exechelp-w32ce.Tpo -c -o libcommonpth_a-exechelp-w32ce.obj `if test -f 'exechelp-w32ce.c'; then $(CYGPATH_W) 'exechelp-w32ce.c'; else $(CYGPATH_W) '$(srcdir)/exechelp-w32ce.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-exechelp-w32ce.Tpo $(DEPDIR)/libcommonpth_a-exechelp-w32ce.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='exechelp-w32ce.c' object='libcommonpth_a-exechelp-w32ce.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-exechelp-w32ce.obj `if test -f 'exechelp-w32ce.c'; then $(CYGPATH_W) 'exechelp-w32ce.c'; else $(CYGPATH_W) '$(srcdir)/exechelp-w32ce.c'; fi`
+
+libcommonpth_a-exechelp-w32.o: exechelp-w32.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-exechelp-w32.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-exechelp-w32.Tpo -c -o libcommonpth_a-exechelp-w32.o `test -f 'exechelp-w32.c' || echo '$(srcdir)/'`exechelp-w32.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-exechelp-w32.Tpo $(DEPDIR)/libcommonpth_a-exechelp-w32.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='exechelp-w32.c' object='libcommonpth_a-exechelp-w32.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-exechelp-w32.o `test -f 'exechelp-w32.c' || echo '$(srcdir)/'`exechelp-w32.c
+
+libcommonpth_a-exechelp-w32.obj: exechelp-w32.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-exechelp-w32.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-exechelp-w32.Tpo -c -o libcommonpth_a-exechelp-w32.obj `if test -f 'exechelp-w32.c'; then $(CYGPATH_W) 'exechelp-w32.c'; else $(CYGPATH_W) '$(srcdir)/exechelp-w32.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-exechelp-w32.Tpo $(DEPDIR)/libcommonpth_a-exechelp-w32.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='exechelp-w32.c' object='libcommonpth_a-exechelp-w32.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-exechelp-w32.obj `if test -f 'exechelp-w32.c'; then $(CYGPATH_W) 'exechelp-w32.c'; else $(CYGPATH_W) '$(srcdir)/exechelp-w32.c'; fi`
+
+libcommonpth_a-exechelp-posix.o: exechelp-posix.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-exechelp-posix.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-exechelp-posix.Tpo -c -o libcommonpth_a-exechelp-posix.o `test -f 'exechelp-posix.c' || echo '$(srcdir)/'`exechelp-posix.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-exechelp-posix.Tpo $(DEPDIR)/libcommonpth_a-exechelp-posix.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='exechelp-posix.c' object='libcommonpth_a-exechelp-posix.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-exechelp-posix.o `test -f 'exechelp-posix.c' || echo '$(srcdir)/'`exechelp-posix.c
+
+libcommonpth_a-exechelp-posix.obj: exechelp-posix.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-exechelp-posix.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-exechelp-posix.Tpo -c -o libcommonpth_a-exechelp-posix.obj `if test -f 'exechelp-posix.c'; then $(CYGPATH_W) 'exechelp-posix.c'; else $(CYGPATH_W) '$(srcdir)/exechelp-posix.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-exechelp-posix.Tpo $(DEPDIR)/libcommonpth_a-exechelp-posix.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='exechelp-posix.c' object='libcommonpth_a-exechelp-posix.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-exechelp-posix.obj `if test -f 'exechelp-posix.c'; then $(CYGPATH_W) 'exechelp-posix.c'; else $(CYGPATH_W) '$(srcdir)/exechelp-posix.c'; fi`
+
+libcommonpth_a-call-gpg.o: call-gpg.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-call-gpg.o -MD -MP -MF $(DEPDIR)/libcommonpth_a-call-gpg.Tpo -c -o libcommonpth_a-call-gpg.o `test -f 'call-gpg.c' || echo '$(srcdir)/'`call-gpg.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-call-gpg.Tpo $(DEPDIR)/libcommonpth_a-call-gpg.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='call-gpg.c' object='libcommonpth_a-call-gpg.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-call-gpg.o `test -f 'call-gpg.c' || echo '$(srcdir)/'`call-gpg.c
+
+libcommonpth_a-call-gpg.obj: call-gpg.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -MT libcommonpth_a-call-gpg.obj -MD -MP -MF $(DEPDIR)/libcommonpth_a-call-gpg.Tpo -c -o libcommonpth_a-call-gpg.obj `if test -f 'call-gpg.c'; then $(CYGPATH_W) 'call-gpg.c'; else $(CYGPATH_W) '$(srcdir)/call-gpg.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonpth_a-call-gpg.Tpo $(DEPDIR)/libcommonpth_a-call-gpg.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='call-gpg.c' object='libcommonpth_a-call-gpg.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonpth_a_CFLAGS) $(CFLAGS) -c -o libcommonpth_a-call-gpg.obj `if test -f 'call-gpg.c'; then $(CYGPATH_W) 'call-gpg.c'; else $(CYGPATH_W) '$(srcdir)/call-gpg.c'; fi`
+
+libsimple_pwquery_a-simple-pwquery.o: simple-pwquery.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsimple_pwquery_a_CFLAGS) $(CFLAGS) -MT libsimple_pwquery_a-simple-pwquery.o -MD -MP -MF $(DEPDIR)/libsimple_pwquery_a-simple-pwquery.Tpo -c -o libsimple_pwquery_a-simple-pwquery.o `test -f 'simple-pwquery.c' || echo '$(srcdir)/'`simple-pwquery.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsimple_pwquery_a-simple-pwquery.Tpo $(DEPDIR)/libsimple_pwquery_a-simple-pwquery.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='simple-pwquery.c' object='libsimple_pwquery_a-simple-pwquery.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsimple_pwquery_a_CFLAGS) $(CFLAGS) -c -o libsimple_pwquery_a-simple-pwquery.o `test -f 'simple-pwquery.c' || echo '$(srcdir)/'`simple-pwquery.c
+
+libsimple_pwquery_a-simple-pwquery.obj: simple-pwquery.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsimple_pwquery_a_CFLAGS) $(CFLAGS) -MT libsimple_pwquery_a-simple-pwquery.obj -MD -MP -MF $(DEPDIR)/libsimple_pwquery_a-simple-pwquery.Tpo -c -o libsimple_pwquery_a-simple-pwquery.obj `if test -f 'simple-pwquery.c'; then $(CYGPATH_W) 'simple-pwquery.c'; else $(CYGPATH_W) '$(srcdir)/simple-pwquery.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsimple_pwquery_a-simple-pwquery.Tpo $(DEPDIR)/libsimple_pwquery_a-simple-pwquery.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='simple-pwquery.c' object='libsimple_pwquery_a-simple-pwquery.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsimple_pwquery_a_CFLAGS) $(CFLAGS) -c -o libsimple_pwquery_a-simple-pwquery.obj `if test -f 'simple-pwquery.c'; then $(CYGPATH_W) 'simple-pwquery.c'; else $(CYGPATH_W) '$(srcdir)/simple-pwquery.c'; fi`
+
+libsimple_pwquery_a-asshelp.o: asshelp.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsimple_pwquery_a_CFLAGS) $(CFLAGS) -MT libsimple_pwquery_a-asshelp.o -MD -MP -MF $(DEPDIR)/libsimple_pwquery_a-asshelp.Tpo -c -o libsimple_pwquery_a-asshelp.o `test -f 'asshelp.c' || echo '$(srcdir)/'`asshelp.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsimple_pwquery_a-asshelp.Tpo $(DEPDIR)/libsimple_pwquery_a-asshelp.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='asshelp.c' object='libsimple_pwquery_a-asshelp.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsimple_pwquery_a_CFLAGS) $(CFLAGS) -c -o libsimple_pwquery_a-asshelp.o `test -f 'asshelp.c' || echo '$(srcdir)/'`asshelp.c
+
+libsimple_pwquery_a-asshelp.obj: asshelp.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsimple_pwquery_a_CFLAGS) $(CFLAGS) -MT libsimple_pwquery_a-asshelp.obj -MD -MP -MF $(DEPDIR)/libsimple_pwquery_a-asshelp.Tpo -c -o libsimple_pwquery_a-asshelp.obj `if test -f 'asshelp.c'; then $(CYGPATH_W) 'asshelp.c'; else $(CYGPATH_W) '$(srcdir)/asshelp.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsimple_pwquery_a-asshelp.Tpo $(DEPDIR)/libsimple_pwquery_a-asshelp.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='asshelp.c' object='libsimple_pwquery_a-asshelp.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsimple_pwquery_a_CFLAGS) $(CFLAGS) -c -o libsimple_pwquery_a-asshelp.obj `if test -f 'asshelp.c'; then $(CYGPATH_W) 'asshelp.c'; else $(CYGPATH_W) '$(srcdir)/asshelp.c'; fi`
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+check-TESTS: $(TESTS)
+ @failed=0; all=0; xfail=0; xpass=0; skip=0; \
+ srcdir=$(srcdir); export srcdir; \
+ list=' $(TESTS) '; \
+ $(am__tty_colors); \
+ if test -n "$$list"; then \
+ for tst in $$list; do \
+ if test -f ./$$tst; then dir=./; \
+ elif test -f $$tst; then dir=; \
+ else dir="$(srcdir)/"; fi; \
+ if $(TESTS_ENVIRONMENT) $${dir}$$tst $(AM_TESTS_FD_REDIRECT); then \
+ all=`expr $$all + 1`; \
+ case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$tst[\ \ ]*) \
+ xpass=`expr $$xpass + 1`; \
+ failed=`expr $$failed + 1`; \
+ col=$$red; res=XPASS; \
+ ;; \
+ *) \
+ col=$$grn; res=PASS; \
+ ;; \
+ esac; \
+ elif test $$? -ne 77; then \
+ all=`expr $$all + 1`; \
+ case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$tst[\ \ ]*) \
+ xfail=`expr $$xfail + 1`; \
+ col=$$lgn; res=XFAIL; \
+ ;; \
+ *) \
+ failed=`expr $$failed + 1`; \
+ col=$$red; res=FAIL; \
+ ;; \
+ esac; \
+ else \
+ skip=`expr $$skip + 1`; \
+ col=$$blu; res=SKIP; \
+ fi; \
+ echo "$${col}$$res$${std}: $$tst"; \
+ done; \
+ if test "$$all" -eq 1; then \
+ tests="test"; \
+ All=""; \
+ else \
+ tests="tests"; \
+ All="All "; \
+ fi; \
+ if test "$$failed" -eq 0; then \
+ if test "$$xfail" -eq 0; then \
+ banner="$$All$$all $$tests passed"; \
+ else \
+ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \
+ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \
+ fi; \
+ else \
+ if test "$$xpass" -eq 0; then \
+ banner="$$failed of $$all $$tests failed"; \
+ else \
+ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \
+ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \
+ fi; \
+ fi; \
+ dashes="$$banner"; \
+ skipped=""; \
+ if test "$$skip" -ne 0; then \
+ if test "$$skip" -eq 1; then \
+ skipped="($$skip test was not run)"; \
+ else \
+ skipped="($$skip tests were not run)"; \
+ fi; \
+ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
+ dashes="$$skipped"; \
+ fi; \
+ report=""; \
+ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
+ report="Please report to $(PACKAGE_BUGREPORT)"; \
+ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
+ dashes="$$report"; \
+ fi; \
+ dashes=`echo "$$dashes" | sed s/./=/g`; \
+ if test "$$failed" -eq 0; then \
+ col="$$grn"; \
+ else \
+ col="$$red"; \
+ fi; \
+ echo "$${col}$$dashes$${std}"; \
+ echo "$${col}$$banner$${std}"; \
+ test -z "$$skipped" || echo "$${col}$$skipped$${std}"; \
+ test -z "$$report" || echo "$${col}$$report$${std}"; \
+ echo "$${col}$$dashes$${std}"; \
+ test "$$failed" -eq 0; \
+ else :; fi
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(PROGRAMS) $(LIBRARIES)
+installdirs:
+install: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-generic clean-noinstLIBRARIES clean-noinstPROGRAMS \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/gpgrlhelp.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-agent-opt.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-argparse.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-asshelp.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-asshelp2.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-audit.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-b64dec.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-b64enc.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-ccparray.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-compliance.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-convert.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-dotlock.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-exechelp-posix.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-exechelp-w32.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-exechelp-w32ce.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-exectool.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-get-passphrase.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-gettime.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-helpfile.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-homedir.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-i18n.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-init.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-iobuf.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-ksba-io-support.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-localename.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-logging.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-mapstrings.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-mbox-util.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-membuf.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-miscellaneous.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-mischelp.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-mkdir_p.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-name-value.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-openpgp-fpr.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-openpgp-oid.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-percent.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-recsel.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-server-help.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-session-env.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-sexputil.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-signal.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-ssh-utils.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-status.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-stringhelp.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-strlist.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-sysutils.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-tlv-builder.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-tlv.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-ttyio.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-userids.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-utf8conv.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-w32-cmdline.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-w32-reg.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-xasprintf.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-xreadline.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-yesno.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-zb32.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-agent-opt.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-argparse.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-asshelp.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-asshelp2.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-audit.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-b64dec.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-b64enc.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-call-gpg.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-ccparray.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-compliance.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-convert.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-dotlock.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-exechelp-posix.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-exechelp-w32.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-exechelp-w32ce.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-exectool.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-gettime.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-helpfile.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-homedir.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-i18n.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-init.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-iobuf.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-ksba-io-support.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-localename.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-logging.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-mapstrings.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-mbox-util.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-membuf.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-miscellaneous.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-mischelp.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-mkdir_p.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-name-value.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-openpgp-fpr.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-openpgp-oid.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-percent.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-recsel.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-server-help.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-session-env.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-sexputil.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-signal.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-ssh-utils.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-status.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-stringhelp.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-strlist.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-sysutils.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-tlv-builder.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-tlv.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-ttyio.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-userids.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-utf8conv.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-w32-cmdline.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-w32-reg.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-xasprintf.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-xreadline.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-yesno.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-zb32.Po
+ -rm -f ./$(DEPDIR)/libsimple_pwquery_a-asshelp.Po
+ -rm -f ./$(DEPDIR)/libsimple_pwquery_a-simple-pwquery.Po
+ -rm -f ./$(DEPDIR)/t-b64.Po
+ -rm -f ./$(DEPDIR)/t-ccparray.Po
+ -rm -f ./$(DEPDIR)/t-convert.Po
+ -rm -f ./$(DEPDIR)/t-exechelp.Po
+ -rm -f ./$(DEPDIR)/t-exectool.Po
+ -rm -f ./$(DEPDIR)/t-gettime.Po
+ -rm -f ./$(DEPDIR)/t-helpfile.Po
+ -rm -f ./$(DEPDIR)/t-iobuf.Po
+ -rm -f ./$(DEPDIR)/t-mapstrings.Po
+ -rm -f ./$(DEPDIR)/t-mbox-util.Po
+ -rm -f ./$(DEPDIR)/t-name-value.Po
+ -rm -f ./$(DEPDIR)/t-openpgp-oid.Po
+ -rm -f ./$(DEPDIR)/t-percent.Po
+ -rm -f ./$(DEPDIR)/t-recsel.Po
+ -rm -f ./$(DEPDIR)/t-session-env.Po
+ -rm -f ./$(DEPDIR)/t-sexputil.Po
+ -rm -f ./$(DEPDIR)/t-ssh-utils.Po
+ -rm -f ./$(DEPDIR)/t-stringhelp.Po
+ -rm -f ./$(DEPDIR)/t-strlist.Po
+ -rm -f ./$(DEPDIR)/t-sysutils.Po
+ -rm -f ./$(DEPDIR)/t-timestuff.Po
+ -rm -f ./$(DEPDIR)/t-w32-cmdline.Po
+ -rm -f ./$(DEPDIR)/t-w32-reg.Po
+ -rm -f ./$(DEPDIR)/t-zb32.Po
+ -rm -f ./$(DEPDIR)/w32-cmdline.Po
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/gpgrlhelp.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-agent-opt.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-argparse.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-asshelp.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-asshelp2.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-audit.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-b64dec.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-b64enc.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-ccparray.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-compliance.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-convert.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-dotlock.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-exechelp-posix.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-exechelp-w32.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-exechelp-w32ce.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-exectool.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-get-passphrase.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-gettime.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-helpfile.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-homedir.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-i18n.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-init.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-iobuf.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-ksba-io-support.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-localename.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-logging.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-mapstrings.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-mbox-util.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-membuf.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-miscellaneous.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-mischelp.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-mkdir_p.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-name-value.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-openpgp-fpr.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-openpgp-oid.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-percent.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-recsel.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-server-help.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-session-env.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-sexputil.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-signal.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-ssh-utils.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-status.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-stringhelp.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-strlist.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-sysutils.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-tlv-builder.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-tlv.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-ttyio.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-userids.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-utf8conv.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-w32-cmdline.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-w32-reg.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-xasprintf.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-xreadline.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-yesno.Po
+ -rm -f ./$(DEPDIR)/libcommon_a-zb32.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-agent-opt.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-argparse.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-asshelp.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-asshelp2.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-audit.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-b64dec.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-b64enc.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-call-gpg.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-ccparray.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-compliance.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-convert.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-dotlock.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-exechelp-posix.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-exechelp-w32.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-exechelp-w32ce.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-exectool.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-gettime.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-helpfile.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-homedir.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-i18n.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-init.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-iobuf.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-ksba-io-support.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-localename.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-logging.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-mapstrings.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-mbox-util.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-membuf.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-miscellaneous.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-mischelp.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-mkdir_p.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-name-value.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-openpgp-fpr.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-openpgp-oid.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-percent.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-recsel.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-server-help.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-session-env.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-sexputil.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-signal.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-ssh-utils.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-status.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-stringhelp.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-strlist.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-sysutils.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-tlv-builder.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-tlv.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-ttyio.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-userids.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-utf8conv.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-w32-cmdline.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-w32-reg.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-xasprintf.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-xreadline.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-yesno.Po
+ -rm -f ./$(DEPDIR)/libcommonpth_a-zb32.Po
+ -rm -f ./$(DEPDIR)/libsimple_pwquery_a-asshelp.Po
+ -rm -f ./$(DEPDIR)/libsimple_pwquery_a-simple-pwquery.Po
+ -rm -f ./$(DEPDIR)/t-b64.Po
+ -rm -f ./$(DEPDIR)/t-ccparray.Po
+ -rm -f ./$(DEPDIR)/t-convert.Po
+ -rm -f ./$(DEPDIR)/t-exechelp.Po
+ -rm -f ./$(DEPDIR)/t-exectool.Po
+ -rm -f ./$(DEPDIR)/t-gettime.Po
+ -rm -f ./$(DEPDIR)/t-helpfile.Po
+ -rm -f ./$(DEPDIR)/t-iobuf.Po
+ -rm -f ./$(DEPDIR)/t-mapstrings.Po
+ -rm -f ./$(DEPDIR)/t-mbox-util.Po
+ -rm -f ./$(DEPDIR)/t-name-value.Po
+ -rm -f ./$(DEPDIR)/t-openpgp-oid.Po
+ -rm -f ./$(DEPDIR)/t-percent.Po
+ -rm -f ./$(DEPDIR)/t-recsel.Po
+ -rm -f ./$(DEPDIR)/t-session-env.Po
+ -rm -f ./$(DEPDIR)/t-sexputil.Po
+ -rm -f ./$(DEPDIR)/t-ssh-utils.Po
+ -rm -f ./$(DEPDIR)/t-stringhelp.Po
+ -rm -f ./$(DEPDIR)/t-strlist.Po
+ -rm -f ./$(DEPDIR)/t-sysutils.Po
+ -rm -f ./$(DEPDIR)/t-timestuff.Po
+ -rm -f ./$(DEPDIR)/t-w32-cmdline.Po
+ -rm -f ./$(DEPDIR)/t-w32-reg.Po
+ -rm -f ./$(DEPDIR)/t-zb32.Po
+ -rm -f ./$(DEPDIR)/w32-cmdline.Po
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: all check check-am install install-am install-exec \
+ install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-TESTS \
+ check-am clean clean-generic clean-noinstLIBRARIES \
+ clean-noinstPROGRAMS cscopelist-am ctags ctags-am distclean \
+ distclean-compile distclean-generic distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \
+ uninstall-am
+
+.PRECIOUS: Makefile
+
+
+@HAVE_W32_SYSTEM_TRUE@.rc.o:
+@HAVE_W32_SYSTEM_TRUE@ $(WINDRES) $(DEFAULT_INCLUDES) $(INCLUDES) "$<" "$@"
+
+# Note: Due to the dependency on Makefile, the file will always be
+# rebuilt, so we allow this only in maintainer mode.
+
+# Create the audit-events.h include file from audit.h
+# Note: We create the target file in the source directory because it
+# is a distributed built source. If we would not do that we may end
+# up with two files and then it is not clear which version of the
+# files will be picked up.
+@MAINTAINER_MODE_TRUE@audit-events.h: Makefile.am mkstrtable.awk exaudit.awk audit.h
+@MAINTAINER_MODE_TRUE@ $(AWK) -f $(srcdir)/exaudit.awk $(srcdir)/audit.h \
+@MAINTAINER_MODE_TRUE@ | $(AWK) -f $(srcdir)/mkstrtable.awk -v textidx=3 -v nogettext=1 \
+@MAINTAINER_MODE_TRUE@ -v pkg_namespace=eventstr_ > $(srcdir)/audit-events.h
+
+# Create the status-codes.h include file from status.h
+@MAINTAINER_MODE_TRUE@status-codes.h: Makefile.am mkstrtable.awk exstatus.awk status.h
+@MAINTAINER_MODE_TRUE@ $(AWK) -f $(srcdir)/exstatus.awk $(srcdir)/status.h \
+@MAINTAINER_MODE_TRUE@ | $(AWK) -f $(srcdir)/mkstrtable.awk -v textidx=3 -v nogettext=1 \
+@MAINTAINER_MODE_TRUE@ -v pkg_namespace=statusstr_ > $(srcdir)/status-codes.h
+
+# All programs should depend on the created libs.
+$(PROGRAMS) : libcommon.a libcommonpth.a
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/common/README b/common/README
new file mode 100644
index 0000000..73799a8
--- /dev/null
+++ b/common/README
@@ -0,0 +1 @@
+Common functionality used by all modules of GnuPG.
diff --git a/common/agent-opt.c b/common/agent-opt.c
new file mode 100644
index 0000000..6d9f9e7
--- /dev/null
+++ b/common/agent-opt.c
@@ -0,0 +1,106 @@
+/* agent-opt.c - Helper for certain agent options
+ * Copyright (C) 2013 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "shareddefs.h"
+
+
+/* Parse VALUE and return an integer representing a pinentry_mode_t.
+ (-1) is returned for an invalid VALUE. */
+int
+parse_pinentry_mode (const char *value)
+{
+ int result;
+
+ if (!strcmp (value, "ask") || !strcmp (value, "default"))
+ result = PINENTRY_MODE_ASK;
+ else if (!strcmp (value, "cancel"))
+ result = PINENTRY_MODE_CANCEL;
+ else if (!strcmp (value, "error"))
+ result = PINENTRY_MODE_ERROR;
+ else if (!strcmp (value, "loopback"))
+ result = PINENTRY_MODE_LOOPBACK;
+ else
+ result = -1;
+
+ return result;
+}
+
+/* Return the string representation for the pinentry MODE. Returns
+ "?" for an invalid mode. */
+const char *
+str_pinentry_mode (pinentry_mode_t mode)
+{
+ switch (mode)
+ {
+ case PINENTRY_MODE_ASK: return "ask";
+ case PINENTRY_MODE_CANCEL: return "cancel";
+ case PINENTRY_MODE_ERROR: return "error";
+ case PINENTRY_MODE_LOOPBACK: return "loopback";
+ }
+ return "?";
+}
+
+
+/* Parse VALUE and return an integer representing a request_origin_t.
+ * (-1) is returned for an invalid VALUE. */
+int
+parse_request_origin (const char *value)
+{
+ int result;
+
+ if (!strcmp (value, "none") || !strcmp (value, "local"))
+ result = REQUEST_ORIGIN_LOCAL;
+ else if (!strcmp (value, "remote"))
+ result = REQUEST_ORIGIN_REMOTE;
+ else if (!strcmp (value, "browser"))
+ result = REQUEST_ORIGIN_BROWSER;
+ else
+ result = -1;
+
+ return result;
+}
+
+
+/* Return the string representation for the request origin. Returns
+ * "?" for an invalid mode. */
+const char *
+str_request_origin (request_origin_t mode)
+{
+ switch (mode)
+ {
+ case REQUEST_ORIGIN_LOCAL: return "local";
+ case REQUEST_ORIGIN_REMOTE: return "remote";
+ case REQUEST_ORIGIN_BROWSER: return "browser";
+ }
+ return "?";
+}
diff --git a/common/all-tests.scm b/common/all-tests.scm
new file mode 100644
index 0000000..54f1153
--- /dev/null
+++ b/common/all-tests.scm
@@ -0,0 +1,45 @@
+;; Copyright (C) 2017 g10 Code GmbH
+;;
+;; This file is part of GnuPG.
+;;
+;; GnuPG is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GnuPG is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+(export all-tests
+ ;; XXX: Currently, the makefile parser does not understand this
+ ;; Makefile.am, so we hardcode the list of tests here.
+ (map (lambda (name)
+ (test::binary #f
+ (path-join "common" name)
+ (path-join (getenv "objdir") "common" name)))
+ (list "t-stringhelp"
+ "t-timestuff"
+ "t-convert"
+ "t-percent"
+ "t-gettime"
+ "t-sysutils"
+ "t-sexputil"
+ "t-session-env"
+ "t-openpgp-oid"
+ "t-ssh-utils"
+ "t-mapstrings"
+ "t-zb32"
+ "t-mbox-util"
+ "t-iobuf"
+ "t-strlist"
+ "t-name-value"
+ "t-ccparray"
+ "t-recsel"
+ "t-exechelp"
+ "t-exectool"
+ )))
diff --git a/common/argparse.c b/common/argparse.c
new file mode 100644
index 0000000..b63f800
--- /dev/null
+++ b/common/argparse.c
@@ -0,0 +1,2809 @@
+/* [argparse.c wk 17.06.97] Argument Parser for option handling
+ * Copyright (C) 1998-2001, 2006-2008, 2012 Free Software Foundation, Inc.
+ * Copyright (C) 1997-2001, 2006-2008, 2013-2017 Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute and/or modify this
+ * part of GnuPG under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * 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 copies of the GNU General Public License
+ * and the GNU Lesser General Public License along with this program;
+ * if not, see <https://gnu.org/licenses/>.
+ */
+
+/* This is a modified version of gpgrt/libgpg-error src/argparse.c.
+ * We use this to require a dependency on a newer gpgrt version.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdarg.h>
+#include <limits.h>
+#include <errno.h>
+#include <unistd.h>
+#include <time.h>
+
+#include "util.h"
+#include "common-defs.h"
+#include "i18n.h"
+#include "mischelp.h"
+#include "stringhelp.h"
+#include "logging.h"
+#include "utf8conv.h"
+#include "sysutils.h"
+#include "argparse.h"
+
+
+/* Optional handler to write strings. See gnupg_set_usage_outfnc. */
+static int (*custom_outfnc) (int, const char *);
+
+
+#if USE_INTERNAL_ARGPARSE
+
+/* The almost always needed user handler for strusage. */
+static const char *(*strusage_handler)( int ) = NULL;
+/* Optional handler to map strings. See gnupg_set_fixed_string_mapper. */
+static const char *(*fixed_string_mapper)(const char*);
+
+
+/* Hidden argparse flag used to mark the object as initialized. */
+#define ARGPARSE_FLAG__INITIALIZED (1u << ((8*4)-1))
+
+/* Special short options which are auto-inserterd. Must fit into an
+ * unsigned short. */
+#define ARGPARSE_SHORTOPT_HELP 32768
+#define ARGPARSE_SHORTOPT_VERSION 32769
+#define ARGPARSE_SHORTOPT_WARRANTY 32770
+#define ARGPARSE_SHORTOPT_DUMP_OPTIONS 32771
+#define ARGPARSE_SHORTOPT_DUMP_OPTTBL 32772
+
+
+/* The malloced configuration directories or NULL. */
+static struct
+{
+ char *user;
+ char *sys;
+} confdir;
+
+
+/* The states for the gnupg_argparser machinery. */
+enum argparser_states
+ {
+ STATE_init = 0,
+ STATE_open_sys,
+ STATE_open_user,
+ STATE_open_cmdline,
+ STATE_read_sys,
+ STATE_read_user,
+ STATE_read_cmdline,
+ STATE_finished
+ };
+
+
+/* An internal object used to store the user provided option table and
+ * some meta information. */
+typedef struct
+{
+ unsigned short short_opt;
+ unsigned short ordinal; /* (for --help) */
+ unsigned int flags;
+ const char *long_opt; /* Points into the user provided table. */
+ const char *description; /* Points into the user provided table. */
+ unsigned int forced:1; /* Forced to use the sysconf value. */
+ unsigned int ignore:1; /* Ignore this option everywhere but in
+ * the sysconf file. */
+ unsigned int explicit_ignore:1; /* Ignore was explicitly set. */
+} opttable_t;
+
+
+/* Internal object of the public gnupg_argparse_t object. */
+struct _argparse_internal_s
+{
+ int idx; /* Note that this is saved and restored in gnupg_argparser. */
+ int inarg; /* (index into args) */
+ unsigned int verbose:1; /* Print diagnostics. */
+ unsigned int stopped:1; /* Option processing has stopped. */
+ unsigned int in_sysconf:1; /* Processing global config file. */
+ unsigned int mark_forced:1; /* Mark options as forced. */
+ unsigned int mark_ignore:1; /* Mark options as to be ignored. */
+ unsigned int explicit_ignore:1; /* Option has explicitly been set
+ * to ignore or unignore. */
+ unsigned int ignore_all_seen:1; /* [ignore-all] has been seen. */
+ unsigned int user_seen:1; /* A [user] has been seen. */
+ unsigned int user_wildcard:1; /* A [user *] has been seen. */
+ unsigned int user_any_active:1; /* Any user section was active. */
+ unsigned int user_active:1; /* User section active. */
+ unsigned int explicit_confopt:1; /* A conffile option has been given. */
+ char *explicit_conffile; /* Malloced name of an explicit
+ * conffile. */
+ char *username; /* Malloced current user name. */
+ unsigned int opt_flags; /* Current option flags. */
+ enum argparser_states state; /* State of the gnupg_argparser. */
+ const char *last;
+ void *aliases;
+ const void *cur_alias;
+ void *iio_list;
+ estream_t conffp;
+ char *confname;
+ opttable_t *opts; /* Malloced option table. */
+ unsigned int nopts; /* Number of items in OPTS. */
+};
+
+
+typedef struct alias_def_s *ALIAS_DEF;
+struct alias_def_s {
+ ALIAS_DEF next;
+ char *name; /* malloced buffer with name, \0, value */
+ const char *value; /* ptr into name */
+};
+
+
+/* Object to store the names for the --ignore-invalid-option option.
+ This is a simple linked list. */
+typedef struct iio_item_def_s *IIO_ITEM_DEF;
+struct iio_item_def_s
+{
+ IIO_ITEM_DEF next;
+ char name[1]; /* String with the long option name. */
+};
+
+
+static int set_opt_arg (gnupg_argparse_t *arg, unsigned int flags, char *s);
+static void show_help (opttable_t *opts, unsigned int nopts,unsigned int flags);
+static void show_version (void);
+static void dump_option_table (gnupg_argparse_t *arg);
+static int writestrings (int is_error, const char *string,
+ ...) GPGRT_ATTR_SENTINEL(0);
+
+static int arg_parse (gnupg_argparse_t *arg, gnupg_opt_t *opts, int no_init);
+
+
+
+/* Set a function to write strings which is then used instead of
+ * estream. The first arg of that function is MODE and the second the
+ * STRING to write. A mode of 1 is used for writing to stdout and a
+ * mode of 2 to write to stderr. Other modes are reserved and should
+ * not output anything. A NULL for STRING requests a flush. */
+void
+gnupg_set_usage_outfnc (int (*f)(int, const char *))
+{
+ custom_outfnc = f;
+}
+
+
+/* Register function F as a string mapper which takes a string as
+ * argument, replaces known "@FOO@" style macros and returns a new
+ * fixed string. Warning: The input STRING must have been allocated
+ * statically. */
+void
+gnupg_set_fixed_string_mapper (const char *(*f)(const char*))
+{
+ fixed_string_mapper = f;
+}
+
+
+/* Register a configuration directory for use by the argparse
+ * functions. The defined values for WHAT are:
+ *
+ * GNUPG_CONFDIR_SYS The systems's configuration dir.
+ * The default is /etc
+ *
+ * GNUPG_CONFDIR_USER The user's configuration directory.
+ * The default is $HOME.
+ *
+ * A trailing slash is ignored; to have the function lookup
+ * configuration files in the current directory, use ".". There is no
+ * error return; more configuraion values may be added in future
+ * revisions of this library.
+ */
+void
+gnupg_set_confdir (int what, const char *name)
+{
+ char *buf, *p;
+
+ if (what == GNUPG_CONFDIR_SYS)
+ {
+ xfree (confdir.sys);
+ buf = confdir.sys = xtrystrdup (name);
+ }
+ else if (what == GNUPG_CONFDIR_USER)
+ {
+ xfree (confdir.user);
+ buf = confdir.user = xtrystrdup (name);
+ }
+ else
+ return;
+
+ if (!buf)
+ log_fatal ("out of core in %s\n", __func__);
+#ifdef HAVE_W32_SYSTEM
+ for (p=buf; *p; p++)
+ if (*p == '\\')
+ *p = '/';
+#endif
+ /* Strip trailing slashes unless buf is "/" or any other single char
+ * string. */
+ if (*buf)
+ {
+ for (p=buf + strlen (buf)-1; p > buf; p--)
+ if (*p == '/')
+ *p = 0;
+ else
+ break;
+ }
+}
+
+
+
+static const char *
+map_fixed_string (const char *string)
+{
+ return fixed_string_mapper? fixed_string_mapper (string) : string;
+}
+
+#endif /* USE_INTERNAL_ARGPARSE */
+
+
+/* Write STRING and all following const char * arguments either to
+ stdout or, if IS_ERROR is set, to stderr. The list of strings must
+ be terminated by a NULL. */
+static int
+writestrings (int is_error, const char *string, ...)
+{
+ va_list arg_ptr;
+ const char *s;
+ int count = 0;
+
+ if (string)
+ {
+ s = string;
+ va_start (arg_ptr, string);
+ do
+ { /* Fixme: Swicth to estream? */
+ if (custom_outfnc)
+ custom_outfnc (is_error? 2:1, s);
+ else
+ fputs (s, is_error? stderr : stdout);
+ count += strlen (s);
+ }
+ while ((s = va_arg (arg_ptr, const char *)));
+ va_end (arg_ptr);
+ }
+ return count;
+}
+
+
+static void
+flushstrings (int is_error)
+{
+ if (custom_outfnc)
+ custom_outfnc (is_error? 2:1, NULL);
+ else
+ fflush (is_error? stderr : stdout);
+}
+
+
+#if USE_INTERNAL_ARGPARSE
+
+static void
+deinitialize (gnupg_argparse_t *arg)
+{
+ if (arg->internal)
+ {
+ xfree (arg->internal->username);
+ xfree (arg->internal->explicit_conffile);
+ xfree (arg->internal->opts);
+ xfree (arg->internal);
+ arg->internal = NULL;
+ }
+
+ arg->flags &= ARGPARSE_FLAG__INITIALIZED;
+ arg->lineno = 0;
+ arg->err = 0;
+}
+
+/* Our own exit handler to clean up used memory. */
+static void
+my_exit (gnupg_argparse_t *arg, int code)
+{
+ deinitialize (arg);
+ exit (code);
+}
+
+
+static gpg_err_code_t
+initialize (gnupg_argparse_t *arg, gnupg_opt_t *opts, estream_t fp)
+{
+ /* We use a dedicated flag to detect whether *ARG has been
+ * initialized. This is because the old version of that struct, as
+ * used in GnuPG, had no requirement to zero out all fields of the
+ * object and existing code still sets only argc,argv and flags. */
+ if (!(arg->flags & ARGPARSE_FLAG__INITIALIZED)
+ || (arg->flags & ARGPARSE_FLAG_RESET)
+ || !arg->internal)
+ {
+ /* Allocate internal data. */
+ if (!(arg->flags & ARGPARSE_FLAG__INITIALIZED) || !arg->internal)
+ {
+ arg->internal = xtrymalloc (sizeof *arg->internal);
+ if (!arg->internal)
+ return gpg_err_code_from_syserror ();
+ arg->flags |= ARGPARSE_FLAG__INITIALIZED; /* Mark as initialized. */
+ }
+ else if (arg->internal->opts)
+ xfree (arg->internal->opts);
+ arg->internal->opts = NULL;
+ arg->internal->nopts = 0;
+
+ /* Initialize this instance. */
+ arg->internal->idx = 0;
+ arg->internal->last = NULL;
+ arg->internal->inarg = 0;
+ arg->internal->stopped = 0;
+ arg->internal->in_sysconf = 0;
+ arg->internal->user_seen = 0;
+ arg->internal->user_wildcard = 0;
+ arg->internal->user_any_active = 0;
+ arg->internal->user_active = 0;
+ arg->internal->username = NULL;
+ arg->internal->mark_forced = 0;
+ arg->internal->mark_ignore = 0;
+ arg->internal->explicit_ignore = 0;
+ arg->internal->ignore_all_seen = 0;
+ arg->internal->explicit_confopt = 0;
+ arg->internal->explicit_conffile = NULL;
+ arg->internal->opt_flags = 0;
+ arg->internal->state = STATE_init;
+ arg->internal->aliases = NULL;
+ arg->internal->cur_alias = NULL;
+ arg->internal->iio_list = NULL;
+ arg->internal->conffp = NULL;
+ arg->internal->confname = NULL;
+
+ /* Clear the copy of the option list. */
+ /* Clear the error indicator. */
+ arg->err = 0;
+
+ /* Usually an option file will be parsed from the start.
+ * However, we do not open the stream and thus we have no way to
+ * know the current lineno. Using this flag we can allow the
+ * user to provide a lineno which we don't reset. */
+ if (fp || arg->internal->conffp || !(arg->flags & ARGPARSE_FLAG_NOLINENO))
+ arg->lineno = 0;
+
+ /* Need to clear the reset request. */
+ arg->flags &= ~ARGPARSE_FLAG_RESET;
+
+ /* Check initial args. */
+ if ( *arg->argc < 0 )
+ log_bug ("invalid argument passed to gnupg_argparse\n");
+
+ }
+
+ /* Create an array with pointers to the provided list of options.
+ * Keeping a copy is useful to sort that array and thus do a binary
+ * search and to allow for extra space at the end to insert the
+ * hidden options. An ARGPARSE_FLAG_RESET can be used to reinit
+ * this array. */
+ if (!arg->internal->opts)
+ {
+ int seen_help = 0;
+ int seen_version = 0;
+ int seen_warranty = 0;
+ int seen_dump_options = 0;
+ int seen_dump_option_table = 0;
+ int i;
+
+ for (i=0; opts[i].short_opt; i++)
+ {
+ if (opts[i].long_opt)
+ {
+ if (!strcmp(opts[i].long_opt, "help"))
+ seen_help = 1;
+ else if (!strcmp(opts[i].long_opt, "version"))
+ seen_version = 1;
+ else if (!strcmp(opts[i].long_opt, "warranty"))
+ seen_warranty = 1;
+ else if (!strcmp(opts[i].long_opt, "dump-options"))
+ seen_dump_options = 1;
+ else if (!strcmp(opts[i].long_opt, "dump-option-table"))
+ seen_dump_option_table = 1;
+ }
+ }
+ i += 5; /* The number of the above internal options. */
+ i++; /* End of list marker. */
+ arg->internal->opts = xtrycalloc (i, sizeof *arg->internal->opts);
+ if (!arg->internal->opts)
+ return gpg_err_code_from_syserror ();
+ for(i=0; opts[i].short_opt; i++)
+ {
+ arg->internal->opts[i].short_opt = opts[i].short_opt;
+ arg->internal->opts[i].flags = opts[i].flags;
+ arg->internal->opts[i].long_opt = opts[i].long_opt;
+ arg->internal->opts[i].description = opts[i].description;
+ arg->internal->opts[i].ordinal = i;
+ }
+
+ if (!seen_help)
+ {
+ arg->internal->opts[i].short_opt = ARGPARSE_SHORTOPT_HELP;
+ arg->internal->opts[i].flags = ARGPARSE_TYPE_NONE;
+ arg->internal->opts[i].long_opt = "help";
+ arg->internal->opts[i].description = "@";
+ arg->internal->opts[i].ordinal = i;
+ i++;
+ }
+ if (!seen_version)
+ {
+ arg->internal->opts[i].short_opt = ARGPARSE_SHORTOPT_VERSION;
+ arg->internal->opts[i].flags = ARGPARSE_TYPE_NONE;
+ arg->internal->opts[i].long_opt = "version";
+ arg->internal->opts[i].description = "@";
+ arg->internal->opts[i].ordinal = i;
+ i++;
+ }
+
+ if (!seen_warranty)
+ {
+ arg->internal->opts[i].short_opt = ARGPARSE_SHORTOPT_WARRANTY;
+ arg->internal->opts[i].flags = ARGPARSE_TYPE_NONE;
+ arg->internal->opts[i].long_opt = "warranty";
+ arg->internal->opts[i].description = "@";
+ arg->internal->opts[i].ordinal = i;
+ i++;
+ }
+
+ if (!seen_dump_option_table)
+ {
+ arg->internal->opts[i].short_opt = ARGPARSE_SHORTOPT_DUMP_OPTTBL;
+ arg->internal->opts[i].flags = ARGPARSE_TYPE_NONE;
+ arg->internal->opts[i].long_opt = "dump-option-table";
+ arg->internal->opts[i].description = "@";
+ arg->internal->opts[i].ordinal = i;
+ i++;
+ }
+
+ if (!seen_dump_options)
+ {
+ arg->internal->opts[i].short_opt = ARGPARSE_SHORTOPT_DUMP_OPTIONS;
+ arg->internal->opts[i].flags = ARGPARSE_TYPE_NONE;
+ arg->internal->opts[i].long_opt = "dump-options";
+ arg->internal->opts[i].description = "@";
+ arg->internal->opts[i].ordinal = i;
+ i++;
+ }
+ /* Take care: When adding new options remember to increase the
+ * size of the array. */
+
+ arg->internal->opts[i].short_opt = 0;
+
+ /* Note that we do not count the end marker but keep it in the
+ * table anyway as an extra item. */
+ arg->internal->nopts = i;
+ }
+
+ if (arg->err)
+ {
+ /* Last option was erroneous. */
+ const char *s;
+
+ if (!fp && arg->internal->conffp)
+ fp = arg->internal->conffp;
+
+ if (fp)
+ {
+ if ( arg->r_opt == ARGPARSE_UNEXPECTED_ARG )
+ s = _("argument not expected");
+ else if ( arg->r_opt == ARGPARSE_READ_ERROR )
+ s = _("read error");
+ else if ( arg->r_opt == ARGPARSE_KEYWORD_TOO_LONG )
+ s = _("keyword too long");
+ else if ( arg->r_opt == ARGPARSE_MISSING_ARG )
+ s = _("missing argument");
+ else if ( arg->r_opt == ARGPARSE_INVALID_ARG )
+ s = _("invalid argument");
+ else if ( arg->r_opt == ARGPARSE_INVALID_COMMAND )
+ s = _("invalid command");
+ else if ( arg->r_opt == ARGPARSE_INVALID_ALIAS )
+ s = _("invalid alias definition");
+ else if ( arg->r_opt == ARGPARSE_PERMISSION_ERROR )
+ s = _("permission error");
+ else if ( arg->r_opt == ARGPARSE_OUT_OF_CORE )
+ s = _("out of core");
+ else if ( arg->r_opt == ARGPARSE_NO_CONFFILE )
+ s = NULL; /* Error has already been printed. */
+ else if ( arg->r_opt == ARGPARSE_INVALID_META )
+ s = _("invalid meta command");
+ else if ( arg->r_opt == ARGPARSE_UNKNOWN_META )
+ s = _("unknown meta command");
+ else if ( arg->r_opt == ARGPARSE_UNEXPECTED_META )
+ s = _("unexpected meta command");
+ else
+ s = _("invalid option");
+ if (s)
+ log_error ("%s:%u: %s\n",
+ gpgrt_fname_get (fp), arg->lineno, s);
+ }
+ else
+ {
+ s = arg->internal->last? arg->internal->last:"[??]";
+
+ if ( arg->r_opt == ARGPARSE_MISSING_ARG )
+ log_error (_("missing argument for option \"%.50s\"\n"), s);
+ else if ( arg->r_opt == ARGPARSE_INVALID_ARG )
+ log_error (_("invalid argument for option \"%.50s\"\n"), s);
+ else if ( arg->r_opt == ARGPARSE_UNEXPECTED_ARG )
+ log_error (_("option \"%.50s\" does not expect "
+ "an argument\n"), s);
+ else if ( arg->r_opt == ARGPARSE_INVALID_COMMAND )
+ log_error (_("invalid command \"%.50s\"\n"), s);
+ else if ( arg->r_opt == ARGPARSE_AMBIGUOUS_OPTION )
+ log_error (_("option \"%.50s\" is ambiguous\n"), s);
+ else if ( arg->r_opt == ARGPARSE_AMBIGUOUS_COMMAND )
+ log_error (_("command \"%.50s\" is ambiguous\n"),s );
+ else if ( arg->r_opt == ARGPARSE_OUT_OF_CORE )
+ log_error ("%s\n", _("out of core"));
+ else if ( arg->r_opt == ARGPARSE_PERMISSION_ERROR )
+ log_error ("%s\n", _("permission error"));
+ else if ( arg->r_opt == ARGPARSE_NO_CONFFILE)
+ ; /* Error has already been printed. */
+ else if ( arg->r_opt == ARGPARSE_INVALID_META )
+ log_error ("%s\n", _("invalid meta command"));
+ else if ( arg->r_opt == ARGPARSE_UNKNOWN_META )
+ log_error ("%s\n", _("unknown meta command"));
+ else if ( arg->r_opt == ARGPARSE_UNEXPECTED_META )
+ log_error ("%s\n",_("unexpected meta command"));
+ else
+ log_error (_("invalid option \"%.50s\"\n"), s);
+ }
+ if (arg->err != ARGPARSE_PRINT_WARNING)
+ my_exit (arg, 2);
+ arg->err = 0;
+ }
+
+ /* Zero out the return value union. */
+ arg->r.ret_str = NULL;
+ arg->r.ret_long = 0;
+
+ return 0;
+}
+
+
+static void
+store_alias( ARGPARSE_ARGS *arg, char *name, char *value )
+{
+ /* TODO: replace this dummy function with a rea one
+ * and fix the probelms IRIX has with (ALIAS_DEV)arg..
+ * used as lvalue
+ */
+ (void)arg;
+ (void)name;
+ (void)value;
+#if 0
+ ALIAS_DEF a = xmalloc( sizeof *a );
+ a->name = name;
+ a->value = value;
+ a->next = (ALIAS_DEF)arg->internal.aliases;
+ (ALIAS_DEF)arg->internal.aliases = a;
+#endif
+}
+
+
+/* Return true if KEYWORD is in the ignore-invalid-option list. */
+static int
+ignore_invalid_option_p (ARGPARSE_ARGS *arg, const char *keyword)
+{
+ IIO_ITEM_DEF item = arg->internal->iio_list;
+
+ for (; item; item = item->next)
+ if (!strcmp (item->name, keyword))
+ return 1;
+ return 0;
+}
+
+
+/* Add the keywords up to the next LF to the list of to be ignored
+ options. After returning FP will either be at EOF or the next
+ character read wll be the first of a new line. The function
+ returns 0 on success or true on malloc failure. */
+static int
+ignore_invalid_option_add (ARGPARSE_ARGS *arg, estream_t fp)
+{
+ IIO_ITEM_DEF item;
+ int c;
+ char name[100];
+ int namelen = 0;
+ int ready = 0;
+ enum { skipWS, collectNAME, skipNAME, addNAME} state = skipWS;
+
+ while (!ready)
+ {
+ c = gpgrt_getc (fp);
+ if (c == '\n')
+ ready = 1;
+ else if (c == EOF)
+ {
+ c = '\n';
+ ready = 1;
+ }
+ again:
+ switch (state)
+ {
+ case skipWS:
+ if (!isascii (c) || !isspace(c))
+ {
+ namelen = 0;
+ state = collectNAME;
+ goto again;
+ }
+ break;
+
+ case collectNAME:
+ if (isspace (c))
+ {
+ state = addNAME;
+ goto again;
+ }
+ else if (namelen < DIM(name)-1)
+ name[namelen++] = c;
+ else /* Too long. */
+ state = skipNAME;
+ break;
+
+ case skipNAME:
+ if (isspace (c))
+ {
+ state = skipWS;
+ goto again;
+ }
+ break;
+
+ case addNAME:
+ name[namelen] = 0;
+ if (!ignore_invalid_option_p (arg, name))
+ {
+ item = xtrymalloc (sizeof *item + namelen);
+ if (!item)
+ return 1;
+ strcpy (item->name, name);
+ item->next = (IIO_ITEM_DEF)arg->internal->iio_list;
+ arg->internal->iio_list = item;
+ }
+ state = skipWS;
+ goto again;
+ }
+ }
+ return 0;
+}
+
+
+/* Clear the entire ignore-invalid-option list. */
+static void
+ignore_invalid_option_clear (ARGPARSE_ARGS *arg)
+{
+ IIO_ITEM_DEF item, tmpitem;
+
+ for (item = arg->internal->iio_list; item; item = tmpitem)
+ {
+ tmpitem = item->next;
+ xfree (item);
+ }
+ arg->internal->iio_list = NULL;
+}
+
+
+/* Make sure the username field is filled. Return 0 on success. */
+static int
+assure_username (gnupg_argparse_t *arg)
+{
+ if (!arg->internal->username)
+ {
+ arg->internal->username = gnupg_getusername ();
+ if (!arg->internal->username)
+ {
+ log_error ("%s:%u: error getting current user's name: %s\n",
+ arg->internal->confname, arg->lineno,
+ gpg_strerror (gpg_error_from_syserror ()));
+ /* Not necessary the correct error code but given that we
+ * either have a malloc error or some internal system error,
+ * it is the best we can do. */
+ return ARGPARSE_PERMISSION_ERROR;
+ }
+ }
+ return 0;
+}
+
+
+/* Implementation of the "user" command. ARG is the context. ARGS is
+ * a non-empty string which this function is allowed to modify. */
+static int
+handle_meta_user (gnupg_argparse_t *arg, unsigned int alternate, char *args)
+{
+ int rc;
+
+ (void)alternate;
+
+ rc = assure_username (arg);
+ if (rc)
+ return rc;
+
+ arg->internal->user_seen = 1;
+ if (*args == '*' && !args[1])
+ {
+ arg->internal->user_wildcard = 1;
+ arg->internal->user_active = !arg->internal->user_any_active;
+ }
+ else if (arg->internal->user_wildcard)
+ {
+ /* All other user statements are ignored after a wildcard. */
+ arg->internal->user_active = 0;
+ }
+ else if (!strcasecmp (args, arg->internal->username))
+ {
+ arg->internal->user_any_active = 1;
+ arg->internal->user_active = 1;
+ }
+ else
+ {
+ arg->internal->user_active = 0;
+ }
+
+ return 0;
+}
+
+
+/* Implementation of the "force" command. ARG is the context. A
+ * value of 0 for ALTERNATE is "force", a value of 1 requests an
+ * unforce". ARGS is the empty string and not used. */
+static int
+handle_meta_force (gnupg_argparse_t *arg, unsigned int alternate, char *args)
+{
+ (void)args;
+
+ arg->internal->mark_forced = alternate? 0 : 1;
+
+ return 0;
+}
+
+
+/* Implementation of the "ignore" command. ARG is the context. A
+ * value of 0 for ALTERNATE is a plain "ignore", a value of 1 request
+ * an "unignore, a value of 2 requests an "ignore-all". ARGS is the
+ * empty string and not used. */
+static int
+handle_meta_ignore (gnupg_argparse_t *arg, unsigned int alternate, char *args)
+{
+ (void)args;
+
+ if (!alternate)
+ {
+ arg->internal->mark_ignore = 1;
+ arg->internal->explicit_ignore = 1;
+ }
+ else if (alternate == 1)
+ {
+ arg->internal->mark_ignore = 0;
+ arg->internal->explicit_ignore = 1;
+ }
+ else
+ arg->internal->ignore_all_seen = 1;
+
+ return 0;
+}
+
+
+/* Implementation of the "echo" command. ARG is the context. If
+ * ALTERNATE is true the filename is not printed. ARGS is the string
+ * to log. */
+static int
+handle_meta_echo (gnupg_argparse_t *arg, unsigned int alternate, char *args)
+{
+ int rc = 0;
+ char *p, *pend;
+
+ if (alternate)
+ log_info ("%s", "");
+ else
+ log_info ("%s:%u: ", arg->internal->confname, arg->lineno);
+
+ while (*args)
+ {
+ p = strchr (args, '$');
+ if (!p)
+ {
+ log_printf ("%s", args);
+ break;
+ }
+ *p = 0;
+ log_printf ("%s", args);
+ if (p[1] == '$')
+ {
+ log_printf ("$");
+ args = p+2;
+ continue;
+ }
+ if (p[1] != '{')
+ {
+ log_printf ("$");
+ args = p+1;
+ continue;
+ }
+ pend = strchr (p+2, '}');
+ if (!pend) /* No closing brace. */
+ {
+ log_printf ("$");
+ args = p+1;
+ continue;
+ }
+ p += 2;
+ *pend = 0;
+ args = pend+1;
+ if (!strcmp (p, "user"))
+ {
+ rc = assure_username (arg);
+ if (rc)
+ goto leave;
+ log_printf ("%s", arg->internal->username);
+ }
+ else if (!strcmp (p, "file"))
+ log_printf ("%s", arg->internal->confname);
+ else if (!strcmp (p, "line"))
+ log_printf ("%u", arg->lineno);
+ else if (!strcmp (p, "epoch"))
+ log_printf ("%lu", (unsigned long)time (NULL));
+ }
+
+ leave:
+ log_printf ("\n");
+ return rc;
+}
+
+
+/* Implementation of the "verbose" command. ARG is the context. If
+ * ALTERNATE is true the verbosity is disabled. ARGS is not used. */
+static int
+handle_meta_verbose (gnupg_argparse_t *arg, unsigned int alternate, char *args)
+{
+ (void)args;
+
+ if (alternate)
+ arg->internal->verbose = 0;
+ else
+ arg->internal->verbose = 1;
+ return 0;
+}
+
+/* Handle a meta command. KEYWORD has the content inside the brackets
+ * with leading and trailing spaces removed. The function may modify
+ * KEYWORD. On success 0 is returned, on error an ARGPARSE_ error
+ * code is returned. */
+static int
+handle_metacmd (gnupg_argparse_t *arg, char *keyword)
+{
+ static struct {
+ const char *name; /* Name of the command. */
+ unsigned short alternate; /* Use alternate version of the command. */
+ unsigned short needarg:1; /* Command requires an argument. */
+ unsigned short always:1; /* Command allowed in all conf files. */
+ unsigned short noskip:1; /* Even done in non-active [user] mode. */
+ int (*func)(gnupg_argparse_t *arg,
+ unsigned int alternate, char *args); /*handler*/
+ } cmds[] =
+ {{ "user", 0, 1, 0, 1, handle_meta_user },
+ { "force", 0, 0, 0, 0, handle_meta_force },
+ { "+force", 0, 0, 0, 0, handle_meta_force },
+ { "-force", 1, 0, 0, 0, handle_meta_force },
+ { "ignore", 0, 0, 0, 0, handle_meta_ignore },
+ { "+ignore", 0, 0, 0, 0, handle_meta_ignore },
+ { "-ignore", 1, 0, 0, 0, handle_meta_ignore },
+ { "ignore-all", 2, 0, 0, 0, handle_meta_ignore },
+ { "+ignore-all", 2, 0, 0, 0, handle_meta_ignore },
+ { "verbose", 0, 0, 1, 1, handle_meta_verbose },
+ { "+verbose", 0, 0, 1, 1, handle_meta_verbose },
+ { "-verbose", 1, 0, 1, 1, handle_meta_verbose },
+ { "echo", 0, 1, 1, 1, handle_meta_echo },
+ { "-echo", 1, 1, 1, 1, handle_meta_echo },
+ { "info", 0, 1, 1, 0, handle_meta_echo },
+ { "-info", 1, 1, 1, 0, handle_meta_echo }
+ };
+ char *rest;
+ int i;
+
+ for (rest = keyword; *rest && !(isascii (*rest) && isspace (*rest)); rest++)
+ ;
+ if (*rest)
+ {
+ *rest++ = 0;
+ trim_spaces (rest);
+ }
+
+ for (i=0; i < DIM (cmds); i++)
+ if (!strcmp (cmds[i].name, keyword))
+ break;
+ if (!(i < DIM (cmds)))
+ return ARGPARSE_UNKNOWN_META;
+ if (cmds[i].needarg && !*rest)
+ return ARGPARSE_MISSING_ARG;
+ if (!cmds[i].needarg && *rest)
+ return ARGPARSE_UNEXPECTED_ARG;
+ if (!arg->internal->in_sysconf && !cmds[i].always)
+ return ARGPARSE_UNEXPECTED_META;
+
+ if (!cmds[i].noskip
+ && arg->internal->in_sysconf
+ && arg->internal->user_seen
+ && !arg->internal->user_active)
+ return 0; /* Skip this meta command. */
+
+ return cmds[i].func (arg, cmds[i].alternate, rest);
+}
+
+
+/* Helper for gnupg_argparse. */
+static void
+prepare_arg_return (gnupg_argparse_t *arg, opttable_t *opts,
+ int idx, int in_alias, int set_ignore)
+{
+ /* No argument found at the end of the line. */
+ if (in_alias)
+ arg->r_opt = ARGPARSE_MISSING_ARG;
+ else if (!(opts[idx].flags & ARGPARSE_TYPE_MASK))
+ arg->r_type = ARGPARSE_TYPE_NONE; /* Does not take an arg. */
+ else if ((opts[idx].flags & ARGPARSE_OPT_OPTIONAL))
+ arg->r_type = ARGPARSE_TYPE_NONE; /* No optional argument. */
+ else if (!(opts[idx].ignore && !opts[idx].forced) && !set_ignore)
+ arg->r_opt = ARGPARSE_MISSING_ARG;
+
+ /* If the caller wants us to return the attributes or
+ * ignored options, or these flags in. */
+ if ((arg->flags & ARGPARSE_FLAG_WITHATTR))
+ {
+ if (opts[idx].ignore)
+ arg->r_type |= ARGPARSE_ATTR_IGNORE;
+ if (opts[idx].forced)
+ arg->r_type |= ARGPARSE_ATTR_FORCE;
+ if (set_ignore)
+ arg->r_type |= ARGPARSE_OPT_IGNORE;
+ }
+}
+
+/****************
+ * Get options from a file.
+ * Lines starting with '#' are comment lines.
+ * Syntax is simply a keyword and the argument.
+ * Valid keywords are all keywords from the long_opt list without
+ * the leading dashes. The special keywords "help", "warranty" and "version"
+ * are not valid here.
+ * The special keyword "alias" may be used to store alias definitions,
+ * which are later expanded like long options.
+ * The option
+ * ignore-invalid-option OPTIONNAMEs
+ * is recognized and updates a list of option which should be ignored if they
+ * are not defined.
+ * Caller must free returned strings.
+ * If called with FP set to NULL command line args are parse instead.
+ *
+ * Q: Should we allow the syntax
+ * keyword = value
+ * and accept for boolean options a value of 1/0, yes/no or true/false?
+ * Note: Abbreviation of options is here not allowed.
+ */
+int
+gnupg_argparse (estream_t fp, gnupg_argparse_t *arg, gnupg_opt_t *opts_orig)
+{
+ enum { Ainit,
+ Acomment, /* In a comment line. */
+ Acopykeyword, /* Collecting a keyword. */
+ Awaitarg, /* Wait for an argument. */
+ Acopyarg, /* Copy the argument. */
+ Akeyword_eol, /* Got keyword at end of line. */
+ Akeyword_spc, /* Got keyword at space. */
+ Acopymetacmd, /* Copy a meta command. */
+ Askipmetacmd, /* Skip spaces after metacmd. */
+ Askipmetacmd2,/* Skip comment after metacmd. */
+ Ametacmd, /* Process the metacmd. */
+ Askipandleave /* Skip the rest of the line and then leave. */
+ } state;
+ opttable_t *opts;
+ unsigned int nopts;
+ int i, c;
+ int idx = 0;
+ char keyword[100];
+ char *buffer = NULL;
+ size_t buflen = 0;
+ int in_alias=0;
+ int set_ignore = 0;
+ int unread_buf[3]; /* We use an int so that we can store EOF. */
+ int unread_buf_count = 0;
+
+ if (arg && !opts_orig)
+ {
+ deinitialize (arg);
+ return 0;
+ }
+
+ if (!fp) /* Divert to arg_parse() in this case. */
+ return arg_parse (arg, opts_orig, 0);
+
+ if (initialize (arg, opts_orig, fp))
+ return (arg->r_opt = ARGPARSE_OUT_OF_CORE);
+
+ opts = arg->internal->opts;
+ nopts = arg->internal->nopts;
+
+ /* If the LINENO is zero we assume that we are at the start of a
+ * file and we skip over a possible Byte Order Mark. */
+ if (!arg->lineno)
+ {
+ unread_buf[0] = gpgrt_fgetc (fp);
+ unread_buf[1] = gpgrt_fgetc (fp);
+ unread_buf[2] = gpgrt_fgetc (fp);
+ if (unread_buf[0] != 0xef
+ || unread_buf[1] != 0xbb
+ || unread_buf[2] != 0xbf)
+ unread_buf_count = 3;
+ }
+
+ arg->internal->opt_flags = 0;
+
+ /* Find the next keyword. */
+ state = Ainit;
+ i = 0;
+ for (;;)
+ {
+ nextstate:
+ /* Before scanning the next char handle the keyword seen states. */
+ if (state == Akeyword_eol || state == Akeyword_spc)
+ {
+ /* We are either at the end of a line or right after a
+ * keyword. In the latter case we need to find the keyword
+ * so that we can decide whether an argument is required. */
+
+ /* Check the keyword. */
+ for (idx=0; idx < nopts; idx++ )
+ {
+ if (opts[idx].long_opt && !strcmp (opts[idx].long_opt, keyword))
+ break;
+ }
+ arg->r_opt = opts[idx].short_opt;
+ if (!(idx < nopts))
+ {
+ /* The option (keyword) is not known - check for
+ * internal keywords before returning an error. */
+ if (state == Akeyword_spc && !strcmp (keyword, "alias"))
+ {
+ in_alias = 1;
+ state = Awaitarg;
+ }
+ else if (!strcmp (keyword, "ignore-invalid-option"))
+ {
+ /* We might have keywords as argument - add them to
+ * the list of ignored keywords. Note that we
+ * ignore empty argument lists and thus do not to
+ * call the function in the Akeyword_eol state. */
+ if (state == Akeyword_spc)
+ {
+ if (ignore_invalid_option_add (arg, fp))
+ {
+ arg->r_opt = ARGPARSE_OUT_OF_CORE;
+ goto leave;
+ }
+ arg->lineno++;
+ }
+ state = Ainit;
+ i = 0;
+ }
+ else if (ignore_invalid_option_p (arg, keyword))
+ {
+ /* This invalid option is already in the iio list. */
+ state = state == Akeyword_eol? Ainit : Acomment;
+ i = 0;
+ }
+ else
+ {
+ arg->r_opt = ((opts[idx].flags & ARGPARSE_OPT_COMMAND)
+ ? ARGPARSE_INVALID_COMMAND
+ : ARGPARSE_INVALID_OPTION);
+ if (state == Akeyword_spc)
+ state = Askipandleave;
+ else
+ goto leave;
+ }
+ }
+ else if (state != Akeyword_spc
+ && arg->internal->in_sysconf
+ && arg->internal->user_seen
+ && !arg->internal->user_active)
+ {
+ /* We are in a [user] meta command and it is not active.
+ * Skip the command. */
+ state = state == Akeyword_eol? Ainit : Acomment;
+ i = 0;
+ }
+ else if (state != Akeyword_spc
+ && (opts[idx].flags & ARGPARSE_OPT_IGNORE))
+ {
+ /* Known option is configured to be ignored. Start from
+ * scratch (new line) or process like a comment. */
+ state = state == Akeyword_eol? Ainit : Acomment;
+ i = 0;
+ }
+ else /* Known option */
+ {
+ set_ignore = 0;
+
+ if (arg->internal->in_sysconf)
+ {
+ /* Set the current forced and ignored attributes. */
+ if (arg->internal->mark_forced)
+ opts[idx].forced = 1;
+ if (arg->internal->mark_ignore)
+ opts[idx].ignore = 1;
+ if (arg->internal->explicit_ignore)
+ opts[idx].explicit_ignore = 1;
+
+ if (opts[idx].ignore && !opts[idx].forced)
+ {
+ if (arg->internal->verbose)
+ log_info ("%s:%u: ignoring option \"--%s\"\n",
+ arg->internal->confname,
+ arg->lineno,
+ opts[idx].long_opt);
+ if ((arg->flags & ARGPARSE_FLAG_WITHATTR))
+ set_ignore = 1;
+ else
+ {
+ state = state == Akeyword_eol? Ainit : Acomment;
+ i = 0;
+ goto nextstate; /* Ignore this one. */
+ }
+ }
+ }
+ else /* Non-sysconf file */
+ { /* Act upon the forced and ignored attributes. */
+ if (opts[idx].ignore || opts[idx].forced)
+ {
+ if (arg->internal->verbose)
+ log_info ("%s:%u: ignoring option \"--%s\""
+ " due to attributes:%s%s\n",
+ arg->internal->confname,
+ arg->lineno,
+ opts[idx].long_opt,
+ opts[idx].forced? " forced":"",
+ opts[idx].ignore? " ignore":"");
+ if ((arg->flags & ARGPARSE_FLAG_WITHATTR))
+ set_ignore = 1;
+ else
+ {
+ state = state == Akeyword_eol? Ainit : Acomment;
+ i = 0;
+ goto nextstate; /* Ignore this one. */
+ }
+ }
+ }
+
+ if (state == Akeyword_spc)
+ {
+ /* If we shall ignore but not set the option we skip
+ * the argument. Otherwise we would need to use a
+ * made-up but not used args in the conf file. */
+ if (set_ignore || (opts[idx].ignore && !opts[idx].forced))
+ {
+ prepare_arg_return (arg, opts, idx, 0, set_ignore);
+ set_ignore = 0;
+ state = Askipandleave;
+ }
+ else
+ state = Awaitarg;
+ }
+ else
+ {
+ prepare_arg_return (arg, opts, idx, 0, set_ignore);
+ set_ignore = 0;
+ goto leave;
+ }
+
+ }
+ } /* (end state Akeyword_eol/Akeyword_spc) */
+ else if (state == Ametacmd)
+ {
+ /* We are at the end of a line. */
+ log_assert (*keyword == '[');
+ trim_spaces (keyword+1);
+ if (!keyword[1])
+ {
+ arg->r_opt = ARGPARSE_INVALID_META; /* Empty. */
+ goto leave;
+ }
+ c = handle_metacmd (arg, keyword+1);
+ if (c)
+ {
+ arg->r_opt = c; /* Return error. */
+ goto leave;
+ }
+ state = Ainit;
+ i = 0;
+ }
+
+ /* Get the next character from the line. */
+ if (unread_buf_count)
+ c = unread_buf[3 - unread_buf_count--];
+ else
+ c = gpgrt_fgetc (fp);
+
+ if (c == '\n' || c== EOF )
+ { /* Handle end of line. */
+ if ( c != EOF )
+ arg->lineno++;
+ if (state == Askipandleave)
+ goto leave;
+ else if (state == Acopykeyword)
+ {
+ keyword[i] = 0;
+ state = Akeyword_eol;
+ goto nextstate;
+ }
+ else if (state == Acopymetacmd)
+ {
+ arg->r_opt = ARGPARSE_INVALID_META; /* "]" missing */
+ goto leave;
+ }
+ else if (state == Askipmetacmd || state == Askipmetacmd2)
+ {
+ state = Ametacmd;
+ goto nextstate;
+ }
+ else if (state == Awaitarg)
+ {
+ /* No argument found at the end of the line. */
+ prepare_arg_return (arg, opts, idx, in_alias, set_ignore);
+ set_ignore = 0;
+ goto leave;
+ }
+ else if (state == Acopyarg)
+ {
+ /* Has an argument at the end of a line. */
+ if (in_alias)
+ {
+ if (!buffer)
+ arg->r_opt = ARGPARSE_UNEXPECTED_ARG;
+ else
+ {
+ char *p;
+
+ buffer[i] = 0;
+ p = strpbrk (buffer, " \t");
+ if (p)
+ {
+ *p++ = 0;
+ trim_spaces (p);
+ }
+ if (!p || !*p)
+ {
+ xfree (buffer);
+ arg->r_opt = ARGPARSE_INVALID_ALIAS;
+ }
+ else
+ {
+ store_alias (arg, buffer, p);
+ }
+ }
+ }
+ else if (!(opts[idx].flags & ARGPARSE_TYPE_MASK))
+ arg->r_opt = ARGPARSE_UNEXPECTED_ARG;
+ else
+ {
+ char *p;
+
+ if (!buffer)
+ {
+ keyword[i] = 0;
+ buffer = xtrystrdup (keyword);
+ if (!buffer)
+ arg->r_opt = ARGPARSE_OUT_OF_CORE;
+ }
+ else
+ buffer[i] = 0;
+
+ if (buffer)
+ {
+ trim_spaces (buffer);
+ p = buffer;
+ if (*p == '"')
+ {
+ /* Remove quotes. */
+ p++;
+ if (*p && p[strlen(p)-1] == '\"' )
+ p[strlen(p)-1] = 0;
+ }
+ if (!set_opt_arg (arg, opts[idx].flags, p))
+ xfree (buffer);
+ else
+ gpgrt_annotate_leaked_object (buffer);
+ /* If the caller wants us to return the attributes or
+ * ignored options, or these flags in. */
+ if ((arg->flags & ARGPARSE_FLAG_WITHATTR))
+ {
+ if (opts[idx].ignore)
+ arg->r_type |= ARGPARSE_ATTR_IGNORE;
+ if (opts[idx].forced)
+ arg->r_type |= ARGPARSE_ATTR_FORCE;
+ if (set_ignore)
+ arg->r_type |= ARGPARSE_OPT_IGNORE;
+ }
+ }
+ }
+ goto leave;
+ }
+ else if (c == EOF)
+ {
+ ignore_invalid_option_clear (arg);
+ if (gpgrt_ferror (fp))
+ arg->r_opt = ARGPARSE_READ_ERROR;
+ else
+ arg->r_opt = 0; /* EOF. */
+ goto leave;
+ }
+ state = Ainit;
+ i = 0;
+ } /* (end handle end of line) */
+ else if (state == Askipandleave)
+ ; /* Skip. */
+ else if (state == Ainit && isascii (c) && isspace(c))
+ ; /* Skip leading white space. */
+ else if (state == Ainit && c == '#' )
+ state = Acomment; /* Start of a comment. */
+ else if (state == Acomment || state == Askipmetacmd2)
+ ; /* Skip comments. */
+ else if (state == Askipmetacmd)
+ {
+ if (c == '#')
+ state = Askipmetacmd2;
+ else if (!(isascii (c) && isspace(c)))
+ {
+ arg->r_opt = ARGPARSE_INVALID_META;
+ state = Askipandleave;
+ }
+ }
+ else if (state == Acopykeyword && isascii (c) && isspace(c))
+ {
+ keyword[i] = 0;
+ state = Akeyword_spc;
+ goto nextstate;
+ }
+ else if (state == Acopymetacmd && c == ']')
+ {
+ keyword[i] = 0;
+ state = Askipmetacmd;
+ goto nextstate;
+ }
+ else if (state == Awaitarg)
+ {
+ /* Skip leading spaces of the argument. */
+ if (!isascii (c) || !isspace(c))
+ {
+ i = 0;
+ keyword[i++] = c;
+ state = Acopyarg;
+ }
+ }
+ else if (state == Acopyarg)
+ {
+ /* Collect the argument. */
+ if (buffer)
+ {
+ if (i < buflen-1)
+ buffer[i++] = c;
+ else
+ {
+ char *tmp;
+ size_t tmplen = buflen + 50;
+
+ tmp = xtryrealloc (buffer, tmplen);
+ if (tmp)
+ {
+ buflen = tmplen;
+ buffer = tmp;
+ buffer[i++] = c;
+ }
+ else
+ {
+ xfree (buffer);
+ arg->r_opt = ARGPARSE_OUT_OF_CORE;
+ goto leave;
+ }
+ }
+ }
+ else if (i < DIM(keyword)-1)
+ keyword[i++] = c;
+ else
+ {
+ size_t tmplen = DIM(keyword) + 50;
+ buffer = xtrymalloc (tmplen);
+ if (buffer)
+ {
+ buflen = tmplen;
+ memcpy(buffer, keyword, i);
+ buffer[i++] = c;
+ }
+ else
+ {
+ arg->r_opt = ARGPARSE_OUT_OF_CORE;
+ goto leave;
+ }
+ }
+ }
+ else if (i >= DIM(keyword)-1)
+ {
+ arg->r_opt = ARGPARSE_KEYWORD_TOO_LONG;
+ state = Askipandleave; /* Skip rest of line and leave. */
+ }
+ else if (!i)
+ {
+ state = c == '[' ? Acopymetacmd : Acopykeyword;
+ keyword[i++] = c;
+ }
+ else
+ {
+ keyword[i++] = c;
+ }
+ }
+
+ leave:
+ return arg->r_opt;
+}
+
+
+/* Return true if the list of options OPTS has any option marked with
+ * ARGPARSE_OPT_CONFFILE. */
+static int
+any_opt_conffile (opttable_t *opts, unsigned int nopts)
+{
+ int i;
+
+ for (i=0; i < nopts; i++ )
+ if ((opts[i].flags & ARGPARSE_OPT_CONFFILE))
+ return 1;
+ return 0;
+}
+
+
+/* Return true if FNAME is an absolute filename. */
+static int
+is_absfname (const char *fname)
+{
+ const char *s;
+
+#ifdef HAVE_W32_SYSTEM
+ s = strchr (fname, ':');
+ if (s)
+ s++;
+ else
+ s = fname;
+#else
+ s = fname;
+#endif
+
+ return (*s == '/'
+#ifdef HAVE_W32_SYSTEM
+ || *s == DIRSEP_C
+#endif
+ );
+}
+
+
+/* If FNAME specifies two files of the form
+ * NAME1:/NAME2 (Unix)
+ * or
+ * NAME1;[x:]/NAME2 (Windows)
+ * return a pointer to the delimiter or NULL if there is none.
+ */
+static const char *
+is_twopartfname (const char *fname)
+{
+ const char *s;
+
+ if ((s = strchr (fname, PATHSEP_C)) && is_absfname (s+1) && s != fname)
+ return s;
+ return NULL;
+}
+
+
+/* Try to use a version-ed config file name. A version-ed config file
+ * name is one which has the packages version number appended. For
+ * example if the standard config file name is "foo.conf" and the
+ * version of the foo program is 1.2.3-beta1 the following config
+ * files are tried in order until one is readable:
+ *
+ * foo.conf-1.2.3-beta1
+ * foo.conf-1.2.3
+ * foo.conf-1.2
+ * foo.conf-1
+ * foo.conf
+ *
+ * The argument CONFIGNAME should already be expanded. On success a
+ * newly allocated file name is returned. On error NULL is returned.
+ */
+static char *
+try_versioned_conffile (const char *configname)
+{
+ const char *version = strusage (13);
+ char *name;
+ char *dash, *endp;
+
+ if (!version || !*version)
+ return NULL; /* No program version known. */
+
+ name = strconcat (configname, "-", version, NULL);
+ if (!name)
+ return NULL; /* Oops: Out of core - ignore. */
+ dash = name + strlen (configname);
+
+ endp = dash + strlen (dash) - 1;
+ while (endp > dash)
+ {
+ if (!gnupg_access (name, R_OK))
+ {
+ return name;
+ }
+ for (; endp > dash; endp--)
+ {
+ if (*endp == '-' || *endp == '.')
+ {
+ *endp = 0;
+ break;
+ }
+ }
+ }
+
+ xfree (name);
+ return NULL;
+}
+
+
+/* This function is called after a sysconf file has been read. */
+static void
+finish_read_sys (gnupg_argparse_t *arg)
+{
+ opttable_t *opts = arg->internal->opts;
+ unsigned int nopts = arg->internal->nopts;
+ int i;
+
+ if (arg->internal->ignore_all_seen)
+ {
+ /* [ignore-all] was used: Set all options which have not
+ * explictly been set as ignore or not ignore to ignore. */
+ for (i = 0; i < nopts; i++)
+ {
+ if (!opts[i].explicit_ignore)
+ opts[i].ignore = 1;
+ }
+ }
+
+ /* Reset all flags which pertain only to sysconf files. */
+ arg->internal->in_sysconf = 0;
+ arg->internal->user_active = 0;
+ arg->internal->mark_forced = 0;
+ arg->internal->mark_ignore = 0;
+ arg->internal->explicit_ignore = 0;
+ arg->internal->ignore_all_seen = 0;
+}
+
+/* The full arg parser which handles option files and command line
+ * arguments. The behaviour depends on the combinations of CONFNAME
+ * and the ARGPARSE_FLAG_xxx values:
+ *
+ * | CONFNAME | SYS | USER | Action |
+ * |----------+-----+------+--------------------|
+ * | NULL | - | - | cmdline |
+ * | string | 0 | 1 | user, cmdline |
+ * | string | 1 | 0 | sys, cmdline |
+ * | string | 1 | 1 | sys, user, cmdline |
+ *
+ * Note that if an option has been flagged with ARGPARSE_OPT_CONFFILE
+ * and a type of ARGPARSE_TYPE_STRING that option is not returned but
+ * the specified configuration file is processed directly; if
+ * ARGPARSE_TYPE_NONE is used no user configuration files are
+ * processed and from the system configuration files only those which
+ * are immutable are processed. The string values for CONFNAME shall
+ * not include a directory part because that is taken from the values
+ * set by gnupg_set_confdir. However, if CONFNAME is a twopart
+ * filename delimited by a colon (semicolon on Windows) with the
+ * second part being an absolute filename, the first part is used for
+ * the SYS file and the the entire second part for the USER file.
+ */
+int
+gnupg_argparser (gnupg_argparse_t *arg, gnupg_opt_t *opts,
+ const char *confname)
+{
+ /* First check whether releasing the resources has been requested. */
+ if (arg && !opts)
+ {
+ deinitialize (arg);
+ return 0;
+ }
+
+ /* Make sure that the internal data object is ready and also print
+ * warnings or errors from the last iteration. */
+ if (initialize (arg, opts, NULL))
+ return (arg->r_opt = ARGPARSE_OUT_OF_CORE);
+
+ next_state:
+ switch (arg->internal->state)
+ {
+ case STATE_init:
+ if (arg->argc && arg->argv && *arg->argc
+ && any_opt_conffile (arg->internal->opts, arg->internal->nopts))
+ {
+ /* The list of option allow for conf files
+ * (e.g. gpg's "--option FILE" and "--no-options")
+ * Now check whether one was really given on the command
+ * line. Note that we don't need to run this code if no
+ * argument array was provided. */
+ int save_argc = *arg->argc;
+ char **save_argv = *arg->argv;
+ unsigned int save_flags = arg->flags;
+ int save_idx = arg->internal->idx;
+ int any_no_conffile = 0;
+
+ arg->flags = (ARGPARSE_FLAG_KEEP | ARGPARSE_FLAG_NOVERSION
+ | ARGPARSE_FLAG__INITIALIZED);
+ while (arg_parse (arg, opts, 1))
+ {
+ if ((arg->internal->opt_flags & ARGPARSE_OPT_CONFFILE))
+ {
+ arg->internal->explicit_confopt = 1;
+ if ((arg->r_type & ARGPARSE_TYPE_MASK) == ARGPARSE_TYPE_STRING
+ && !arg->internal->explicit_conffile)
+ {
+ /* Store the first conffile name. All further
+ * conf file options are not handled. */
+ arg->internal->explicit_conffile
+ = xtrystrdup (arg->r.ret_str);
+ if (!arg->internal->explicit_conffile)
+ return (arg->r_opt = ARGPARSE_OUT_OF_CORE);
+
+ }
+ else if ((arg->r_type & ARGPARSE_TYPE_MASK)
+ == ARGPARSE_TYPE_NONE)
+ any_no_conffile = 1;
+ }
+ }
+ if (any_no_conffile)
+ {
+ /* A NoConffile option overrides any other conf file option. */
+ xfree (arg->internal->explicit_conffile);
+ arg->internal->explicit_conffile = NULL;
+ }
+ /* Restore parser. */
+ *arg->argc = save_argc;
+ *arg->argv = save_argv;
+ arg->flags = save_flags;
+ arg->internal->idx = save_idx;
+ }
+
+ if (confname && *confname)
+ {
+ if ((arg->flags & ARGPARSE_FLAG_SYS))
+ arg->internal->state = STATE_open_sys;
+ else if ((arg->flags & ARGPARSE_FLAG_USER))
+ arg->internal->state = STATE_open_user;
+ else
+ return (arg->r_opt = ARGPARSE_INVALID_ARG);
+ }
+ else
+ arg->internal->state = STATE_open_cmdline;
+ goto next_state;
+
+ case STATE_open_sys:
+ {
+ /* If it is a two part name take the first part. */
+ const char *s;
+ char *tmpname = NULL;
+
+ if ((s = is_twopartfname (confname)))
+ {
+ tmpname = xtrymalloc (s - confname + 1);
+ if (!tmpname)
+ return (arg->r_opt = ARGPARSE_OUT_OF_CORE);
+ memcpy (tmpname, confname, s-confname);
+ tmpname[s-confname] = 0;
+ s = tmpname;
+ }
+ else
+ s = confname;
+ xfree (arg->internal->confname);
+ arg->internal->confname = make_filename_try
+ (confdir.sys? confdir.sys : "/etc", s, NULL);
+ xfree (tmpname);
+ if (!arg->internal->confname)
+ return (arg->r_opt = ARGPARSE_OUT_OF_CORE);
+ }
+ arg->lineno = 0;
+ arg->internal->idx = 0;
+ arg->internal->verbose = 0;
+ arg->internal->stopped = 0;
+ arg->internal->inarg = 0;
+ gpgrt_fclose (arg->internal->conffp);
+ arg->internal->conffp = gpgrt_fopen (arg->internal->confname, "r");
+ if (!arg->internal->conffp)
+ {
+ if ((arg->flags & ARGPARSE_FLAG_VERBOSE) || arg->internal->verbose)
+ log_info (_("Note: no default option file '%s'\n"),
+ arg->internal->confname);
+ if ((arg->flags & ARGPARSE_FLAG_USER))
+ arg->internal->state = STATE_open_user;
+ else
+ arg->internal->state = STATE_open_cmdline;
+ goto next_state;
+ }
+
+ if ((arg->flags & ARGPARSE_FLAG_VERBOSE) || arg->internal->verbose)
+ log_info (_("reading options from '%s'\n"),
+ arg->internal->confname);
+ arg->internal->state = STATE_read_sys;
+ arg->internal->in_sysconf = 1;
+ arg->r.ret_str = xtrystrdup (arg->internal->confname);
+ if (!arg->r.ret_str)
+ arg->r_opt = ARGPARSE_OUT_OF_CORE;
+ else
+ {
+ gpgrt_annotate_leaked_object (arg->r.ret_str);
+ arg->r_opt = ARGPARSE_CONFFILE;
+ arg->r_type = ARGPARSE_TYPE_STRING;
+ }
+ break;
+
+ case STATE_open_user:
+ if (arg->internal->explicit_confopt
+ && arg->internal->explicit_conffile)
+ {
+ /* An explict option to use a specific configuration file
+ * has been given - use that one. */
+ xfree (arg->internal->confname);
+ arg->internal->confname
+ = xtrystrdup (arg->internal->explicit_conffile);
+ if (!arg->internal->confname)
+ return (arg->r_opt = ARGPARSE_OUT_OF_CORE);
+ }
+ else if (arg->internal->explicit_confopt)
+ {
+ /* An explict option not to use a configuration file has
+ * been given - leap direct to command line reading. */
+ arg->internal->state = STATE_open_cmdline;
+ goto next_state;
+ }
+ else
+ {
+ /* Use the standard configure file. If it is a two part
+ * name take the second part. If it is the standard name
+ * and ARGPARSE_FLAG_USERVERS is set try versioned config
+ * files. */
+ const char *s;
+ char *nconf;
+
+ xfree (arg->internal->confname);
+ if ((s = is_twopartfname (confname)))
+ {
+ arg->internal->confname = make_filename_try (s + 1, NULL);
+ if (!arg->internal->confname)
+ return (arg->r_opt = ARGPARSE_OUT_OF_CORE);
+ }
+ else
+ {
+ arg->internal->confname = make_filename_try
+ (confdir.user? confdir.user : "~/.config", confname, NULL);
+ if (!arg->internal->confname)
+ return (arg->r_opt = ARGPARSE_OUT_OF_CORE);
+ if ((arg->flags & ARGPARSE_FLAG_USERVERS)
+ && (nconf = try_versioned_conffile (arg->internal->confname)))
+ {
+ xfree (arg->internal->confname);
+ arg->internal->confname = nconf;
+ }
+ }
+ }
+ arg->lineno = 0;
+ arg->internal->idx = 0;
+ arg->internal->verbose = 0;
+ arg->internal->stopped = 0;
+ arg->internal->inarg = 0;
+ arg->internal->in_sysconf = 0;
+ gpgrt_fclose (arg->internal->conffp);
+ arg->internal->conffp = gpgrt_fopen (arg->internal->confname, "r");
+ if (!arg->internal->conffp)
+ {
+ arg->internal->state = STATE_open_cmdline;
+ if (arg->internal->explicit_confopt)
+ {
+ log_error (_("option file '%s': %s\n"),
+ arg->internal->confname, strerror (errno));
+ return (arg->r_opt = ARGPARSE_NO_CONFFILE);
+ }
+ else
+ {
+ if ((arg->flags & ARGPARSE_FLAG_VERBOSE)
+ || arg->internal->verbose)
+ log_info (_("Note: no default option file '%s'\n"),
+ arg->internal->confname);
+ goto next_state;
+ }
+ }
+
+ if ((arg->flags & ARGPARSE_FLAG_VERBOSE) || arg->internal->verbose)
+ log_info (_("reading options from '%s'\n"),
+ arg->internal->confname);
+ arg->internal->state = STATE_read_user;
+ arg->r.ret_str = xtrystrdup (arg->internal->confname);
+ if (!arg->r.ret_str)
+ arg->r_opt = ARGPARSE_OUT_OF_CORE;
+ else
+ {
+ gpgrt_annotate_leaked_object (arg->r.ret_str);
+ arg->r_opt = ARGPARSE_CONFFILE;
+ arg->r_type = ARGPARSE_TYPE_STRING;
+ }
+ break;
+
+ case STATE_open_cmdline:
+ gpgrt_fclose (arg->internal->conffp);
+ arg->internal->conffp = NULL;
+ xfree (arg->internal->confname);
+ arg->internal->confname = NULL;
+ arg->internal->idx = 0;
+ arg->internal->verbose = 0;
+ arg->internal->stopped = 0;
+ arg->internal->inarg = 0;
+ arg->internal->in_sysconf = 0;
+ if (!arg->argc || !arg->argv || !*arg->argv)
+ {
+ /* No or empty argument vector - don't bother to parse things. */
+ arg->internal->state = STATE_finished;
+ goto next_state;
+ }
+ arg->r_opt = ARGPARSE_CONFFILE;
+ arg->r_type = ARGPARSE_TYPE_NONE;
+ arg->r.ret_str = NULL;
+ arg->internal->state = STATE_read_cmdline;
+ break;
+
+ case STATE_read_sys:
+ arg->r_opt = gnupg_argparse (arg->internal->conffp, arg, opts);
+ if (!arg->r_opt)
+ {
+ finish_read_sys (arg);
+ arg->internal->state = STATE_open_user;
+ goto next_state;
+ }
+ if ((arg->internal->opt_flags & ARGPARSE_OPT_CONFFILE))
+ goto next_state; /* Already handled - again. */
+ break;
+
+ case STATE_read_user:
+ arg->r_opt = gnupg_argparse (arg->internal->conffp, arg, opts);
+ if (!arg->r_opt)
+ {
+ arg->internal->state = STATE_open_cmdline;
+ goto next_state;
+ }
+ if ((arg->internal->opt_flags & ARGPARSE_OPT_CONFFILE))
+ goto next_state; /* Already handled - again. */
+ break;
+
+ case STATE_read_cmdline:
+ arg->r_opt = arg_parse (arg, opts, 1);
+ if (!arg->r_opt)
+ {
+ arg->internal->state = STATE_finished;
+ goto next_state;
+ }
+ if ((arg->internal->opt_flags & ARGPARSE_OPT_CONFFILE))
+ goto next_state; /* Already handled - again. */
+ break;
+
+ case STATE_finished:
+ arg->r_opt = 0;
+ break;
+ }
+
+ return arg->r_opt;
+}
+
+
+
+/* Given the list of options in ARG and a keyword, return the index of
+ * the long option matching KEYWORD. On error -1 is returned for not
+ * found or -2 for ambigious keyword. */
+static int
+find_long_option (gnupg_argparse_t *arg, const char *keyword)
+{
+ int i;
+ size_t n;
+ opttable_t *opts = arg->internal->opts;
+ unsigned int nopts = arg->internal->nopts;
+
+ /* Would be better if we can do a binary search, but it is not
+ * possible to reorder our option table because we would mess up our
+ * help strings. What we can do is: Build an option lookup table
+ * when this function is first invoked. The latter has already been
+ * done. */
+ if (!*keyword)
+ return -1;
+ for (i=0; i < nopts; i++ )
+ if (opts[i].long_opt && !strcmp (opts[i].long_opt, keyword))
+ return i;
+ /* Not found. See whether it is an abbreviation. Aliases may not
+ * be abbreviated, though. */
+ n = strlen (keyword);
+ for (i=0; i < nopts; i++)
+ {
+ if (opts[i].long_opt && !strncmp (opts[i].long_opt, keyword, n))
+ {
+ int j;
+ for (j=i+1; j < nopts; j++)
+ {
+ if (opts[j].long_opt
+ && !strncmp (opts[j].long_opt, keyword, n)
+ && !(opts[j].short_opt == opts[i].short_opt
+ && opts[j].flags == opts[i].flags ) )
+ return -2; /* Abbreviation is ambiguous. */
+ }
+ return i;
+ }
+ }
+ return -1; /* Not found. */
+}
+
+
+/* The option parser for command line options. */
+static int
+arg_parse (gnupg_argparse_t *arg, gnupg_opt_t *opts_orig, int no_init)
+{
+ int idx;
+ opttable_t *opts;
+ unsigned int nopts;
+ int argc;
+ char **argv;
+ char *s, *s2;
+ int i;
+
+ if (no_init)
+ ;
+ else if (initialize (arg, opts_orig, NULL))
+ return (arg->r_opt = ARGPARSE_OUT_OF_CORE);
+
+ opts = arg->internal->opts;
+ nopts = arg->internal->nopts;
+ argc = *arg->argc;
+ argv = *arg->argv;
+ idx = arg->internal->idx;
+
+ if (!idx && argc && !(arg->flags & ARGPARSE_FLAG_ARG0))
+ {
+ /* Skip the first argument. */
+ argc--; argv++; idx++;
+ }
+
+ next_one:
+ if (!argc || (s = *argv) == NULL)
+ {
+ /* No more args. */
+ arg->r_opt = 0;
+ goto leave; /* Ready. */
+ }
+
+ arg->internal->last = s;
+ arg->internal->opt_flags = 0;
+
+ if (arg->internal->stopped && (arg->flags & ARGPARSE_FLAG_ALL))
+ {
+ arg->r_opt = ARGPARSE_IS_ARG; /* Not an option but an argument. */
+ arg->r_type = ARGPARSE_TYPE_STRING;
+ arg->r.ret_str = s;
+ argc--; argv++; idx++; /* set to next one */
+ }
+ else if (arg->internal->stopped)
+ {
+ arg->r_opt = 0;
+ goto leave; /* Ready. */
+ }
+ else if ( *s == '-' && s[1] == '-' )
+ {
+ /* Long option. */
+ char *argpos;
+
+ arg->internal->inarg = 0;
+ if (!s[2] && !(arg->flags & ARGPARSE_FLAG_NOSTOP))
+ {
+ /* Stop option processing. */
+ arg->internal->stopped = 1;
+ arg->flags |= ARGPARSE_FLAG_STOP_SEEN;
+ argc--; argv++; idx++;
+ goto next_one;
+ }
+
+ argpos = strchr( s+2, '=' );
+ if ( argpos )
+ *argpos = 0;
+ i = find_long_option (arg, s+2);
+ if ( argpos )
+ *argpos = '=';
+
+ if (i > 0 && opts[i].short_opt == ARGPARSE_SHORTOPT_HELP)
+ {
+ show_help (opts, nopts, arg->flags);
+ my_exit (arg, 0);
+ }
+ else if (i > 0 && opts[i].short_opt == ARGPARSE_SHORTOPT_VERSION)
+ {
+ if (!(arg->flags & ARGPARSE_FLAG_NOVERSION))
+ {
+ show_version ();
+ my_exit (arg, 0);
+ }
+ }
+ else if (i > 0 && opts[i].short_opt == ARGPARSE_SHORTOPT_WARRANTY)
+ {
+ writestrings (0, strusage (16), "\n", NULL);
+ my_exit (arg, 0);
+ }
+ else if (i > 0 && opts[i].short_opt == ARGPARSE_SHORTOPT_DUMP_OPTTBL)
+ dump_option_table (arg);
+ else if (i > 0 && opts[i].short_opt == ARGPARSE_SHORTOPT_DUMP_OPTIONS)
+ {
+ for (i=0; i < nopts; i++ )
+ {
+ if (opts[i].long_opt && !(opts[i].flags & ARGPARSE_OPT_IGNORE))
+ writestrings (0, "--", opts[i].long_opt, "\n", NULL);
+ }
+ my_exit (arg, 0);
+ }
+
+ if ( i == -2 )
+ arg->r_opt = ARGPARSE_AMBIGUOUS_OPTION;
+ else if ( i == -1 )
+ {
+ arg->r_opt = ARGPARSE_INVALID_OPTION;
+ arg->r.ret_str = s+2;
+ }
+ else
+ arg->r_opt = opts[i].short_opt;
+
+ if ( i < 0 )
+ ;
+ else if ( (opts[i].flags & ARGPARSE_TYPE_MASK) )
+ {
+ if ( argpos )
+ {
+ s2 = argpos+1;
+ if ( !*s2 )
+ s2 = NULL;
+ }
+ else
+ s2 = argv[1];
+
+ if ( !s2 && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) )
+ {
+ arg->r_type = ARGPARSE_TYPE_NONE; /* Argument is optional. */
+ }
+ else if ( !s2 )
+ {
+ arg->r_opt = ARGPARSE_MISSING_ARG;
+ }
+ else if ( !argpos && *s2 == '-'
+ && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) )
+ {
+ /* The argument is optional and the next seems to be an
+ option. We do not check this possible option but
+ assume no argument */
+ arg->r_type = ARGPARSE_TYPE_NONE;
+ }
+ else
+ {
+ set_opt_arg (arg, opts[i].flags, s2);
+ if ( !argpos )
+ {
+ argc--; argv++; idx++; /* Skip one. */
+ }
+ }
+ }
+ else
+ {
+ /* Does not take an argument. */
+ if ( argpos )
+ arg->r_type = ARGPARSE_UNEXPECTED_ARG;
+ else
+ {
+ arg->internal->opt_flags = opts[i].flags;
+ arg->r_type = ARGPARSE_TYPE_NONE;
+ }
+ }
+ argc--; argv++; idx++; /* Set to next one. */
+ }
+ else if ( (*s == '-' && s[1]) || arg->internal->inarg )
+ {
+ /* Short option. */
+ int dash_kludge = 0;
+
+ i = 0;
+ if ( !arg->internal->inarg )
+ {
+ arg->internal->inarg++;
+ if ( (arg->flags & ARGPARSE_FLAG_ONEDASH) )
+ {
+ for (i=0; i < nopts; i++ )
+ if ( opts[i].long_opt && !strcmp (opts[i].long_opt, s+1))
+ {
+ dash_kludge = 1;
+ break;
+ }
+ }
+ }
+ s += arg->internal->inarg;
+
+ if (!dash_kludge )
+ {
+ for (i=0; i < nopts; i++ )
+ if ( opts[i].short_opt == *s )
+ break;
+ }
+
+ if ( !opts[i].short_opt && ( *s == 'h' || *s == '?' ) )
+ {
+ show_help (opts, nopts, arg->flags);
+ my_exit (arg, 0);
+ }
+
+ arg->r_opt = opts[i].short_opt;
+ if (!opts[i].short_opt )
+ {
+ arg->r_opt = (opts[i].flags & ARGPARSE_OPT_COMMAND)?
+ ARGPARSE_INVALID_COMMAND:ARGPARSE_INVALID_OPTION;
+ arg->internal->inarg++; /* Point to the next arg. */
+ arg->r.ret_str = s;
+ }
+ else if ( (opts[i].flags & ARGPARSE_TYPE_MASK) )
+ {
+ if ( s[1] && !dash_kludge )
+ {
+ s2 = s+1;
+ set_opt_arg (arg, opts[i].flags, s2);
+ }
+ else
+ {
+ s2 = argv[1];
+ if ( !s2 && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) )
+ {
+ arg->r_type = ARGPARSE_TYPE_NONE;
+ arg->internal->opt_flags = opts[i].flags;
+ }
+ else if ( !s2 )
+ {
+ arg->r_opt = ARGPARSE_MISSING_ARG;
+ }
+ else if ( *s2 == '-' && s2[1]
+ && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) )
+ {
+ /* The argument is optional and the next seems to
+ be an option. We do not check this possible
+ option but assume no argument. */
+ arg->r_type = ARGPARSE_TYPE_NONE;
+ arg->internal->opt_flags = opts[i].flags;
+ }
+ else
+ {
+ set_opt_arg (arg, opts[i].flags, s2);
+ argc--; argv++; idx++; /* Skip one. */
+ }
+ }
+ s = "x"; /* This is so that !s[1] yields false. */
+ }
+ else
+ {
+ /* Does not take an argument. */
+ arg->r_type = ARGPARSE_TYPE_NONE;
+ arg->internal->opt_flags = opts[i].flags;
+ arg->internal->inarg++; /* Point to the next arg. */
+ }
+ if ( !s[1] || dash_kludge )
+ {
+ /* No more concatenated short options. */
+ arg->internal->inarg = 0;
+ argc--; argv++; idx++;
+ }
+ }
+ else if ( arg->flags & ARGPARSE_FLAG_MIXED )
+ {
+ arg->r_opt = ARGPARSE_IS_ARG;
+ arg->r_type = ARGPARSE_TYPE_STRING;
+ arg->r.ret_str = s;
+ argc--; argv++; idx++; /* Set to next one. */
+ }
+ else
+ {
+ arg->internal->stopped = 1; /* Stop option processing. */
+ goto next_one;
+ }
+
+ if (arg->r_opt > 0 && i >= 0 && i < nopts
+ && ((opts[i].ignore && opts[i].explicit_ignore) || opts[i].forced))
+ {
+
+ if ((arg->flags & ARGPARSE_FLAG_WITHATTR))
+ {
+ if (opts[i].ignore)
+ arg->r_type |= ARGPARSE_ATTR_IGNORE;
+ if (opts[i].forced)
+ arg->r_type |= ARGPARSE_ATTR_FORCE;
+ arg->r_type |= ARGPARSE_OPT_IGNORE;
+ }
+ else
+ {
+ log_info (_("Note: ignoring option \"--%s\""
+ " due to global config\n"),
+ opts[i].long_opt);
+ goto next_one; /* Skip ignored/forced option. */
+ }
+ }
+
+ leave:
+ *arg->argc = argc;
+ *arg->argv = argv;
+ arg->internal->idx = idx;
+ return arg->r_opt;
+}
+
+
+
+/* Returns: -1 on error, 0 for an integer type and 1 for a non integer
+ type argument. */
+static int
+set_opt_arg (gnupg_argparse_t *arg, unsigned flags, char *s)
+{
+ int base = (flags & ARGPARSE_OPT_PREFIX)? 0 : 10;
+ long l;
+
+ arg->internal->opt_flags = flags;
+ switch ( (arg->r_type = (flags & ARGPARSE_TYPE_MASK)) )
+ {
+ case ARGPARSE_TYPE_LONG:
+ case ARGPARSE_TYPE_INT:
+ errno = 0;
+ l = strtol (s, NULL, base);
+ if ((l == LONG_MIN || l == LONG_MAX) && errno == ERANGE)
+ {
+ arg->r_opt = ARGPARSE_INVALID_ARG;
+ return -1;
+ }
+ if (arg->r_type == ARGPARSE_TYPE_LONG)
+ arg->r.ret_long = l;
+ else if ( (l < 0 && l < INT_MIN) || l > INT_MAX )
+ {
+ arg->r_opt = ARGPARSE_INVALID_ARG;
+ return -1;
+ }
+ else
+ arg->r.ret_int = (int)l;
+ return 0;
+
+ case ARGPARSE_TYPE_ULONG:
+ while (isascii (*s) && isspace(*s))
+ s++;
+ if (*s == '-')
+ {
+ arg->r.ret_ulong = 0;
+ arg->r_opt = ARGPARSE_INVALID_ARG;
+ return -1;
+ }
+ errno = 0;
+ arg->r.ret_ulong = strtoul (s, NULL, base);
+ if (arg->r.ret_ulong == ULONG_MAX && errno == ERANGE)
+ {
+ arg->r_opt = ARGPARSE_INVALID_ARG;
+ return -1;
+ }
+ return 0;
+
+ case ARGPARSE_TYPE_STRING:
+ default:
+ arg->r.ret_str = s;
+ return 1;
+ }
+}
+
+
+/* Return the length of the option O. This needs to consider the
+ * description as well as the option name. */
+static size_t
+long_opt_strlen (opttable_t *o)
+{
+ size_t n = strlen (o->long_opt);
+
+ if ( o->description && *o->description == '|' )
+ {
+ const char *s;
+ int is_utf8 = is_native_utf8 ();
+
+ s=o->description+1;
+ if ( *s != '=' )
+ n++;
+ /* For a (mostly) correct length calculation we exclude
+ * continuation bytes (10xxxxxx) if we are on a native utf8
+ * terminal. */
+ for (; *s && *s != '|'; s++ )
+ if ( is_utf8 && (*s&0xc0) != 0x80 )
+ n++;
+ }
+ return n;
+}
+
+
+/* Qsort compare for show_help. */
+static int
+cmp_ordtbl (const void *a_v, const void *b_v)
+{
+ const unsigned short *a = a_v;
+ const unsigned short *b = b_v;
+
+ return *a - *b;
+}
+
+
+/****************
+ * Print formatted help. The description string has some special
+ * meanings:
+ * - A description string which is "@" suppresses help output for
+ * this option
+ * - a description which starts with a '@' and is followed by
+ * any other characters is printed as is; this may be used for examples
+ * and such. This is a legacy methiod, moder codes uses the flags
+ * ARGPARSE_OPT_VERBATIM or ARGPARSE_OPT_HEADER.
+ * - A description which starts with a '|' outputs the string between this
+ * bar and the next one as arguments of the long option.
+ */
+static void
+show_help (opttable_t *opts, unsigned int nopts, unsigned int flags)
+{
+ const char *s;
+ char tmp[2];
+ unsigned int *ordtbl = NULL;
+
+ show_version ();
+ writestrings (0, "\n", NULL);
+ s = strusage (42);
+ if (s && *s == '1')
+ {
+ s = strusage (40);
+ writestrings (1, s, NULL);
+ if (*s && s[strlen(s)] != '\n')
+ writestrings (1, "\n", NULL);
+ }
+ s = strusage(41);
+ writestrings (0, s, "\n", NULL);
+ if ( nopts )
+ {
+ /* Auto format the option description. */
+ int i,j,indent;
+ const char *last_header = NULL;
+
+ ordtbl = xtrycalloc (nopts, sizeof *ordtbl);
+ if (!ordtbl)
+ {
+ writestrings (1, "\nOoops: Out of memory whilst printing the help.\n",
+ NULL);
+ goto leave;
+ }
+
+ /* Get max. length of long options. */
+ for (i=indent=0; i < nopts; i++ )
+ {
+ if ( opts[i].long_opt )
+ if ( !opts[i].description || *opts[i].description != '@' )
+ if ( (j=long_opt_strlen(opts+i)) > indent && j < 35 )
+ indent = j;
+ ordtbl[i] = opts[i].ordinal;
+ }
+
+ qsort (ordtbl, nopts, sizeof *ordtbl, cmp_ordtbl);
+
+ /* The first option needs to have a description; if not do not
+ * print the help at all. */
+ if (!opts[ordtbl[0]].description)
+ goto leave;
+
+ /* Example: " -v, --verbose Viele Sachen ausgeben" */
+ indent += 10;
+ if ( *opts[ordtbl[0]].description != '@'
+ && !(opts[ordtbl[0]].flags
+ & (ARGPARSE_OPT_VERBATIM|ARGPARSE_OPT_HEADER)))
+ writestrings (0, "Options:", "\n", NULL);
+ for (i=0; i < nopts; i++ )
+ {
+ s = map_fixed_string (_( opts[ordtbl[i]].description ));
+ if ( s && *s== '@' && !s[1] ) /* Hide this line. */
+ continue;
+ if ( s && (opts[ordtbl[i]].flags & ARGPARSE_OPT_HEADER))
+ {
+ /* We delay printing until we have found one real output
+ * line. This avoids having a header above an empty
+ * section. */
+ last_header = s;
+ continue;
+ }
+ if (last_header)
+ {
+ if (*last_header)
+ writestrings (0, "\n", last_header, ":\n", NULL);
+ last_header = NULL;
+ }
+ if ( s && (opts[ordtbl[i]].flags & ARGPARSE_OPT_VERBATIM))
+ {
+ writestrings (0, s, NULL);
+ continue;
+ }
+ if ( s && *s == '@' ) /* Unindented legacy comment only line. */
+ {
+ for (s++; *s; s++ )
+ {
+ if ( *s == '\n' )
+ {
+ if( s[1] )
+ writestrings (0, "\n", NULL);
+ }
+ else
+ {
+ tmp[0] = *s;
+ tmp[1] = 0;
+ writestrings (0, tmp, NULL);
+ }
+ }
+ writestrings (0, "\n", NULL);
+ continue;
+ }
+
+ j = 3;
+ if ( opts[ordtbl[i]].short_opt < 256 )
+ {
+ tmp[0] = opts[ordtbl[i]].short_opt;
+ tmp[1] = 0;
+ writestrings (0, " -", tmp, NULL );
+ if ( !opts[ordtbl[i]].long_opt )
+ {
+ if (s && *s == '|' )
+ {
+ writestrings (0, " ", NULL); j++;
+ for (s++ ; *s && *s != '|'; s++, j++ )
+ {
+ tmp[0] = *s;
+ tmp[1] = 0;
+ writestrings (0, tmp, NULL);
+ }
+ if ( *s )
+ s++;
+ }
+ }
+ }
+ else
+ writestrings (0, " ", NULL);
+ if ( opts[ordtbl[i]].long_opt )
+ {
+ tmp[0] = opts[ordtbl[i]].short_opt < 256?',':' ';
+ tmp[1] = 0;
+ j += writestrings (0, tmp, " --", opts[ordtbl[i]].long_opt, NULL);
+ if (s && *s == '|' )
+ {
+ if ( *++s != '=' )
+ {
+ writestrings (0, " ", NULL);
+ j++;
+ }
+ for ( ; *s && *s != '|'; s++, j++ )
+ {
+ tmp[0] = *s;
+ tmp[1] = 0;
+ writestrings (0, tmp, NULL);
+ }
+ if ( *s )
+ s++;
+ }
+ writestrings (0, " ", NULL);
+ j += 3;
+ }
+ for (;j < indent; j++ )
+ writestrings (0, " ", NULL);
+ if ( s )
+ {
+ if ( *s && j > indent )
+ {
+ writestrings (0, "\n", NULL);
+ for (j=0;j < indent; j++ )
+ writestrings (0, " ", NULL);
+ }
+ for (; *s; s++ )
+ {
+ if ( *s == '\n' )
+ {
+ if ( s[1] )
+ {
+ writestrings (0, "\n", NULL);
+ for (j=0; j < indent; j++ )
+ writestrings (0, " ", NULL);
+ }
+ }
+ else
+ {
+ tmp[0] = *s;
+ tmp[1] = 0;
+ writestrings (0, tmp, NULL);
+ }
+ }
+ }
+ writestrings (0, "\n", NULL);
+ }
+ if ( (flags & ARGPARSE_FLAG_ONEDASH) )
+ writestrings (0, "\n(A single dash may be used "
+ "instead of the double ones)\n", NULL);
+ }
+ if ( (s=strusage(19)) )
+ {
+ writestrings (0, "\n", NULL);
+ writestrings (0, s, NULL);
+ }
+
+ leave:
+ flushstrings (0);
+ xfree (ordtbl);
+}
+
+
+static void
+show_version ()
+{
+ const char *s;
+ int i;
+
+ /* Version line. */
+ writestrings (0, strusage (11), NULL);
+ if ((s=strusage (12)))
+ writestrings (0, " (", s, ")", NULL);
+ writestrings (0, " ", strusage (13), "\n", NULL);
+ /* Additional version lines. */
+ for (i=20; i < 30; i++)
+ if ((s=strusage (i)))
+ writestrings (0, s, "\n", NULL);
+ /* Copyright string. */
+ if ((s=strusage (14)))
+ writestrings (0, s, "\n", NULL);
+ /* Licence string. */
+ if( (s=strusage (10)) )
+ writestrings (0, s, "\n", NULL);
+ /* Copying conditions. */
+ if ( (s=strusage(15)) )
+ writestrings (0, s, NULL);
+ /* Thanks. */
+ if ((s=strusage(18)))
+ writestrings (0, s, NULL);
+ /* Additional program info. */
+ for (i=30; i < 40; i++ )
+ if ( (s=strusage (i)) )
+ writestrings (0, s, NULL);
+ flushstrings (0);
+}
+
+
+/* Print the table of options with flags etc. */
+static void
+dump_option_table (gnupg_argparse_t *arg)
+{
+ opttable_t *opts;
+ unsigned int nopts;
+ const char *s;
+ char tmp[50];
+ unsigned int *ordtbl = NULL;
+ int i;
+
+ opts = arg->internal->opts;
+ nopts = arg->internal->nopts;
+ if (!nopts)
+ return;
+
+ ordtbl = xtrycalloc (nopts, sizeof *ordtbl);
+ if (!ordtbl)
+ {
+ writestrings (1, "\nOoops: Out of memory whilst dumping the table.\n",
+ NULL);
+ flushstrings (1);
+ my_exit (arg, 2);
+ }
+ for (i=0; i < nopts; i++ )
+ ordtbl[i] = opts[i].ordinal;
+ qsort (ordtbl, nopts, sizeof *ordtbl, cmp_ordtbl);
+ for (i=0; i < nopts; i++ )
+ {
+ if (!opts[ordtbl[i]].long_opt)
+ continue;
+ writestrings (0, opts[ordtbl[i]].long_opt, ":", NULL);
+ snprintf (tmp, sizeof tmp, "%u:%u:",
+ opts[ordtbl[i]].short_opt,
+ opts[ordtbl[i]].flags);
+ writestrings (0, tmp, NULL);
+ s = opts[ordtbl[i]].description;
+ if (s)
+ {
+ for (; *s; s++)
+ {
+ if (*s == '%' || *s == ':' || *s == '\n')
+ snprintf (tmp, sizeof tmp, "%%%02X", *s);
+ else
+ {
+ tmp[0] = *s;
+ tmp[1] = 0;
+ }
+ writestrings (0, tmp, NULL);
+ }
+ }
+ writestrings (0, ":\n", NULL);
+ }
+
+ flushstrings (0);
+ xfree (ordtbl);
+ my_exit (arg, 0);
+}
+
+
+
+/* Level
+ * 0: Print copyright string to stderr
+ * 1: Print a short usage hint to stderr and terminate
+ * 2: Print a long usage hint to stdout and terminate
+ * 8: Return NULL for UTF-8 or string with the native charset.
+ * 9: Return the SPDX License tag.
+ * 10: Return license info string
+ * 11: Return the name of the program
+ * 12: Return optional name of package which includes this program.
+ * 13: version string
+ * 14: copyright string
+ * 15: Short copying conditions (with LFs)
+ * 16: Long copying conditions (with LFs)
+ * 17: Optional printable OS name
+ * 18: Optional thanks list (with LFs)
+ * 19: Bug report info
+ *20..29: Additional lib version strings.
+ *30..39: Additional program info (with LFs)
+ * 40: short usage note (with LF)
+ * 41: long usage note (with LF)
+ * 42: Flag string:
+ * First char is '1':
+ * The short usage notes needs to be printed
+ * before the long usage note.
+ */
+const char *
+strusage( int level )
+{
+ const char *p = strusage_handler? strusage_handler(level) : NULL;
+ const char *tmp;
+
+ if ( p )
+ return map_static_macro_string (p);
+
+ switch ( level )
+ {
+
+ case 8: break; /* Default to utf-8. */
+ case 9: p = "GPL-3.0-or-later"; break;
+ case 10:
+ tmp = strusage (9);
+ if (tmp && !strcmp (tmp, "LGPL-2.1-or-later"))
+ p = ("License GNU LGPL-2.1-or-later <https://gnu.org/licenses/>");
+ else /* Default to GPLv3+. */
+ p =("License GNU GPL-3.0-or-later <https://gnu.org/licenses/gpl.html>");
+ break;
+ case 11: p = "foo"; break;
+ case 13: p = "0.0"; break;
+ case 14: p = GNUPG_DEF_COPYRIGHT_LINE; break;
+ case 15: p =
+"This is free software: you are free to change and redistribute it.\n"
+"There is NO WARRANTY, to the extent permitted by law.\n";
+ break;
+ case 16:
+ tmp = strusage (9);
+ if (tmp && !strcmp (tmp, "LGPL-2.1-or-later"))
+ p =
+"This is free software; you can redistribute it and/or modify\n"
+"it under the terms of the GNU Lesser General Public License as\n"
+"published by the Free Software Foundation; either version 2.1 of\n"
+"the License, or (at your option) any later version.\n\n"
+"It is distributed in the hope that it will be useful,\n"
+"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+"GNU Lesser General Public License for more details.\n\n"
+"You should have received a copy of the GNU Lesser General Public License\n"
+"along with this software. If not, see <https://gnu.org/licenses/>.\n";
+ else /* Default */
+ p =
+"This is free software; you can redistribute it and/or modify\n"
+"it under the terms of the GNU General Public License as published by\n"
+"the Free Software Foundation; either version 3 of the License, or\n"
+"(at your option) any later version.\n\n"
+"It is distributed in the hope that it will be useful,\n"
+"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+"GNU General Public License for more details.\n\n"
+"You should have received a copy of the GNU General Public License\n"
+"along with this software. If not, see <https://gnu.org/licenses/>.\n";
+ break;
+ case 40: /* short and long usage */
+ case 41: p = ""; break;
+ }
+
+ return p;
+}
+
+
+/* Set the usage handler. This function is basically a constructor. */
+void
+set_strusage ( const char *(*f)( int ) )
+{
+ strusage_handler = f;
+}
+
+#endif /* USE_INTERNAL_ARGPARSE */
+
+
+void
+usage (int level)
+{
+ const char *p;
+
+ if (!level)
+ {
+ writestrings (1, strusage(11), " ", strusage(13), "; ",
+ strusage (14), "\n", NULL);
+ flushstrings (1);
+ }
+ else if (level == 1)
+ {
+ p = strusage (40);
+ writestrings (1, p, NULL);
+ if (*p && p[strlen(p)] != '\n')
+ writestrings (1, "\n", NULL);
+ exit (2);
+ }
+ else if (level == 2)
+ {
+ p = strusage (42);
+ if (p && *p == '1')
+ {
+ p = strusage (40);
+ writestrings (1, p, NULL);
+ if (*p && p[strlen(p)] != '\n')
+ writestrings (1, "\n", NULL);
+ }
+ writestrings (0, strusage(41), "\n", NULL);
+ exit (0);
+ }
+}
diff --git a/common/argparse.h b/common/argparse.h
new file mode 100644
index 0000000..282aaea
--- /dev/null
+++ b/common/argparse.h
@@ -0,0 +1,281 @@
+/* argparse.h - Argument parser for option handling.
+ * Copyright (C) 1998,1999,2000,2001,2006 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute and/or modify this
+ * part of GnuPG under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * 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 copies of the GNU General Public License
+ * and the GNU Lesser General Public License along with this program;
+ * if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_COMMON_ARGPARSE_H
+#define GNUPG_COMMON_ARGPARSE_H
+
+#include <stdio.h>
+#include <gpg-error.h>
+
+#if GPGRT_VERSION_NUMBER < 0x012600 /* 1.38 */
+
+#define USE_INTERNAL_ARGPARSE 1
+
+/* We use a copy of the code from the new gpgrt parser. */
+
+struct _argparse_internal_s;
+typedef struct
+{
+ int *argc; /* Pointer to ARGC (value subject to change). */
+ char ***argv; /* Pointer to ARGV (value subject to change). */
+ unsigned int flags; /* Global flags. May be set prior to calling the
+ parser. The parser may change the value. */
+ int err; /* Print error description for last option.
+ Either 0, ARGPARSE_PRINT_WARNING or
+ ARGPARSE_PRINT_ERROR. */
+ unsigned int lineno;/* The current line number. */
+ int r_opt; /* Returns option code. */
+ int r_type; /* Returns type of option value. */
+ union {
+ int ret_int;
+ long ret_long;
+ unsigned long ret_ulong;
+ char *ret_str;
+ } r; /* Return values */
+
+ struct _argparse_internal_s *internal;
+} gnupg_argparse_t;
+
+
+typedef struct
+{
+ int short_opt;
+ const char *long_opt;
+ unsigned int flags;
+ const char *description; /* Optional option description. */
+} gnupg_opt_t;
+
+
+typedef gnupg_argparse_t ARGPARSE_ARGS;
+typedef gnupg_opt_t ARGPARSE_OPTS;
+
+/* Short options. */
+#define ARGPARSE_SHORTOPT_HELP 32768
+#define ARGPARSE_SHORTOPT_VERSION 32769
+#define ARGPARSE_SHORTOPT_WARRANTY 32770
+#define ARGPARSE_SHORTOPT_DUMP_OPTIONS 32771
+
+
+/* Global flags (ARGPARSE_ARGS). */
+#define ARGPARSE_FLAG_KEEP 1 /* Do not remove options form argv. */
+#define ARGPARSE_FLAG_ALL 2 /* Do not stop at last option but return
+ remaining args with R_OPT set to -1. */
+#define ARGPARSE_FLAG_MIXED 4 /* Assume options and args are mixed. */
+#define ARGPARSE_FLAG_NOSTOP 8 /* Do not stop processing at "--". */
+#define ARGPARSE_FLAG_ARG0 16 /* Do not skip the first arg. */
+#define ARGPARSE_FLAG_ONEDASH 32 /* Allow long options with one dash. */
+#define ARGPARSE_FLAG_NOVERSION 64 /* No output for "--version". */
+#define ARGPARSE_FLAG_RESET 128 /* Request to reset the internal state. */
+#define ARGPARSE_FLAG_STOP_SEEN 256 /* Set to true if a "--" has been seen. */
+#define ARGPARSE_FLAG_NOLINENO 512 /* Do not zero the lineno field. */
+#define ARGPARSE_FLAG_SYS 1024 /* Use system config file. */
+#define ARGPARSE_FLAG_USER 2048 /* Use user config file. */
+#define ARGPARSE_FLAG_VERBOSE 4096 /* Print additional argparser info. */
+#define ARGPARSE_FLAG_USERVERS 8192 /* Try version-ed user config files. */
+#define ARGPARSE_FLAG_WITHATTR 16384 /* Return attribute bits. */
+
+/* Flags for each option (ARGPARSE_OPTS). The type code may be
+ ORed with the OPT flags. */
+#define ARGPARSE_TYPE_NONE 0 /* Does not take an argument. */
+#define ARGPARSE_TYPE_INT 1 /* Takes an int argument. */
+#define ARGPARSE_TYPE_STRING 2 /* Takes a string argument. */
+#define ARGPARSE_TYPE_LONG 3 /* Takes a long argument. */
+#define ARGPARSE_TYPE_ULONG 4 /* Takes an unsigned long argument. */
+#define ARGPARSE_OPT_OPTIONAL (1<<3) /* Argument is optional. */
+#define ARGPARSE_OPT_PREFIX (1<<4) /* Allow 0x etc. prefixed values. */
+#define ARGPARSE_OPT_IGNORE (1<<6) /* Ignore command or option. */
+#define ARGPARSE_OPT_COMMAND (1<<7) /* The argument is a command. */
+#define ARGPARSE_OPT_CONFFILE (1<<8) /* The value is a conffile. */
+#define ARGPARSE_OPT_HEADER (1<<9) /* The value is printed as a header. */
+#define ARGPARSE_OPT_VERBATIM (1<<10)/* The value is printed verbatim. */
+#define ARGPARSE_ATTR_FORCE (1<<14)/* Attribute force is set. */
+#define ARGPARSE_ATTR_IGNORE (1<<15)/* Attribute ignore is set. */
+
+#define ARGPARSE_TYPE_MASK 7 /* Mask for the type values (internal). */
+
+/* A set of macros to make option definitions easier to read. */
+#define ARGPARSE_x(s,l,t,f,d) \
+ { (s), (l), ARGPARSE_TYPE_ ## t | (f), (d) }
+
+#define ARGPARSE_s(s,l,t,d) \
+ { (s), (l), ARGPARSE_TYPE_ ## t, (d) }
+#define ARGPARSE_s_n(s,l,d) \
+ { (s), (l), ARGPARSE_TYPE_NONE, (d) }
+#define ARGPARSE_s_i(s,l,d) \
+ { (s), (l), ARGPARSE_TYPE_INT, (d) }
+#define ARGPARSE_s_s(s,l,d) \
+ { (s), (l), ARGPARSE_TYPE_STRING, (d) }
+#define ARGPARSE_s_l(s,l,d) \
+ { (s), (l), ARGPARSE_TYPE_LONG, (d) }
+#define ARGPARSE_s_u(s,l,d) \
+ { (s), (l), ARGPARSE_TYPE_ULONG, (d) }
+
+#define ARGPARSE_o(s,l,t,d) \
+ { (s), (l), (ARGPARSE_TYPE_ ## t | ARGPARSE_OPT_OPTIONAL), (d) }
+#define ARGPARSE_o_n(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_NONE | ARGPARSE_OPT_OPTIONAL), (d) }
+#define ARGPARSE_o_i(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_INT | ARGPARSE_OPT_OPTIONAL), (d) }
+#define ARGPARSE_o_s(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_STRING | ARGPARSE_OPT_OPTIONAL), (d) }
+#define ARGPARSE_o_l(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_LONG | ARGPARSE_OPT_OPTIONAL), (d) }
+#define ARGPARSE_o_u(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_ULONG | ARGPARSE_OPT_OPTIONAL), (d) }
+
+#define ARGPARSE_p(s,l,t,d) \
+ { (s), (l), (ARGPARSE_TYPE_ ## t | ARGPARSE_OPT_PREFIX), (d) }
+#define ARGPARSE_p_n(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_NONE | ARGPARSE_OPT_PREFIX), (d) }
+#define ARGPARSE_p_i(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_INT | ARGPARSE_OPT_PREFIX), (d) }
+#define ARGPARSE_p_s(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_STRING | ARGPARSE_OPT_PREFIX), (d) }
+#define ARGPARSE_p_l(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_LONG | ARGPARSE_OPT_PREFIX), (d) }
+#define ARGPARSE_p_u(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_ULONG | ARGPARSE_OPT_PREFIX), (d) }
+
+#define ARGPARSE_op(s,l,t,d) \
+ { (s), (l), (ARGPARSE_TYPE_ ## t \
+ | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) }
+#define ARGPARSE_op_n(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_NONE \
+ | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) }
+#define ARGPARSE_op_i(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_INT \
+ | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) }
+#define ARGPARSE_op_s(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_STRING \
+ | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) }
+#define ARGPARSE_op_l(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_LONG \
+ | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) }
+#define ARGPARSE_op_u(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_ULONG \
+ | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) }
+
+#define ARGPARSE_c(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_NONE | ARGPARSE_OPT_COMMAND), (d) }
+
+#define ARGPARSE_conffile(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_STRING|ARGPARSE_OPT_CONFFILE), (d) }
+
+#define ARGPARSE_noconffile(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_NONE|ARGPARSE_OPT_CONFFILE), (d) }
+
+#define ARGPARSE_ignore(s,l) \
+ { (s), (l), (ARGPARSE_OPT_IGNORE), "@" }
+
+#define ARGPARSE_group(s,d) \
+ { (s), NULL, 0, (d) }
+
+/* Verbatim print the string D in the help output. It does not make
+ * use of the "@" hack as ARGPARSE_group does. */
+#define ARGPARSE_verbatim(d) \
+ { 1, NULL, (ARGPARSE_OPT_VERBATIM), (d) }
+
+/* Same as ARGPARSE_verbatim but also print a colon and a LF. N can
+ * be used give a symbolic name to the header. Nothing is printed if
+ * D is the empty string. */
+#define ARGPARSE_header(n,d) \
+ { 1, (n), (ARGPARSE_OPT_HEADER), (d) }
+
+/* Mark the end of the list (mandatory). */
+#define ARGPARSE_end() \
+ { 0, NULL, 0, NULL }
+
+
+/* Other constants. */
+#define ARGPARSE_PRINT_WARNING 1
+#define ARGPARSE_PRINT_ERROR 2
+
+
+/* Error values. */
+#define ARGPARSE_IS_ARG (-1)
+#define ARGPARSE_INVALID_OPTION (-2)
+#define ARGPARSE_MISSING_ARG (-3)
+#define ARGPARSE_KEYWORD_TOO_LONG (-4)
+#define ARGPARSE_READ_ERROR (-5)
+#define ARGPARSE_UNEXPECTED_ARG (-6)
+#define ARGPARSE_INVALID_COMMAND (-7)
+#define ARGPARSE_AMBIGUOUS_OPTION (-8)
+#define ARGPARSE_AMBIGUOUS_COMMAND (-9)
+#define ARGPARSE_INVALID_ALIAS (-10)
+#define ARGPARSE_OUT_OF_CORE (-11)
+#define ARGPARSE_INVALID_ARG (-12)
+#define ARGPARSE_PERMISSION_ERROR (-13)
+#define ARGPARSE_NO_CONFFILE (-14)
+#define ARGPARSE_CONFFILE (-15)
+#define ARGPARSE_INVALID_META (-16)
+#define ARGPARSE_UNKNOWN_META (-17)
+#define ARGPARSE_UNEXPECTED_META (-18)
+
+/* Values used for gnupg_set_confdir. */
+#define GNUPG_CONFDIR_USER 1 /* The user's configuration dir. */
+#define GNUPG_CONFDIR_SYS 2 /* The systems's configuration dir. */
+
+/* Take care: gpgrt_argparse keeps state in ARG and requires that
+ * either ARGPARSE_FLAG_RESET is used after OPTS has been changed or
+ * gpgrt_argparse (NULL, ARG, NULL) is called first. */
+int gnupg_argparse (gpgrt_stream_t fp,
+ gnupg_argparse_t *arg, gnupg_opt_t *opts);
+int gnupg_argparser (gnupg_argparse_t *arg, gnupg_opt_t *opts,
+ const char *confname);
+
+const char *strusage (int level);
+void set_strusage (const char *(*f)( int ));
+void gnupg_set_usage_outfnc (int (*f)(int, const char *));
+void gnupg_set_fixed_string_mapper (const char *(*f)(const char*));
+void gnupg_set_confdir (int what, const char *name);
+
+#else /* !USE_INTERNAL_ARGPARSE */
+
+#define GNUPG_CONFDIR_USER GPGRT_CONFDIR_USER
+#define GNUPG_CONFDIR_SYS GPGRT_CONFDIR_SYS
+
+typedef gpgrt_argparse_t gnupg_argparse_t;
+typedef gpgrt_opt_t gnupg_opt_t;
+typedef gpgrt_argparse_t ARGPARSE_ARGS;
+typedef gpgrt_opt_t ARGPARSE_OPTS;
+
+#define gnupg_argparse(a,b,c) gpgrt_argparse ((a),(b),(c))
+#define gnupg_argparser(a,b,c) gpgrt_argparser ((a),(b),(c))
+#define strusage(a) gpgrt_strusage (a)
+#define set_strusage(a) gpgrt_set_strusage (a)
+#define gnupg_set_usage_outfnc(a) gpgrt_set_usage_outfnc ((a))
+#define gnupg_set_fixed_string_mapper(a) gpgrt_set_fixed_string_mapper ((a))
+#define gnupg_set_confdir(a,b) gpgrt_set_confdir ((a),(b))
+
+#endif /* !USE_INTERNAL_ARGPARSE */
+
+void usage (int level);
+
+#endif /*GNUPG_COMMON_ARGPARSE_H*/
diff --git a/common/asshelp.c b/common/asshelp.c
new file mode 100644
index 0000000..d87017e
--- /dev/null
+++ b/common/asshelp.c
@@ -0,0 +1,685 @@
+/* asshelp.c - Helper functions for Assuan
+ * Copyright (C) 2002, 2004, 2007, 2009, 2010 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#ifdef HAVE_LOCALE_H
+#include <locale.h>
+#endif
+
+#include "i18n.h"
+#include "util.h"
+#include "exechelp.h"
+#include "sysutils.h"
+#include "status.h"
+#include "membuf.h"
+#include "asshelp.h"
+
+/* The type we use for lock_agent_spawning. */
+#ifdef HAVE_W32_SYSTEM
+# define lock_spawn_t HANDLE
+#else
+# define lock_spawn_t dotlock_t
+#endif
+
+/* The time we wait until the agent or the dirmngr are ready for
+ operation after we started them before giving up. */
+#ifdef HAVE_W32CE_SYSTEM
+# define SECS_TO_WAIT_FOR_AGENT 30
+# define SECS_TO_WAIT_FOR_DIRMNGR 30
+#else
+# define SECS_TO_WAIT_FOR_AGENT 5
+# define SECS_TO_WAIT_FOR_DIRMNGR 5
+#endif
+
+/* A bitfield that specifies the assuan categories to log. This is
+ identical to the default log handler of libassuan. We need to do
+ it ourselves because we use a custom log handler and want to use
+ the same assuan variables to select the categories to log. */
+static int log_cats;
+#define TEST_LOG_CAT(x) (!! (log_cats & (1 << (x - 1))))
+
+/* The assuan log monitor used to temporary inhibit log messages from
+ * assuan. */
+static int (*my_log_monitor) (assuan_context_t ctx,
+ unsigned int cat,
+ const char *msg);
+
+
+static int
+my_libassuan_log_handler (assuan_context_t ctx, void *hook,
+ unsigned int cat, const char *msg)
+{
+ unsigned int dbgval;
+
+ if (! TEST_LOG_CAT (cat))
+ return 0;
+
+ dbgval = hook? *(unsigned int*)hook : 0;
+ if (!(dbgval & 1024))
+ return 0; /* Assuan debugging is not enabled. */
+
+ if (ctx && my_log_monitor && !my_log_monitor (ctx, cat, msg))
+ return 0; /* Temporary disabled. */
+
+ if (msg)
+ log_string (GPGRT_LOG_DEBUG, msg);
+
+ return 1;
+}
+
+
+/* Setup libassuan to use our own logging functions. Should be used
+ early at startup. */
+void
+setup_libassuan_logging (unsigned int *debug_var_address,
+ int (*log_monitor)(assuan_context_t ctx,
+ unsigned int cat,
+ const char *msg))
+{
+ char *flagstr;
+
+ flagstr = getenv ("ASSUAN_DEBUG");
+ if (flagstr)
+ log_cats = atoi (flagstr);
+ else /* Default to log the control channel. */
+ log_cats = (1 << (ASSUAN_LOG_CONTROL - 1));
+ my_log_monitor = log_monitor;
+ assuan_set_log_cb (my_libassuan_log_handler, debug_var_address);
+}
+
+
+/* Change the Libassuan log categories to those given by NEWCATS.
+ NEWCATS is 0 the default category of ASSUAN_LOG_CONTROL is
+ selected. Note, that setup_libassuan_logging overrides the values
+ given here. */
+void
+set_libassuan_log_cats (unsigned int newcats)
+{
+ if (newcats)
+ log_cats = newcats;
+ else /* Default to log the control channel. */
+ log_cats = (1 << (ASSUAN_LOG_CONTROL - 1));
+}
+
+
+
+static gpg_error_t
+send_one_option (assuan_context_t ctx, gpg_err_source_t errsource,
+ const char *name, const char *value, int use_putenv)
+{
+ gpg_error_t err;
+ char *optstr;
+
+ (void)errsource;
+
+ if (!value || !*value)
+ err = 0; /* Avoid sending empty strings. */
+ else if (asprintf (&optstr, "OPTION %s%s=%s",
+ use_putenv? "putenv=":"", name, value) < 0)
+ err = gpg_error_from_syserror ();
+ else
+ {
+ err = assuan_transact (ctx, optstr, NULL, NULL, NULL, NULL, NULL, NULL);
+ xfree (optstr);
+ }
+
+ return err;
+}
+
+
+/* Send the assuan commands pertaining to the pinentry environment. The
+ OPT_* arguments are optional and may be used to override the
+ defaults taken from the current locale. */
+gpg_error_t
+send_pinentry_environment (assuan_context_t ctx,
+ gpg_err_source_t errsource,
+ const char *opt_lc_ctype,
+ const char *opt_lc_messages,
+ session_env_t session_env)
+
+{
+ gpg_error_t err = 0;
+#if defined(HAVE_SETLOCALE)
+ char *old_lc = NULL;
+#endif
+ char *dft_lc = NULL;
+ const char *dft_ttyname;
+ int iterator;
+ const char *name, *assname, *value;
+ int is_default;
+
+ iterator = 0;
+ while ((name = session_env_list_stdenvnames (&iterator, &assname)))
+ {
+ value = session_env_getenv_or_default (session_env, name, NULL);
+ if (!value)
+ continue;
+
+ if (assname)
+ err = send_one_option (ctx, errsource, assname, value, 0);
+ else
+ {
+ err = send_one_option (ctx, errsource, name, value, 1);
+ if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION)
+ err = 0; /* Server too old; can't pass the new envvars. */
+ }
+ if (err)
+ return err;
+ }
+
+
+ dft_ttyname = session_env_getenv_or_default (session_env, "GPG_TTY",
+ &is_default);
+ if (dft_ttyname && !is_default)
+ dft_ttyname = NULL; /* We need the default value. */
+
+ /* Send the value for LC_CTYPE. */
+#if defined(HAVE_SETLOCALE) && defined(LC_CTYPE)
+ old_lc = setlocale (LC_CTYPE, NULL);
+ if (old_lc)
+ {
+ old_lc = xtrystrdup (old_lc);
+ if (!old_lc)
+ return gpg_error_from_syserror ();
+ }
+ dft_lc = setlocale (LC_CTYPE, "");
+#endif
+ if (opt_lc_ctype || (dft_ttyname && dft_lc))
+ {
+ err = send_one_option (ctx, errsource, "lc-ctype",
+ opt_lc_ctype ? opt_lc_ctype : dft_lc, 0);
+ }
+#if defined(HAVE_SETLOCALE) && defined(LC_CTYPE)
+ if (old_lc)
+ {
+ setlocale (LC_CTYPE, old_lc);
+ xfree (old_lc);
+ }
+#endif
+ if (err)
+ return err;
+
+ /* Send the value for LC_MESSAGES. */
+#if defined(HAVE_SETLOCALE) && defined(LC_MESSAGES)
+ old_lc = setlocale (LC_MESSAGES, NULL);
+ if (old_lc)
+ {
+ old_lc = xtrystrdup (old_lc);
+ if (!old_lc)
+ return gpg_error_from_syserror ();
+ }
+ dft_lc = setlocale (LC_MESSAGES, "");
+#endif
+ if (opt_lc_messages || (dft_ttyname && dft_lc))
+ {
+ err = send_one_option (ctx, errsource, "lc-messages",
+ opt_lc_messages ? opt_lc_messages : dft_lc, 0);
+ }
+#if defined(HAVE_SETLOCALE) && defined(LC_MESSAGES)
+ if (old_lc)
+ {
+ setlocale (LC_MESSAGES, old_lc);
+ xfree (old_lc);
+ }
+#endif
+ if (err)
+ return err;
+
+ return 0;
+}
+
+
+/* Lock a spawning process. The caller needs to provide the address
+ of a variable to store the lock information and the name or the
+ process. */
+static gpg_error_t
+lock_spawning (lock_spawn_t *lock, const char *homedir, const char *name,
+ int verbose)
+{
+ char *fname;
+ (void)verbose;
+
+ *lock = NULL;
+
+ fname = make_absfilename_try
+ (homedir,
+ !strcmp (name, "agent")? "gnupg_spawn_agent_sentinel":
+ !strcmp (name, "dirmngr")? "gnupg_spawn_dirmngr_sentinel":
+ /* */ "gnupg_spawn_unknown_sentinel",
+ NULL);
+ if (!fname)
+ return gpg_error_from_syserror ();
+
+ *lock = dotlock_create (fname, 0);
+ xfree (fname);
+ if (!*lock)
+ return gpg_error_from_syserror ();
+
+ /* FIXME: We should use a timeout of 5000 here - however
+ make_dotlock does not yet support values other than -1 and 0. */
+ if (dotlock_take (*lock, -1))
+ return gpg_error_from_syserror ();
+
+ return 0;
+}
+
+
+/* Unlock the spawning process. */
+static void
+unlock_spawning (lock_spawn_t *lock, const char *name)
+{
+ if (*lock)
+ {
+ (void)name;
+ dotlock_destroy (*lock);
+ *lock = NULL;
+ }
+}
+
+static gpg_error_t
+wait_for_sock (int secs, const char *name, const char *sockname, int verbose, assuan_context_t ctx, int *did_success_msg)
+{
+ gpg_error_t err = 0;
+ int target_us = secs * 1000000;
+ int elapsed_us = 0;
+ /*
+ * 977us * 1024 = just a little more than 1s.
+ * so we will double this timeout 10 times in the first
+ * second, and then switch over to 1s checkins.
+ */
+ int next_sleep_us = 977;
+ int lastalert = secs+1;
+ int secsleft;
+
+ while (elapsed_us < target_us)
+ {
+ if (verbose)
+ {
+ secsleft = (target_us - elapsed_us + 999999)/1000000;
+ /* log_clock ("left=%d last=%d targ=%d elap=%d next=%d\n", */
+ /* secsleft, lastalert, target_us, elapsed_us, */
+ /* next_sleep_us); */
+ if (secsleft < lastalert)
+ {
+ log_info (_("waiting for the %s to come up ... (%ds)\n"),
+ name, secsleft);
+ lastalert = secsleft;
+ }
+ }
+ gnupg_usleep (next_sleep_us);
+ elapsed_us += next_sleep_us;
+ err = assuan_socket_connect (ctx, sockname, 0, 0);
+ if (!err)
+ {
+ if (verbose)
+ {
+ log_info (_("connection to %s established\n"),
+ name);
+ *did_success_msg = 1;
+ }
+ break;
+ }
+ next_sleep_us *= 2;
+ if (next_sleep_us > 1000000)
+ next_sleep_us = 1000000;
+ }
+ return err;
+}
+
+/* Try to connect to the agent via socket or start it if it is not
+ running and AUTOSTART is set. Handle the server's initial
+ greeting. Returns a new assuan context at R_CTX or an error
+ code. */
+gpg_error_t
+start_new_gpg_agent (assuan_context_t *r_ctx,
+ gpg_err_source_t errsource,
+ const char *agent_program,
+ const char *opt_lc_ctype,
+ const char *opt_lc_messages,
+ session_env_t session_env,
+ int autostart, int verbose, int debug,
+ gpg_error_t (*status_cb)(ctrl_t, int, ...),
+ ctrl_t status_cb_arg)
+{
+ gpg_error_t err;
+ assuan_context_t ctx;
+ int did_success_msg = 0;
+ char *sockname;
+ const char *argv[6];
+
+ *r_ctx = NULL;
+
+ err = assuan_new (&ctx);
+ if (err)
+ {
+ log_error ("error allocating assuan context: %s\n", gpg_strerror (err));
+ return err;
+ }
+
+ sockname = make_filename_try (gnupg_socketdir (), GPG_AGENT_SOCK_NAME, NULL);
+ if (!sockname)
+ {
+ err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
+ assuan_release (ctx);
+ return err;
+ }
+
+ err = assuan_socket_connect (ctx, sockname, 0, 0);
+ if (err && autostart)
+ {
+ char *abs_homedir;
+ lock_spawn_t lock;
+ char *program = NULL;
+ const char *program_arg = NULL;
+ char *p;
+ const char *s;
+ int i;
+
+ /* With no success start a new server. */
+ if (!agent_program || !*agent_program)
+ agent_program = gnupg_module_name (GNUPG_MODULE_NAME_AGENT);
+ else if ((s=strchr (agent_program, '|')) && s[1] == '-' && s[2]=='-')
+ {
+ /* Hack to insert an additional option on the command line. */
+ program = xtrystrdup (agent_program);
+ if (!program)
+ {
+ gpg_error_t tmperr = gpg_err_make (errsource,
+ gpg_err_code_from_syserror ());
+ xfree (sockname);
+ assuan_release (ctx);
+ return tmperr;
+ }
+ p = strchr (program, '|');
+ *p++ = 0;
+ program_arg = p;
+ }
+
+ if (verbose)
+ log_info (_("no running gpg-agent - starting '%s'\n"),
+ agent_program);
+
+ if (status_cb)
+ status_cb (status_cb_arg, STATUS_PROGRESS,
+ "starting_agent ? 0 0", NULL);
+
+ /* We better pass an absolute home directory to the agent just
+ in case gpg-agent does not convert the passed name to an
+ absolute one (which it should do). */
+ abs_homedir = make_absfilename_try (gnupg_homedir (), NULL);
+ if (!abs_homedir)
+ {
+ gpg_error_t tmperr = gpg_err_make (errsource,
+ gpg_err_code_from_syserror ());
+ log_error ("error building filename: %s\n",gpg_strerror (tmperr));
+ xfree (sockname);
+ assuan_release (ctx);
+ xfree (program);
+ return tmperr;
+ }
+
+ if (fflush (NULL))
+ {
+ gpg_error_t tmperr = gpg_err_make (errsource,
+ gpg_err_code_from_syserror ());
+ log_error ("error flushing pending output: %s\n",
+ strerror (errno));
+ xfree (sockname);
+ assuan_release (ctx);
+ xfree (abs_homedir);
+ xfree (program);
+ return tmperr;
+ }
+
+ /* If the agent has been configured for use with a standard
+ socket, an environment variable is not required and thus
+ we can safely start the agent here. */
+ i = 0;
+ argv[i++] = "--homedir";
+ argv[i++] = abs_homedir;
+ argv[i++] = "--use-standard-socket";
+ if (program_arg)
+ argv[i++] = program_arg;
+ argv[i++] = "--daemon";
+ argv[i++] = NULL;
+
+ if (!(err = lock_spawning (&lock, gnupg_homedir (), "agent", verbose))
+ && assuan_socket_connect (ctx, sockname, 0, 0))
+ {
+ err = gnupg_spawn_process_detached (program? program : agent_program,
+ argv, NULL);
+ if (err)
+ log_error ("failed to start agent '%s': %s\n",
+ agent_program, gpg_strerror (err));
+ else
+ err = wait_for_sock (SECS_TO_WAIT_FOR_AGENT, "agent",
+ sockname, verbose, ctx, &did_success_msg);
+ }
+
+ unlock_spawning (&lock, "agent");
+ xfree (abs_homedir);
+ xfree (program);
+ }
+ xfree (sockname);
+ if (err)
+ {
+ if (autostart || gpg_err_code (err) != GPG_ERR_ASS_CONNECT_FAILED)
+ log_error ("can't connect to the agent: %s\n", gpg_strerror (err));
+ assuan_release (ctx);
+ return gpg_err_make (errsource, GPG_ERR_NO_AGENT);
+ }
+
+ if (debug && !did_success_msg)
+ log_debug ("connection to agent established\n");
+
+ err = assuan_transact (ctx, "RESET",
+ NULL, NULL, NULL, NULL, NULL, NULL);
+ if (!err)
+ {
+ err = send_pinentry_environment (ctx, errsource,
+ opt_lc_ctype, opt_lc_messages,
+ session_env);
+ if (gpg_err_code (err) == GPG_ERR_FORBIDDEN
+ && gpg_err_source (err) == GPG_ERR_SOURCE_GPGAGENT)
+ {
+ /* Check whether we are in restricted mode. */
+ if (!assuan_transact (ctx, "GETINFO restricted",
+ NULL, NULL, NULL, NULL, NULL, NULL))
+ {
+ if (verbose)
+ log_info (_("connection to agent is in restricted mode\n"));
+ err = 0;
+ }
+ }
+ }
+ if (err)
+ {
+ assuan_release (ctx);
+ return err;
+ }
+
+ *r_ctx = ctx;
+ return 0;
+}
+
+
+/* Try to connect to the dirmngr via a socket. On platforms
+ supporting it, start it up if needed and if AUTOSTART is true.
+ Returns a new assuan context at R_CTX or an error code. */
+gpg_error_t
+start_new_dirmngr (assuan_context_t *r_ctx,
+ gpg_err_source_t errsource,
+ const char *dirmngr_program,
+ int autostart,
+ int verbose, int debug,
+ gpg_error_t (*status_cb)(ctrl_t, int, ...),
+ ctrl_t status_cb_arg)
+{
+ gpg_error_t err;
+ assuan_context_t ctx;
+ const char *sockname;
+ int did_success_msg = 0;
+
+ *r_ctx = NULL;
+
+ err = assuan_new (&ctx);
+ if (err)
+ {
+ log_error ("error allocating assuan context: %s\n", gpg_strerror (err));
+ return err;
+ }
+
+ sockname = dirmngr_socket_name ();
+ err = assuan_socket_connect (ctx, sockname, 0, 0);
+
+#ifdef USE_DIRMNGR_AUTO_START
+ if (err && autostart)
+ {
+ lock_spawn_t lock;
+ const char *argv[4];
+ char *abs_homedir;
+
+ /* No connection: Try start a new Dirmngr. */
+ if (!dirmngr_program || !*dirmngr_program)
+ dirmngr_program = gnupg_module_name (GNUPG_MODULE_NAME_DIRMNGR);
+
+ if (verbose)
+ log_info (_("no running Dirmngr - starting '%s'\n"),
+ dirmngr_program);
+
+ if (status_cb)
+ status_cb (status_cb_arg, STATUS_PROGRESS,
+ "starting_dirmngr ? 0 0", NULL);
+
+ abs_homedir = make_absfilename (gnupg_homedir (), NULL);
+ if (!abs_homedir)
+ {
+ gpg_error_t tmperr = gpg_err_make (errsource,
+ gpg_err_code_from_syserror ());
+ log_error ("error building filename: %s\n",gpg_strerror (tmperr));
+ assuan_release (ctx);
+ return tmperr;
+ }
+
+ if (fflush (NULL))
+ {
+ gpg_error_t tmperr = gpg_err_make (errsource,
+ gpg_err_code_from_syserror ());
+ log_error ("error flushing pending output: %s\n",
+ strerror (errno));
+ assuan_release (ctx);
+ return tmperr;
+ }
+
+ argv[0] = "--daemon";
+ /* Try starting the daemon. Versions of dirmngr < 2.1.15 do
+ * this only if the home directory is given on the command line. */
+ argv[1] = "--homedir";
+ argv[2] = abs_homedir;
+ argv[3] = NULL;
+
+ if (!(err = lock_spawning (&lock, gnupg_homedir (), "dirmngr", verbose))
+ && assuan_socket_connect (ctx, sockname, 0, 0))
+ {
+ err = gnupg_spawn_process_detached (dirmngr_program, argv, NULL);
+ if (err)
+ log_error ("failed to start the dirmngr '%s': %s\n",
+ dirmngr_program, gpg_strerror (err));
+ else
+ err = wait_for_sock (SECS_TO_WAIT_FOR_DIRMNGR, "dirmngr",
+ sockname, verbose, ctx, &did_success_msg);
+ }
+
+ unlock_spawning (&lock, "dirmngr");
+ xfree (abs_homedir);
+ }
+#else
+ (void)dirmngr_program;
+ (void)verbose;
+ (void)status_cb;
+ (void)status_cb_arg;
+#endif /*USE_DIRMNGR_AUTO_START*/
+
+ if (err)
+ {
+ if (autostart || gpg_err_code (err) != GPG_ERR_ASS_CONNECT_FAILED)
+ log_error ("connecting dirmngr at '%s' failed: %s\n",
+ sockname, gpg_strerror (err));
+ assuan_release (ctx);
+ return gpg_err_make (errsource, GPG_ERR_NO_DIRMNGR);
+ }
+
+ if (debug && !did_success_msg)
+ log_debug ("connection to the dirmngr established\n");
+
+ *r_ctx = ctx;
+ return 0;
+}
+
+
+/* Return the version of a server using "GETINFO version". On success
+ 0 is returned and R_VERSION receives a malloced string with the
+ version which must be freed by the caller. On error NULL is stored
+ at R_VERSION and an error code returned. Mode is in general 0 but
+ certain values may be used to modify the used version command:
+
+ MODE == 0 = Use "GETINFO version"
+ MODE == 2 - Use "SCD GETINFO version"
+ */
+gpg_error_t
+get_assuan_server_version (assuan_context_t ctx, int mode, char **r_version)
+{
+ gpg_error_t err;
+ membuf_t data;
+
+ init_membuf (&data, 64);
+ err = assuan_transact (ctx,
+ mode == 2? "SCD GETINFO version"
+ /**/ : "GETINFO version",
+ put_membuf_cb, &data,
+ NULL, NULL, NULL, NULL);
+ if (err)
+ {
+ xfree (get_membuf (&data, NULL));
+ *r_version = NULL;
+ }
+ else
+ {
+ put_membuf (&data, "", 1);
+ *r_version = get_membuf (&data, NULL);
+ if (!*r_version)
+ err = gpg_error_from_syserror ();
+ }
+ return err;
+}
diff --git a/common/asshelp.h b/common/asshelp.h
new file mode 100644
index 0000000..bf1bd17
--- /dev/null
+++ b/common/asshelp.h
@@ -0,0 +1,104 @@
+/* asshelp.h - Helper functions for Assuan
+ * Copyright (C) 2004, 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_COMMON_ASSHELP_H
+#define GNUPG_COMMON_ASSHELP_H
+
+#include <assuan.h>
+#include <gpg-error.h>
+
+#include "session-env.h"
+#include "util.h"
+
+/*-- asshelp.c --*/
+
+void setup_libassuan_logging (unsigned int *debug_var_address,
+ int (*log_monitor)(assuan_context_t ctx,
+ unsigned int cat,
+ const char *msg));
+void set_libassuan_log_cats (unsigned int newcats);
+
+
+gpg_error_t
+send_pinentry_environment (assuan_context_t ctx,
+ gpg_err_source_t errsource,
+ const char *opt_lc_ctype,
+ const char *opt_lc_messages,
+ session_env_t session_env);
+
+/* This function is used by the call-agent.c modules to fire up a new
+ agent. */
+gpg_error_t
+start_new_gpg_agent (assuan_context_t *r_ctx,
+ gpg_err_source_t errsource,
+ const char *agent_program,
+ const char *opt_lc_ctype,
+ const char *opt_lc_messages,
+ session_env_t session_env,
+ int autostart, int verbose, int debug,
+ gpg_error_t (*status_cb)(ctrl_t, int, ...),
+ ctrl_t status_cb_arg);
+
+/* This function is used to connect to the dirmngr. On some platforms
+ the function is able starts a dirmngr process if needed. */
+gpg_error_t
+start_new_dirmngr (assuan_context_t *r_ctx,
+ gpg_err_source_t errsource,
+ const char *dirmngr_program,
+ int autostart, int verbose, int debug,
+ gpg_error_t (*status_cb)(ctrl_t, int, ...),
+ ctrl_t status_cb_arg);
+
+/* Return the version of a server using "GETINFO version". */
+gpg_error_t get_assuan_server_version (assuan_context_t ctx,
+ int mode, char **r_version);
+
+
+/*-- asshelp2.c --*/
+
+/* Helper function to print an assuan status line using a printf
+ format string. */
+gpg_error_t print_assuan_status (assuan_context_t ctx,
+ const char *keyword,
+ const char *format,
+ ...) GPGRT_ATTR_PRINTF(3,4);
+gpg_error_t vprint_assuan_status (assuan_context_t ctx,
+ const char *keyword,
+ const char *format,
+ va_list arg_ptr) GPGRT_ATTR_PRINTF(3,0);
+
+gpg_error_t vprint_assuan_status_strings (assuan_context_t ctx,
+ const char *keyword,
+ va_list arg_ptr);
+gpg_error_t print_assuan_status_strings (assuan_context_t ctx,
+ const char *keyword,
+ ...) GPGRT_ATTR_SENTINEL(1);
+
+
+#endif /*GNUPG_COMMON_ASSHELP_H*/
diff --git a/common/asshelp2.c b/common/asshelp2.c
new file mode 100644
index 0000000..0a7c454
--- /dev/null
+++ b/common/asshelp2.c
@@ -0,0 +1,136 @@
+/* asshelp2.c - More helper functions for Assuan
+ * Copyright (C) 2012 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assuan.h>
+
+#include "util.h"
+#include "asshelp.h"
+
+/* Helper function to print an assuan status line using a printf
+ format string. */
+gpg_error_t
+vprint_assuan_status (assuan_context_t ctx,
+ const char *keyword,
+ const char *format, va_list arg_ptr)
+{
+ int rc;
+ char *buf;
+
+ rc = gpgrt_vasprintf (&buf, format, arg_ptr);
+ if (rc < 0)
+ return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
+ rc = assuan_write_status (ctx, keyword, buf);
+ xfree (buf);
+ return rc;
+}
+
+
+/* Helper function to print an assuan status line using a printf
+ format string. */
+gpg_error_t
+print_assuan_status (assuan_context_t ctx,
+ const char *keyword,
+ const char *format, ...)
+{
+ va_list arg_ptr;
+ gpg_error_t err;
+
+ va_start (arg_ptr, format);
+ err = vprint_assuan_status (ctx, keyword, format, arg_ptr);
+ va_end (arg_ptr);
+ return err;
+}
+
+
+/* Helper function to print a list of strings as an assuan status
+ * line. KEYWORD is the first item on the status line. ARG_PTR is a
+ * list of strings which are all separated by a space in the output.
+ * The last argument must be a NULL. Linefeeds and carriage returns
+ * characters (which are not allowed in an Assuan status line) are
+ * silently quoted in C-style. */
+gpg_error_t
+vprint_assuan_status_strings (assuan_context_t ctx,
+ const char *keyword, va_list arg_ptr)
+{
+ gpg_error_t err = 0;
+ const char *text;
+ char buf[950], *p;
+ size_t n;
+
+ p = buf;
+ n = 0;
+ while ((text = va_arg (arg_ptr, const char *)) && n < DIM (buf)-3 )
+ {
+ if (n)
+ {
+ *p++ = ' ';
+ n++;
+ }
+ for ( ; *text && n < DIM (buf)-3; n++, text++)
+ {
+ if (*text == '\n')
+ {
+ *p++ = '\\';
+ *p++ = 'n';
+ n++;
+ }
+ else if (*text == '\r')
+ {
+ *p++ = '\\';
+ *p++ = 'r';
+ n++;
+ }
+ else
+ *p++ = *text;
+ }
+ }
+ *p = 0;
+ err = assuan_write_status (ctx, keyword, buf);
+
+ return err;
+}
+
+
+/* See vprint_assuan_status_strings. */
+gpg_error_t
+print_assuan_status_strings (assuan_context_t ctx, const char *keyword, ...)
+{
+ va_list arg_ptr;
+ gpg_error_t err;
+
+ va_start (arg_ptr, keyword);
+ err = vprint_assuan_status_strings (ctx, keyword, arg_ptr);
+ va_end (arg_ptr);
+ return err;
+}
diff --git a/common/audit-events.h b/common/audit-events.h
new file mode 100644
index 0000000..ae9fde2
--- /dev/null
+++ b/common/audit-events.h
@@ -0,0 +1,116 @@
+/* Output of mkstrtable.awk. DO NOT EDIT. */
+
+/* audit.h - Definitions for the audit subsystem
+ * Copyright (C) 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+/* The purpose of this complex string table is to produce
+ optimal code with a minimum of relocations. */
+
+static const char eventstr_msgstr[] =
+ "null event" "\0"
+ "setup ready" "\0"
+ "agent ready" "\0"
+ "dirmngr ready" "\0"
+ "gpg ready" "\0"
+ "gpgsm ready" "\0"
+ "g13 ready" "\0"
+ "got data" "\0"
+ "detached signature" "\0"
+ "cert only sig" "\0"
+ "data hash algo" "\0"
+ "attr hash algo" "\0"
+ "data cipher algo" "\0"
+ "bad data hash algo" "\0"
+ "bad data cipher algo" "\0"
+ "data hashing" "\0"
+ "read error" "\0"
+ "write error" "\0"
+ "usage error" "\0"
+ "save cert" "\0"
+ "new sig" "\0"
+ "sig name" "\0"
+ "sig status" "\0"
+ "new recp" "\0"
+ "recp name" "\0"
+ "recp result" "\0"
+ "decryption result" "\0"
+ "validate chain" "\0"
+ "chain begin" "\0"
+ "chain cert" "\0"
+ "chain rootcert" "\0"
+ "chain end" "\0"
+ "chain status" "\0"
+ "root trusted" "\0"
+ "crl check" "\0"
+ "got recipients" "\0"
+ "session key" "\0"
+ "encrypted to" "\0"
+ "encryption done" "\0"
+ "signed by" "\0"
+ "signing done";
+
+static const int eventstr_msgidx[] =
+ {
+ 0,
+ 11,
+ 23,
+ 35,
+ 49,
+ 59,
+ 71,
+ 81,
+ 90,
+ 109,
+ 123,
+ 138,
+ 153,
+ 170,
+ 189,
+ 210,
+ 223,
+ 234,
+ 246,
+ 258,
+ 268,
+ 276,
+ 285,
+ 296,
+ 305,
+ 315,
+ 327,
+ 345,
+ 360,
+ 372,
+ 383,
+ 398,
+ 408,
+ 421,
+ 434,
+ 444,
+ 459,
+ 471,
+ 484,
+ 500,
+ 510,
+
+ };
+
+#define eventstr_msgidxof(code) (0 ? -1 \
+ : ((code >= 0) && (code <= 40)) ? (code - 0) \
+ : -1)
diff --git a/common/audit.c b/common/audit.c
new file mode 100644
index 0000000..718f729
--- /dev/null
+++ b/common/audit.c
@@ -0,0 +1,1324 @@
+/* audit.c - GnuPG's audit subsystem
+ * Copyright (C) 2007, 2009 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <assert.h>
+
+#include "util.h"
+#include "i18n.h"
+#include "audit.h"
+#include "audit-events.h"
+
+/* A list to maintain a list of helptags. */
+struct helptag_s
+{
+ struct helptag_s *next;
+ const char *name;
+};
+typedef struct helptag_s *helptag_t;
+
+
+/* One log entry. */
+struct log_item_s
+{
+ audit_event_t event; /* The event. */
+ gpg_error_t err; /* The logged error code. */
+ int intvalue; /* A logged integer value. */
+ char *string; /* A malloced string or NULL. */
+ ksba_cert_t cert; /* A certifciate or NULL. */
+ int have_err:1;
+ int have_intvalue:1;
+};
+typedef struct log_item_s *log_item_t;
+
+
+
+/* The main audit object. */
+struct audit_ctx_s
+{
+ const char *failure; /* If set a description of the internal failure. */
+ audit_type_t type;
+
+ log_item_t log; /* The table with the log entries. */
+ size_t logsize; /* The allocated size for LOG. */
+ size_t logused; /* The used size of LOG. */
+
+ estream_t outstream; /* The current output stream. */
+ int use_html; /* The output shall be HTML formatted. */
+ int indentlevel; /* Current level of indentation. */
+ helptag_t helptags; /* List of help keys. */
+};
+
+
+
+
+static void writeout_para (audit_ctx_t ctx,
+ const char *format, ...) GPGRT_ATTR_PRINTF(2,3);
+static void writeout_li (audit_ctx_t ctx, const char *oktext,
+ const char *format, ...) GPGRT_ATTR_PRINTF(3,4);
+static void writeout_rem (audit_ctx_t ctx,
+ const char *format, ...) GPGRT_ATTR_PRINTF(2,3);
+
+
+/* Add NAME to the list of help tags. NAME needs to be a const string
+ an this function merly stores this pointer. */
+static void
+add_helptag (audit_ctx_t ctx, const char *name)
+{
+ helptag_t item;
+
+ for (item=ctx->helptags; item; item = item->next)
+ if (!strcmp (item->name, name))
+ return; /* Already in the list. */
+ item = xtrycalloc (1, sizeof *item);
+ if (!item)
+ return; /* Don't care about memory problems. */
+ item->name = name;
+ item->next = ctx->helptags;
+ ctx->helptags = item;
+}
+
+
+/* Remove all help tags from the context. */
+static void
+clear_helptags (audit_ctx_t ctx)
+{
+ while (ctx->helptags)
+ {
+ helptag_t tmp = ctx->helptags->next;
+ xfree (ctx->helptags);
+ ctx->helptags = tmp;
+ }
+}
+
+
+
+static const char *
+event2str (audit_event_t event)
+{
+ /* We need the cast so that compiler does not complain about an
+ always true comparison (>= 0) for an unsigned value. */
+ int idx = eventstr_msgidxof ((int)event);
+ if (idx == -1)
+ return "Unknown event";
+ else
+ return eventstr_msgstr + eventstr_msgidx[idx];
+}
+
+
+
+/* Create a new audit context. In case of an error NULL is returned
+ and errno set appropriately. */
+audit_ctx_t
+audit_new (void)
+{
+ audit_ctx_t ctx;
+
+ ctx = xtrycalloc (1, sizeof *ctx);
+
+ return ctx;
+}
+
+
+/* Release an audit context. Passing NULL for CTX is allowed and does
+ nothing. */
+void
+audit_release (audit_ctx_t ctx)
+{
+ int idx;
+ if (!ctx)
+ return;
+ if (ctx->log)
+ {
+ for (idx=0; idx < ctx->logused; idx++)
+ {
+ if (ctx->log[idx].string)
+ xfree (ctx->log[idx].string);
+ if (ctx->log[idx].cert)
+ ksba_cert_release (ctx->log[idx].cert);
+ }
+ xfree (ctx->log);
+ }
+ clear_helptags (ctx);
+ xfree (ctx);
+}
+
+
+/* Set the type for the audit operation. If CTX is NULL, this is a
+ dummy function. */
+void
+audit_set_type (audit_ctx_t ctx, audit_type_t type)
+{
+ if (!ctx || ctx->failure)
+ return; /* Audit not enabled or an internal error has occurred. */
+
+ if (ctx->type && ctx->type != type)
+ {
+ ctx->failure = "conflict in type initialization";
+ return;
+ }
+ ctx->type = type;
+}
+
+
+/* Create a new log item and put it into the table. Return that log
+ item on success; return NULL on memory failure and mark that in
+ CTX. */
+static log_item_t
+create_log_item (audit_ctx_t ctx)
+{
+ log_item_t item, table;
+ size_t size;
+
+ if (!ctx->log)
+ {
+ size = 10;
+ table = xtrymalloc (size * sizeof *table);
+ if (!table)
+ {
+ ctx->failure = "Out of memory in create_log_item";
+ return NULL;
+ }
+ ctx->log = table;
+ ctx->logsize = size;
+ item = ctx->log + 0;
+ ctx->logused = 1;
+ }
+ else if (ctx->logused >= ctx->logsize)
+ {
+ size = ctx->logsize + 10;
+ table = xtryrealloc (ctx->log, size * sizeof *table);
+ if (!table)
+ {
+ ctx->failure = "Out of memory while reallocating in create_log_item";
+ return NULL;
+ }
+ ctx->log = table;
+ ctx->logsize = size;
+ item = ctx->log + ctx->logused++;
+ }
+ else
+ item = ctx->log + ctx->logused++;
+
+ item->event = AUDIT_NULL_EVENT;
+ item->err = 0;
+ item->have_err = 0;
+ item->intvalue = 0;
+ item->have_intvalue = 0;
+ item->string = NULL;
+ item->cert = NULL;
+
+ return item;
+
+}
+
+/* Add a new event to the audit log. If CTX is NULL, this function
+ does nothing. */
+void
+audit_log (audit_ctx_t ctx, audit_event_t event)
+{
+ log_item_t item;
+
+ if (!ctx || ctx->failure)
+ return; /* Audit not enabled or an internal error has occurred. */
+ if (!event)
+ {
+ ctx->failure = "Invalid event passed to audit_log";
+ return;
+ }
+ if (!(item = create_log_item (ctx)))
+ return;
+ item->event = event;
+}
+
+/* Add a new event to the audit log. If CTX is NULL, this function
+ does nothing. This version also adds the result of the operation
+ to the log. */
+void
+audit_log_ok (audit_ctx_t ctx, audit_event_t event, gpg_error_t err)
+{
+ log_item_t item;
+
+ if (!ctx || ctx->failure)
+ return; /* Audit not enabled or an internal error has occurred. */
+ if (!event)
+ {
+ ctx->failure = "Invalid event passed to audit_log_ok";
+ return;
+ }
+ if (!(item = create_log_item (ctx)))
+ return;
+ item->event = event;
+ item->err = err;
+ item->have_err = 1;
+}
+
+
+/* Add a new event to the audit log. If CTX is NULL, this function
+ does nothing. This version also add the integer VALUE to the log. */
+void
+audit_log_i (audit_ctx_t ctx, audit_event_t event, int value)
+{
+ log_item_t item;
+
+ if (!ctx || ctx->failure)
+ return; /* Audit not enabled or an internal error has occurred. */
+ if (!event)
+ {
+ ctx->failure = "Invalid event passed to audit_log_i";
+ return;
+ }
+ if (!(item = create_log_item (ctx)))
+ return;
+ item->event = event;
+ item->intvalue = value;
+ item->have_intvalue = 1;
+}
+
+
+/* Add a new event to the audit log. If CTX is NULL, this function
+ does nothing. This version also add the integer VALUE to the log. */
+void
+audit_log_s (audit_ctx_t ctx, audit_event_t event, const char *value)
+{
+ log_item_t item;
+ char *tmp;
+
+ if (!ctx || ctx->failure)
+ return; /* Audit not enabled or an internal error has occurred. */
+ if (!event)
+ {
+ ctx->failure = "Invalid event passed to audit_log_s";
+ return;
+ }
+ tmp = xtrystrdup (value? value : "");
+ if (!tmp)
+ {
+ ctx->failure = "Out of memory in audit_event";
+ return;
+ }
+ if (!(item = create_log_item (ctx)))
+ {
+ xfree (tmp);
+ return;
+ }
+ item->event = event;
+ item->string = tmp;
+}
+
+/* Add a new event to the audit log. If CTX is NULL, this function
+ does nothing. This version also adds the certificate CERT and the
+ result of an operation to the log. */
+void
+audit_log_cert (audit_ctx_t ctx, audit_event_t event,
+ ksba_cert_t cert, gpg_error_t err)
+{
+ log_item_t item;
+
+ if (!ctx || ctx->failure)
+ return; /* Audit not enabled or an internal error has occurred. */
+ if (!event)
+ {
+ ctx->failure = "Invalid event passed to audit_log_cert";
+ return;
+ }
+ if (!(item = create_log_item (ctx)))
+ return;
+ item->event = event;
+ item->err = err;
+ item->have_err = 1;
+ if (cert)
+ {
+ ksba_cert_ref (cert);
+ item->cert = cert;
+ }
+}
+
+
+/* Write TEXT to the outstream. */
+static void
+writeout (audit_ctx_t ctx, const char *text)
+{
+ if (ctx->use_html)
+ {
+ for (; *text; text++)
+ {
+ if (*text == '<')
+ es_fputs ("&lt;", ctx->outstream);
+ else if (*text == '&')
+ es_fputs ("&amp;", ctx->outstream);
+ else
+ es_putc (*text, ctx->outstream);
+ }
+ }
+ else
+ es_fputs (text, ctx->outstream);
+}
+
+
+/* Write TEXT to the outstream using a variable argument list. */
+static void
+writeout_v (audit_ctx_t ctx, const char *format, va_list arg_ptr)
+{
+ char *buf;
+
+ gpgrt_vasprintf (&buf, format, arg_ptr);
+ if (buf)
+ {
+ writeout (ctx, buf);
+ xfree (buf);
+ }
+ else
+ writeout (ctx, "[!!Out of core!!]");
+}
+
+
+/* Write TEXT as a paragraph. */
+static void
+writeout_para (audit_ctx_t ctx, const char *format, ...)
+{
+ va_list arg_ptr;
+
+ if (ctx->use_html)
+ es_fputs ("<p>", ctx->outstream);
+ va_start (arg_ptr, format) ;
+ writeout_v (ctx, format, arg_ptr);
+ va_end (arg_ptr);
+ if (ctx->use_html)
+ es_fputs ("</p>\n", ctx->outstream);
+ else
+ es_fputc ('\n', ctx->outstream);
+}
+
+
+static void
+enter_li (audit_ctx_t ctx)
+{
+ if (ctx->use_html)
+ {
+ if (!ctx->indentlevel)
+ {
+ es_fputs ("<table border=\"0\">\n"
+ " <colgroup>\n"
+ " <col width=\"80%\" />\n"
+ " <col width=\"20%\" />\n"
+ " </colgroup>\n",
+ ctx->outstream);
+ }
+ }
+ ctx->indentlevel++;
+}
+
+
+static void
+leave_li (audit_ctx_t ctx)
+{
+ ctx->indentlevel--;
+ if (ctx->use_html)
+ {
+ if (!ctx->indentlevel)
+ es_fputs ("</table>\n", ctx->outstream);
+ }
+}
+
+
+/* Write TEXT as a list element. If OKTEXT is not NULL, append it to
+ the last line. */
+static void
+writeout_li (audit_ctx_t ctx, const char *oktext, const char *format, ...)
+{
+ va_list arg_ptr;
+ const char *color = NULL;
+
+ if (ctx->use_html && format && oktext)
+ {
+ if (!strcmp (oktext, "Yes")
+ || !strcmp (oktext, "good") )
+ color = "green";
+ else if (!strcmp (oktext, "No")
+ || !strcmp (oktext, "bad") )
+ color = "red";
+ }
+
+ if (format && oktext)
+ {
+ const char *s = NULL;
+
+ if (!strcmp (oktext, "Yes"))
+ oktext = _("Yes");
+ else if (!strcmp (oktext, "No"))
+ oktext = _("No");
+ else if (!strcmp (oktext, "good"))
+ {
+ /* TRANSLATORS: Copy the prefix between the vertical bars
+ verbatim. It will not be printed. */
+ oktext = _("|audit-log-result|Good");
+ }
+ else if (!strcmp (oktext, "bad"))
+ oktext = _("|audit-log-result|Bad");
+ else if (!strcmp (oktext, "unsupported"))
+ oktext = _("|audit-log-result|Not supported");
+ else if (!strcmp (oktext, "no-cert"))
+ oktext = _("|audit-log-result|No certificate");
+ else if (!strcmp (oktext, "disabled"))
+ oktext = _("|audit-log-result|Not enabled");
+ else if (!strcmp (oktext, "error"))
+ oktext = _("|audit-log-result|Error");
+ else if (!strcmp (oktext, "not-used"))
+ oktext = _("|audit-log-result|Not used");
+ else if (!strcmp (oktext, "okay"))
+ oktext = _("|audit-log-result|Okay");
+ else if (!strcmp (oktext, "skipped"))
+ oktext = _("|audit-log-result|Skipped");
+ else if (!strcmp (oktext, "some"))
+ oktext = _("|audit-log-result|Some");
+ else
+ s = "";
+
+ /* If we have set a prefix, skip it. */
+ if (!s && *oktext == '|' && (s=strchr (oktext+1,'|')))
+ oktext = s+1;
+ }
+
+ if (ctx->use_html)
+ {
+ int i;
+
+ es_fputs (" <tr><td><table><tr><td>", ctx->outstream);
+ if (color)
+ es_fprintf (ctx->outstream, "<font color=\"%s\">*</font>", color);
+ else
+ es_fputs ("*", ctx->outstream);
+ for (i=1; i < ctx->indentlevel; i++)
+ es_fputs ("&nbsp;&nbsp;", ctx->outstream);
+ es_fputs ("</td><td>", ctx->outstream);
+ }
+ else
+ es_fprintf (ctx->outstream, "* %*s", (ctx->indentlevel-1)*2, "");
+ if (format)
+ {
+ va_start (arg_ptr, format) ;
+ writeout_v (ctx, format, arg_ptr);
+ va_end (arg_ptr);
+ }
+ if (ctx->use_html)
+ es_fputs ("</td></tr></table>", ctx->outstream);
+ if (format && oktext)
+ {
+ if (ctx->use_html)
+ {
+ es_fputs ("</td><td>", ctx->outstream);
+ if (color)
+ es_fprintf (ctx->outstream, "<font color=\"%s\">", color);
+ }
+ else
+ writeout (ctx, ": ");
+ writeout (ctx, oktext);
+ if (color)
+ es_fputs ("</font>", ctx->outstream);
+ }
+
+ if (ctx->use_html)
+ es_fputs ("</td></tr>\n", ctx->outstream);
+ else
+ es_fputc ('\n', ctx->outstream);
+}
+
+
+/* Write a remark line. */
+static void
+writeout_rem (audit_ctx_t ctx, const char *format, ...)
+{
+ va_list arg_ptr;
+
+ if (ctx->use_html)
+ {
+ int i;
+
+ es_fputs (" <tr><td><table><tr><td>*", ctx->outstream);
+ for (i=1; i < ctx->indentlevel; i++)
+ es_fputs ("&nbsp;&nbsp;", ctx->outstream);
+ es_fputs ("&nbsp;&nbsp;&nbsp;</td><td> (", ctx->outstream);
+
+ }
+ else
+ es_fprintf (ctx->outstream, "* %*s (", (ctx->indentlevel-1)*2, "");
+ if (format)
+ {
+ va_start (arg_ptr, format) ;
+ writeout_v (ctx, format, arg_ptr);
+ va_end (arg_ptr);
+ }
+ if (ctx->use_html)
+ es_fputs (")</td></tr></table></td></tr>\n", ctx->outstream);
+ else
+ es_fputs (")\n", ctx->outstream);
+}
+
+
+/* Return the first log item for EVENT. If STOPEVENT is not 0 never
+ look behind that event in the log. If STARTITEM is not NULL start
+ search _after_that item. */
+static log_item_t
+find_next_log_item (audit_ctx_t ctx, log_item_t startitem,
+ audit_event_t event, audit_event_t stopevent)
+{
+ int idx;
+
+ for (idx=0; idx < ctx->logused; idx++)
+ {
+ if (startitem)
+ {
+ if (ctx->log + idx == startitem)
+ startitem = NULL;
+ }
+ else if (stopevent && ctx->log[idx].event == stopevent)
+ break;
+ else if (ctx->log[idx].event == event)
+ return ctx->log + idx;
+ }
+ return NULL;
+}
+
+
+static log_item_t
+find_log_item (audit_ctx_t ctx, audit_event_t event, audit_event_t stopevent)
+{
+ return find_next_log_item (ctx, NULL, event, stopevent);
+}
+
+
+/* Helper to a format a serial number. */
+static char *
+format_serial (ksba_const_sexp_t sn)
+{
+ const char *p = (const char *)sn;
+ unsigned long n;
+ char *endp;
+
+ if (!p)
+ return NULL;
+ if (*p != '(')
+ BUG (); /* Not a valid S-expression. */
+ n = strtoul (p+1, &endp, 10);
+ p = endp;
+ if (*p != ':')
+ BUG (); /* Not a valid S-expression. */
+ return bin2hex (p+1, n, NULL);
+}
+
+
+/* Return a malloced string with the serial number and the issuer DN
+ of the certificate. */
+static char *
+get_cert_name (ksba_cert_t cert)
+{
+ char *result;
+ ksba_sexp_t sn;
+ char *issuer, *p;
+
+ if (!cert)
+ return xtrystrdup ("[no certificate]");
+
+ issuer = ksba_cert_get_issuer (cert, 0);
+ sn = ksba_cert_get_serial (cert);
+ if (issuer && sn)
+ {
+ p = format_serial (sn);
+ if (!p)
+ result = xtrystrdup ("[invalid S/N]");
+ else
+ {
+ result = xtrymalloc (strlen (p) + strlen (issuer) + 2 + 1);
+ if (result)
+ {
+ *result = '#';
+ strcpy (stpcpy (stpcpy (result+1, p),"/"), issuer);
+ }
+ xfree (p);
+ }
+ }
+ else
+ result = xtrystrdup ("[missing S/N or issuer]");
+ ksba_free (sn);
+ xfree (issuer);
+ return result;
+}
+
+/* Return a malloced string with the serial number and the issuer DN
+ of the certificate. */
+static char *
+get_cert_subject (ksba_cert_t cert, int idx)
+{
+ char *result;
+ char *subject;
+
+ if (!cert)
+ return xtrystrdup ("[no certificate]");
+
+ subject = ksba_cert_get_subject (cert, idx);
+ if (subject)
+ {
+ result = xtrymalloc (strlen (subject) + 1 + 1);
+ if (result)
+ {
+ *result = '/';
+ strcpy (result+1, subject);
+ }
+ }
+ else
+ result = NULL;
+ xfree (subject);
+ return result;
+}
+
+
+/* List the given certificiate. If CERT is NULL, this is a NOP. */
+static void
+list_cert (audit_ctx_t ctx, ksba_cert_t cert, int with_subj)
+{
+ char *name;
+ int idx;
+
+ name = get_cert_name (cert);
+ writeout_rem (ctx, "%s", name);
+ xfree (name);
+ if (with_subj)
+ {
+ enter_li (ctx);
+ for (idx=0; (name = get_cert_subject (cert, idx)); idx++)
+ {
+ writeout_rem (ctx, "%s", name);
+ xfree (name);
+ }
+ leave_li (ctx);
+ }
+}
+
+
+/* List the chain of certificates from STARTITEM up to STOPEVENT. The
+ certificates are written out as comments. */
+static void
+list_certchain (audit_ctx_t ctx, log_item_t startitem, audit_event_t stopevent)
+{
+ log_item_t item;
+
+ startitem = find_next_log_item (ctx, startitem, AUDIT_CHAIN_BEGIN,stopevent);
+ writeout_li (ctx, startitem? "Yes":"No", _("Certificate chain available"));
+ if (!startitem)
+ return;
+
+ item = find_next_log_item (ctx, startitem,
+ AUDIT_CHAIN_ROOTCERT, AUDIT_CHAIN_END);
+ if (!item)
+ writeout_rem (ctx, "%s", _("root certificate missing"));
+ else
+ {
+ list_cert (ctx, item->cert, 0);
+ }
+ item = startitem;
+ while ( ((item = find_next_log_item (ctx, item,
+ AUDIT_CHAIN_CERT, AUDIT_CHAIN_END))))
+ {
+ list_cert (ctx, item->cert, 1);
+ }
+}
+
+
+
+/* Process an encrypt operation's log. */
+static void
+proc_type_encrypt (audit_ctx_t ctx)
+{
+ log_item_t loopitem, item;
+ int recp_no, idx;
+ char numbuf[35];
+ int algo;
+ char *name;
+
+ item = find_log_item (ctx, AUDIT_ENCRYPTION_DONE, 0);
+ writeout_li (ctx, item?"Yes":"No", "%s", _("Data encryption succeeded"));
+
+ enter_li (ctx);
+
+ item = find_log_item (ctx, AUDIT_GOT_DATA, 0);
+ writeout_li (ctx, item? "Yes":"No", "%s", _("Data available"));
+
+ item = find_log_item (ctx, AUDIT_SESSION_KEY, 0);
+ writeout_li (ctx, item? "Yes":"No", "%s", _("Session key created"));
+ if (item)
+ {
+ algo = gcry_cipher_map_name (item->string);
+ if (algo)
+ writeout_rem (ctx, _("algorithm: %s"), gnupg_cipher_algo_name (algo));
+ else if (item->string && !strcmp (item->string, "1.2.840.113549.3.2"))
+ writeout_rem (ctx, _("unsupported algorithm: %s"), "RC2");
+ else if (item->string)
+ writeout_rem (ctx, _("unsupported algorithm: %s"), item->string);
+ else
+ writeout_rem (ctx, _("seems to be not encrypted"));
+ }
+
+ item = find_log_item (ctx, AUDIT_GOT_RECIPIENTS, 0);
+ snprintf (numbuf, sizeof numbuf, "%d",
+ item && item->have_intvalue? item->intvalue : 0);
+ writeout_li (ctx, numbuf, "%s", _("Number of recipients"));
+
+ /* Loop over all recipients. */
+ loopitem = NULL;
+ recp_no = 0;
+ while ((loopitem=find_next_log_item (ctx, loopitem, AUDIT_ENCRYPTED_TO, 0)))
+ {
+ recp_no++;
+ writeout_li (ctx, NULL, _("Recipient %d"), recp_no);
+ if (loopitem->cert)
+ {
+ name = get_cert_name (loopitem->cert);
+ writeout_rem (ctx, "%s", name);
+ xfree (name);
+ enter_li (ctx);
+ for (idx=0; (name = get_cert_subject (loopitem->cert, idx)); idx++)
+ {
+ writeout_rem (ctx, "%s", name);
+ xfree (name);
+ }
+ leave_li (ctx);
+ }
+ }
+
+ leave_li (ctx);
+}
+
+
+
+/* Process a sign operation's log. */
+static void
+proc_type_sign (audit_ctx_t ctx)
+{
+ log_item_t item, loopitem;
+ int signer, idx;
+ const char *result;
+ ksba_cert_t cert;
+ char *name;
+ int lastalgo;
+
+ item = find_log_item (ctx, AUDIT_SIGNING_DONE, 0);
+ writeout_li (ctx, item?"Yes":"No", "%s", _("Data signing succeeded"));
+
+ enter_li (ctx);
+
+ item = find_log_item (ctx, AUDIT_GOT_DATA, 0);
+ writeout_li (ctx, item? "Yes":"No", "%s", _("Data available"));
+ /* Write remarks with the data hash algorithms. We use a very
+ simple scheme to avoid some duplicates. */
+ loopitem = NULL;
+ lastalgo = 0;
+ while ((loopitem = find_next_log_item
+ (ctx, loopitem, AUDIT_DATA_HASH_ALGO, AUDIT_NEW_SIG)))
+ {
+ if (loopitem->intvalue && loopitem->intvalue != lastalgo)
+ writeout_rem (ctx, _("data hash algorithm: %s"),
+ gcry_md_algo_name (loopitem->intvalue));
+ lastalgo = loopitem->intvalue;
+ }
+
+ /* Loop over all signer. */
+ loopitem = NULL;
+ signer = 0;
+ while ((loopitem=find_next_log_item (ctx, loopitem, AUDIT_NEW_SIG, 0)))
+ {
+ signer++;
+
+ item = find_next_log_item (ctx, loopitem, AUDIT_SIGNED_BY, AUDIT_NEW_SIG);
+ if (!item)
+ result = "error";
+ else if (!item->err)
+ result = "okay";
+ else if (gpg_err_code (item->err) == GPG_ERR_CANCELED)
+ result = "skipped";
+ else
+ result = gpg_strerror (item->err);
+ cert = item? item->cert : NULL;
+
+ writeout_li (ctx, result, _("Signer %d"), signer);
+ item = find_next_log_item (ctx, loopitem,
+ AUDIT_ATTR_HASH_ALGO, AUDIT_NEW_SIG);
+ if (item)
+ writeout_rem (ctx, _("attr hash algorithm: %s"),
+ gcry_md_algo_name (item->intvalue));
+
+ if (cert)
+ {
+ name = get_cert_name (cert);
+ writeout_rem (ctx, "%s", name);
+ xfree (name);
+ enter_li (ctx);
+ for (idx=0; (name = get_cert_subject (cert, idx)); idx++)
+ {
+ writeout_rem (ctx, "%s", name);
+ xfree (name);
+ }
+ leave_li (ctx);
+ }
+ }
+
+ leave_li (ctx);
+}
+
+
+
+/* Process a decrypt operation's log. */
+static void
+proc_type_decrypt (audit_ctx_t ctx)
+{
+ log_item_t loopitem, item;
+ int algo, recpno;
+ char *name;
+ char numbuf[35];
+ int idx;
+
+ item = find_log_item (ctx, AUDIT_DECRYPTION_RESULT, 0);
+ writeout_li (ctx, item && !item->err?"Yes":"No",
+ "%s", _("Data decryption succeeded"));
+
+ enter_li (ctx);
+
+ item = find_log_item (ctx, AUDIT_GOT_DATA, 0);
+ writeout_li (ctx, item? "Yes":"No", "%s", _("Data available"));
+
+ item = find_log_item (ctx, AUDIT_DATA_CIPHER_ALGO, 0);
+ algo = item? item->intvalue : 0;
+ writeout_li (ctx, algo?"Yes":"No", "%s", _("Encryption algorithm supported"));
+ if (algo)
+ writeout_rem (ctx, _("algorithm: %s"), gnupg_cipher_algo_name (algo));
+
+ item = find_log_item (ctx, AUDIT_BAD_DATA_CIPHER_ALGO, 0);
+ if (item && item->string)
+ {
+ algo = gcry_cipher_map_name (item->string);
+ if (algo)
+ writeout_rem (ctx, _("algorithm: %s"), gnupg_cipher_algo_name (algo));
+ else if (item->string && !strcmp (item->string, "1.2.840.113549.3.2"))
+ writeout_rem (ctx, _("unsupported algorithm: %s"), "RC2");
+ else if (item->string)
+ writeout_rem (ctx, _("unsupported algorithm: %s"), item->string);
+ else
+ writeout_rem (ctx, _("seems to be not encrypted"));
+ }
+
+
+ for (recpno = 0, item = NULL;
+ (item = find_next_log_item (ctx, item, AUDIT_NEW_RECP, 0)); recpno++)
+ ;
+ snprintf (numbuf, sizeof numbuf, "%d", recpno);
+ writeout_li (ctx, numbuf, "%s", _("Number of recipients"));
+
+ /* Loop over all recipients. */
+ loopitem = NULL;
+ while ((loopitem = find_next_log_item (ctx, loopitem, AUDIT_NEW_RECP, 0)))
+ {
+ const char *result;
+
+ recpno = loopitem->have_intvalue? loopitem->intvalue : -1;
+
+ item = find_next_log_item (ctx, loopitem,
+ AUDIT_RECP_RESULT, AUDIT_NEW_RECP);
+ if (!item)
+ result = "not-used";
+ else if (!item->err)
+ result = "okay";
+ else if (gpg_err_code (item->err) == GPG_ERR_CANCELED)
+ result = "skipped";
+ else
+ result = gpg_strerror (item->err);
+
+ item = find_next_log_item (ctx, loopitem,
+ AUDIT_RECP_NAME, AUDIT_NEW_RECP);
+ writeout_li (ctx, result, _("Recipient %d"), recpno);
+ if (item && item->string)
+ writeout_rem (ctx, "%s", item->string);
+
+ /* If we have a certificate write out more infos. */
+ item = find_next_log_item (ctx, loopitem,
+ AUDIT_SAVE_CERT, AUDIT_NEW_RECP);
+ if (item && item->cert)
+ {
+ enter_li (ctx);
+ for (idx=0; (name = get_cert_subject (item->cert, idx)); idx++)
+ {
+ writeout_rem (ctx, "%s", name);
+ xfree (name);
+ }
+ leave_li (ctx);
+ }
+ }
+
+ leave_li (ctx);
+}
+
+
+
+/* Process a verification operation's log. */
+static void
+proc_type_verify (audit_ctx_t ctx)
+{
+ log_item_t loopitem, item;
+ int signo, count, idx, n_good, n_bad;
+ char numbuf[35];
+ const char *result;
+
+ /* If there is at least one signature status we claim that the
+ verification succeeded. This does not mean that the data has
+ verified okay. */
+ item = find_log_item (ctx, AUDIT_SIG_STATUS, 0);
+ writeout_li (ctx, item?"Yes":"No", "%s", _("Data verification succeeded"));
+ enter_li (ctx);
+
+ item = find_log_item (ctx, AUDIT_GOT_DATA, AUDIT_NEW_SIG);
+ writeout_li (ctx, item? "Yes":"No", "%s", _("Data available"));
+ if (!item)
+ goto leave;
+
+ item = find_log_item (ctx, AUDIT_NEW_SIG, 0);
+ writeout_li (ctx, item? "Yes":"No", "%s", _("Signature available"));
+ if (!item)
+ goto leave;
+
+ /* Print info about the used data hashing algorithms. */
+ for (idx=0, n_good=n_bad=0; idx < ctx->logused; idx++)
+ {
+ item = ctx->log + idx;
+ if (item->event == AUDIT_NEW_SIG)
+ break;
+ else if (item->event == AUDIT_DATA_HASH_ALGO)
+ n_good++;
+ else if (item->event == AUDIT_BAD_DATA_HASH_ALGO)
+ n_bad++;
+ }
+ item = find_log_item (ctx, AUDIT_DATA_HASHING, AUDIT_NEW_SIG);
+ if (!item || item->err || !n_good)
+ result = "No";
+ else if (n_good && !n_bad)
+ result = "Yes";
+ else
+ result = "Some";
+ writeout_li (ctx, result, "%s", _("Parsing data succeeded"));
+ if (n_good || n_bad)
+ {
+ for (idx=0; idx < ctx->logused; idx++)
+ {
+ item = ctx->log + idx;
+ if (item->event == AUDIT_NEW_SIG)
+ break;
+ else if (item->event == AUDIT_DATA_HASH_ALGO)
+ writeout_rem (ctx, _("data hash algorithm: %s"),
+ gcry_md_algo_name (item->intvalue));
+ else if (item->event == AUDIT_BAD_DATA_HASH_ALGO)
+ writeout_rem (ctx, _("bad data hash algorithm: %s"),
+ item->string? item->string:"?");
+ }
+ }
+
+
+ /* Loop over all signatures. */
+ loopitem = find_log_item (ctx, AUDIT_NEW_SIG, 0);
+ assert (loopitem);
+ do
+ {
+ signo = loopitem->have_intvalue? loopitem->intvalue : -1;
+
+ item = find_next_log_item (ctx, loopitem,
+ AUDIT_SIG_STATUS, AUDIT_NEW_SIG);
+ writeout_li (ctx, item? item->string:"?", _("Signature %d"), signo);
+ item = find_next_log_item (ctx, loopitem,
+ AUDIT_SIG_NAME, AUDIT_NEW_SIG);
+ if (item)
+ writeout_rem (ctx, "%s", item->string);
+
+ item = find_next_log_item (ctx, loopitem,
+ AUDIT_DATA_HASH_ALGO, AUDIT_NEW_SIG);
+ if (item)
+ writeout_rem (ctx, _("data hash algorithm: %s"),
+ gcry_md_algo_name (item->intvalue));
+ item = find_next_log_item (ctx, loopitem,
+ AUDIT_ATTR_HASH_ALGO, AUDIT_NEW_SIG);
+ if (item)
+ writeout_rem (ctx, _("attr hash algorithm: %s"),
+ gcry_md_algo_name (item->intvalue));
+
+ enter_li (ctx);
+
+ /* List the certificate chain. */
+ list_certchain (ctx, loopitem, AUDIT_NEW_SIG);
+
+ /* Show the result of the chain validation. */
+ item = find_next_log_item (ctx, loopitem,
+ AUDIT_CHAIN_STATUS, AUDIT_NEW_SIG);
+ if (item && item->have_err)
+ {
+ writeout_li (ctx, item->err? "No":"Yes",
+ _("Certificate chain valid"));
+ if (item->err)
+ writeout_rem (ctx, "%s", gpg_strerror (item->err));
+ }
+
+ /* Show whether the root certificate is fine. */
+ item = find_next_log_item (ctx, loopitem,
+ AUDIT_ROOT_TRUSTED, AUDIT_CHAIN_STATUS);
+ if (item)
+ {
+ writeout_li (ctx, item->err?"No":"Yes", "%s",
+ _("Root certificate trustworthy"));
+ if (item->err)
+ {
+ add_helptag (ctx, "gpgsm.root-cert-not-trusted");
+ writeout_rem (ctx, "%s", gpg_strerror (item->err));
+ list_cert (ctx, item->cert, 0);
+ }
+ }
+
+ /* Show result of the CRL/OCSP check. */
+ item = find_next_log_item (ctx, loopitem,
+ AUDIT_CRL_CHECK, AUDIT_NEW_SIG);
+ if (item)
+ {
+ const char *ok;
+ switch (gpg_err_code (item->err))
+ {
+ case 0: ok = "good"; break;
+ case GPG_ERR_TRUE: ok = "n/a"; break;
+ case GPG_ERR_CERT_REVOKED: ok = "bad"; break;
+ case GPG_ERR_NOT_ENABLED: ok = "disabled"; break;
+ case GPG_ERR_NO_CRL_KNOWN:
+ ok = _("no CRL found for certificate");
+ break;
+ case GPG_ERR_CRL_TOO_OLD:
+ ok = _("the available CRL is too old");
+ break;
+ default: ok = gpg_strerror (item->err); break;
+ }
+
+ writeout_li (ctx, ok, "%s", _("CRL/OCSP check of certificates"));
+ if (item->err
+ && gpg_err_code (item->err) != GPG_ERR_CERT_REVOKED
+ && gpg_err_code (item->err) != GPG_ERR_NOT_ENABLED)
+ add_helptag (ctx, "gpgsm.crl-problem");
+ }
+
+ leave_li (ctx);
+ }
+ while ((loopitem = find_next_log_item (ctx, loopitem, AUDIT_NEW_SIG, 0)));
+
+
+ leave:
+ /* Always list the certificates stored in the signature. */
+ item = NULL;
+ count = 0;
+ while ( ((item = find_next_log_item (ctx, item,
+ AUDIT_SAVE_CERT, AUDIT_NEW_SIG))))
+ count++;
+ snprintf (numbuf, sizeof numbuf, "%d", count);
+ writeout_li (ctx, numbuf, _("Included certificates"));
+ item = NULL;
+ while ( ((item = find_next_log_item (ctx, item,
+ AUDIT_SAVE_CERT, AUDIT_NEW_SIG))))
+ {
+ char *name = get_cert_name (item->cert);
+ writeout_rem (ctx, "%s", name);
+ xfree (name);
+ enter_li (ctx);
+ for (idx=0; (name = get_cert_subject (item->cert, idx)); idx++)
+ {
+ writeout_rem (ctx, "%s", name);
+ xfree (name);
+ }
+ leave_li (ctx);
+ }
+ leave_li (ctx);
+}
+
+
+
+
+/* Print the formatted audit result. THIS IS WORK IN PROGRESS. */
+void
+audit_print_result (audit_ctx_t ctx, estream_t out, int use_html)
+{
+ int idx;
+ size_t n;
+ log_item_t item;
+ helptag_t helptag;
+ const char *s;
+ int show_raw = 0;
+ char *orig_codeset;
+
+ if (!ctx)
+ return;
+
+ orig_codeset = i18n_switchto_utf8 ();
+
+ /* We use an environment variable to include some debug info in the
+ log. */
+ if ((s = getenv ("gnupg_debug_audit")))
+ show_raw = 1;
+
+ assert (!ctx->outstream);
+ ctx->outstream = out;
+ ctx->use_html = use_html;
+ ctx->indentlevel = 0;
+ clear_helptags (ctx);
+
+ if (use_html)
+ es_fputs ("<div class=\"" GNUPG_NAME "AuditLog\">\n", ctx->outstream);
+
+ if (!ctx->log || !ctx->logused)
+ {
+ writeout_para (ctx, _("No audit log entries."));
+ goto leave;
+ }
+
+ if (show_raw)
+ {
+ int maxlen;
+
+ for (idx=0,maxlen=0; idx < DIM (eventstr_msgidx); idx++)
+ {
+ n = strlen (eventstr_msgstr + eventstr_msgidx[idx]);
+ if (n > maxlen)
+ maxlen = n;
+ }
+
+ if (use_html)
+ es_fputs ("<pre>\n", out);
+ for (idx=0; idx < ctx->logused; idx++)
+ {
+ es_fprintf (out, "log: %-*s",
+ maxlen, event2str (ctx->log[idx].event));
+ if (ctx->log[idx].have_intvalue)
+ es_fprintf (out, " i=%d", ctx->log[idx].intvalue);
+ if (ctx->log[idx].string)
+ {
+ es_fputs (" s='", out);
+ writeout (ctx, ctx->log[idx].string);
+ es_fputs ("'", out);
+ }
+ if (ctx->log[idx].cert)
+ es_fprintf (out, " has_cert");
+ if (ctx->log[idx].have_err)
+ {
+ es_fputs (" err='", out);
+ writeout (ctx, gpg_strerror (ctx->log[idx].err));
+ es_fputs ("'", out);
+ }
+ es_fputs ("\n", out);
+ }
+ if (use_html)
+ es_fputs ("</pre>\n", out);
+ else
+ es_fputs ("\n", out);
+ }
+
+ enter_li (ctx);
+ switch (ctx->type)
+ {
+ case AUDIT_TYPE_NONE:
+ writeout_li (ctx, NULL, _("Unknown operation"));
+ break;
+ case AUDIT_TYPE_ENCRYPT:
+ proc_type_encrypt (ctx);
+ break;
+ case AUDIT_TYPE_SIGN:
+ proc_type_sign (ctx);
+ break;
+ case AUDIT_TYPE_DECRYPT:
+ proc_type_decrypt (ctx);
+ break;
+ case AUDIT_TYPE_VERIFY:
+ proc_type_verify (ctx);
+ break;
+ }
+ item = find_log_item (ctx, AUDIT_AGENT_READY, 0);
+ if (item && item->have_err)
+ {
+ writeout_li (ctx, item->err? "No":"Yes", "%s", _("Gpg-Agent usable"));
+ if (item->err)
+ {
+ writeout_rem (ctx, "%s", gpg_strerror (item->err));
+ add_helptag (ctx, "gnupg.agent-problem");
+ }
+ }
+ item = find_log_item (ctx, AUDIT_DIRMNGR_READY, 0);
+ if (item && item->have_err)
+ {
+ writeout_li (ctx, item->err? "No":"Yes", "%s", _("Dirmngr usable"));
+ if (item->err)
+ {
+ writeout_rem (ctx, "%s", gpg_strerror (item->err));
+ add_helptag (ctx, "gnupg.dirmngr-problem");
+ }
+ }
+ leave_li (ctx);
+
+
+ /* Show the help from the collected help tags. */
+ if (ctx->helptags)
+ {
+ if (use_html)
+ {
+ es_fputs ("<hr/>\n", ctx->outstream);
+ if (ctx->helptags->next)
+ es_fputs ("<ul>\n", ctx->outstream);
+ }
+ else
+ es_fputs ("\n\n", ctx->outstream);
+ }
+ for (helptag = ctx->helptags; helptag; helptag = helptag->next)
+ {
+ char *text;
+
+ if (use_html && ctx->helptags->next)
+ es_fputs ("<li>\n", ctx->outstream);
+
+ text = gnupg_get_help_string (helptag->name, 0);
+ if (text)
+ {
+ writeout_para (ctx, "%s", text);
+ xfree (text);
+ }
+ else
+ writeout_para (ctx, _("No help available for '%s'."), helptag->name);
+ if (use_html && ctx->helptags->next)
+ es_fputs ("</li>\n", ctx->outstream);
+ if (helptag->next)
+ es_fputs ("\n", ctx->outstream);
+ }
+ if (use_html && ctx->helptags && ctx->helptags->next)
+ es_fputs ("</ul>\n", ctx->outstream);
+
+ leave:
+ if (use_html)
+ es_fputs ("</div>\n", ctx->outstream);
+ ctx->outstream = NULL;
+ ctx->use_html = 0;
+ clear_helptags (ctx);
+ i18n_switchback (orig_codeset);
+}
diff --git a/common/audit.h b/common/audit.h
new file mode 100644
index 0000000..4ef2645
--- /dev/null
+++ b/common/audit.h
@@ -0,0 +1,225 @@
+/* audit.h - Definitions for the audit subsystem
+ * Copyright (C) 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_COMMON_AUDIT_H
+#define GNUPG_COMMON_AUDIT_H
+
+#include <ksba.h>
+
+struct audit_ctx_s;
+typedef struct audit_ctx_s *audit_ctx_t;
+
+/* Constants for the audit type. */
+typedef enum
+ {
+ AUDIT_TYPE_NONE = 0, /* No type set. */
+ AUDIT_TYPE_ENCRYPT, /* Data encryption. */
+ AUDIT_TYPE_SIGN, /* Signature creation. */
+ AUDIT_TYPE_DECRYPT, /* Data decryption. */
+ AUDIT_TYPE_VERIFY /* Signature verification. */
+ }
+audit_type_t;
+
+/* The events we support. */
+typedef enum
+ {
+ AUDIT_NULL_EVENT = 0,
+ /* No such event. Its value shall be 0 and no other values shall
+ be assigned to the other enum symbols. This is required so
+ that the exaudit.awk script comes up with correct values
+ without running cc. */
+
+ AUDIT_SETUP_READY,
+ /* All preparations done so that the actual processing can start
+ now. This indicates that all parameters are okay and we can
+ start to process the actual data. */
+
+ AUDIT_AGENT_READY, /* err */
+ /* Indicates whether the gpg-agent is available. For some
+ operations the agent is not required and thus no such event
+ will be logged. */
+
+ AUDIT_DIRMNGR_READY, /* err */
+ /* Indicates whether the Dirmngr is available. For some
+ operations the Dirmngr is not required and thus no such event
+ will be logged. */
+
+ AUDIT_GPG_READY, /* err */
+ /* Indicates whether the Gpg engine is available. */
+
+ AUDIT_GPGSM_READY, /* err */
+ /* Indicates whether the Gpgsm engine is available. */
+
+ AUDIT_G13_READY, /* err */
+ /* Indicates whether the G13 engine is available. */
+
+ AUDIT_GOT_DATA,
+ /* Data to be processed has been seen. */
+
+ AUDIT_DETACHED_SIGNATURE,
+ /* The signature is a detached one. */
+
+ AUDIT_CERT_ONLY_SIG,
+ /* A certifciate only signature has been detected. */
+
+ AUDIT_DATA_HASH_ALGO, /* int */
+ /* The hash algo given as argument is used for the data. This
+ event will be repeated for all hash algorithms used with the
+ data. */
+
+ AUDIT_ATTR_HASH_ALGO, /* int */
+ /* The hash algo given as argument is used to hash the message
+ digest and other signed attributes of this signature. */
+
+ AUDIT_DATA_CIPHER_ALGO, /* int */
+ /* The cipher algo given as argument is used for this data. */
+
+ AUDIT_BAD_DATA_HASH_ALGO, /* string */
+ /* The hash algo as specified by the signature can't be used.
+ STRING is the description of this algorithm which usually is an
+ OID string. STRING may be NULL. */
+
+ AUDIT_BAD_DATA_CIPHER_ALGO, /* string */
+ /* The symmetric cipher algorithm is not supported. STRING is the
+ description of this algorithm which usually is an OID string.
+ STRING may be NULL. */
+
+ AUDIT_DATA_HASHING, /* ok_err */
+ /* Logs the result of the data hashing. */
+
+ AUDIT_READ_ERROR, /* ok_err */
+ /* A generic read error occurred. */
+
+ AUDIT_WRITE_ERROR, /* ok_err */
+ /* A generic write error occurred. */
+
+ AUDIT_USAGE_ERROR,
+ /* The program was used in an inappropriate way; For example by
+ passing a data object while the signature does not expect one
+ or vice versa. */
+
+ AUDIT_SAVE_CERT, /* cert, ok_err */
+ /* Save the certificate received in a message. */
+
+ AUDIT_NEW_SIG, /* int */
+ /* Start the verification of a new signature for the last data
+ object. The argument is the signature number as used
+ internally by the program. */
+
+ AUDIT_SIG_NAME, /* string */
+ /* The name of a signer. This is the name or other identification
+ data as known from the signature and not the name from the
+ certificate used for verification. An example for STRING when
+ using CMS is: "#1234/CN=Prostetnic Vogon Jeltz". */
+
+ AUDIT_SIG_STATUS, /* string */
+ /* The signature status of the current signer. This is the last
+ audit information for one signature. STRING gives the status:
+
+ "error" - there was a problem checking this or any signature.
+ "unsupported" - the signature type is not supported.
+ "no-cert" - The certificate of the signer was not found (the
+ S/N+issuer of the signer is already in the log).
+ "bad" - bad signature
+ "good" - good signature
+ */
+
+ AUDIT_NEW_RECP, /* int */
+ /* A new recipient has been seen during decryption. The argument
+ is the recipient number as used internally by the program. */
+
+ AUDIT_RECP_NAME, /* string */
+ /* The name of a recipient. This is the name or other identification
+ data as known from the decryption and not the name from the
+ certificate used for decryption. An example for STRING when
+ using CMS is: "#1234/CN=Prostetnic Vogon Jeltz". */
+
+ AUDIT_RECP_RESULT, /* ok_err */
+ /* The status of the session key decryption. This is only written
+ for recipients tried. */
+
+ AUDIT_DECRYPTION_RESULT, /* ok_err */
+ /* The status of the entire decryption. The decryption was
+ successful if the error code is 0. */
+
+ AUDIT_VALIDATE_CHAIN,
+ /* Start the validation of a certificate chain. */
+
+ AUDIT_CHAIN_BEGIN,
+ AUDIT_CHAIN_CERT, /* cert */
+ AUDIT_CHAIN_ROOTCERT,/* cert */
+ AUDIT_CHAIN_END,
+ /* These 4 events are used to log the certificates making up a
+ certificate chain. ROOTCERT is used for the trustanchor and
+ CERT for all other certificates. */
+
+ AUDIT_CHAIN_STATUS, /* err */
+ /* Tells the final status of the chain validation. */
+
+ AUDIT_ROOT_TRUSTED, /* cert, err */
+ /* Tells whether the root certificate is trusted. This event is
+ emitted during chain validation. */
+
+ AUDIT_CRL_CHECK, /* err */
+ /* Tells the status of a CRL or OCSP check. */
+
+ AUDIT_GOT_RECIPIENTS, /* int */
+ /* Records the number of recipients to be used for encryption.
+ This includes the recipients set by --encrypt-to but records 0
+ if no real recipient has been given. */
+
+ AUDIT_SESSION_KEY, /* string */
+ /* Mark the creation or availibility of the session key. The
+ parameter is the algorithm ID. */
+
+ AUDIT_ENCRYPTED_TO, /* cert, err */
+ /* Records the certificate used for encryption and whether the
+ session key could be encrypted to it (err==0). */
+
+ AUDIT_ENCRYPTION_DONE,
+ /* Encryption succeeded. */
+
+ AUDIT_SIGNED_BY, /* cert, err */
+ /* Records the certificate used for signed and whether the signure
+ could be created (if err==0). */
+
+ AUDIT_SIGNING_DONE,
+ /* Signing succeeded. */
+
+
+ AUDIT_LAST_EVENT /* Marker for parsing this list. */
+ }
+audit_event_t;
+
+
+audit_ctx_t audit_new (void);
+void audit_release (audit_ctx_t ctx);
+void audit_set_type (audit_ctx_t ctx, audit_type_t type);
+void audit_log (audit_ctx_t ctx, audit_event_t event);
+void audit_log_ok (audit_ctx_t ctx, audit_event_t event, gpg_error_t err);
+void audit_log_i (audit_ctx_t ctx, audit_event_t event, int value);
+void audit_log_s (audit_ctx_t ctx, audit_event_t event, const char *value);
+void audit_log_cert (audit_ctx_t ctx, audit_event_t event,
+ ksba_cert_t cert, gpg_error_t err);
+
+void audit_print_result (audit_ctx_t ctx, estream_t stream, int use_html);
+
+
+
+#endif /*GNUPG_COMMON_AUDIT_H*/
diff --git a/common/b64dec.c b/common/b64dec.c
new file mode 100644
index 0000000..6af494b
--- /dev/null
+++ b/common/b64dec.c
@@ -0,0 +1,254 @@
+/* b64dec.c - Simple Base64 decoder.
+ * Copyright (C) 2008, 2011 Free Software Foundation, Inc.
+ * Copyright (C) 2008, 2011, 2016 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This file 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 Lesser General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "i18n.h"
+#include "util.h"
+
+
+/* The reverse base-64 list used for base-64 decoding. */
+static unsigned char const asctobin[128] =
+ {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
+ 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
+ 0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+ 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
+ 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
+ 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+ 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+ 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
+ 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff
+ };
+
+enum decoder_states
+ {
+ s_init, s_idle, s_lfseen, s_beginseen, s_waitheader, s_waitblank, s_begin,
+ s_b64_0, s_b64_1, s_b64_2, s_b64_3,
+ s_waitendtitle, s_waitend
+ };
+
+
+
+/* Initialize the context for the base64 decoder. If TITLE is NULL a
+ plain base64 decoding is done. If it is the empty string the
+ decoder will skip everything until a "-----BEGIN " line has been
+ seen, decoding ends at a "----END " line. */
+gpg_error_t
+b64dec_start (struct b64state *state, const char *title)
+{
+ memset (state, 0, sizeof *state);
+ if (title)
+ {
+ state->title = xtrystrdup (title);
+ if (!state->title)
+ state->lasterr = gpg_error_from_syserror ();
+ else
+ state->idx = s_init;
+ }
+ else
+ state->idx = s_b64_0;
+ return state->lasterr;
+}
+
+
+/* Do in-place decoding of base-64 data of LENGTH in BUFFER. Stores the
+ new length of the buffer at R_NBYTES. */
+gpg_error_t
+b64dec_proc (struct b64state *state, void *buffer, size_t length,
+ size_t *r_nbytes)
+{
+ enum decoder_states ds = state->idx;
+ unsigned char val = state->radbuf[0];
+ int pos = state->quad_count;
+ char *d, *s;
+
+ if (state->lasterr)
+ return state->lasterr;
+
+ if (state->stop_seen)
+ {
+ *r_nbytes = 0;
+ state->lasterr = gpg_error (GPG_ERR_EOF);
+ xfree (state->title);
+ state->title = NULL;
+ return state->lasterr;
+ }
+
+ for (s=d=buffer; length && !state->stop_seen; length--, s++)
+ {
+ again:
+ switch (ds)
+ {
+ case s_idle:
+ if (*s == '\n')
+ {
+ ds = s_lfseen;
+ pos = 0;
+ }
+ break;
+ case s_init:
+ ds = s_lfseen;
+ /* fall through */
+ case s_lfseen:
+ if (*s != "-----BEGIN "[pos])
+ {
+ ds = s_idle;
+ goto again;
+ }
+ else if (pos == 10)
+ {
+ pos = 0;
+ ds = s_beginseen;
+ }
+ else
+ pos++;
+ break;
+ case s_beginseen:
+ if (*s != "PGP "[pos])
+ ds = s_begin; /* Not a PGP armor. */
+ else if (pos == 3)
+ ds = s_waitheader;
+ else
+ pos++;
+ break;
+ case s_waitheader:
+ if (*s == '\n')
+ ds = s_waitblank;
+ break;
+ case s_waitblank:
+ if (*s == '\n')
+ ds = s_b64_0; /* blank line found. */
+ else if (*s == ' ' || *s == '\r' || *s == '\t')
+ ; /* Ignore spaces. */
+ else
+ {
+ /* Armor header line. Note that we don't care that our
+ * FSM accepts a header prefixed with spaces. */
+ ds = s_waitheader; /* Wait for next header. */
+ }
+ break;
+ case s_begin:
+ if (*s == '\n')
+ ds = s_b64_0;
+ break;
+ case s_b64_0:
+ case s_b64_1:
+ case s_b64_2:
+ case s_b64_3:
+ {
+ int c;
+
+ if (*s == '-' && state->title)
+ {
+ /* Not a valid Base64 character: assume end
+ header. */
+ ds = s_waitend;
+ }
+ else if (*s == '=')
+ {
+ /* Pad character: stop */
+ if (ds == s_b64_1)
+ *d++ = val;
+ ds = state->title? s_waitendtitle : s_waitend;
+ }
+ else if (*s == '\n' || *s == ' ' || *s == '\r' || *s == '\t')
+ ; /* Skip white spaces. */
+ else if ( (*s & 0x80)
+ || (c = asctobin[*(unsigned char *)s]) == 255)
+ {
+ /* Skip invalid encodings. */
+ state->invalid_encoding = 1;
+ }
+ else if (ds == s_b64_0)
+ {
+ val = c << 2;
+ ds = s_b64_1;
+ }
+ else if (ds == s_b64_1)
+ {
+ val |= (c>>4)&3;
+ *d++ = val;
+ val = (c<<4)&0xf0;
+ ds = s_b64_2;
+ }
+ else if (ds == s_b64_2)
+ {
+ val |= (c>>2)&15;
+ *d++ = val;
+ val = (c<<6)&0xc0;
+ ds = s_b64_3;
+ }
+ else
+ {
+ val |= c&0x3f;
+ *d++ = val;
+ ds = s_b64_0;
+ }
+ }
+ break;
+ case s_waitendtitle:
+ if (*s == '-')
+ ds = s_waitend;
+ break;
+ case s_waitend:
+ if ( *s == '\n')
+ state->stop_seen = 1;
+ break;
+ default:
+ BUG();
+ }
+ }
+
+
+ state->idx = ds;
+ state->radbuf[0] = val;
+ state->quad_count = pos;
+ *r_nbytes = (d -(char*) buffer);
+ return 0;
+}
+
+
+/* This function needs to be called before releasing the decoder
+ state. It may return an error code in case an encoding error has
+ been found during decoding. */
+gpg_error_t
+b64dec_finish (struct b64state *state)
+{
+ xfree (state->title);
+ state->title = NULL;
+
+ if (state->lasterr)
+ return state->lasterr;
+
+ return state->invalid_encoding? gpg_error(GPG_ERR_BAD_DATA): 0;
+}
diff --git a/common/b64enc.c b/common/b64enc.c
new file mode 100644
index 0000000..d633048
--- /dev/null
+++ b/common/b64enc.c
@@ -0,0 +1,422 @@
+/* b64enc.c - Simple Base64 encoder.
+ * Copyright (C) 2001, 2003, 2004, 2008, 2010,
+ * 2011 Free Software Foundation, Inc.
+ * Copyright (C) 2001, 2003, 2004, 2008, 2010,
+ * 2011 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This file 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 Lesser General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "i18n.h"
+#include "util.h"
+
+#define B64ENC_DID_HEADER 1
+#define B64ENC_DID_TRAILER 2
+#define B64ENC_NO_LINEFEEDS 16
+#define B64ENC_USE_PGPCRC 32
+
+/* The base-64 character list */
+static unsigned char bintoasc[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789+/";
+
+/* Stuff required to create the OpenPGP CRC. This crc_table has been
+ created using this code:
+
+ #include <stdio.h>
+ #include <stdint.h>
+
+ #define CRCPOLY 0x864CFB
+
+ int
+ main (void)
+ {
+ int i, j;
+ uint32_t t;
+ uint32_t crc_table[256];
+
+ crc_table[0] = 0;
+ for (i=j=0; j < 128; j++ )
+ {
+ t = crc_table[j];
+ if ( (t & 0x00800000) )
+ {
+ t <<= 1;
+ crc_table[i++] = t ^ CRCPOLY;
+ crc_table[i++] = t;
+ }
+ else
+ {
+ t <<= 1;
+ crc_table[i++] = t;
+ crc_table[i++] = t ^ CRCPOLY;
+ }
+ }
+
+ puts ("static const u32 crc_table[256] = {");
+ for (i=j=0; i < 256; i++)
+ {
+ printf ("%s 0x%08lx", j? "":" ", (unsigned long)crc_table[i]);
+ if (i != 255)
+ {
+ putchar (',');
+ if ( ++j > 5)
+ {
+ j = 0;
+ putchar ('\n');
+ }
+ }
+ }
+ puts ("\n};");
+ return 0;
+ }
+*/
+#define CRCINIT 0xB704CE
+static const u32 crc_table[256] = {
+ 0x00000000, 0x00864cfb, 0x018ad50d, 0x010c99f6, 0x0393e6e1, 0x0315aa1a,
+ 0x021933ec, 0x029f7f17, 0x07a18139, 0x0727cdc2, 0x062b5434, 0x06ad18cf,
+ 0x043267d8, 0x04b42b23, 0x05b8b2d5, 0x053efe2e, 0x0fc54e89, 0x0f430272,
+ 0x0e4f9b84, 0x0ec9d77f, 0x0c56a868, 0x0cd0e493, 0x0ddc7d65, 0x0d5a319e,
+ 0x0864cfb0, 0x08e2834b, 0x09ee1abd, 0x09685646, 0x0bf72951, 0x0b7165aa,
+ 0x0a7dfc5c, 0x0afbb0a7, 0x1f0cd1e9, 0x1f8a9d12, 0x1e8604e4, 0x1e00481f,
+ 0x1c9f3708, 0x1c197bf3, 0x1d15e205, 0x1d93aefe, 0x18ad50d0, 0x182b1c2b,
+ 0x192785dd, 0x19a1c926, 0x1b3eb631, 0x1bb8faca, 0x1ab4633c, 0x1a322fc7,
+ 0x10c99f60, 0x104fd39b, 0x11434a6d, 0x11c50696, 0x135a7981, 0x13dc357a,
+ 0x12d0ac8c, 0x1256e077, 0x17681e59, 0x17ee52a2, 0x16e2cb54, 0x166487af,
+ 0x14fbf8b8, 0x147db443, 0x15712db5, 0x15f7614e, 0x3e19a3d2, 0x3e9fef29,
+ 0x3f9376df, 0x3f153a24, 0x3d8a4533, 0x3d0c09c8, 0x3c00903e, 0x3c86dcc5,
+ 0x39b822eb, 0x393e6e10, 0x3832f7e6, 0x38b4bb1d, 0x3a2bc40a, 0x3aad88f1,
+ 0x3ba11107, 0x3b275dfc, 0x31dced5b, 0x315aa1a0, 0x30563856, 0x30d074ad,
+ 0x324f0bba, 0x32c94741, 0x33c5deb7, 0x3343924c, 0x367d6c62, 0x36fb2099,
+ 0x37f7b96f, 0x3771f594, 0x35ee8a83, 0x3568c678, 0x34645f8e, 0x34e21375,
+ 0x2115723b, 0x21933ec0, 0x209fa736, 0x2019ebcd, 0x228694da, 0x2200d821,
+ 0x230c41d7, 0x238a0d2c, 0x26b4f302, 0x2632bff9, 0x273e260f, 0x27b86af4,
+ 0x252715e3, 0x25a15918, 0x24adc0ee, 0x242b8c15, 0x2ed03cb2, 0x2e567049,
+ 0x2f5ae9bf, 0x2fdca544, 0x2d43da53, 0x2dc596a8, 0x2cc90f5e, 0x2c4f43a5,
+ 0x2971bd8b, 0x29f7f170, 0x28fb6886, 0x287d247d, 0x2ae25b6a, 0x2a641791,
+ 0x2b688e67, 0x2beec29c, 0x7c3347a4, 0x7cb50b5f, 0x7db992a9, 0x7d3fde52,
+ 0x7fa0a145, 0x7f26edbe, 0x7e2a7448, 0x7eac38b3, 0x7b92c69d, 0x7b148a66,
+ 0x7a181390, 0x7a9e5f6b, 0x7801207c, 0x78876c87, 0x798bf571, 0x790db98a,
+ 0x73f6092d, 0x737045d6, 0x727cdc20, 0x72fa90db, 0x7065efcc, 0x70e3a337,
+ 0x71ef3ac1, 0x7169763a, 0x74578814, 0x74d1c4ef, 0x75dd5d19, 0x755b11e2,
+ 0x77c46ef5, 0x7742220e, 0x764ebbf8, 0x76c8f703, 0x633f964d, 0x63b9dab6,
+ 0x62b54340, 0x62330fbb, 0x60ac70ac, 0x602a3c57, 0x6126a5a1, 0x61a0e95a,
+ 0x649e1774, 0x64185b8f, 0x6514c279, 0x65928e82, 0x670df195, 0x678bbd6e,
+ 0x66872498, 0x66016863, 0x6cfad8c4, 0x6c7c943f, 0x6d700dc9, 0x6df64132,
+ 0x6f693e25, 0x6fef72de, 0x6ee3eb28, 0x6e65a7d3, 0x6b5b59fd, 0x6bdd1506,
+ 0x6ad18cf0, 0x6a57c00b, 0x68c8bf1c, 0x684ef3e7, 0x69426a11, 0x69c426ea,
+ 0x422ae476, 0x42aca88d, 0x43a0317b, 0x43267d80, 0x41b90297, 0x413f4e6c,
+ 0x4033d79a, 0x40b59b61, 0x458b654f, 0x450d29b4, 0x4401b042, 0x4487fcb9,
+ 0x461883ae, 0x469ecf55, 0x479256a3, 0x47141a58, 0x4defaaff, 0x4d69e604,
+ 0x4c657ff2, 0x4ce33309, 0x4e7c4c1e, 0x4efa00e5, 0x4ff69913, 0x4f70d5e8,
+ 0x4a4e2bc6, 0x4ac8673d, 0x4bc4fecb, 0x4b42b230, 0x49ddcd27, 0x495b81dc,
+ 0x4857182a, 0x48d154d1, 0x5d26359f, 0x5da07964, 0x5cace092, 0x5c2aac69,
+ 0x5eb5d37e, 0x5e339f85, 0x5f3f0673, 0x5fb94a88, 0x5a87b4a6, 0x5a01f85d,
+ 0x5b0d61ab, 0x5b8b2d50, 0x59145247, 0x59921ebc, 0x589e874a, 0x5818cbb1,
+ 0x52e37b16, 0x526537ed, 0x5369ae1b, 0x53efe2e0, 0x51709df7, 0x51f6d10c,
+ 0x50fa48fa, 0x507c0401, 0x5542fa2f, 0x55c4b6d4, 0x54c82f22, 0x544e63d9,
+ 0x56d11cce, 0x56575035, 0x575bc9c3, 0x57dd8538
+};
+
+
+static gpg_error_t
+enc_start (struct b64state *state, FILE *fp, estream_t stream,
+ const char *title)
+{
+ memset (state, 0, sizeof *state);
+ state->fp = fp;
+ state->stream = stream;
+ state->lasterr = 0;
+ if (title && !*title)
+ state->flags |= B64ENC_NO_LINEFEEDS;
+ else if (title)
+ {
+ if (!strncmp (title, "PGP ", 4))
+ {
+ state->flags |= B64ENC_USE_PGPCRC;
+ state->crc = CRCINIT;
+ }
+ state->title = xtrystrdup (title);
+ if (!state->title)
+ state->lasterr = gpg_error_from_syserror ();
+ }
+ return state->lasterr;
+}
+
+
+/* Prepare for base-64 writing to the stream FP. If TITLE is not NULL
+ and not an empty string, this string will be used as the title for
+ the armor lines, with TITLE being an empty string, we don't write
+ the header lines and furthermore even don't write any linefeeds.
+ If TITLE starts with "PGP " the OpenPGP CRC checksum will be
+ written as well. With TITLE being NULL, we merely don't write
+ header but make sure that lines are not too long. Note, that we
+ don't write any output unless at least one byte get written using
+ b64enc_write. */
+gpg_error_t
+b64enc_start (struct b64state *state, FILE *fp, const char *title)
+{
+ return enc_start (state, fp, NULL, title);
+}
+
+/* Same as b64enc_start but takes an estream. */
+gpg_error_t
+b64enc_start_es (struct b64state *state, estream_t fp, const char *title)
+{
+ return enc_start (state, NULL, fp, title);
+}
+
+
+static int
+my_fputs (const char *string, struct b64state *state)
+{
+ if (state->stream)
+ return es_fputs (string, state->stream);
+ else
+ return fputs (string, state->fp);
+}
+
+
+/* Write NBYTES from BUFFER to the Base 64 stream identified by
+ STATE. With BUFFER and NBYTES being 0, merely do a fflush on the
+ stream. */
+gpg_error_t
+b64enc_write (struct b64state *state, const void *buffer, size_t nbytes)
+{
+ unsigned char radbuf[4];
+ int idx, quad_count;
+ const unsigned char *p;
+
+ if (state->lasterr)
+ return state->lasterr;
+
+ if (!nbytes)
+ {
+ if (buffer)
+ if (state->stream? es_fflush (state->stream) : fflush (state->fp))
+ goto write_error;
+ return 0;
+ }
+
+ if (!(state->flags & B64ENC_DID_HEADER))
+ {
+ if (state->title)
+ {
+ if ( my_fputs ("-----BEGIN ", state) == EOF
+ || my_fputs (state->title, state) == EOF
+ || my_fputs ("-----\n", state) == EOF)
+ goto write_error;
+ if ( (state->flags & B64ENC_USE_PGPCRC)
+ && my_fputs ("\n", state) == EOF)
+ goto write_error;
+ }
+
+ state->flags |= B64ENC_DID_HEADER;
+ }
+
+ idx = state->idx;
+ quad_count = state->quad_count;
+ assert (idx < 4);
+ memcpy (radbuf, state->radbuf, idx);
+
+ if ( (state->flags & B64ENC_USE_PGPCRC) )
+ {
+ size_t n;
+ u32 crc = state->crc;
+
+ for (p=buffer, n=nbytes; n; p++, n-- )
+ crc = ((u32)crc << 8) ^ crc_table[((crc >> 16)&0xff) ^ *p];
+ state->crc = (crc & 0x00ffffff);
+ }
+
+ for (p=buffer; nbytes; p++, nbytes--)
+ {
+ radbuf[idx++] = *p;
+ if (idx > 2)
+ {
+ char tmp[4];
+
+ tmp[0] = bintoasc[(*radbuf >> 2) & 077];
+ tmp[1] = bintoasc[(((*radbuf<<4)&060)|((radbuf[1] >> 4)&017))&077];
+ tmp[2] = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077];
+ tmp[3] = bintoasc[radbuf[2]&077];
+ if (state->stream)
+ {
+ for (idx=0; idx < 4; idx++)
+ es_putc (tmp[idx], state->stream);
+ idx = 0;
+ if (es_ferror (state->stream))
+ goto write_error;
+ }
+ else
+ {
+ for (idx=0; idx < 4; idx++)
+ putc (tmp[idx], state->fp);
+ idx = 0;
+ if (ferror (state->fp))
+ goto write_error;
+ }
+ if (++quad_count >= (64/4))
+ {
+ quad_count = 0;
+ if (!(state->flags & B64ENC_NO_LINEFEEDS)
+ && my_fputs ("\n", state) == EOF)
+ goto write_error;
+ }
+ }
+ }
+ memcpy (state->radbuf, radbuf, idx);
+ state->idx = idx;
+ state->quad_count = quad_count;
+ return 0;
+
+ write_error:
+ state->lasterr = gpg_error_from_syserror ();
+ if (state->title)
+ {
+ xfree (state->title);
+ state->title = NULL;
+ }
+ return state->lasterr;
+}
+
+
+gpg_error_t
+b64enc_finish (struct b64state *state)
+{
+ gpg_error_t err = 0;
+ unsigned char radbuf[4];
+ int idx, quad_count;
+ char tmp[4];
+
+ if (state->lasterr)
+ return state->lasterr;
+
+ if (!(state->flags & B64ENC_DID_HEADER))
+ goto cleanup;
+
+ /* Flush the base64 encoding */
+ idx = state->idx;
+ quad_count = state->quad_count;
+ assert (idx < 4);
+ memcpy (radbuf, state->radbuf, idx);
+
+ if (idx)
+ {
+ tmp[0] = bintoasc[(*radbuf>>2)&077];
+ if (idx == 1)
+ {
+ tmp[1] = bintoasc[((*radbuf << 4) & 060) & 077];
+ tmp[2] = '=';
+ tmp[3] = '=';
+ }
+ else
+ {
+ tmp[1] = bintoasc[(((*radbuf<<4)&060)|((radbuf[1]>>4)&017))&077];
+ tmp[2] = bintoasc[((radbuf[1] << 2) & 074) & 077];
+ tmp[3] = '=';
+ }
+ if (state->stream)
+ {
+ for (idx=0; idx < 4; idx++)
+ es_putc (tmp[idx], state->stream);
+ if (es_ferror (state->stream))
+ goto write_error;
+ }
+ else
+ {
+ for (idx=0; idx < 4; idx++)
+ putc (tmp[idx], state->fp);
+ if (ferror (state->fp))
+ goto write_error;
+ }
+
+ if (++quad_count >= (64/4))
+ {
+ quad_count = 0;
+ if (!(state->flags & B64ENC_NO_LINEFEEDS)
+ && my_fputs ("\n", state) == EOF)
+ goto write_error;
+ }
+ }
+
+ /* Finish the last line and write the trailer. */
+ if (quad_count
+ && !(state->flags & B64ENC_NO_LINEFEEDS)
+ && my_fputs ("\n", state) == EOF)
+ goto write_error;
+
+ if ( (state->flags & B64ENC_USE_PGPCRC) )
+ {
+ /* Write the CRC. */
+ my_fputs ("=", state);
+ radbuf[0] = state->crc >>16;
+ radbuf[1] = state->crc >> 8;
+ radbuf[2] = state->crc;
+ tmp[0] = bintoasc[(*radbuf>>2)&077];
+ tmp[1] = bintoasc[(((*radbuf<<4)&060)|((radbuf[1]>>4)&017))&077];
+ tmp[2] = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077];
+ tmp[3] = bintoasc[radbuf[2]&077];
+ if (state->stream)
+ {
+ for (idx=0; idx < 4; idx++)
+ es_putc (tmp[idx], state->stream);
+ if (es_ferror (state->stream))
+ goto write_error;
+ }
+ else
+ {
+ for (idx=0; idx < 4; idx++)
+ putc (tmp[idx], state->fp);
+ if (ferror (state->fp))
+ goto write_error;
+ }
+ if (!(state->flags & B64ENC_NO_LINEFEEDS)
+ && my_fputs ("\n", state) == EOF)
+ goto write_error;
+ }
+
+ if (state->title)
+ {
+ if ( my_fputs ("-----END ", state) == EOF
+ || my_fputs (state->title, state) == EOF
+ || my_fputs ("-----\n", state) == EOF)
+ goto write_error;
+ }
+
+ goto cleanup;
+
+ write_error:
+ err = gpg_error_from_syserror ();
+
+ cleanup:
+ if (state->title)
+ {
+ xfree (state->title);
+ state->title = NULL;
+ }
+ state->fp = NULL;
+ state->stream = NULL;
+ state->lasterr = err;
+ return err;
+}
diff --git a/common/call-gpg.c b/common/call-gpg.c
new file mode 100644
index 0000000..c1472e9
--- /dev/null
+++ b/common/call-gpg.c
@@ -0,0 +1,753 @@
+/* call-gpg.c - Communication with the GPG
+ * Copyright (C) 2009 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include <assert.h>
+#include <assuan.h>
+#include <errno.h>
+#include <npth.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#include "call-gpg.h"
+#include "exechelp.h"
+#include "i18n.h"
+#include "logging.h"
+#include "membuf.h"
+#include "strlist.h"
+#include "util.h"
+
+
+static GPGRT_INLINE gpg_error_t
+my_error_from_syserror (void)
+{
+ return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
+}
+
+static GPGRT_INLINE gpg_error_t
+my_error_from_errno (int e)
+{
+ return gpg_err_make (default_errsource, gpg_err_code_from_errno (e));
+}
+
+
+/* Fire up a new GPG. Handle the server's initial greeting. Returns
+ 0 on success and stores the assuan context at R_CTX. */
+static gpg_error_t
+start_gpg (ctrl_t ctrl, const char *gpg_program, strlist_t gpg_arguments,
+ int input_fd, int output_fd, assuan_context_t *r_ctx)
+{
+ gpg_error_t err;
+ assuan_context_t ctx = NULL;
+ const char *pgmname;
+ const char **argv;
+ assuan_fd_t no_close_list[5];
+ int i;
+ char line[ASSUAN_LINELENGTH];
+
+ (void)ctrl;
+
+ *r_ctx = NULL;
+
+ err = assuan_new (&ctx);
+ if (err)
+ {
+ log_error ("can't allocate assuan context: %s\n", gpg_strerror (err));
+ return err;
+ }
+
+ /* The first time we are used, initialize the gpg_program variable. */
+ if ( !gpg_program || !*gpg_program )
+ gpg_program = gnupg_module_name (GNUPG_MODULE_NAME_GPG);
+
+ /* Compute argv[0]. */
+ if ( !(pgmname = strrchr (gpg_program, '/')))
+ pgmname = gpg_program;
+ else
+ pgmname++;
+
+ if (fflush (NULL))
+ {
+ err = my_error_from_syserror ();
+ log_error ("error flushing pending output: %s\n", gpg_strerror (err));
+ return err;
+ }
+
+ argv = xtrycalloc (strlist_length (gpg_arguments) + 3, sizeof *argv);
+ if (argv == NULL)
+ {
+ err = my_error_from_syserror ();
+ return err;
+ }
+ i = 0;
+ argv[i++] = pgmname;
+ argv[i++] = "--server";
+ for (; gpg_arguments; gpg_arguments = gpg_arguments->next)
+ argv[i++] = gpg_arguments->d;
+ argv[i++] = NULL;
+
+ i = 0;
+ if (log_get_fd () != -1)
+ no_close_list[i++] = assuan_fd_from_posix_fd (log_get_fd ());
+ no_close_list[i++] = assuan_fd_from_posix_fd (fileno (stderr));
+ if (input_fd != -1)
+ no_close_list[i++] = assuan_fd_from_posix_fd (input_fd);
+ if (output_fd != -1)
+ no_close_list[i++] = assuan_fd_from_posix_fd (output_fd);
+ no_close_list[i] = ASSUAN_INVALID_FD;
+
+ /* Connect to GPG and perform initial handshaking. */
+ err = assuan_pipe_connect (ctx, gpg_program, argv, no_close_list,
+ NULL, NULL, 0);
+ if (err)
+ {
+ assuan_release (ctx);
+ log_error ("can't connect to GPG: %s\n", gpg_strerror (err));
+ return gpg_error (GPG_ERR_NO_ENGINE);
+ }
+
+ if (input_fd != -1)
+ {
+ snprintf (line, sizeof line, "INPUT FD=%d", input_fd);
+ err = assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
+ if (err)
+ {
+ assuan_release (ctx);
+ log_error ("error sending INPUT command: %s\n", gpg_strerror (err));
+ return err;
+ }
+ }
+
+ if (output_fd != -1)
+ {
+ snprintf (line, sizeof line, "OUTPUT FD=%d", output_fd);
+ err = assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
+ if (err)
+ {
+ assuan_release (ctx);
+ log_error ("error sending OUTPUT command: %s\n", gpg_strerror (err));
+ return err;
+ }
+ }
+
+ *r_ctx = ctx;
+ return 0;
+}
+
+
+/* Release the assuan context created by start_gpg. */
+static void
+release_gpg (assuan_context_t ctx)
+{
+ assuan_release (ctx);
+}
+
+
+
+/* The data passed to the writer_thread. */
+struct writer_thread_parms
+{
+ int fd;
+ const void *data;
+ size_t datalen;
+ estream_t stream;
+ gpg_error_t *err_addr;
+};
+
+
+/* The thread started by start_writer. */
+static void *
+writer_thread_main (void *arg)
+{
+ gpg_error_t err = 0;
+ struct writer_thread_parms *parm = arg;
+ char _buffer[4096];
+ char *buffer;
+ size_t length;
+
+ if (parm->stream)
+ {
+ buffer = _buffer;
+ err = es_read (parm->stream, buffer, sizeof _buffer, &length);
+ if (err)
+ {
+ log_error ("reading stream failed: %s\n", gpg_strerror (err));
+ goto leave;
+ }
+ }
+ else
+ {
+ buffer = (char *) parm->data;
+ length = parm->datalen;
+ }
+
+ while (length)
+ {
+ ssize_t nwritten;
+
+ nwritten = npth_write (parm->fd, buffer, length < 4096? length:4096);
+ if (nwritten < 0)
+ {
+ if (errno == EINTR)
+ continue;
+ err = my_error_from_syserror ();
+ break; /* Write error. */
+ }
+ length -= nwritten;
+
+ if (parm->stream)
+ {
+ if (length == 0)
+ {
+ err = es_read (parm->stream, buffer, sizeof _buffer, &length);
+ if (err)
+ {
+ log_error ("reading stream failed: %s\n",
+ gpg_strerror (err));
+ break;
+ }
+ if (length == 0)
+ /* We're done. */
+ break;
+ }
+ }
+ else
+ buffer += nwritten;
+ }
+
+ leave:
+ *parm->err_addr = err;
+ if (close (parm->fd))
+ log_error ("closing writer fd %d failed: %s\n", parm->fd, strerror (errno));
+ xfree (parm);
+ return NULL;
+}
+
+
+/* Fire up a thread to send (DATA,DATALEN) to the file descriptor FD.
+ On success the thread receives the ownership over FD. The thread
+ ID is stored at R_TID. WRITER_ERR is the address of an gpg_error_t
+ variable to receive a possible write error after the thread has
+ finished. */
+static gpg_error_t
+start_writer (int fd, const void *data, size_t datalen, estream_t stream,
+ npth_t *r_thread, gpg_error_t *err_addr)
+{
+ gpg_error_t err;
+ struct writer_thread_parms *parm;
+ npth_attr_t tattr;
+ npth_t thread;
+ int ret;
+
+ memset (r_thread, '\0', sizeof (*r_thread));
+ *err_addr = 0;
+
+ parm = xtrymalloc (sizeof *parm);
+ if (!parm)
+ return my_error_from_syserror ();
+ parm->fd = fd;
+ parm->data = data;
+ parm->datalen = datalen;
+ parm->stream = stream;
+ parm->err_addr = err_addr;
+
+ npth_attr_init (&tattr);
+ npth_attr_setdetachstate (&tattr, NPTH_CREATE_JOINABLE);
+
+ ret = npth_create (&thread, &tattr, writer_thread_main, parm);
+ if (ret)
+ {
+ err = my_error_from_errno (ret);
+ log_error ("error spawning writer thread: %s\n", gpg_strerror (err));
+ }
+ else
+ {
+ npth_setname_np (thread, "fd-writer");
+ err = 0;
+ *r_thread = thread;
+ }
+ npth_attr_destroy (&tattr);
+
+ return err;
+}
+
+
+
+/* The data passed to the reader_thread. */
+struct reader_thread_parms
+{
+ int fd;
+ membuf_t *mb;
+ estream_t stream;
+ gpg_error_t *err_addr;
+};
+
+
+/* The thread started by start_reader. */
+static void *
+reader_thread_main (void *arg)
+{
+ gpg_error_t err = 0;
+ struct reader_thread_parms *parm = arg;
+ char buffer[4096];
+ int nread;
+
+ while ( (nread = npth_read (parm->fd, buffer, sizeof buffer)) )
+ {
+ if (nread < 0)
+ {
+ if (errno == EINTR)
+ continue;
+ err = my_error_from_syserror ();
+ break; /* Read error. */
+ }
+
+ if (parm->stream)
+ {
+ const char *p = buffer;
+ size_t nwritten;
+ while (nread)
+ {
+ err = es_write (parm->stream, p, nread, &nwritten);
+ if (err)
+ {
+ log_error ("writing stream failed: %s\n",
+ gpg_strerror (err));
+ goto leave;
+ }
+ nread -= nwritten;
+ p += nwritten;
+ }
+ }
+ else
+ put_membuf (parm->mb, buffer, nread);
+ }
+
+ leave:
+ *parm->err_addr = err;
+ if (close (parm->fd))
+ log_error ("closing reader fd %d failed: %s\n", parm->fd, strerror (errno));
+ xfree (parm);
+ return NULL;
+}
+
+
+/* Fire up a thread to receive data from the file descriptor FD. On
+ success the thread receives the ownership over FD. The thread ID
+ is stored at R_TID. After the thread has finished an error from
+ the thread will be stored at ERR_ADDR. */
+static gpg_error_t
+start_reader (int fd, membuf_t *mb, estream_t stream,
+ npth_t *r_thread, gpg_error_t *err_addr)
+{
+ gpg_error_t err;
+ struct reader_thread_parms *parm;
+ npth_attr_t tattr;
+ npth_t thread;
+ int ret;
+
+ memset (r_thread, '\0', sizeof (*r_thread));
+ *err_addr = 0;
+
+ parm = xtrymalloc (sizeof *parm);
+ if (!parm)
+ return my_error_from_syserror ();
+ parm->fd = fd;
+ parm->mb = mb;
+ parm->stream = stream;
+ parm->err_addr = err_addr;
+
+ npth_attr_init (&tattr);
+ npth_attr_setdetachstate (&tattr, NPTH_CREATE_JOINABLE);
+
+ ret = npth_create (&thread, &tattr, reader_thread_main, parm);
+ if (ret)
+ {
+ err = my_error_from_errno (ret);
+ log_error ("error spawning reader thread: %s\n", gpg_strerror (err));
+ }
+ else
+ {
+ npth_setname_np (thread, "fd-reader");
+ err = 0;
+ *r_thread = thread;
+ }
+ npth_attr_destroy (&tattr);
+
+ return err;
+}
+
+
+
+
+/* Call GPG to encrypt a block of data.
+
+
+ */
+static gpg_error_t
+_gpg_encrypt (ctrl_t ctrl,
+ const char *gpg_program,
+ strlist_t gpg_arguments,
+ const void *plain, size_t plainlen,
+ estream_t plain_stream,
+ strlist_t keys,
+ membuf_t *reader_mb,
+ estream_t cipher_stream)
+{
+ gpg_error_t err;
+ assuan_context_t ctx = NULL;
+ int outbound_fds[2] = { -1, -1 };
+ int inbound_fds[2] = { -1, -1 };
+ npth_t writer_thread = (npth_t)0;
+ npth_t reader_thread = (npth_t)0;
+ gpg_error_t writer_err, reader_err;
+ char line[ASSUAN_LINELENGTH];
+ strlist_t sl;
+ int ret;
+
+ /* Make sure that either the stream interface xor the buffer
+ interface is used. */
+ assert ((plain == NULL) != (plain_stream == NULL));
+ assert ((reader_mb == NULL) != (cipher_stream == NULL));
+
+ /* Create two pipes. */
+ err = gnupg_create_outbound_pipe (outbound_fds, NULL, 0);
+ if (!err)
+ err = gnupg_create_inbound_pipe (inbound_fds, NULL, 0);
+ if (err)
+ {
+ log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
+ goto leave;
+ }
+
+ /* Start GPG and send the INPUT and OUTPUT commands. */
+ err = start_gpg (ctrl, gpg_program, gpg_arguments,
+ outbound_fds[0], inbound_fds[1], &ctx);
+ if (err)
+ goto leave;
+ close (outbound_fds[0]); outbound_fds[0] = -1;
+ close (inbound_fds[1]); inbound_fds[1] = -1;
+
+ /* Start a writer thread to feed the INPUT command of the server. */
+ err = start_writer (outbound_fds[1], plain, plainlen, plain_stream,
+ &writer_thread, &writer_err);
+ if (err)
+ return err;
+ outbound_fds[1] = -1; /* The thread owns the FD now. */
+
+ /* Start a reader thread to eat from the OUTPUT command of the
+ server. */
+ err = start_reader (inbound_fds[0], reader_mb, cipher_stream,
+ &reader_thread, &reader_err);
+ if (err)
+ return err;
+ outbound_fds[0] = -1; /* The thread owns the FD now. */
+
+ /* Run the encryption. */
+ for (sl = keys; sl; sl = sl->next)
+ {
+ snprintf (line, sizeof line, "RECIPIENT -- %s", sl->d);
+ err = assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
+ if (err)
+ {
+ log_error ("the engine's RECIPIENT command failed: %s <%s>\n",
+ gpg_strerror (err), gpg_strsource (err));
+ goto leave;
+ }
+ }
+
+ err = assuan_transact (ctx, "ENCRYPT", NULL, NULL, NULL, NULL, NULL, NULL);
+ if (err)
+ {
+ log_error ("the engine's ENCRYPT command failed: %s <%s>\n",
+ gpg_strerror (err), gpg_strsource (err));
+ goto leave;
+ }
+
+ /* Wait for reader and return the data. */
+ ret = npth_join (reader_thread, NULL);
+ if (ret)
+ {
+ err = my_error_from_errno (ret);
+ log_error ("waiting for reader thread failed: %s\n", gpg_strerror (err));
+ goto leave;
+ }
+ /* FIXME: Not really valid, as npth_t is an opaque type. */
+ memset (&reader_thread, '\0', sizeof (reader_thread));
+ if (reader_err)
+ {
+ err = reader_err;
+ log_error ("read error in reader thread: %s\n", gpg_strerror (err));
+ goto leave;
+ }
+
+ /* Wait for the writer to catch a writer error. */
+ ret = npth_join (writer_thread, NULL);
+ if (ret)
+ {
+ err = my_error_from_errno (ret);
+ log_error ("waiting for writer thread failed: %s\n", gpg_strerror (err));
+ goto leave;
+ }
+ memset (&writer_thread, '\0', sizeof (writer_thread));
+ if (writer_err)
+ {
+ err = writer_err;
+ log_error ("write error in writer thread: %s\n", gpg_strerror (err));
+ goto leave;
+ }
+
+ leave:
+ /* FIXME: Not valid, as npth_t is an opaque type. */
+ if (reader_thread)
+ npth_detach (reader_thread);
+ if (writer_thread)
+ npth_detach (writer_thread);
+ if (outbound_fds[0] != -1)
+ close (outbound_fds[0]);
+ if (outbound_fds[1] != -1)
+ close (outbound_fds[1]);
+ if (inbound_fds[0] != -1)
+ close (inbound_fds[0]);
+ if (inbound_fds[1] != -1)
+ close (inbound_fds[1]);
+ release_gpg (ctx);
+ return err;
+}
+
+gpg_error_t
+gpg_encrypt_blob (ctrl_t ctrl,
+ const char *gpg_program,
+ strlist_t gpg_arguments,
+ const void *plain, size_t plainlen,
+ strlist_t keys,
+ void **r_ciph, size_t *r_ciphlen)
+{
+ gpg_error_t err;
+ membuf_t reader_mb;
+
+ *r_ciph = NULL;
+ *r_ciphlen = 0;
+
+ /* Init the memory buffer to receive the encrypted stuff. */
+ init_membuf (&reader_mb, 4096);
+
+ err = _gpg_encrypt (ctrl, gpg_program, gpg_arguments,
+ plain, plainlen, NULL,
+ keys,
+ &reader_mb, NULL);
+
+ if (! err)
+ {
+ /* Return the data. */
+ *r_ciph = get_membuf (&reader_mb, r_ciphlen);
+ if (!*r_ciph)
+ {
+ err = my_error_from_syserror ();
+ log_error ("error while storing the data in the reader thread: %s\n",
+ gpg_strerror (err));
+ }
+ }
+
+ xfree (get_membuf (&reader_mb, NULL));
+ return err;
+}
+
+gpg_error_t
+gpg_encrypt_stream (ctrl_t ctrl,
+ const char *gpg_program,
+ strlist_t gpg_arguments,
+ estream_t plain_stream,
+ strlist_t keys,
+ estream_t cipher_stream)
+{
+ return _gpg_encrypt (ctrl, gpg_program, gpg_arguments,
+ NULL, 0, plain_stream,
+ keys,
+ NULL, cipher_stream);
+}
+
+/* Call GPG to decrypt a block of data.
+
+
+ */
+static gpg_error_t
+_gpg_decrypt (ctrl_t ctrl,
+ const char *gpg_program,
+ strlist_t gpg_arguments,
+ const void *ciph, size_t ciphlen,
+ estream_t cipher_stream,
+ membuf_t *reader_mb,
+ estream_t plain_stream)
+{
+ gpg_error_t err;
+ assuan_context_t ctx = NULL;
+ int outbound_fds[2] = { -1, -1 };
+ int inbound_fds[2] = { -1, -1 };
+ npth_t writer_thread = (npth_t)0;
+ npth_t reader_thread = (npth_t)0;
+ gpg_error_t writer_err, reader_err;
+ int ret;
+
+ /* Make sure that either the stream interface xor the buffer
+ interface is used. */
+ assert ((ciph == NULL) != (cipher_stream == NULL));
+ assert ((reader_mb == NULL) != (plain_stream == NULL));
+
+ /* Create two pipes. */
+ err = gnupg_create_outbound_pipe (outbound_fds, NULL, 0);
+ if (!err)
+ err = gnupg_create_inbound_pipe (inbound_fds, NULL, 0);
+ if (err)
+ {
+ log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
+ goto leave;
+ }
+
+ /* Start GPG and send the INPUT and OUTPUT commands. */
+ err = start_gpg (ctrl, gpg_program, gpg_arguments,
+ outbound_fds[0], inbound_fds[1], &ctx);
+ if (err)
+ goto leave;
+ close (outbound_fds[0]); outbound_fds[0] = -1;
+ close (inbound_fds[1]); inbound_fds[1] = -1;
+
+ /* Start a writer thread to feed the INPUT command of the server. */
+ err = start_writer (outbound_fds[1], ciph, ciphlen, cipher_stream,
+ &writer_thread, &writer_err);
+ if (err)
+ return err;
+ outbound_fds[1] = -1; /* The thread owns the FD now. */
+
+ /* Start a reader thread to eat from the OUTPUT command of the
+ server. */
+ err = start_reader (inbound_fds[0], reader_mb, plain_stream,
+ &reader_thread, &reader_err);
+ if (err)
+ return err;
+ outbound_fds[0] = -1; /* The thread owns the FD now. */
+
+ /* Run the decryption. */
+ err = assuan_transact (ctx, "DECRYPT", NULL, NULL, NULL, NULL, NULL, NULL);
+ if (err)
+ {
+ log_error ("the engine's DECRYPT command failed: %s <%s>\n",
+ gpg_strerror (err), gpg_strsource (err));
+ goto leave;
+ }
+
+ /* Wait for reader and return the data. */
+ ret = npth_join (reader_thread, NULL);
+ if (ret)
+ {
+ err = my_error_from_errno (ret);
+ log_error ("waiting for reader thread failed: %s\n", gpg_strerror (err));
+ goto leave;
+ }
+ memset (&reader_thread, '\0', sizeof (reader_thread));
+ if (reader_err)
+ {
+ err = reader_err;
+ log_error ("read error in reader thread: %s\n", gpg_strerror (err));
+ goto leave;
+ }
+
+ /* Wait for the writer to catch a writer error. */
+ ret = npth_join (writer_thread, NULL);
+ if (ret)
+ {
+ err = my_error_from_errno (ret);
+ log_error ("waiting for writer thread failed: %s\n", gpg_strerror (err));
+ goto leave;
+ }
+ memset (&writer_thread, '\0', sizeof (writer_thread));
+ if (writer_err)
+ {
+ err = writer_err;
+ log_error ("write error in writer thread: %s\n", gpg_strerror (err));
+ goto leave;
+ }
+
+ leave:
+ if (reader_thread)
+ npth_detach (reader_thread);
+ if (writer_thread)
+ npth_detach (writer_thread);
+ if (outbound_fds[0] != -1)
+ close (outbound_fds[0]);
+ if (outbound_fds[1] != -1)
+ close (outbound_fds[1]);
+ if (inbound_fds[0] != -1)
+ close (inbound_fds[0]);
+ if (inbound_fds[1] != -1)
+ close (inbound_fds[1]);
+ release_gpg (ctx);
+ return err;
+}
+
+gpg_error_t
+gpg_decrypt_blob (ctrl_t ctrl,
+ const char *gpg_program,
+ strlist_t gpg_arguments,
+ const void *ciph, size_t ciphlen,
+ void **r_plain, size_t *r_plainlen)
+{
+ gpg_error_t err;
+ membuf_t reader_mb;
+
+ *r_plain = NULL;
+ *r_plainlen = 0;
+
+ /* Init the memory buffer to receive the encrypted stuff. */
+ init_membuf_secure (&reader_mb, 1024);
+
+ err = _gpg_decrypt (ctrl, gpg_program, gpg_arguments,
+ ciph, ciphlen, NULL,
+ &reader_mb, NULL);
+
+ if (! err)
+ {
+ /* Return the data. */
+ *r_plain = get_membuf (&reader_mb, r_plainlen);
+ if (!*r_plain)
+ {
+ err = my_error_from_syserror ();
+ log_error ("error while storing the data in the reader thread: %s\n",
+ gpg_strerror (err));
+ }
+ }
+
+ xfree (get_membuf (&reader_mb, NULL));
+ return err;
+}
+
+gpg_error_t
+gpg_decrypt_stream (ctrl_t ctrl,
+ const char *gpg_program,
+ strlist_t gpg_arguments,
+ estream_t cipher_stream,
+ estream_t plain_stream)
+{
+ return _gpg_decrypt (ctrl, gpg_program, gpg_arguments,
+ NULL, 0, cipher_stream,
+ NULL, plain_stream);
+}
diff --git a/common/call-gpg.h b/common/call-gpg.h
new file mode 100644
index 0000000..fd7d2e6
--- /dev/null
+++ b/common/call-gpg.h
@@ -0,0 +1,54 @@
+/* call-gpg.h - Defs for the communication with GPG
+ * Copyright (C) 2009 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_COMMON_CALL_GPG_H
+#define GNUPG_COMMON_CALL_GPG_H
+
+#include <gpg-error.h>
+
+#include "fwddecl.h"
+#include "strlist.h"
+
+gpg_error_t gpg_encrypt_blob (ctrl_t ctrl,
+ const char *gpg_program,
+ strlist_t gpg_arguments,
+ const void *plain, size_t plainlen,
+ strlist_t keys,
+ void **r_ciph, size_t *r_ciphlen);
+
+gpg_error_t gpg_encrypt_stream (ctrl_t ctrl,
+ const char *gpg_program,
+ strlist_t gpg_arguments,
+ estream_t plain_stream,
+ strlist_t keys,
+ estream_t cipher_stream);
+
+gpg_error_t gpg_decrypt_blob (ctrl_t ctrl,
+ const char *gpg_program,
+ strlist_t gpg_arguments,
+ const void *ciph, size_t ciphlen,
+ void **r_plain, size_t *r_plainlen);
+
+gpg_error_t gpg_decrypt_stream (ctrl_t ctrl,
+ const char *gpg_program,
+ strlist_t gpg_arguments,
+ estream_t cipher_stream,
+ estream_t plain_stream);
+
+#endif /*GNUPG_COMMON_CALL_GPG_H*/
diff --git a/common/ccparray.c b/common/ccparray.c
new file mode 100644
index 0000000..ff3eb40
--- /dev/null
+++ b/common/ccparray.c
@@ -0,0 +1,148 @@
+/* ccparray.c - A simple dynamic array for character pointer.
+ * Copyright (C) 2016 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stdarg.h>
+
+#include "util.h"
+#include "ccparray.h"
+
+
+/* A simple implementation of a dynamic array of const char pointers.
+ * The example code:
+ *
+ * ccparray_t ccp;
+ * const char **argv;
+ * int i;
+ *
+ * ccparray_init (&ccp, 0);
+ * ccparray_put (&ccp, "First arg");
+ * ccparray_put (&ccp, "Second arg");
+ * ccparray_put (&ccp, NULL);
+ * ccparray_put (&ccp, "Fourth arg");
+ * argv = ccparray_get (&ccp, NULL);
+ * if (!argv)
+ * die ("error building array: %s\n", strerror (errno));
+ * for (i=0; argv[i]; i++)
+ * printf ("[%d] = '%s'\n", i, argv[i]);
+ * xfree (argv);
+ *
+ * will result in this output:
+ *
+ * [0] = 'First arg'
+ * [1] = 'Second arg'
+ *
+ * Note that allocation errors are detected but only returned with the
+ * final ccparray_get(); this helps not to clutter the code with out
+ * of core checks.
+ */
+
+void
+ccparray_init (ccparray_t *cpa, unsigned int initialsize)
+{
+ if (!initialsize)
+ cpa->size = 16;
+ else if (initialsize < (1<<16))
+ cpa->size = initialsize;
+ else
+ cpa->size = (1<<16);
+
+ cpa->count = 0;
+ cpa->out_of_core = 0;
+ cpa->array = xtrycalloc (cpa->size, sizeof *cpa->array);
+ if (!cpa->array)
+ cpa->out_of_core = errno;
+}
+
+
+void
+ccparray_put (ccparray_t *cpa, const char *value)
+{
+ if (cpa->out_of_core)
+ return;
+
+ if (cpa->count + 1 >= cpa->size)
+ {
+ const char **newarray;
+ size_t n, newsize;
+
+ if (cpa->size < 8)
+ newsize = 16;
+ else if (cpa->size < 4096)
+ newsize = 2 * cpa->size;
+ else if (cpa->size < (1<<16))
+ newsize = cpa->size + 2048;
+ else
+ {
+ cpa->out_of_core = ENOMEM;
+ return;
+ }
+
+ newarray = xtrycalloc (newsize, sizeof *newarray);
+ if (!newarray)
+ {
+ cpa->out_of_core = errno ? errno : ENOMEM;
+ return;
+ }
+ for (n=0; n < cpa->size; n++)
+ newarray[n] = cpa->array[n];
+ xfree (cpa->array);
+ cpa->array = newarray;
+ cpa->size = newsize;
+
+ }
+ cpa->array[cpa->count++] = value;
+}
+
+
+const char **
+ccparray_get (ccparray_t *cpa, size_t *r_count)
+{
+ const char **result;
+
+ if (cpa->out_of_core)
+ {
+ if (cpa->array)
+ {
+ xfree (cpa->array);
+ cpa->array = NULL;
+ }
+ gpg_err_set_errno (cpa->out_of_core);
+ return NULL;
+ }
+
+ result= cpa->array;
+ if (r_count)
+ *r_count = cpa->count;
+ cpa->array = NULL;
+ cpa->out_of_core = ENOMEM; /* hack to make sure it won't get reused. */
+ return result;
+}
diff --git a/common/ccparray.h b/common/ccparray.h
new file mode 100644
index 0000000..1ecf95b
--- /dev/null
+++ b/common/ccparray.h
@@ -0,0 +1,51 @@
+/* ccparray.c - A simple dynamic array for character pointer.
+ * Copyright (C) 2016 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_COMMON_CCPARRAY_H
+#define GNUPG_COMMON_CCPARRAY_H
+
+/* The definition of the structure is private, we only need it here,
+ * so it can be allocated on the stack. */
+struct _ccparray_private_s
+{
+ unsigned int count;
+ unsigned int size;
+ int out_of_core;
+ const char **array;
+};
+
+typedef struct _ccparray_private_s ccparray_t;
+
+
+void ccparray_init (ccparray_t *cpa, unsigned int initialsize);
+void ccparray_put (ccparray_t *cpa, const char *value);
+const char **ccparray_get (ccparray_t *cpa, size_t *r_nelems);
+
+
+#endif /*GNUPG_COMMON_CCPARRAY_H*/
diff --git a/common/common-defs.h b/common/common-defs.h
new file mode 100644
index 0000000..b1928e6
--- /dev/null
+++ b/common/common-defs.h
@@ -0,0 +1,54 @@
+/* common-defs.h - Private declarations for common/
+ * Copyright (C) 2006 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_COMMON_COMMON_DEFS_H
+#define GNUPG_COMMON_COMMON_DEFS_H
+
+
+/* Dummy replacement for getenv. */
+#ifndef HAVE_GETENV
+#define getenv(a) (NULL)
+#endif
+
+#ifdef HAVE_W32CE_SYSTEM
+#define getpid() GetCurrentProcessId ()
+#endif
+
+
+/*-- ttyio.c --*/
+void tty_private_set_rl_hooks (void (*init_stream) (FILE *),
+ void (*set_completer) (rl_completion_func_t*),
+ void (*inhibit_completion) (int),
+ void (*cleanup_after_signal) (void),
+ char *(*readline_fun) (const char*),
+ void (*add_history_fun) (const char*));
+
+
+
+#endif /*GNUPG_COMMON_COMMON_DEFS_H*/
diff --git a/common/compliance.c b/common/compliance.c
new file mode 100644
index 0000000..eaecee7
--- /dev/null
+++ b/common/compliance.c
@@ -0,0 +1,702 @@
+/* compliance.c - Functions for compliance modi
+ * Copyright (C) 2017 g10 Code GmbH
+ * Copyright (C) 2017 Bundesamt für Sicherheit in der Informationstechnik
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <gcrypt.h>
+
+#include "openpgpdefs.h"
+#include "logging.h"
+#include "util.h"
+#include "i18n.h"
+#include "compliance.h"
+
+static int initialized;
+static int module;
+
+/* This value is used by DSA and RSA checks in addition to the hard
+ * coded length checks. It allows to increase the required key length
+ * using a confue file. */
+static unsigned int min_compliant_rsa_length;
+
+/* Return the address of a compliance cache variable for COMPLIANCE.
+ * If no such variable exists NULL is returned. FOR_RNG returns the
+ * cache variable for the RNG compliance check. */
+static int *
+get_compliance_cache (enum gnupg_compliance_mode compliance, int for_rng)
+{
+ static int r_gnupg = -1, s_gnupg = -1;
+ static int r_rfc4880 = -1, s_rfc4880 = -1;
+ static int r_rfc2440 = -1, s_rfc2440 = -1;
+ static int r_pgp6 = -1, s_pgp6 = -1;
+ static int r_pgp7 = -1, s_pgp7 = -1;
+ static int r_pgp8 = -1, s_pgp8 = -1;
+ static int r_de_vs = -1, s_de_vs = -1;
+
+ int *ptr = NULL;
+
+ switch (compliance)
+ {
+ case CO_GNUPG: ptr = for_rng? &r_gnupg : &s_gnupg ; break;
+ case CO_RFC4880: ptr = for_rng? &r_rfc4880 : &s_rfc4880; break;
+ case CO_RFC2440: ptr = for_rng? &r_rfc2440 : &s_rfc2440; break;
+ case CO_PGP6: ptr = for_rng? &r_pgp6 : &s_pgp6 ; break;
+ case CO_PGP7: ptr = for_rng? &r_pgp7 : &s_pgp7 ; break;
+ case CO_PGP8: ptr = for_rng? &r_pgp8 : &s_pgp8 ; break;
+ case CO_DE_VS: ptr = for_rng? &r_de_vs : &s_de_vs ; break;
+ }
+
+ return ptr;
+}
+
+
+/* Initializes the module. Must be called with the current
+ * GNUPG_MODULE_NAME. Checks a few invariants, and tunes the policies
+ * for the given module. */
+void
+gnupg_initialize_compliance (int gnupg_module_name)
+{
+ log_assert (! initialized);
+
+ /* We accept both OpenPGP-style and gcrypt-style algorithm ids.
+ * Assert that they are compatible. */
+ log_assert ((int) GCRY_PK_RSA == (int) PUBKEY_ALGO_RSA);
+ log_assert ((int) GCRY_PK_RSA_E == (int) PUBKEY_ALGO_RSA_E);
+ log_assert ((int) GCRY_PK_RSA_S == (int) PUBKEY_ALGO_RSA_S);
+ log_assert ((int) GCRY_PK_ELG_E == (int) PUBKEY_ALGO_ELGAMAL_E);
+ log_assert ((int) GCRY_PK_DSA == (int) PUBKEY_ALGO_DSA);
+ log_assert ((int) GCRY_PK_ECC == (int) PUBKEY_ALGO_ECDH);
+ log_assert ((int) GCRY_PK_ELG == (int) PUBKEY_ALGO_ELGAMAL);
+ log_assert ((int) GCRY_CIPHER_NONE == (int) CIPHER_ALGO_NONE);
+ log_assert ((int) GCRY_CIPHER_IDEA == (int) CIPHER_ALGO_IDEA);
+ log_assert ((int) GCRY_CIPHER_3DES == (int) CIPHER_ALGO_3DES);
+ log_assert ((int) GCRY_CIPHER_CAST5 == (int) CIPHER_ALGO_CAST5);
+ log_assert ((int) GCRY_CIPHER_BLOWFISH == (int) CIPHER_ALGO_BLOWFISH);
+ log_assert ((int) GCRY_CIPHER_AES == (int) CIPHER_ALGO_AES);
+ log_assert ((int) GCRY_CIPHER_AES192 == (int) CIPHER_ALGO_AES192);
+ log_assert ((int) GCRY_CIPHER_AES256 == (int) CIPHER_ALGO_AES256);
+ log_assert ((int) GCRY_CIPHER_TWOFISH == (int) CIPHER_ALGO_TWOFISH);
+ log_assert ((int) GCRY_MD_MD5 == (int) DIGEST_ALGO_MD5);
+ log_assert ((int) GCRY_MD_SHA1 == (int) DIGEST_ALGO_SHA1);
+ log_assert ((int) GCRY_MD_RMD160 == (int) DIGEST_ALGO_RMD160);
+ log_assert ((int) GCRY_MD_SHA256 == (int) DIGEST_ALGO_SHA256);
+ log_assert ((int) GCRY_MD_SHA384 == (int) DIGEST_ALGO_SHA384);
+ log_assert ((int) GCRY_MD_SHA512 == (int) DIGEST_ALGO_SHA512);
+ log_assert ((int) GCRY_MD_SHA224 == (int) DIGEST_ALGO_SHA224);
+
+ switch (gnupg_module_name)
+ {
+ case GNUPG_MODULE_NAME_GPGSM:
+ case GNUPG_MODULE_NAME_GPG:
+ break;
+
+ default:
+ log_assert (!"no policies for this module");
+ }
+
+ module = gnupg_module_name;
+ initialized = 1;
+}
+
+/* Return true if ALGO with a key of KEYLENGTH is compliant to the
+ * given COMPLIANCE mode. If KEY is not NULL, various bits of
+ * information will be extracted from it. If CURVENAME is not NULL, it
+ * is assumed to be the already computed. ALGO may be either an
+ * OpenPGP-style pubkey_algo_t, or a gcrypt-style enum gcry_pk_algos,
+ * both are compatible from the point of view of this function. */
+int
+gnupg_pk_is_compliant (enum gnupg_compliance_mode compliance, int algo,
+ unsigned int algo_flags,
+ gcry_mpi_t key[], unsigned int keylength,
+ const char *curvename)
+{
+ enum { is_rsa, is_dsa, is_elg, is_ecc } algotype;
+ int result = 0;
+
+ if (! initialized)
+ return 0;
+
+ switch (algo)
+ {
+ case PUBKEY_ALGO_RSA:
+ case PUBKEY_ALGO_RSA_E:
+ case PUBKEY_ALGO_RSA_S:
+ algotype = is_rsa;
+ break;
+
+ case PUBKEY_ALGO_DSA:
+ algotype = is_dsa;
+ break;
+
+ case PUBKEY_ALGO_ELGAMAL_E:
+ algotype = is_elg;
+ break;
+
+ case PUBKEY_ALGO_ECDH:
+ case PUBKEY_ALGO_ECDSA:
+ case PUBKEY_ALGO_EDDSA:
+ algotype = is_ecc;
+ break;
+
+ case PUBKEY_ALGO_ELGAMAL:
+ return 0; /* Signing with Elgamal is not at all supported. */
+
+ default: /* Unknown. */
+ return 0;
+ }
+
+ if (compliance == CO_DE_VS)
+ {
+ char *curve = NULL;
+
+ switch (algotype)
+ {
+ case is_elg:
+ result = 0;
+ break;
+
+ case is_rsa:
+ result = ((keylength == 2048
+ || keylength == 3072
+ || keylength == 4096)
+ && keylength >= min_compliant_rsa_length);
+ /* Although rsaPSS was not part of the original evaluation
+ * we got word that we can claim compliance. */
+ (void)algo_flags;
+ break;
+
+ case is_dsa:
+ if (key)
+ {
+ size_t P = gcry_mpi_get_nbits (key[0]);
+ size_t Q = gcry_mpi_get_nbits (key[1]);
+ result = (Q == 256
+ && (P == 2048 || P == 3072)
+ && P >= min_compliant_rsa_length);
+ }
+ break;
+
+ case is_ecc:
+ if (!curvename && key)
+ {
+ curve = openpgp_oid_to_str (key[0]);
+ curvename = openpgp_oid_to_curve (curve, 0);
+ if (!curvename)
+ curvename = curve;
+ }
+
+ result = (curvename
+ && (algo == PUBKEY_ALGO_ECDH
+ || algo == PUBKEY_ALGO_ECDSA)
+ && (!strcmp (curvename, "brainpoolP256r1")
+ || !strcmp (curvename, "brainpoolP384r1")
+ || !strcmp (curvename, "brainpoolP512r1")));
+ break;
+
+ default:
+ result = 0;
+ }
+ xfree (curve);
+ }
+ else
+ {
+ result = 1; /* Assume compliance. */
+ }
+
+ return result;
+}
+
+
+/* Return true if ALGO with the given KEYLENGTH is allowed in the
+ * given COMPLIANCE mode. USE specifies for which use case the
+ * predicate is evaluated. This way policies can be strict in what
+ * they produce, and liberal in what they accept. */
+int
+gnupg_pk_is_allowed (enum gnupg_compliance_mode compliance,
+ enum pk_use_case use, int algo,
+ unsigned int algo_flags, gcry_mpi_t key[],
+ unsigned int keylength, const char *curvename)
+{
+ int result = 0;
+
+ if (! initialized)
+ return 1;
+
+ switch (compliance)
+ {
+ case CO_DE_VS:
+ switch (algo)
+ {
+ case PUBKEY_ALGO_RSA:
+ case PUBKEY_ALGO_RSA_E:
+ case PUBKEY_ALGO_RSA_S:
+ switch (use)
+ {
+ case PK_USE_DECRYPTION:
+ case PK_USE_VERIFICATION:
+ result = 1;
+ break;
+ case PK_USE_ENCRYPTION:
+ case PK_USE_SIGNING:
+ result = ((keylength == 2048
+ || keylength == 3072
+ || keylength == 4096)
+ && keylength >= min_compliant_rsa_length);
+ break;
+ default:
+ log_assert (!"reached");
+ }
+ (void)algo_flags;
+ break;
+
+ case PUBKEY_ALGO_DSA:
+ if (use == PK_USE_VERIFICATION)
+ result = 1;
+ else if (use == PK_USE_SIGNING && key)
+ {
+ size_t P = gcry_mpi_get_nbits (key[0]);
+ size_t Q = gcry_mpi_get_nbits (key[1]);
+ result = (Q == 256
+ && (P == 2048 || P == 3072)
+ && keylength >= min_compliant_rsa_length);
+ }
+ break;
+
+ case PUBKEY_ALGO_ELGAMAL:
+ case PUBKEY_ALGO_ELGAMAL_E:
+ result = (use == PK_USE_DECRYPTION);
+ break;
+
+ case PUBKEY_ALGO_ECDH:
+ if (use == PK_USE_DECRYPTION)
+ result = 1;
+ else if (use == PK_USE_ENCRYPTION)
+ {
+ char *curve = NULL;
+
+ if (!curvename && key)
+ {
+ curve = openpgp_oid_to_str (key[0]);
+ curvename = openpgp_oid_to_curve (curve, 0);
+ if (!curvename)
+ curvename = curve;
+ }
+
+ result = (curvename
+ && (!strcmp (curvename, "brainpoolP256r1")
+ || !strcmp (curvename, "brainpoolP384r1")
+ || !strcmp (curvename, "brainpoolP512r1")));
+
+ xfree (curve);
+ }
+ break;
+
+ case PUBKEY_ALGO_ECDSA:
+ if (use == PK_USE_VERIFICATION)
+ result = 1;
+ else
+ {
+ char *curve = NULL;
+
+ if (! curvename && key)
+ {
+ curve = openpgp_oid_to_str (key[0]);
+ curvename = openpgp_oid_to_curve (curve, 0);
+ if (!curvename)
+ curvename = curve;
+ }
+
+ result = (use == PK_USE_SIGNING
+ && curvename
+ && (!strcmp (curvename, "brainpoolP256r1")
+ || !strcmp (curvename, "brainpoolP384r1")
+ || !strcmp (curvename, "brainpoolP512r1")));
+ xfree (curve);
+ }
+ break;
+
+
+ case PUBKEY_ALGO_EDDSA:
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ default:
+ /* The default policy is to allow all algorithms. */
+ result = 1;
+ }
+
+ return result;
+}
+
+
+/* Return true if (CIPHER, MODE) is compliant to the given COMPLIANCE mode. */
+int
+gnupg_cipher_is_compliant (enum gnupg_compliance_mode compliance,
+ cipher_algo_t cipher,
+ enum gcry_cipher_modes mode)
+{
+ if (! initialized)
+ return 0;
+
+ switch (compliance)
+ {
+ case CO_DE_VS:
+ switch (cipher)
+ {
+ case CIPHER_ALGO_AES:
+ case CIPHER_ALGO_AES192:
+ case CIPHER_ALGO_AES256:
+ case CIPHER_ALGO_3DES:
+ switch (module)
+ {
+ case GNUPG_MODULE_NAME_GPG:
+ return mode == GCRY_CIPHER_MODE_CFB;
+ case GNUPG_MODULE_NAME_GPGSM:
+ return mode == GCRY_CIPHER_MODE_CBC;
+ }
+ log_assert (!"reached");
+
+ default:
+ return 0;
+ }
+ log_assert (!"reached");
+
+ default:
+ return 0;
+ }
+
+ log_assert (!"reached");
+}
+
+
+/* Return true if CIPHER is allowed in the given COMPLIANCE mode. If
+ * PRODUCER is true, the predicate is evaluated for the producer, if
+ * false for the consumer. This way policies can be strict in what
+ * they produce, and liberal in what they accept. */
+int
+gnupg_cipher_is_allowed (enum gnupg_compliance_mode compliance, int producer,
+ cipher_algo_t cipher,
+ enum gcry_cipher_modes mode)
+{
+ if (! initialized)
+ return 1;
+
+ switch (compliance)
+ {
+ case CO_DE_VS:
+ switch (cipher)
+ {
+ case CIPHER_ALGO_AES:
+ case CIPHER_ALGO_AES192:
+ case CIPHER_ALGO_AES256:
+ case CIPHER_ALGO_3DES:
+ switch (module)
+ {
+ case GNUPG_MODULE_NAME_GPG:
+ return (mode == GCRY_CIPHER_MODE_NONE
+ || mode == GCRY_CIPHER_MODE_CFB);
+ case GNUPG_MODULE_NAME_GPGSM:
+ return (mode == GCRY_CIPHER_MODE_NONE
+ || mode == GCRY_CIPHER_MODE_CBC
+ || (mode == GCRY_CIPHER_MODE_GCM && !producer));
+ }
+ log_assert (!"reached");
+
+ case CIPHER_ALGO_BLOWFISH:
+ case CIPHER_ALGO_CAMELLIA128:
+ case CIPHER_ALGO_CAMELLIA192:
+ case CIPHER_ALGO_CAMELLIA256:
+ case CIPHER_ALGO_CAST5:
+ case CIPHER_ALGO_IDEA:
+ case CIPHER_ALGO_TWOFISH:
+ return (module == GNUPG_MODULE_NAME_GPG
+ && (mode == GCRY_CIPHER_MODE_NONE
+ || mode == GCRY_CIPHER_MODE_CFB)
+ && ! producer);
+ default:
+ return 0;
+ }
+ log_assert (!"reached");
+
+ default:
+ /* The default policy is to allow all algorithms. */
+ return 1;
+ }
+
+ log_assert (!"reached");
+}
+
+
+/* Return true if DIGEST is compliant to the given COMPLIANCE mode. */
+int
+gnupg_digest_is_compliant (enum gnupg_compliance_mode compliance,
+ digest_algo_t digest)
+{
+ if (! initialized)
+ return 0;
+
+ switch (compliance)
+ {
+ case CO_DE_VS:
+ switch (digest)
+ {
+ case DIGEST_ALGO_SHA256:
+ case DIGEST_ALGO_SHA384:
+ case DIGEST_ALGO_SHA512:
+ return 1;
+ default:
+ return 0;
+ }
+ log_assert (!"reached");
+
+ default:
+ return 0;
+ }
+
+ log_assert (!"reached");
+}
+
+
+/* Return true if DIGEST is allowed in the given COMPLIANCE mode. If
+ * PRODUCER is true, the predicate is evaluated for the producer, if
+ * false for the consumer. This way policies can be strict in what
+ * they produce, and liberal in what they accept. */
+int
+gnupg_digest_is_allowed (enum gnupg_compliance_mode compliance, int producer,
+ digest_algo_t digest)
+{
+ if (! initialized)
+ return 1;
+
+ switch (compliance)
+ {
+ case CO_DE_VS:
+ switch (digest)
+ {
+ case DIGEST_ALGO_SHA256:
+ case DIGEST_ALGO_SHA384:
+ case DIGEST_ALGO_SHA512:
+ return 1;
+ case DIGEST_ALGO_SHA1:
+ case DIGEST_ALGO_SHA224:
+ case DIGEST_ALGO_RMD160:
+ return ! producer;
+ case DIGEST_ALGO_MD5:
+ return ! producer && module == GNUPG_MODULE_NAME_GPGSM;
+ default:
+ return 0;
+ }
+ log_assert (!"reached");
+
+ default:
+ /* The default policy is to allow all algorithms. */
+ return 1;
+ }
+
+ log_assert (!"reached");
+}
+
+
+/* Return True if the random number generator is compliant in
+ * COMPLIANCE mode. */
+int
+gnupg_rng_is_compliant (enum gnupg_compliance_mode compliance)
+{
+ int *result;
+ int res;
+
+ result = get_compliance_cache (compliance, 1);
+
+ if (result && *result != -1)
+ res = *result; /* Use cached result. */
+ else if (compliance == CO_DE_VS)
+ {
+ /* We also check whether the library is at all compliant. */
+ res = gnupg_gcrypt_is_compliant (compliance);
+
+ /* In DE_VS mode under Windows we also require that the JENT RNG
+ * is active. Check it here. */
+#ifdef HAVE_W32_SYSTEM
+ if (res == 1)
+ {
+ char *buf;
+ char *fields[5];
+
+ buf = gcry_get_config (0, "rng-type");
+ if (buf
+ && split_fields_colon (buf, fields, DIM (fields)) >= 5
+ && atoi (fields[4]) > 0)
+ ; /* Field 5 > 0 := Jent is active. */
+ else
+ result = 0; /* Force non-compliance. */
+ gcry_free (buf);
+ }
+#endif /*HAVE_W32_SYSTEM*/
+ }
+ else
+ res = 1;
+
+ if (result)
+ *result = res;
+
+ return res;
+}
+
+
+/* Return true if the used Libgcrypt is compliant in COMPLIANCE
+ * mode. */
+int
+gnupg_gcrypt_is_compliant (enum gnupg_compliance_mode compliance)
+{
+ int *result;
+ int res;
+
+ result = get_compliance_cache (compliance, 0);
+
+ if (result && *result != -1)
+ res = *result; /* Use cached result. */
+ else if (compliance == CO_DE_VS)
+ {
+ int is19orlater = !!gcry_check_version ("1.9.0");
+
+ /* A compliant version of GnuPG requires Libgcrypt >= 1.8.1 and
+ * less than 1.9.0. Version 1.9.0 requires a re-evaluation and
+ * can thus not be used for de-vs. */
+ if (gcry_check_version ("1.8.1") && !is19orlater)
+ res = 1; /* Compliant version of Libgcrypt. */
+ else if (is19orlater)
+ {
+ /* Libgcrypt might be nice enough to tell us whether it is
+ * compliant. */
+ char *buf;
+ char *fields[3];
+
+ buf = gcry_get_config (0, "compliance");
+ if (buf
+ && split_fields_colon (buf, fields, DIM (fields)) >= 2
+ && strstr (fields[1], "de-vs"))
+ res = 1; /* Compliant. */
+ else
+ res = 0; /* Non-compliant. */
+ gcry_free (buf);
+ }
+ else
+ res = 0; /* Non-compliant version of Libgcrypt. */
+ }
+ else
+ res = 1;
+
+ if (result)
+ *result = res;
+
+ return res;
+}
+
+
+const char *
+gnupg_status_compliance_flag (enum gnupg_compliance_mode compliance)
+{
+ switch (compliance)
+ {
+ case CO_GNUPG:
+ return "8";
+ case CO_RFC4880:
+ case CO_RFC2440:
+ case CO_PGP6:
+ case CO_PGP7:
+ case CO_PGP8:
+ log_assert (!"no status code assigned for this compliance mode");
+ case CO_DE_VS:
+ return "23";
+ }
+ log_assert (!"invalid compliance mode");
+}
+
+
+/* Parse the value of --compliance. Returns the value corresponding
+ * to the given STRING according to OPTIONS of size LENGTH, or -1
+ * indicating that the lookup was unsuccessful, or the list of options
+ * was printed. If quiet is false, an additional hint to use 'help'
+ * is printed on unsuccessful lookups. */
+int
+gnupg_parse_compliance_option (const char *string,
+ struct gnupg_compliance_option options[],
+ size_t length,
+ int quiet)
+{
+ size_t i;
+
+ if (! ascii_strcasecmp (string, "help"))
+ {
+ log_info (_("valid values for option '%s':\n"), "--compliance");
+ for (i = 0; i < length; i++)
+ log_info (" %s\n", options[i].keyword);
+ return -1;
+ }
+
+ for (i = 0; i < length; i++)
+ if (! ascii_strcasecmp (string, options[i].keyword))
+ return options[i].value;
+
+ log_error (_("invalid value for option '%s'\n"), "--compliance");
+ if (! quiet)
+ log_info (_("(use \"help\" to list choices)\n"));
+ return -1;
+}
+
+
+/* Return the command line option for the given COMPLIANCE mode. */
+const char *
+gnupg_compliance_option_string (enum gnupg_compliance_mode compliance)
+{
+ switch (compliance)
+ {
+ case CO_GNUPG: return "--compliance=gnupg";
+ case CO_RFC4880: return "--compliance=openpgp";
+ case CO_RFC2440: return "--compliance=rfc2440";
+ case CO_PGP6: return "--compliance=pgp6";
+ case CO_PGP7: return "--compliance=pgp7";
+ case CO_PGP8: return "--compliance=pgp8";
+ case CO_DE_VS: return "--compliance=de-vs";
+ }
+
+ log_assert (!"invalid compliance mode");
+}
+
+
+/* Set additional infos for example taken from config files at startup. */
+void
+gnupg_set_compliance_extra_info (unsigned int min_rsa)
+{
+ min_compliant_rsa_length = min_rsa;
+}
diff --git a/common/compliance.h b/common/compliance.h
new file mode 100644
index 0000000..e29ff4e
--- /dev/null
+++ b/common/compliance.h
@@ -0,0 +1,97 @@
+/* compliance.h - Definitions for compliance modi
+ * Copyright (C) 2017 g10 Code GmbH
+ * Copyright (C) 2017 Bundesamt für Sicherheit in der Informationstechnik
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_COMMON_COMPLIANCE_H
+#define GNUPG_COMMON_COMPLIANCE_H
+
+#include <gcrypt.h>
+#include "openpgpdefs.h"
+
+void gnupg_initialize_compliance (int gnupg_module_name);
+
+enum gnupg_compliance_mode
+ {
+ CO_GNUPG, CO_RFC4880, CO_RFC2440,
+ CO_PGP6, CO_PGP7, CO_PGP8, CO_DE_VS
+ };
+
+enum pk_use_case
+ {
+ PK_USE_ENCRYPTION, PK_USE_DECRYPTION,
+ PK_USE_SIGNING, PK_USE_VERIFICATION,
+ };
+
+/* Flags to distinguish public key algorithm variants. */
+#define PK_ALGO_FLAG_RSAPSS 1 /* Use rsaPSS padding. */
+
+
+int gnupg_pk_is_compliant (enum gnupg_compliance_mode compliance, int algo,
+ unsigned int algo_flags,
+ gcry_mpi_t key[], unsigned int keylength,
+ const char *curvename);
+int gnupg_pk_is_allowed (enum gnupg_compliance_mode compliance,
+ enum pk_use_case use, int algo,
+ unsigned int algo_flags, gcry_mpi_t key[],
+ unsigned int keylength, const char *curvename);
+int gnupg_cipher_is_compliant (enum gnupg_compliance_mode compliance,
+ cipher_algo_t cipher,
+ enum gcry_cipher_modes mode);
+int gnupg_cipher_is_allowed (enum gnupg_compliance_mode compliance,
+ int producer,
+ cipher_algo_t cipher,
+ enum gcry_cipher_modes mode);
+int gnupg_digest_is_compliant (enum gnupg_compliance_mode compliance,
+ digest_algo_t digest);
+int gnupg_digest_is_allowed (enum gnupg_compliance_mode compliance,
+ int producer,
+ digest_algo_t digest);
+int gnupg_rng_is_compliant (enum gnupg_compliance_mode compliance);
+int gnupg_gcrypt_is_compliant (enum gnupg_compliance_mode compliance);
+
+const char *gnupg_status_compliance_flag (enum gnupg_compliance_mode
+ compliance);
+
+struct gnupg_compliance_option
+{
+ const char *keyword;
+ int value;
+};
+
+int gnupg_parse_compliance_option (const char *string,
+ struct gnupg_compliance_option options[],
+ size_t length,
+ int quiet);
+const char *gnupg_compliance_option_string (enum gnupg_compliance_mode
+ compliance);
+
+void gnupg_set_compliance_extra_info (unsigned int min_rsa);
+
+
+#endif /*GNUPG_COMMON_COMPLIANCE_H*/
diff --git a/common/convert.c b/common/convert.c
new file mode 100644
index 0000000..ee2f117
--- /dev/null
+++ b/common/convert.c
@@ -0,0 +1,267 @@
+/* convert.c - Hex conversion functions.
+ * Copyright (C) 2006, 2008 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "util.h"
+
+
+#define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A'))
+
+
+/* Convert STRING consisting of hex characters into its binary
+ representation and store that at BUFFER. BUFFER needs to be of
+ LENGTH bytes. The function checks that the STRING will convert
+ exactly to LENGTH bytes. The string is delimited by either end of
+ string or a white space character. The function returns -1 on
+ error or the length of the parsed string. In-place conversion is
+ allowed but the Source string might be garbled on error. */
+int
+hex2bin (const char *string, void *buffer, size_t length)
+{
+ int i;
+ const char *s = string;
+
+ for (i=0; i < length; )
+ {
+ if (!hexdigitp (s) || !hexdigitp (s+1))
+ return -1; /* Invalid hex digits. */
+ ((unsigned char*)buffer)[i++] = xtoi_2 (s);
+ s += 2;
+ }
+ if (*s && (!isascii (*s) || !isspace (*s)) )
+ return -1; /* Not followed by Nul or white space. */
+ if (i != length)
+ return -1; /* Not of expected length. */
+ if (*s)
+ s++; /* Skip the delimiter. */
+ return s - string;
+}
+
+
+/* Convert STRING consisting of hex characters into its binary representation
+ and store that at BUFFER. BUFFER needs to be of LENGTH bytes. The
+ function check that the STRING will convert exactly to LENGTH
+ bytes. Colons between the hex digits are allowed, if one colon
+ has been given a colon is expected very 2 characters. The string
+ is delimited by either end of string or a white space character.
+ The function returns -1 on error or the length of the parsed
+ string. */
+int
+hexcolon2bin (const char *string, void *buffer, size_t length)
+{
+ int i;
+ const char *s = string;
+ int need_colon = 0;
+
+ for (i=0; i < length; )
+ {
+ if (i==1 && *s == ':') /* Skip colons between hex digits. */
+ {
+ need_colon = 1;
+ s++;
+ }
+ else if (need_colon && *s == ':')
+ s++;
+ else if (need_colon)
+ return -1; /* Colon expected. */
+ if (!hexdigitp (s) || !hexdigitp (s+1))
+ return -1; /* Invalid hex digits. */
+ ((unsigned char*)buffer)[i++] = xtoi_2 (s);
+ s += 2;
+ }
+ if (*s == ':')
+ return -1; /* Trailing colons are not allowed. */
+ if (*s && (!isascii (*s) || !isspace (*s)) )
+ return -1; /* Not followed by Nul or white space. */
+ if (i != length)
+ return -1; /* Not of expected length. */
+ if (*s)
+ s++; /* Skip the delimiter. */
+ return s - string;
+}
+
+
+
+static char *
+do_bin2hex (const void *buffer, size_t length, char *stringbuf, int with_colon)
+{
+ const unsigned char *s;
+ char *p;
+
+ if (!stringbuf)
+ {
+ /* Not really correct for with_colon but we don't care about the
+ one wasted byte. */
+ size_t n = with_colon? 3:2;
+ size_t nbytes = n * length + 1;
+ if (length && (nbytes-1) / n != length)
+ {
+ gpg_err_set_errno (ENOMEM);
+ return NULL;
+ }
+ stringbuf = xtrymalloc (nbytes);
+ if (!stringbuf)
+ return NULL;
+ }
+
+ for (s = buffer, p = stringbuf; length; length--, s++)
+ {
+ if (with_colon && s != buffer)
+ *p++ = ':';
+ *p++ = tohex ((*s>>4)&15);
+ *p++ = tohex (*s&15);
+ }
+ *p = 0;
+
+ return stringbuf;
+}
+
+
+/* Convert LENGTH bytes of data in BUFFER into hex encoding and store
+ that at the provided STRINGBUF. STRINGBUF must be allocated of at
+ least (2*LENGTH+1) bytes or be NULL so that the function mallocs an
+ appropriate buffer. Returns STRINGBUF or NULL on error (which may
+ only occur if STRINGBUF has been NULL and the internal malloc
+ failed). */
+char *
+bin2hex (const void *buffer, size_t length, char *stringbuf)
+{
+ return do_bin2hex (buffer, length, stringbuf, 0);
+}
+
+/* Convert LENGTH bytes of data in BUFFER into hex encoding and store
+ that at the provided STRINGBUF. STRINGBUF must be allocated of at
+ least (3*LENGTH+1) bytes or be NULL so that the function mallocs an
+ appropriate buffer. Returns STRINGBUF or NULL on error (which may
+ only occur if STRINGBUF has been NULL and the internal malloc
+ failed). */
+char *
+bin2hexcolon (const void *buffer, size_t length, char *stringbuf)
+{
+ return do_bin2hex (buffer, length, stringbuf, 1);
+}
+
+
+
+/* Convert HEXSTRING consisting of hex characters into string and
+ store that at BUFFER. HEXSTRING is either delimited by end of
+ string or a white space character. The function makes sure that
+ the resulting string in BUFFER is terminated by a Nul byte. Note
+ that the returned string may include embedded Nul bytes; the extra
+ Nul byte at the end is used to make sure tha the result can always
+ be used as a C-string.
+
+ BUFSIZE is the available length of BUFFER; if the converted result
+ plus a possible required extra Nul character does not fit into this
+ buffer, the function returns NULL and won't change the existing
+ content of BUFFER. In-place conversion is possible as long as
+ BUFFER points to HEXSTRING.
+
+ If BUFFER is NULL and BUFSIZE is 0 the function scans HEXSTRING but
+ does not store anything. This may be used to find the end of
+ HEXSTRING.
+
+ On success the function returns a pointer to the next character
+ after HEXSTRING (which is either end-of-string or a the next white
+ space). If BUFLEN is not NULL the number of valid vytes in BUFFER
+ is stored there (an extra Nul byte is not counted); this will even
+ be done if BUFFER has been passed as NULL. */
+const char *
+hex2str (const char *hexstring, char *buffer, size_t bufsize, size_t *buflen)
+{
+ const char *s = hexstring;
+ int idx, count;
+ int need_nul = 0;
+
+ if (buflen)
+ *buflen = 0;
+
+ for (s=hexstring, count=0; hexdigitp (s) && hexdigitp (s+1); s += 2, count++)
+ ;
+ if (*s && (!isascii (*s) || !isspace (*s)) )
+ {
+ gpg_err_set_errno (EINVAL);
+ return NULL; /* Not followed by Nul or white space. */
+ }
+ /* We need to append a nul character. However we don't want that if
+ the hexstring already ends with "00". */
+ need_nul = ((s == hexstring) || !(s[-2] == '0' && s[-1] == '0'));
+ if (need_nul)
+ count++;
+
+ if (buffer)
+ {
+ if (count > bufsize)
+ {
+ gpg_err_set_errno (EINVAL);
+ return NULL; /* Too long. */
+ }
+
+ for (s=hexstring, idx=0; hexdigitp (s) && hexdigitp (s+1); s += 2)
+ ((unsigned char*)buffer)[idx++] = xtoi_2 (s);
+ if (need_nul)
+ buffer[idx] = 0;
+ }
+
+ if (buflen)
+ *buflen = count - need_nul;
+ return s;
+}
+
+
+/* Same as hex2str but this function allocated a new string. Returns
+ NULL on error. If R_COUNT is not NULL, the number of scanned bytes
+ will be stored there. ERRNO is set on error. */
+char *
+hex2str_alloc (const char *hexstring, size_t *r_count)
+{
+ const char *tail;
+ size_t nbytes;
+ char *result;
+
+ tail = hex2str (hexstring, NULL, 0, &nbytes);
+ if (!tail)
+ {
+ if (r_count)
+ *r_count = 0;
+ return NULL;
+ }
+ if (r_count)
+ *r_count = tail - hexstring;
+ result = xtrymalloc (nbytes+1);
+ if (!result)
+ return NULL;
+ if (!hex2str (hexstring, result, nbytes+1, NULL))
+ BUG ();
+ return result;
+}
diff --git a/common/dotlock.c b/common/dotlock.c
new file mode 100644
index 0000000..772bda3
--- /dev/null
+++ b/common/dotlock.c
@@ -0,0 +1,1443 @@
+/* dotlock.c - dotfile locking
+ * Copyright (C) 1998, 2000, 2001, 2003, 2004,
+ * 2005, 2006, 2008, 2010, 2011 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute and/or modify this
+ * part of GnuPG under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * 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 copies of the GNU General Public License
+ * and the GNU Lesser General Public License along with this program;
+ * if not, see <https://www.gnu.org/licenses/>.
+ *
+ * ALTERNATIVELY, this file may be distributed under the terms of the
+ * following license, in which case the provisions of this license are
+ * required INSTEAD OF the GNU Lesser General License or the GNU
+ * General Public License. If you wish to allow use of your version of
+ * this file only under the terms of the GNU Lesser General License or
+ * the GNU General Public License, and not to allow others to use your
+ * version of this file under the terms of the following license,
+ * indicate your decision by deleting this paragraph and the license
+ * below.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ Overview:
+ =========
+
+ This module implements advisory file locking in a portable way.
+ Due to the problems with POSIX fcntl locking a separate lock file
+ is used. It would be possible to use fcntl locking on this lock
+ file and thus avoid the weird auto unlock bug of POSIX while still
+ having an unproved better performance of fcntl locking. However
+ there are still problems left, thus we resort to use a hardlink
+ which has the well defined property that a link call will fail if
+ the target file already exists.
+
+ Given that hardlinks are also available on NTFS file systems since
+ Windows XP; it will be possible to enhance this module to use
+ hardlinks even on Windows and thus allow Windows and Posix clients
+ to use locking on the same directory. This is not yet implemented;
+ instead we use a lockfile on Windows along with W32 style file
+ locking.
+
+ On FAT file systems hardlinks are not supported. Thus this method
+ does not work. Our solution is to use a O_EXCL locking instead.
+ Querying the type of the file system is not easy to do in a
+ portable way (e.g. Linux has a statfs, BSDs have a the same call
+ but using different structures and constants). What we do instead
+ is to check at runtime whether link(2) works for a specific lock
+ file.
+
+
+ How to use:
+ ===========
+
+ At program initialization time, the module should be explicitly
+ initialized:
+
+ dotlock_create (NULL, 0);
+
+ This installs an atexit handler and may also initialize mutex etc.
+ It is optional for non-threaded applications. Only the first call
+ has an effect. This needs to be done before any extra threads are
+ started.
+
+ To create a lock file (which prepares it but does not take the
+ lock) you do:
+
+ dotlock_t h
+
+ h = dotlock_create (fname, 0);
+ if (!h)
+ error ("error creating lock file: %s\n", strerror (errno));
+
+ It is important to handle the error. For example on a read-only
+ file system a lock can't be created (but is usually not needed).
+ FNAME is the file you want to lock; the actual lockfile is that
+ name with the suffix ".lock" appended. On success a handle to be
+ used with the other functions is returned or NULL on error. Note
+ that the handle shall only be used by one thread at a time. This
+ function creates a unique file temporary file (".#lk*") in the same
+ directory as FNAME and returns a handle for further operations.
+ The module keeps track of these unique files so that they will be
+ unlinked using the atexit handler. If you don't need the lock file
+ anymore, you may also explicitly remove it with a call to:
+
+ dotlock_destroy (h);
+
+ To actually lock the file, you use:
+
+ if (dotlock_take (h, -1))
+ error ("error taking lock: %s\n", strerror (errno));
+
+ This function will wait until the lock is acquired. If an
+ unexpected error occurs if will return non-zero and set ERRNO. If
+ you pass (0) instead of (-1) the function does not wait in case the
+ file is already locked but returns -1 and sets ERRNO to EACCES.
+ Any other positive value for the second parameter is considered a
+ timeout value in milliseconds.
+
+ To release the lock you call:
+
+ if (dotlock_release (h))
+ error ("error releasing lock: %s\n", strerror (errno));
+
+ or, if the lock file is not anymore needed, you may just call
+ dotlock_destroy. However dotlock_release does some extra checks
+ before releasing the lock and prints diagnostics to help detecting
+ bugs.
+
+ If you want to explicitly destroy all lock files you may call
+
+ dotlock_remove_lockfiles ();
+
+ which is the core of the installed atexit handler. In case your
+ application wants to disable locking completely it may call
+
+ disable_locking ()
+
+ before any locks are created.
+
+ There are two convenience functions to store an integer (e.g. a
+ file descriptor) value with the handle:
+
+ void dotlock_set_fd (dotlock_t h, int fd);
+ int dotlock_get_fd (dotlock_t h);
+
+ If nothing has been stored dotlock_get_fd returns -1.
+
+
+
+ How to build:
+ =============
+
+ This module was originally developed for GnuPG but later changed to
+ allow its use without any GnuPG dependency. If you want to use it
+ with you application you may simply use it and it should figure out
+ most things automagically.
+
+ You may use the common config.h file to pass macros, but take care
+ to pass -DHAVE_CONFIG_H to the compiler. Macros used by this
+ module are:
+
+ DOTLOCK_USE_PTHREAD - Define if POSIX threads are in use.
+
+ DOTLOCK_GLIB_LOGGING - Define this to use Glib logging functions.
+
+ DOTLOCK_EXT_SYM_PREFIX - Prefix all external symbols with the
+ string to which this macro evaluates.
+
+ GNUPG_MAJOR_VERSION - Defined when used by GnuPG.
+
+ HAVE_DOSISH_SYSTEM - Defined for Windows etc. Will be
+ automatically defined if a the target is
+ Windows.
+
+ HAVE_POSIX_SYSTEM - Internally defined to !HAVE_DOSISH_SYSTEM.
+
+ HAVE_SIGNAL_H - Should be defined on Posix systems. If config.h
+ is not used defaults to defined.
+
+ DIRSEP_C - Separation character for file name parts.
+ Usually not redefined.
+
+ EXTSEP_S - Separation string for file name suffixes.
+ Usually not redefined.
+
+ HAVE_W32CE_SYSTEM - Currently only used by GnuPG.
+
+ Note that there is a test program t-dotlock which has compile
+ instructions at its end. At least for SMBFS and CIFS it is
+ important that 64 bit versions of stat are used; most programming
+ environments do this these days, just in case you want to compile
+ it on the command line, remember to pass -D_FILE_OFFSET_BITS=64
+
+
+ Bugs:
+ =====
+
+ On Windows this module is not yet thread-safe.
+
+
+ Miscellaneous notes:
+ ====================
+
+ On hardlinks:
+ - Hardlinks are supported under Windows with NTFS since XP/Server2003.
+ - In Linux 2.6.33 both SMBFS and CIFS seem to support hardlinks.
+ - NFS supports hard links. But there are solvable problems.
+ - FAT does not support links
+
+ On the file locking API:
+ - CIFS on Linux 2.6.33 supports several locking methods.
+ SMBFS seems not to support locking. No closer checks done.
+ - NFS supports Posix locks. flock is emulated in the server.
+ However there are a couple of problems; see below.
+ - FAT does not support locks.
+ - An advantage of fcntl locking is that R/W locks can be
+ implemented which is not easy with a straight lock file.
+
+ On O_EXCL:
+ - Does not work reliable on NFS
+ - Should work on CIFS and SMBFS but how can we delete lockfiles?
+
+ On NFS problems:
+ - Locks vanish if the server crashes and reboots.
+ - Client crashes keep the lock in the server until the client
+ re-connects.
+ - Communication problems may return unreliable error codes. The
+ MUA Postfix's workaround is to compare the link count after
+ seeing an error for link. However that gives a race. If using a
+ unique file to link to a lockfile and using stat to check the
+ link count instead of looking at the error return of link(2) is
+ the best solution.
+ - O_EXCL seems to have a race and may re-create a file anyway.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Some quick replacements for stuff we usually expect to be defined
+ in config.h. Define HAVE_POSIX_SYSTEM for better readability. */
+#if !defined (HAVE_DOSISH_SYSTEM) && defined(_WIN32)
+# define HAVE_DOSISH_SYSTEM 1
+#endif
+#if !defined (HAVE_DOSISH_SYSTEM) && !defined (HAVE_POSIX_SYSTEM)
+# define HAVE_POSIX_SYSTEM 1
+#endif
+
+/* With no config.h assume that we have sitgnal.h. */
+#if !defined (HAVE_CONFIG_H) && defined (HAVE_POSIX_SYSTEM)
+# define HAVE_SIGNAL_H 1
+#endif
+
+/* Standard headers. */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <errno.h>
+#include <unistd.h>
+#ifdef HAVE_DOSISH_SYSTEM
+# define WIN32_LEAN_AND_MEAN /* We only need the OS core stuff. */
+# include <windows.h>
+#else
+# include <sys/types.h>
+# include <sys/stat.h>
+# include <sys/utsname.h>
+#endif
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#ifdef HAVE_SIGNAL_H
+# include <signal.h>
+#endif
+#ifdef DOTLOCK_USE_PTHREAD
+# include <pthread.h>
+#endif
+
+#ifdef DOTLOCK_GLIB_LOGGING
+# include <glib.h>
+#endif
+
+#ifdef GNUPG_MAJOR_VERSION
+# include "util.h"
+# include "common-defs.h"
+# include "stringhelp.h" /* For stpcpy and w32_strerror. */
+#endif
+#ifdef HAVE_W32CE_SYSTEM
+# include "utf8conv.h" /* WindowsCE requires filename conversion. */
+#endif
+
+#include "dotlock.h"
+
+
+/* Define constants for file name construction. */
+#if !defined(DIRSEP_C) && !defined(EXTSEP_S)
+# ifdef HAVE_DOSISH_SYSTEM
+# define DIRSEP_C '\\'
+# define EXTSEP_S "."
+#else
+# define DIRSEP_C '/'
+# define EXTSEP_S "."
+# endif
+#endif
+
+/* In GnuPG we use wrappers around the malloc functions. If they are
+ not defined we assume that this code is used outside of GnuPG and
+ fall back to the regular malloc functions. */
+#ifndef xtrymalloc
+# define xtrymalloc(a) malloc ((a))
+# define xtrycalloc(a,b) calloc ((a), (b))
+# define xfree(a) free ((a))
+#endif
+
+/* Wrapper to set ERRNO (required for W32CE). */
+#ifdef GPG_ERROR_VERSION
+# define my_set_errno(e) gpg_err_set_errno ((e))
+#else
+# define my_set_errno(e) do { errno = (e); } while (0)
+#endif
+
+/* Gettext macro replacement. */
+#ifndef _
+# define _(a) (a)
+#endif
+
+#ifdef GNUPG_MAJOR_VERSION
+# define my_info_0(a) log_info ((a))
+# define my_info_1(a,b) log_info ((a), (b))
+# define my_info_2(a,b,c) log_info ((a), (b), (c))
+# define my_info_3(a,b,c,d) log_info ((a), (b), (c), (d))
+# define my_error_0(a) log_error ((a))
+# define my_error_1(a,b) log_error ((a), (b))
+# define my_error_2(a,b,c) log_error ((a), (b), (c))
+# define my_debug_1(a,b) log_debug ((a), (b))
+# define my_fatal_0(a) log_fatal ((a))
+#elif defined (DOTLOCK_GLIB_LOGGING)
+# define my_info_0(a) g_message ((a))
+# define my_info_1(a,b) g_message ((a), (b))
+# define my_info_2(a,b,c) g_message ((a), (b), (c))
+# define my_info_3(a,b,c,d) g_message ((a), (b), (c), (d))
+# define my_error_0(a) g_warning ((a))
+# define my_error_1(a,b) g_warning ((a), (b))
+# define my_error_2(a,b,c) g_warning ((a), (b), (c))
+# define my_debug_1(a,b) g_debug ((a), (b))
+# define my_fatal_0(a) g_error ((a))
+#else
+# define my_info_0(a) fprintf (stderr, (a))
+# define my_info_1(a,b) fprintf (stderr, (a), (b))
+# define my_info_2(a,b,c) fprintf (stderr, (a), (b), (c))
+# define my_info_3(a,b,c,d) fprintf (stderr, (a), (b), (c), (d))
+# define my_error_0(a) fprintf (stderr, (a))
+# define my_error_1(a,b) fprintf (stderr, (a), (b))
+# define my_error_2(a,b,c) fprintf (stderr, (a), (b), (c))
+# define my_debug_1(a,b) fprintf (stderr, (a), (b))
+# define my_fatal_0(a) do { fprintf (stderr,(a)); fflush (stderr); \
+ abort (); } while (0)
+#endif
+
+
+
+
+
+/* The object describing a lock. */
+struct dotlock_handle
+{
+ struct dotlock_handle *next;
+ char *lockname; /* Name of the actual lockfile. */
+ unsigned int locked:1; /* Lock status. */
+ unsigned int disable:1; /* If true, locking is disabled. */
+ unsigned int use_o_excl:1; /* Use open (O_EXCL) for locking. */
+
+ int extra_fd; /* A place for the caller to store an FD. */
+
+#ifdef HAVE_DOSISH_SYSTEM
+ HANDLE lockhd; /* The W32 handle of the lock file. */
+#else /*!HAVE_DOSISH_SYSTEM */
+ char *tname; /* Name of the lockfile template. */
+ size_t nodename_off; /* Offset in TNAME of the nodename part. */
+ size_t nodename_len; /* Length of the nodename part. */
+#endif /*!HAVE_DOSISH_SYSTEM */
+};
+
+
+/* A list of all lock handles. The volatile attribute might help
+ if used in an atexit handler. Note that [UN]LOCK_all_lockfiles
+ must not change ERRNO. */
+static volatile dotlock_t all_lockfiles;
+#ifdef DOTLOCK_USE_PTHREAD
+static pthread_mutex_t all_lockfiles_mutex = PTHREAD_MUTEX_INITIALIZER;
+# define LOCK_all_lockfiles() do { \
+ if (pthread_mutex_lock (&all_lockfiles_mutex)) \
+ my_fatal_0 ("locking all_lockfiles_mutex failed\n"); \
+ } while (0)
+# define UNLOCK_all_lockfiles() do { \
+ if (pthread_mutex_unlock (&all_lockfiles_mutex)) \
+ my_fatal_0 ("unlocking all_lockfiles_mutex failed\n"); \
+ } while (0)
+#else /*!DOTLOCK_USE_PTHREAD*/
+# define LOCK_all_lockfiles() do { } while (0)
+# define UNLOCK_all_lockfiles() do { } while (0)
+#endif /*!DOTLOCK_USE_PTHREAD*/
+
+/* If this has the value true all locking is disabled. */
+static int never_lock;
+
+
+
+
+#ifdef HAVE_DOSISH_SYSTEM
+/* FIXME: For use in GnuPG this can be replaced by
+ * gnupg_w32_set_errno. */
+static int
+map_w32_to_errno (DWORD w32_err)
+{
+ switch (w32_err)
+ {
+ case 0:
+ return 0;
+
+ case ERROR_FILE_NOT_FOUND:
+ return ENOENT;
+
+ case ERROR_PATH_NOT_FOUND:
+ return ENOENT;
+
+ case ERROR_ACCESS_DENIED:
+ return EPERM;
+
+ case ERROR_INVALID_HANDLE:
+ case ERROR_INVALID_BLOCK:
+ return EINVAL;
+
+ case ERROR_NOT_ENOUGH_MEMORY:
+ return ENOMEM;
+
+ case ERROR_NO_DATA:
+ case ERROR_BROKEN_PIPE:
+ return EPIPE;
+
+ default:
+ return EIO;
+ }
+}
+#endif /*HAVE_DOSISH_SYSTEM*/
+
+
+#ifdef HAVE_W32_SYSTEM
+static int
+any8bitchar (const char *string)
+{
+ if (string)
+ for ( ; *string; string++)
+ if ((*string & 0x80))
+ return 1;
+ return 0;
+}
+#endif /*HAVE_W32_SYSTEM*/
+
+
+
+
+/* Entirely disable all locking. This function should be called
+ before any locking is done. It may be called right at startup of
+ the process as it only sets a global value. */
+void
+dotlock_disable (void)
+{
+ never_lock = 1;
+}
+
+
+#ifdef HAVE_POSIX_SYSTEM
+static int
+maybe_deadlock (dotlock_t h)
+{
+ dotlock_t r;
+ int res = 0;
+
+ LOCK_all_lockfiles ();
+ for (r=all_lockfiles; r; r = r->next)
+ {
+ if ( r != h && r->locked )
+ {
+ res = 1;
+ break;
+ }
+ }
+ UNLOCK_all_lockfiles ();
+ return res;
+}
+#endif /*HAVE_POSIX_SYSTEM*/
+
+
+/* Read the lock file and return the pid, returns -1 on error. True
+ will be stored in the integer at address SAME_NODE if the lock file
+ has been created on the same node. */
+#ifdef HAVE_POSIX_SYSTEM
+static int
+read_lockfile (dotlock_t h, int *same_node, int *r_fd)
+{
+ char buffer_space[10+1+70+1]; /* 70 is just an estimated value; node
+ names are usually shorter. */
+ int fd;
+ int pid = -1;
+ char *buffer, *p;
+ size_t expected_len;
+ int res, nread;
+
+ *same_node = 0;
+ expected_len = 10 + 1 + h->nodename_len + 1;
+ if ( expected_len >= sizeof buffer_space)
+ {
+ buffer = xtrymalloc (expected_len);
+ if (!buffer)
+ return -1;
+ }
+ else
+ buffer = buffer_space;
+
+ if ( (fd = open (h->lockname, O_RDONLY)) == -1 )
+ {
+ int e = errno;
+ my_info_2 ("error opening lockfile '%s': %s\n",
+ h->lockname, strerror(errno) );
+ if (buffer != buffer_space)
+ xfree (buffer);
+ my_set_errno (e); /* Need to return ERRNO here. */
+ return -1;
+ }
+
+ p = buffer;
+ nread = 0;
+ do
+ {
+ res = read (fd, p, expected_len - nread);
+ if (res == -1 && errno == EINTR)
+ continue;
+ if (res < 0)
+ {
+ int e = errno;
+ my_info_1 ("error reading lockfile '%s'\n", h->lockname );
+ close (fd);
+ if (buffer != buffer_space)
+ xfree (buffer);
+ my_set_errno (e);
+ return -1;
+ }
+ p += res;
+ nread += res;
+ }
+ while (res && nread != expected_len);
+
+ if (r_fd)
+ *r_fd = fd;
+ else
+ close(fd);
+
+ if (nread < 11)
+ {
+ my_info_1 ("invalid size of lockfile '%s'\n", h->lockname);
+ if (buffer != buffer_space)
+ xfree (buffer);
+ my_set_errno (EINVAL);
+ return -1;
+ }
+
+ if (buffer[10] != '\n'
+ || (buffer[10] = 0, pid = atoi (buffer)) == -1
+ || !pid )
+ {
+ my_error_2 ("invalid pid %d in lockfile '%s'\n", pid, h->lockname);
+ if (buffer != buffer_space)
+ xfree (buffer);
+ my_set_errno (EINVAL);
+ return -1;
+ }
+
+ if (nread == expected_len
+ && !memcmp (h->tname+h->nodename_off, buffer+11, h->nodename_len)
+ && buffer[11+h->nodename_len] == '\n')
+ *same_node = 1;
+
+ if (buffer != buffer_space)
+ xfree (buffer);
+ return pid;
+}
+#endif /*HAVE_POSIX_SYSTEM */
+
+
+/* Check whether the file system which stores TNAME supports
+ hardlinks. Instead of using the non-portable statsfs call which
+ differs between various Unix versions, we do a runtime test.
+ Returns: 0 supports hardlinks; 1 no hardlink support, -1 unknown
+ (test error). */
+#ifdef HAVE_POSIX_SYSTEM
+static int
+use_hardlinks_p (const char *tname)
+{
+ char *lname;
+ struct stat sb;
+ unsigned int nlink;
+ int res;
+
+ if (stat (tname, &sb))
+ return -1;
+ nlink = (unsigned int)sb.st_nlink;
+
+ lname = xtrymalloc (strlen (tname) + 1 + 1);
+ if (!lname)
+ return -1;
+ strcpy (lname, tname);
+ strcat (lname, "x");
+
+ /* We ignore the return value of link() because it is unreliable. */
+ (void) link (tname, lname);
+
+ if (stat (tname, &sb))
+ res = -1; /* Ooops. */
+ else if (sb.st_nlink == nlink + 1)
+ res = 0; /* Yeah, hardlinks are supported. */
+ else
+ res = 1; /* No hardlink support. */
+
+ unlink (lname);
+ xfree (lname);
+ return res;
+}
+#endif /*HAVE_POSIX_SYSTEM */
+
+
+
+#ifdef HAVE_POSIX_SYSTEM
+/* Locking core for Unix. It used a temporary file and the link
+ system call to make locking an atomic operation. */
+static dotlock_t
+dotlock_create_unix (dotlock_t h, const char *file_to_lock)
+{
+ int fd = -1;
+ char pidstr[16];
+ const char *nodename;
+ const char *dirpart;
+ int dirpartlen;
+ struct utsname utsbuf;
+ size_t tnamelen;
+
+ snprintf (pidstr, sizeof pidstr, "%10d\n", (int)getpid() );
+
+ /* Create a temporary file. */
+ if ( uname ( &utsbuf ) )
+ nodename = "unknown";
+ else
+ nodename = utsbuf.nodename;
+
+ if ( !(dirpart = strrchr (file_to_lock, DIRSEP_C)) )
+ {
+ dirpart = EXTSEP_S;
+ dirpartlen = 1;
+ }
+ else
+ {
+ dirpartlen = dirpart - file_to_lock;
+ dirpart = file_to_lock;
+ }
+
+ LOCK_all_lockfiles ();
+ h->next = all_lockfiles;
+ all_lockfiles = h;
+
+ tnamelen = dirpartlen + 6 + 30 + strlen(nodename) + 10 + 1;
+ h->tname = xtrymalloc (tnamelen + 1);
+ if (!h->tname)
+ {
+ all_lockfiles = h->next;
+ UNLOCK_all_lockfiles ();
+ xfree (h);
+ return NULL;
+ }
+ h->nodename_len = strlen (nodename);
+
+ snprintf (h->tname, tnamelen, "%.*s/.#lk%p.", dirpartlen, dirpart, h );
+ h->nodename_off = strlen (h->tname);
+ snprintf (h->tname+h->nodename_off, tnamelen - h->nodename_off,
+ "%s.%d", nodename, (int)getpid ());
+
+ do
+ {
+ my_set_errno (0);
+ fd = open (h->tname, O_WRONLY|O_CREAT|O_EXCL,
+ S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR );
+ }
+ while (fd == -1 && errno == EINTR);
+
+ if ( fd == -1 )
+ {
+ int saveerrno = errno;
+ all_lockfiles = h->next;
+ UNLOCK_all_lockfiles ();
+ my_error_2 (_("failed to create temporary file '%s': %s\n"),
+ h->tname, strerror (errno));
+ xfree (h->tname);
+ xfree (h);
+ my_set_errno (saveerrno);
+ return NULL;
+ }
+ if ( write (fd, pidstr, 11 ) != 11 )
+ goto write_failed;
+ if ( write (fd, nodename, strlen (nodename) ) != strlen (nodename) )
+ goto write_failed;
+ if ( write (fd, "\n", 1 ) != 1 )
+ goto write_failed;
+ if ( close (fd) )
+ {
+ if ( errno == EINTR )
+ fd = -1;
+ goto write_failed;
+ }
+ fd = -1;
+
+ /* Check whether we support hard links. */
+ switch (use_hardlinks_p (h->tname))
+ {
+ case 0: /* Yes. */
+ break;
+ case 1: /* No. */
+ unlink (h->tname);
+ h->use_o_excl = 1;
+ break;
+ default:
+ {
+ int saveerrno = errno;
+ my_error_2 ("can't check whether hardlinks are supported for '%s': %s\n"
+ , h->tname, strerror (saveerrno));
+ my_set_errno (saveerrno);
+ }
+ goto write_failed;
+ }
+
+ h->lockname = xtrymalloc (strlen (file_to_lock) + 6 );
+ if (!h->lockname)
+ {
+ int saveerrno = errno;
+ all_lockfiles = h->next;
+ UNLOCK_all_lockfiles ();
+ unlink (h->tname);
+ xfree (h->tname);
+ xfree (h);
+ my_set_errno (saveerrno);
+ return NULL;
+ }
+ strcpy (stpcpy (h->lockname, file_to_lock), EXTSEP_S "lock");
+ UNLOCK_all_lockfiles ();
+
+ return h;
+
+ write_failed:
+ {
+ int saveerrno = errno;
+ all_lockfiles = h->next;
+ UNLOCK_all_lockfiles ();
+ my_error_2 (_("error writing to '%s': %s\n"), h->tname, strerror (errno));
+ if ( fd != -1 )
+ close (fd);
+ unlink (h->tname);
+ xfree (h->tname);
+ xfree (h);
+ my_set_errno (saveerrno);
+ }
+ return NULL;
+}
+#endif /*HAVE_POSIX_SYSTEM*/
+
+
+#ifdef HAVE_DOSISH_SYSTEM
+/* Locking core for Windows. This version does not need a temporary
+ file but uses the plain lock file along with record locking. We
+ create this file here so that we later only need to do the file
+ locking. For error reporting it is useful to keep the name of the
+ file in the handle. */
+static dotlock_t
+dotlock_create_w32 (dotlock_t h, const char *file_to_lock)
+{
+ LOCK_all_lockfiles ();
+ h->next = all_lockfiles;
+ all_lockfiles = h;
+
+ h->lockname = strconcat (file_to_lock, EXTSEP_S "lock", NULL);
+ if (!h->lockname)
+ {
+ all_lockfiles = h->next;
+ UNLOCK_all_lockfiles ();
+ xfree (h);
+ return NULL;
+ }
+
+ /* If would be nice if we would use the FILE_FLAG_DELETE_ON_CLOSE
+ along with FILE_SHARE_DELETE but that does not work due to a race
+ condition: Despite the OPEN_ALWAYS flag CreateFile may return an
+ error and we can't reliable create/open the lock file unless we
+ would wait here until it works - however there are other valid
+ reasons why a lock file can't be created and thus the process
+ would not stop as expected but spin until Windows crashes. Our
+ solution is to keep the lock file open; that does not harm. */
+ if (any8bitchar (h->lockname))
+ {
+ wchar_t *wname = utf8_to_wchar (h->lockname);
+
+ if (wname)
+ h->lockhd = CreateFileW (wname,
+ GENERIC_READ|GENERIC_WRITE,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL, OPEN_ALWAYS, 0, NULL);
+ else
+ h->lockhd = INVALID_HANDLE_VALUE;
+ xfree (wname);
+ }
+ else
+ h->lockhd = CreateFileA (h->lockname,
+ GENERIC_READ|GENERIC_WRITE,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL, OPEN_ALWAYS, 0, NULL);
+ if (h->lockhd == INVALID_HANDLE_VALUE)
+ {
+ int saveerrno = map_w32_to_errno (GetLastError ());
+ all_lockfiles = h->next;
+ UNLOCK_all_lockfiles ();
+ my_error_2 (_("can't create '%s': %s\n"), h->lockname, w32_strerror (-1));
+ xfree (h->lockname);
+ xfree (h);
+ my_set_errno (saveerrno);
+ return NULL;
+ }
+ return h;
+}
+#endif /*HAVE_DOSISH_SYSTEM*/
+
+
+/* Create a lockfile for a file name FILE_TO_LOCK and returns an
+ object of type dotlock_t which may be used later to actually acquire
+ the lock. A cleanup routine gets installed to cleanup left over
+ locks or other files used internally by the lock mechanism.
+
+ Calling this function with NULL does only install the atexit
+ handler and may thus be used to assure that the cleanup is called
+ after all other atexit handlers.
+
+ This function creates a lock file in the same directory as
+ FILE_TO_LOCK using that name and a suffix of ".lock". Note that on
+ POSIX systems a temporary file ".#lk.<hostname>.pid[.threadid] is
+ used.
+
+ FLAGS must be 0.
+
+ The function returns an new handle which needs to be released using
+ destroy_dotlock but gets also released at the termination of the
+ process. On error NULL is returned.
+ */
+
+dotlock_t
+dotlock_create (const char *file_to_lock, unsigned int flags)
+{
+ static int initialized;
+ dotlock_t h;
+
+ if ( !initialized )
+ {
+ atexit (dotlock_remove_lockfiles);
+ initialized = 1;
+ }
+
+ if ( !file_to_lock )
+ return NULL; /* Only initialization was requested. */
+
+ if (flags)
+ {
+ my_set_errno (EINVAL);
+ return NULL;
+ }
+
+ h = xtrycalloc (1, sizeof *h);
+ if (!h)
+ return NULL;
+ h->extra_fd = -1;
+
+ if (never_lock)
+ {
+ h->disable = 1;
+ LOCK_all_lockfiles ();
+ h->next = all_lockfiles;
+ all_lockfiles = h;
+ UNLOCK_all_lockfiles ();
+ return h;
+ }
+
+#ifdef HAVE_DOSISH_SYSTEM
+ return dotlock_create_w32 (h, file_to_lock);
+#else /*!HAVE_DOSISH_SYSTEM */
+ return dotlock_create_unix (h, file_to_lock);
+#endif /*!HAVE_DOSISH_SYSTEM*/
+}
+
+
+
+/* Convenience function to store a file descriptor (or any other
+ integer value) in the context of handle H. */
+void
+dotlock_set_fd (dotlock_t h, int fd)
+{
+ h->extra_fd = fd;
+}
+
+/* Convenience function to retrieve a file descriptor (or any other
+ integer value) stored in the context of handle H. */
+int
+dotlock_get_fd (dotlock_t h)
+{
+ return h->extra_fd;
+}
+
+
+
+#ifdef HAVE_POSIX_SYSTEM
+/* Unix specific code of destroy_dotlock. */
+static void
+dotlock_destroy_unix (dotlock_t h)
+{
+ if (h->locked && h->lockname)
+ unlink (h->lockname);
+ if (h->tname && !h->use_o_excl)
+ unlink (h->tname);
+ xfree (h->tname);
+}
+#endif /*HAVE_POSIX_SYSTEM*/
+
+
+#ifdef HAVE_DOSISH_SYSTEM
+/* Windows specific code of destroy_dotlock. */
+static void
+dotlock_destroy_w32 (dotlock_t h)
+{
+ if (h->locked)
+ {
+ OVERLAPPED ovl;
+
+ memset (&ovl, 0, sizeof ovl);
+ UnlockFileEx (h->lockhd, 0, 1, 0, &ovl);
+ }
+ CloseHandle (h->lockhd);
+}
+#endif /*HAVE_DOSISH_SYSTEM*/
+
+
+/* Destroy the lock handle H and release the lock. */
+void
+dotlock_destroy (dotlock_t h)
+{
+ dotlock_t hprev, htmp;
+
+ if ( !h )
+ return;
+
+ /* First remove the handle from our global list of all locks. */
+ LOCK_all_lockfiles ();
+ for (hprev=NULL, htmp=all_lockfiles; htmp; hprev=htmp, htmp=htmp->next)
+ if (htmp == h)
+ {
+ if (hprev)
+ hprev->next = htmp->next;
+ else
+ all_lockfiles = htmp->next;
+ h->next = NULL;
+ break;
+ }
+ UNLOCK_all_lockfiles ();
+
+ /* Then destroy the lock. */
+ if (!h->disable)
+ {
+#ifdef HAVE_DOSISH_SYSTEM
+ dotlock_destroy_w32 (h);
+#else /* !HAVE_DOSISH_SYSTEM */
+ dotlock_destroy_unix (h);
+#endif /* HAVE_DOSISH_SYSTEM */
+ xfree (h->lockname);
+ }
+ xfree(h);
+}
+
+
+/* Return true if H has been taken. */
+int
+dotlock_is_locked (dotlock_t h)
+{
+ return h && !!h->locked;
+}
+
+
+
+#ifdef HAVE_POSIX_SYSTEM
+/* Unix specific code of make_dotlock. Returns 0 on success and -1 on
+ error. */
+static int
+dotlock_take_unix (dotlock_t h, long timeout)
+{
+ int wtime = 0;
+ int sumtime = 0;
+ int pid;
+ int lastpid = -1;
+ int ownerchanged;
+ const char *maybe_dead="";
+ int same_node;
+ int saveerrno;
+ int fd;
+
+ again:
+ if (h->use_o_excl)
+ {
+ /* No hardlink support - use open(O_EXCL). */
+ do
+ {
+ my_set_errno (0);
+ fd = open (h->lockname, O_WRONLY|O_CREAT|O_EXCL,
+ S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR );
+ }
+ while (fd == -1 && errno == EINTR);
+
+ if (fd == -1 && errno == EEXIST)
+ ; /* Lock held by another process. */
+ else if (fd == -1)
+ {
+ saveerrno = errno;
+ my_error_2 ("lock not made: open(O_EXCL) of '%s' failed: %s\n",
+ h->lockname, strerror (saveerrno));
+ my_set_errno (saveerrno);
+ return -1;
+ }
+ else
+ {
+ char pidstr[16];
+
+ snprintf (pidstr, sizeof pidstr, "%10d\n", (int)getpid());
+ if (write (fd, pidstr, 11 ) == 11
+ && write (fd, h->tname + h->nodename_off,h->nodename_len)
+ == h->nodename_len
+ && write (fd, "\n", 1) == 1
+ && !close (fd))
+ {
+ h->locked = 1;
+ return 0;
+ }
+ /* Write error. */
+ saveerrno = errno;
+ my_error_2 ("lock not made: writing to '%s' failed: %s\n",
+ h->lockname, strerror (errno));
+ close (fd);
+ unlink (h->lockname);
+ my_set_errno (saveerrno);
+ return -1;
+ }
+ }
+ else /* Standard method: Use hardlinks. */
+ {
+ struct stat sb;
+
+ /* We ignore the return value of link() because it is unreliable. */
+ (void) link (h->tname, h->lockname);
+
+ if (stat (h->tname, &sb))
+ {
+ saveerrno = errno;
+ my_error_1 ("lock not made: Oops: stat of tmp file failed: %s\n",
+ strerror (errno));
+ /* In theory this might be a severe error: It is possible
+ that link succeeded but stat failed due to changed
+ permissions. We can't do anything about it, though. */
+ my_set_errno (saveerrno);
+ return -1;
+ }
+
+ if (sb.st_nlink == 2)
+ {
+ h->locked = 1;
+ return 0; /* Okay. */
+ }
+ }
+
+ /* Check for stale lock files. */
+ if ( (pid = read_lockfile (h, &same_node, &fd)) == -1 )
+ {
+ if ( errno != ENOENT )
+ {
+ saveerrno = errno;
+ my_info_0 ("cannot read lockfile\n");
+ my_set_errno (saveerrno);
+ return -1;
+ }
+ my_info_0 ("lockfile disappeared\n");
+ goto again;
+ }
+ else if ( (pid == getpid() && same_node)
+ || (same_node && kill (pid, 0) && errno == ESRCH) )
+ /* Stale lockfile is detected. */
+ {
+ struct stat sb;
+
+ /* Check if it's unlocked during examining the lockfile. */
+ if (fstat (fd, &sb) || sb.st_nlink == 0)
+ {
+ /* It's gone already by another process. */
+ close (fd);
+ goto again;
+ }
+
+ /*
+ * Here, although it's quite _rare_, we have a race condition.
+ *
+ * When multiple processes race on a stale lockfile, detecting
+ * AND removing should be done atomically. That is, to work
+ * correctly, the file to be removed should be the one which is
+ * examined for detection.
+ *
+ * But, when it's not atomic, consider the case for us where it
+ * takes some time between the detection and the removal of the
+ * lockfile.
+ *
+ * In this situation, it is possible that the file which was
+ * detected as stale is already removed by another process and
+ * then new lockfile is created (by that process or other one).
+ *
+ * And it is newly created valid lockfile which is going to be
+ * removed by us.
+ *
+ * Consider this long comment as it expresses possible (long)
+ * time between fstat above and unlink below; Meanwhile, the
+ * lockfile in question may be removed and there may be new
+ * valid one.
+ *
+ * In short, when you see the message of removing stale lockfile
+ * when there are multiple processes for the work, there is
+ * (very) little possibility something went wrong.
+ */
+
+ unlink (h->lockname);
+ my_info_1 (_("removing stale lockfile (created by %d)\n"), pid);
+ close (fd);
+ goto again;
+ }
+
+ close (fd);
+ if (lastpid == -1)
+ lastpid = pid;
+ ownerchanged = (pid != lastpid);
+
+ if (timeout)
+ {
+ struct timeval tv;
+
+ /* Wait until lock has been released. We use increasing retry
+ intervals of 50ms, 100ms, 200ms, 400ms, 800ms, 2s, 4s and 8s
+ but reset it if the lock owner meanwhile changed. */
+ if (!wtime || ownerchanged)
+ wtime = 50;
+ else if (wtime < 800)
+ wtime *= 2;
+ else if (wtime == 800)
+ wtime = 2000;
+ else if (wtime < 8000)
+ wtime *= 2;
+
+ if (timeout > 0)
+ {
+ if (wtime > timeout)
+ wtime = timeout;
+ timeout -= wtime;
+ }
+
+ sumtime += wtime;
+ if (sumtime >= 1500)
+ {
+ sumtime = 0;
+ my_info_3 (_("waiting for lock (held by %d%s) %s...\n"),
+ pid, maybe_dead, maybe_deadlock(h)? _("(deadlock?) "):"");
+ }
+
+
+ tv.tv_sec = wtime / 1000;
+ tv.tv_usec = (wtime % 1000) * 1000;
+ select (0, NULL, NULL, NULL, &tv);
+ goto again;
+ }
+
+ my_set_errno (EACCES);
+ return -1;
+}
+#endif /*HAVE_POSIX_SYSTEM*/
+
+
+#ifdef HAVE_DOSISH_SYSTEM
+/* Windows specific code of make_dotlock. Returns 0 on success and -1 on
+ error. */
+static int
+dotlock_take_w32 (dotlock_t h, long timeout)
+{
+ int wtime = 0;
+ int w32err;
+ OVERLAPPED ovl;
+
+ again:
+ /* Lock one byte at offset 0. The offset is given by OVL. */
+ memset (&ovl, 0, sizeof ovl);
+ if (LockFileEx (h->lockhd, (LOCKFILE_EXCLUSIVE_LOCK
+ | LOCKFILE_FAIL_IMMEDIATELY), 0, 1, 0, &ovl))
+ {
+ h->locked = 1;
+ return 0; /* okay */
+ }
+
+ w32err = GetLastError ();
+ if (w32err != ERROR_LOCK_VIOLATION)
+ {
+ my_error_2 (_("lock '%s' not made: %s\n"),
+ h->lockname, w32_strerror (w32err));
+ my_set_errno (map_w32_to_errno (w32err));
+ return -1;
+ }
+
+ if (timeout)
+ {
+ /* Wait until lock has been released. We use retry intervals of
+ 50ms, 100ms, 200ms, 400ms, 800ms, 2s, 4s and 8s. */
+ if (!wtime)
+ wtime = 50;
+ else if (wtime < 800)
+ wtime *= 2;
+ else if (wtime == 800)
+ wtime = 2000;
+ else if (wtime < 8000)
+ wtime *= 2;
+
+ if (timeout > 0)
+ {
+ if (wtime > timeout)
+ wtime = timeout;
+ timeout -= wtime;
+ }
+
+ if (wtime >= 800)
+ my_info_1 (_("waiting for lock %s...\n"), h->lockname);
+
+ Sleep (wtime);
+ goto again;
+ }
+
+ my_set_errno (EACCES);
+ return -1;
+}
+#endif /*HAVE_DOSISH_SYSTEM*/
+
+
+/* Take a lock on H. A value of 0 for TIMEOUT returns immediately if
+ the lock can't be taken, -1 waits forever (hopefully not), other
+ values wait for TIMEOUT milliseconds. Returns: 0 on success */
+int
+dotlock_take (dotlock_t h, long timeout)
+{
+ int ret;
+
+ if ( h->disable )
+ {
+ h->locked = 1;
+ return 0; /* Locks are completely disabled. Return success. */
+ }
+
+ if ( h->locked )
+ {
+ /* my_debug_1 ("'%s' is already locked (%s)\n", h->lockname); */
+ return 0;
+ }
+
+#ifdef HAVE_DOSISH_SYSTEM
+ ret = dotlock_take_w32 (h, timeout);
+#else /*!HAVE_DOSISH_SYSTEM*/
+ ret = dotlock_take_unix (h, timeout);
+#endif /*!HAVE_DOSISH_SYSTEM*/
+
+ return ret;
+}
+
+
+
+#ifdef HAVE_POSIX_SYSTEM
+/* Unix specific code of release_dotlock. */
+static int
+dotlock_release_unix (dotlock_t h)
+{
+ int pid, same_node;
+ int saveerrno;
+
+ pid = read_lockfile (h, &same_node, NULL);
+ if ( pid == -1 )
+ {
+ saveerrno = errno;
+ my_error_0 ("release_dotlock: lockfile error\n");
+ my_set_errno (saveerrno);
+ return -1;
+ }
+ if ( pid != getpid() || !same_node )
+ {
+ my_error_1 ("release_dotlock: not our lock (pid=%d)\n", pid);
+ my_set_errno (EACCES);
+ return -1;
+ }
+
+ if ( unlink( h->lockname ) )
+ {
+ saveerrno = errno;
+ my_error_1 ("release_dotlock: error removing lockfile '%s'\n",
+ h->lockname);
+ my_set_errno (saveerrno);
+ return -1;
+ }
+ /* Fixme: As an extra check we could check whether the link count is
+ now really at 1. */
+ return 0;
+}
+#endif /*HAVE_POSIX_SYSTEM */
+
+
+#ifdef HAVE_DOSISH_SYSTEM
+/* Windows specific code of release_dotlock. */
+static int
+dotlock_release_w32 (dotlock_t h)
+{
+ OVERLAPPED ovl;
+
+ memset (&ovl, 0, sizeof ovl);
+ if (!UnlockFileEx (h->lockhd, 0, 1, 0, &ovl))
+ {
+ int saveerrno = map_w32_to_errno (GetLastError ());
+ my_error_2 ("release_dotlock: error removing lockfile '%s': %s\n",
+ h->lockname, w32_strerror (-1));
+ my_set_errno (saveerrno);
+ return -1;
+ }
+
+ return 0;
+}
+#endif /*HAVE_DOSISH_SYSTEM */
+
+
+/* Release a lock. Returns 0 on success. */
+int
+dotlock_release (dotlock_t h)
+{
+ int ret;
+
+ /* To avoid atexit race conditions we first check whether there are
+ any locks left. It might happen that another atexit handler
+ tries to release the lock while the atexit handler of this module
+ already ran and thus H is undefined. */
+ LOCK_all_lockfiles ();
+ ret = !all_lockfiles;
+ UNLOCK_all_lockfiles ();
+ if (ret)
+ return 0;
+
+ if ( h->disable )
+ {
+ h->locked = 0;
+ return 0;
+ }
+
+ if ( !h->locked )
+ {
+ /* my_debug_1 ("Oops, '%s' is not locked (%s)\n", h->lockname); */
+ return 0;
+ }
+
+#ifdef HAVE_DOSISH_SYSTEM
+ ret = dotlock_release_w32 (h);
+#else
+ ret = dotlock_release_unix (h);
+#endif
+
+ if (!ret)
+ h->locked = 0;
+ return ret;
+}
+
+
+
+/* Remove all lockfiles. This is called by the atexit handler
+ installed by this module but may also be called by other
+ termination handlers. */
+void
+dotlock_remove_lockfiles (void)
+{
+ dotlock_t h, h2;
+
+ /* First set the lockfiles list to NULL so that for example
+ dotlock_release is aware that this function is currently
+ running. */
+ LOCK_all_lockfiles ();
+ h = all_lockfiles;
+ all_lockfiles = NULL;
+ UNLOCK_all_lockfiles ();
+
+ while ( h )
+ {
+ h2 = h->next;
+ dotlock_destroy (h);
+ h = h2;
+ }
+}
diff --git a/common/dotlock.h b/common/dotlock.h
new file mode 100644
index 0000000..9869739
--- /dev/null
+++ b/common/dotlock.h
@@ -0,0 +1,113 @@
+/* dotlock.h - dotfile locking declarations
+ * Copyright (C) 2000, 2001, 2006, 2011 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute and/or modify this
+ * part of GnuPG under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * 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 copies of the GNU General Public License
+ * and the GNU Lesser General Public License along with this program;
+ * if not, see <https://www.gnu.org/licenses/>.
+ *
+ * ALTERNATIVELY, this file may be distributed under the terms of the
+ * following license, in which case the provisions of this license are
+ * required INSTEAD OF the GNU Lesser General License or the GNU
+ * General Public License. If you wish to allow use of your version of
+ * this file only under the terms of the GNU Lesser General License or
+ * the GNU General Public License, and not to allow others to use your
+ * version of this file under the terms of the following license,
+ * indicate your decision by deleting this paragraph and the license
+ * below.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef GNUPG_COMMON_DOTLOCK_H
+#define GNUPG_COMMON_DOTLOCK_H
+
+/* See dotlock.c for a description. */
+
+#ifdef DOTLOCK_EXT_SYM_PREFIX
+# ifndef _DOTLOCK_PREFIX
+# define _DOTLOCK_PREFIX1(x,y) x ## y
+# define _DOTLOCK_PREFIX2(x,y) _DOTLOCK_PREFIX1(x,y)
+# define _DOTLOCK_PREFIX(x) _DOTLOCK_PREFIX2(DOTLOCK_EXT_SYM_PREFIX,x)
+# endif /*_DOTLOCK_PREFIX*/
+# define dotlock_disable _DOTLOCK_PREFIX(dotlock_disable)
+# define dotlock_create _DOTLOCK_PREFIX(dotlock_create)
+# define dotlock_set_fd _DOTLOCK_PREFIX(dotlock_set_fd)
+# define dotlock_get_fd _DOTLOCK_PREFIX(dotlock_get_fd)
+# define dotlock_destroy _DOTLOCK_PREFIX(dotlock_destroy)
+# define dotlock_take _DOTLOCK_PREFIX(dotlock_take)
+# define dotlock_release _DOTLOCK_PREFIX(dotlock_release)
+# define dotlock_remove_lockfiles _DOTLOCK_PREFIX(dotlock_remove_lockfiles)
+#endif /*DOTLOCK_EXT_SYM_PREFIX*/
+
+#ifdef __cplusplus
+extern "C"
+{
+#if 0
+}
+#endif
+#endif
+
+
+struct dotlock_handle;
+typedef struct dotlock_handle *dotlock_t;
+
+void dotlock_disable (void);
+dotlock_t dotlock_create (const char *file_to_lock, unsigned int flags);
+void dotlock_set_fd (dotlock_t h, int fd);
+int dotlock_get_fd (dotlock_t h);
+void dotlock_destroy (dotlock_t h);
+int dotlock_is_locked (dotlock_t h);
+int dotlock_take (dotlock_t h, long timeout);
+int dotlock_release (dotlock_t h);
+void dotlock_remove_lockfiles (void);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /*GNUPG_COMMON_DOTLOCK_H*/
diff --git a/common/dynload.h b/common/dynload.h
new file mode 100644
index 0000000..f1dc3f0
--- /dev/null
+++ b/common/dynload.h
@@ -0,0 +1,100 @@
+/* dynload.h - Wrapper functions for run-time dynamic loading
+ * Copyright (C) 2003, 2010 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute and/or modify this
+ * part of GnuPG under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * 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 copies of the GNU General Public License
+ * and the GNU Lesser General Public License along with this program;
+ * if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_COMMON_DYNLOAD_H
+#define GNUPG_COMMON_DYNLOAD_H
+
+#ifndef __MINGW32__
+# include <dlfcn.h>
+#else
+# ifdef HAVE_WINSOCK2_H
+# include <winsock2.h> /* needs to be included before windows.h */
+# endif
+# include <windows.h>
+# include "utf8conv.h"
+# include "mischelp.h"
+# define RTLD_LAZY 0
+
+static inline void *
+dlopen (const char *name, int flag)
+{
+ void *hd;
+#ifdef HAVE_W32CE_SYSTEM
+ wchar_t *wname = utf8_to_wchar (name);
+ hd = wname? LoadLibrary (wname) : NULL;
+ xfree (wname);
+#else
+ hd = LoadLibrary (name);
+#endif
+ (void)flag;
+ return hd;
+}
+
+static inline void *
+dlsym (void *hd, const char *sym)
+{
+ if (hd && sym)
+ {
+#ifdef HAVE_W32CE_SYSTEM
+ wchar_t *wsym = utf8_to_wchar (sym);
+ void *fnc = wsym? GetProcAddress (hd, wsym) : NULL;
+ xfree (wsym);
+#else
+ void *fnc = GetProcAddress (hd, sym);
+#endif
+ if (!fnc)
+ return NULL;
+ return fnc;
+ }
+ return NULL;
+}
+
+
+static inline const char *
+dlerror (void)
+{
+ static char buf[32];
+ snprintf (buf, sizeof buf, "ec=%lu", GetLastError ());
+ return buf;
+}
+
+
+static inline int
+dlclose (void * hd)
+{
+ if (hd)
+ {
+ CloseHandle (hd);
+ return 0;
+ }
+ return -1;
+}
+# endif /*__MINGW32__*/
+#endif /*GNUPG_COMMON_DYNLOAD_H*/
diff --git a/common/exaudit.awk b/common/exaudit.awk
new file mode 100644
index 0000000..0d2f95e
--- /dev/null
+++ b/common/exaudit.awk
@@ -0,0 +1,43 @@
+# exaudit.awk - Extract audit event codes from audit.h
+# Copyright (C) 2007 Free Software Foundation, Inc.
+#
+# This file is part of GnuPG.
+#
+# GnuPG is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# GnuPG is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+BEGIN {
+ print "# Output of exaudit.awk - DO NOT EDIT."
+ topheader = 0;
+ okay = 0;
+ code = 0;
+}
+
+topheader == 0 && /^\/\*/ { topheader = 1 }
+topheader == 1 { print $0 }
+topheader == 1 && /\*\// { topheader = 2; print "" }
+
+/AUDIT_NULL_EVENT/ { okay = 1 }
+!okay { next }
+/AUDIT_LAST_EVENT/ { exit }
+/AUDIT_[A-Za-z_]+/ {
+ sub (/[,\/\*]+/, "", $1);
+ desc = tolower (substr($1,7));
+ gsub (/_/," ",desc);
+ printf "%d\t%s\t%s\n", code, $1, desc;
+ code++;
+}
+
+END {
+ print "# end of audit codes."
+}
diff --git a/common/exechelp-posix.c b/common/exechelp-posix.c
new file mode 100644
index 0000000..e9cb7ed
--- /dev/null
+++ b/common/exechelp-posix.c
@@ -0,0 +1,909 @@
+/* exechelp.c - Fork and exec helpers for POSIX
+ * Copyright (C) 2004, 2007, 2008, 2009,
+ * 2010 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#if defined(HAVE_W32_SYSTEM) || defined (HAVE_W32CE_SYSTEM)
+#error This code is only used on POSIX
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#ifdef HAVE_SIGNAL_H
+# include <signal.h>
+#endif
+#include <unistd.h>
+#include <fcntl.h>
+
+#ifdef WITHOUT_NPTH /* Give the Makefile a chance to build without Pth. */
+#undef HAVE_NPTH
+#undef USE_NPTH
+#endif
+
+#ifdef HAVE_NPTH
+#include <npth.h>
+#endif
+#include <sys/wait.h>
+
+#ifdef HAVE_GETRLIMIT
+#include <sys/time.h>
+#include <sys/resource.h>
+#endif /*HAVE_GETRLIMIT*/
+
+#ifdef HAVE_STAT
+# include <sys/stat.h>
+#endif
+
+#if __linux__
+# include <sys/types.h>
+# include <dirent.h>
+#endif /*__linux__ */
+
+#include "util.h"
+#include "i18n.h"
+#include "sysutils.h"
+#include "exechelp.h"
+
+
+/* Helper */
+static inline gpg_error_t
+my_error_from_syserror (void)
+{
+ return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
+}
+
+static inline gpg_error_t
+my_error (int errcode)
+{
+ return gpg_err_make (default_errsource, errcode);
+}
+
+
+/* Return the maximum number of currently allowed open file
+ descriptors. Only useful on POSIX systems but returns a value on
+ other systems too. */
+int
+get_max_fds (void)
+{
+ int max_fds = -1;
+#ifdef HAVE_GETRLIMIT
+ struct rlimit rl;
+
+ /* Under Linux we can figure out the highest used file descriptor by
+ * reading /proc/PID/fd. This is in the common cases much fast than
+ * for example doing 4096 close calls where almost all of them will
+ * fail. On a system with a limit of 4096 files and only 8 files
+ * open with the highest number being 10, we speedup close_all_fds
+ * from 125ms to 0.4ms including readdir.
+ *
+ * Another option would be to close the file descriptors as returned
+ * from reading that directory - however then we need to snapshot
+ * that list before starting to close them. */
+#ifdef __linux__
+ {
+ DIR *dir = NULL;
+ struct dirent *dir_entry;
+ const char *s;
+ int x;
+
+ dir = opendir ("/proc/self/fd");
+ if (dir)
+ {
+ while ((dir_entry = readdir (dir)))
+ {
+ s = dir_entry->d_name;
+ if ( *s < '0' || *s > '9')
+ continue;
+ x = atoi (s);
+ if (x > max_fds)
+ max_fds = x;
+ }
+ closedir (dir);
+ }
+ if (max_fds != -1)
+ return max_fds + 1;
+ }
+#endif /* __linux__ */
+
+
+# ifdef RLIMIT_NOFILE
+ if (!getrlimit (RLIMIT_NOFILE, &rl))
+ max_fds = rl.rlim_max;
+# endif
+
+# ifdef RLIMIT_OFILE
+ if (max_fds == -1 && !getrlimit (RLIMIT_OFILE, &rl))
+ max_fds = rl.rlim_max;
+
+# endif
+#endif /*HAVE_GETRLIMIT*/
+
+#ifdef _SC_OPEN_MAX
+ if (max_fds == -1)
+ {
+ long int scres = sysconf (_SC_OPEN_MAX);
+ if (scres >= 0)
+ max_fds = scres;
+ }
+#endif
+
+#ifdef _POSIX_OPEN_MAX
+ if (max_fds == -1)
+ max_fds = _POSIX_OPEN_MAX;
+#endif
+
+#ifdef OPEN_MAX
+ if (max_fds == -1)
+ max_fds = OPEN_MAX;
+#endif
+
+ if (max_fds == -1)
+ max_fds = 256; /* Arbitrary limit. */
+
+ /* AIX returns INT32_MAX instead of a proper value. We assume that
+ this is always an error and use an arbitrary limit. */
+#ifdef INT32_MAX
+ if (max_fds == INT32_MAX)
+ max_fds = 256;
+#endif
+
+ return max_fds;
+}
+
+
+/* Close all file descriptors starting with descriptor FIRST. If
+ EXCEPT is not NULL, it is expected to be a list of file descriptors
+ which shall not be closed. This list shall be sorted in ascending
+ order with the end marked by -1. */
+void
+close_all_fds (int first, int *except)
+{
+ int max_fd = get_max_fds ();
+ int fd, i, except_start;
+
+ if (except)
+ {
+ except_start = 0;
+ for (fd=first; fd < max_fd; fd++)
+ {
+ for (i=except_start; except[i] != -1; i++)
+ {
+ if (except[i] == fd)
+ {
+ /* If we found the descriptor in the exception list
+ we can start the next compare run at the next
+ index because the exception list is ordered. */
+ except_start = i + 1;
+ break;
+ }
+ }
+ if (except[i] == -1)
+ close (fd);
+ }
+ }
+ else
+ {
+ for (fd=first; fd < max_fd; fd++)
+ close (fd);
+ }
+
+ gpg_err_set_errno (0);
+}
+
+
+/* Returns an array with all currently open file descriptors. The end
+ of the array is marked by -1. The caller needs to release this
+ array using the *standard free* and not with xfree. This allow the
+ use of this function right at startup even before libgcrypt has
+ been initialized. Returns NULL on error and sets ERRNO
+ accordingly. */
+int *
+get_all_open_fds (void)
+{
+ int *array;
+ size_t narray;
+ int fd, max_fd, idx;
+#ifndef HAVE_STAT
+ array = calloc (1, sizeof *array);
+ if (array)
+ array[0] = -1;
+#else /*HAVE_STAT*/
+ struct stat statbuf;
+
+ max_fd = get_max_fds ();
+ narray = 32; /* If you change this change also t-exechelp.c. */
+ array = calloc (narray, sizeof *array);
+ if (!array)
+ return NULL;
+
+ /* Note: The list we return is ordered. */
+ for (idx=0, fd=0; fd < max_fd; fd++)
+ if (!(fstat (fd, &statbuf) == -1 && errno == EBADF))
+ {
+ if (idx+1 >= narray)
+ {
+ int *tmp;
+
+ narray += (narray < 256)? 32:256;
+ tmp = realloc (array, narray * sizeof *array);
+ if (!tmp)
+ {
+ free (array);
+ return NULL;
+ }
+ array = tmp;
+ }
+ array[idx++] = fd;
+ }
+ array[idx] = -1;
+#endif /*HAVE_STAT*/
+ return array;
+}
+
+
+/* The exec core used right after the fork. This will never return. */
+static void
+do_exec (const char *pgmname, const char *argv[],
+ int fd_in, int fd_out, int fd_err,
+ int *except, void (*preexec)(void), unsigned int flags)
+{
+ char **arg_list;
+ int i, j;
+ int fds[3];
+ int nodevnull[3];
+
+ fds[0] = fd_in;
+ fds[1] = fd_out;
+ fds[2] = fd_err;
+
+ nodevnull[0] = !!(flags & GNUPG_SPAWN_KEEP_STDIN);
+ nodevnull[1] = !!(flags & GNUPG_SPAWN_KEEP_STDOUT);
+ nodevnull[2] = !!(flags & GNUPG_SPAWN_KEEP_STDERR);
+
+ /* Create the command line argument array. */
+ i = 0;
+ if (argv)
+ while (argv[i])
+ i++;
+ arg_list = xcalloc (i+2, sizeof *arg_list);
+ arg_list[0] = strrchr (pgmname, '/');
+ if (arg_list[0])
+ arg_list[0]++;
+ else
+ arg_list[0] = xstrdup (pgmname);
+ if (argv)
+ for (i=0,j=1; argv[i]; i++, j++)
+ arg_list[j] = (char*)argv[i];
+
+ /* Assign /dev/null to unused FDs. */
+ for (i=0; i <= 2; i++)
+ {
+ if (nodevnull[i])
+ continue;
+ if (fds[i] == -1)
+ {
+ fds[i] = open ("/dev/null", i? O_WRONLY : O_RDONLY);
+ if (fds[i] == -1)
+ log_fatal ("failed to open '%s': %s\n",
+ "/dev/null", strerror (errno));
+ }
+ }
+
+ /* Connect the standard files. */
+ for (i=0; i <= 2; i++)
+ {
+ if (nodevnull[i])
+ continue;
+ if (fds[i] != i && dup2 (fds[i], i) == -1)
+ log_fatal ("dup2 std%s failed: %s\n",
+ i==0?"in":i==1?"out":"err", strerror (errno));
+ }
+
+ /* Close all other files. */
+ close_all_fds (3, except);
+
+ if (preexec)
+ preexec ();
+ execv (pgmname, arg_list);
+ /* No way to print anything, as we have closed all streams. */
+ _exit (127);
+}
+
+
+static gpg_error_t
+do_create_pipe (int filedes[2])
+{
+ gpg_error_t err = 0;
+
+ if (pipe (filedes) == -1)
+ {
+ err = my_error_from_syserror ();
+ filedes[0] = filedes[1] = -1;
+ }
+
+ return err;
+}
+
+
+static gpg_error_t
+create_pipe_and_estream (int filedes[2], estream_t *r_fp,
+ int outbound, int nonblock)
+{
+ gpg_error_t err;
+
+ if (pipe (filedes) == -1)
+ {
+ err = my_error_from_syserror ();
+ log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
+ filedes[0] = filedes[1] = -1;
+ *r_fp = NULL;
+ return err;
+ }
+
+ if (!outbound)
+ *r_fp = es_fdopen (filedes[0], nonblock? "r,nonblock" : "r");
+ else
+ *r_fp = es_fdopen (filedes[1], nonblock? "w,nonblock" : "w");
+ if (!*r_fp)
+ {
+ err = my_error_from_syserror ();
+ log_error (_("error creating a stream for a pipe: %s\n"),
+ gpg_strerror (err));
+ close (filedes[0]);
+ close (filedes[1]);
+ filedes[0] = filedes[1] = -1;
+ return err;
+ }
+ return 0;
+}
+
+
+/* Portable function to create a pipe. Under Windows the write end is
+ inheritable. If R_FP is not NULL, an estream is created for the
+ read end and stored at R_FP. */
+gpg_error_t
+gnupg_create_inbound_pipe (int filedes[2], estream_t *r_fp, int nonblock)
+{
+ if (r_fp)
+ return create_pipe_and_estream (filedes, r_fp, 0, nonblock);
+ else
+ return do_create_pipe (filedes);
+}
+
+
+/* Portable function to create a pipe. Under Windows the read end is
+ inheritable. If R_FP is not NULL, an estream is created for the
+ write end and stored at R_FP. */
+gpg_error_t
+gnupg_create_outbound_pipe (int filedes[2], estream_t *r_fp, int nonblock)
+{
+ if (r_fp)
+ return create_pipe_and_estream (filedes, r_fp, 1, nonblock);
+ else
+ return do_create_pipe (filedes);
+}
+
+
+/* Portable function to create a pipe. Under Windows both ends are
+ inheritable. */
+gpg_error_t
+gnupg_create_pipe (int filedes[2])
+{
+ return do_create_pipe (filedes);
+}
+
+
+/* Fork and exec the PGMNAME, see exechelp.h for details. */
+gpg_error_t
+gnupg_spawn_process (const char *pgmname, const char *argv[],
+ int *except, void (*preexec)(void), unsigned int flags,
+ estream_t *r_infp,
+ estream_t *r_outfp,
+ estream_t *r_errfp,
+ pid_t *pid)
+{
+ gpg_error_t err;
+ int inpipe[2] = {-1, -1};
+ int outpipe[2] = {-1, -1};
+ int errpipe[2] = {-1, -1};
+ estream_t infp = NULL;
+ estream_t outfp = NULL;
+ estream_t errfp = NULL;
+ int nonblock = !!(flags & GNUPG_SPAWN_NONBLOCK);
+
+ if (r_infp)
+ *r_infp = NULL;
+ if (r_outfp)
+ *r_outfp = NULL;
+ if (r_errfp)
+ *r_errfp = NULL;
+ *pid = (pid_t)(-1); /* Always required. */
+
+ if (r_infp)
+ {
+ err = create_pipe_and_estream (inpipe, &infp, 1, nonblock);
+ if (err)
+ return err;
+ }
+
+ if (r_outfp)
+ {
+ err = create_pipe_and_estream (outpipe, &outfp, 0, nonblock);
+ if (err)
+ {
+ if (infp)
+ es_fclose (infp);
+ else if (inpipe[1] != -1)
+ close (inpipe[1]);
+ if (inpipe[0] != -1)
+ close (inpipe[0]);
+
+ return err;
+ }
+ }
+
+ if (r_errfp)
+ {
+ err = create_pipe_and_estream (errpipe, &errfp, 0, nonblock);
+ if (err)
+ {
+ if (infp)
+ es_fclose (infp);
+ else if (inpipe[1] != -1)
+ close (inpipe[1]);
+ if (inpipe[0] != -1)
+ close (inpipe[0]);
+
+ if (outfp)
+ es_fclose (outfp);
+ else if (outpipe[0] != -1)
+ close (outpipe[0]);
+ if (outpipe[1] != -1)
+ close (outpipe[1]);
+
+ return err;
+ }
+ }
+
+
+ *pid = fork ();
+ if (*pid == (pid_t)(-1))
+ {
+ err = my_error_from_syserror ();
+ log_error (_("error forking process: %s\n"), gpg_strerror (err));
+
+ if (infp)
+ es_fclose (infp);
+ else if (inpipe[1] != -1)
+ close (inpipe[1]);
+ if (inpipe[0] != -1)
+ close (inpipe[0]);
+
+ if (outfp)
+ es_fclose (outfp);
+ else if (outpipe[0] != -1)
+ close (outpipe[0]);
+ if (outpipe[1] != -1)
+ close (outpipe[1]);
+
+ if (errfp)
+ es_fclose (errfp);
+ else if (errpipe[0] != -1)
+ close (errpipe[0]);
+ if (errpipe[1] != -1)
+ close (errpipe[1]);
+ return err;
+ }
+
+ if (!*pid)
+ {
+ /* This is the child. */
+ gcry_control (GCRYCTL_TERM_SECMEM);
+ es_fclose (infp);
+ es_fclose (outfp);
+ es_fclose (errfp);
+ do_exec (pgmname, argv, inpipe[0], outpipe[1], errpipe[1],
+ except, preexec, flags);
+ /*NOTREACHED*/
+ }
+
+ /* This is the parent. */
+ if (inpipe[0] != -1)
+ close (inpipe[0]);
+ if (outpipe[1] != -1)
+ close (outpipe[1]);
+ if (errpipe[1] != -1)
+ close (errpipe[1]);
+
+ if (r_infp)
+ *r_infp = infp;
+ if (r_outfp)
+ *r_outfp = outfp;
+ if (r_errfp)
+ *r_errfp = errfp;
+
+ return 0;
+}
+
+
+
+/* Simplified version of gnupg_spawn_process. This function forks and
+ then execs PGMNAME, while connecting INFD to stdin, OUTFD to stdout
+ and ERRFD to stderr (any of them may be -1 to connect them to
+ /dev/null). The arguments for the process are expected in the NULL
+ terminated array ARGV. The program name itself should not be
+ included there. Calling gnupg_wait_process is required.
+
+ Returns 0 on success or an error code. */
+gpg_error_t
+gnupg_spawn_process_fd (const char *pgmname, const char *argv[],
+ int infd, int outfd, int errfd, pid_t *pid)
+{
+ gpg_error_t err;
+
+ *pid = fork ();
+ if (*pid == (pid_t)(-1))
+ {
+ err = my_error_from_syserror ();
+ log_error (_("error forking process: %s\n"), strerror (errno));
+ return err;
+ }
+
+ if (!*pid)
+ {
+ gcry_control (GCRYCTL_TERM_SECMEM);
+ /* Run child. */
+ do_exec (pgmname, argv, infd, outfd, errfd, NULL, NULL, 0);
+ /*NOTREACHED*/
+ }
+
+ return 0;
+}
+
+
+
+
+/* Waiting for child processes.
+
+ waitpid(2) may return information about terminated children that we
+ did not yet request, and there is no portable way to wait for a
+ specific set of children.
+
+ As a workaround, we store the results of children for later use.
+
+ XXX: This assumes that PIDs are not reused too quickly. */
+
+struct terminated_child
+{
+ pid_t pid;
+ int exitcode;
+ struct terminated_child *next;
+};
+
+struct terminated_child *terminated_children;
+
+
+static gpg_error_t
+store_result (pid_t pid, int exitcode)
+{
+ struct terminated_child *c;
+
+ c = xtrymalloc (sizeof *c);
+ if (c == NULL)
+ return gpg_err_code_from_syserror ();
+
+ c->pid = pid;
+ c->exitcode = exitcode;
+ c->next = terminated_children;
+ terminated_children = c;
+
+ return 0;
+}
+
+
+static int
+get_result (pid_t pid, int *r_exitcode)
+{
+ struct terminated_child *c, **prevp;
+
+ for (prevp = &terminated_children, c = terminated_children;
+ c;
+ prevp = &c->next, c = c->next)
+ if (c->pid == pid)
+ {
+ *prevp = c->next;
+ *r_exitcode = c->exitcode;
+ xfree (c);
+ return 1;
+ }
+
+ return 0;
+}
+
+
+/* See exechelp.h for a description. */
+gpg_error_t
+gnupg_wait_process (const char *pgmname, pid_t pid, int hang, int *r_exitcode)
+{
+ gpg_err_code_t ec;
+ int i, status;
+
+ if (r_exitcode)
+ *r_exitcode = -1;
+
+ if (pid == (pid_t)(-1))
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+#ifdef USE_NPTH
+ i = npth_waitpid (pid, &status, hang? 0:WNOHANG);
+#else
+ while ((i=waitpid (pid, &status, hang? 0:WNOHANG)) == (pid_t)(-1)
+ && errno == EINTR);
+#endif
+
+ if (i == (pid_t)(-1))
+ {
+ ec = gpg_err_code_from_errno (errno);
+ log_error (_("waiting for process %d to terminate failed: %s\n"),
+ (int)pid, strerror (errno));
+ }
+ else if (!i)
+ {
+ ec = GPG_ERR_TIMEOUT; /* Still running. */
+ }
+ else if (WIFEXITED (status) && WEXITSTATUS (status) == 127)
+ {
+ log_error (_("error running '%s': probably not installed\n"), pgmname);
+ ec = GPG_ERR_CONFIGURATION;
+ }
+ else if (WIFEXITED (status) && WEXITSTATUS (status))
+ {
+ if (!r_exitcode)
+ log_error (_("error running '%s': exit status %d\n"), pgmname,
+ WEXITSTATUS (status));
+ else
+ *r_exitcode = WEXITSTATUS (status);
+ ec = GPG_ERR_GENERAL;
+ }
+ else if (!WIFEXITED (status))
+ {
+ log_error (_("error running '%s': terminated\n"), pgmname);
+ ec = GPG_ERR_GENERAL;
+ }
+ else
+ {
+ if (r_exitcode)
+ *r_exitcode = 0;
+ ec = 0;
+ }
+
+ return gpg_err_make (GPG_ERR_SOURCE_DEFAULT, ec);
+}
+
+/* See exechelp.h for a description. */
+gpg_error_t
+gnupg_wait_processes (const char **pgmnames, pid_t *pids, size_t count,
+ int hang, int *r_exitcodes)
+{
+ gpg_err_code_t ec = 0;
+ size_t i, left;
+ int *dummy = NULL;
+
+ if (r_exitcodes == NULL)
+ {
+ dummy = r_exitcodes = xtrymalloc (sizeof *r_exitcodes * count);
+ if (dummy == NULL)
+ return gpg_err_code_from_syserror ();
+ }
+
+ for (i = 0, left = count; i < count; i++)
+ {
+ int status = -1;
+
+ /* Skip invalid PID. */
+ if (pids[i] == (pid_t)(-1))
+ {
+ r_exitcodes[i] = -1;
+ left -= 1;
+ continue;
+ }
+
+ /* See if there was a previously stored result for this pid. */
+ if (get_result (pids[i], &status))
+ left -= 1;
+
+ r_exitcodes[i] = status;
+ }
+
+ while (left > 0)
+ {
+ pid_t pid;
+ int status;
+
+#ifdef USE_NPTH
+ pid = npth_waitpid (-1, &status, hang ? 0 : WNOHANG);
+#else
+ while ((pid = waitpid (-1, &status, hang ? 0 : WNOHANG)) == (pid_t)(-1)
+ && errno == EINTR);
+#endif
+
+ if (pid == (pid_t)(-1))
+ {
+ ec = gpg_err_code_from_errno (errno);
+ log_error (_("waiting for processes to terminate failed: %s\n"),
+ strerror (errno));
+ break;
+ }
+ else if (!pid)
+ {
+ ec = GPG_ERR_TIMEOUT; /* Still running. */
+ break;
+ }
+ else
+ {
+ for (i = 0; i < count; i++)
+ if (pid == pids[i])
+ break;
+
+ if (i == count)
+ {
+ /* No match, store this result. */
+ ec = store_result (pid, status);
+ if (ec)
+ break;
+ continue;
+ }
+
+ /* Process PIDS[i] died. */
+ if (r_exitcodes[i] != (pid_t) -1)
+ {
+ log_error ("PID %d was reused", pid);
+ ec = GPG_ERR_GENERAL;
+ break;
+ }
+
+ left -= 1;
+ r_exitcodes[i] = status;
+ }
+ }
+
+ for (i = 0; i < count; i++)
+ {
+ if (r_exitcodes[i] == -1)
+ continue;
+
+ if (WIFEXITED (r_exitcodes[i]) && WEXITSTATUS (r_exitcodes[i]) == 127)
+ {
+ log_error (_("error running '%s': probably not installed\n"),
+ pgmnames[i]);
+ ec = GPG_ERR_CONFIGURATION;
+ }
+ else if (WIFEXITED (r_exitcodes[i]) && WEXITSTATUS (r_exitcodes[i]))
+ {
+ if (dummy)
+ log_error (_("error running '%s': exit status %d\n"),
+ pgmnames[i], WEXITSTATUS (r_exitcodes[i]));
+ else
+ r_exitcodes[i] = WEXITSTATUS (r_exitcodes[i]);
+ ec = GPG_ERR_GENERAL;
+ }
+ else if (!WIFEXITED (r_exitcodes[i]))
+ {
+ log_error (_("error running '%s': terminated\n"), pgmnames[i]);
+ ec = GPG_ERR_GENERAL;
+ }
+ }
+
+ xfree (dummy);
+ return gpg_err_make (GPG_ERR_SOURCE_DEFAULT, ec);
+}
+
+
+
+void
+gnupg_release_process (pid_t pid)
+{
+ (void)pid;
+}
+
+
+/* Spawn a new process and immediately detach from it. The name of
+ the program to exec is PGMNAME and its arguments are in ARGV (the
+ programname is automatically passed as first argument).
+ Environment strings in ENVP are set. An error is returned if
+ pgmname is not executable; to make this work it is necessary to
+ provide an absolute file name. All standard file descriptors are
+ connected to /dev/null. */
+gpg_error_t
+gnupg_spawn_process_detached (const char *pgmname, const char *argv[],
+ const char *envp[] )
+{
+ gpg_err_code_t ec;
+ pid_t pid;
+ int i;
+
+ if (getuid() != geteuid())
+ return my_error (GPG_ERR_BUG);
+
+ if ((ec = gnupg_access (pgmname, X_OK)))
+ return gpg_err_make (default_errsource, ec);
+
+ pid = fork ();
+ if (pid == (pid_t)(-1))
+ {
+ log_error (_("error forking process: %s\n"), strerror (errno));
+ return my_error_from_syserror ();
+ }
+ if (!pid)
+ {
+ pid_t pid2;
+
+ gcry_control (GCRYCTL_TERM_SECMEM);
+ if (setsid() == -1 || chdir ("/"))
+ _exit (1);
+
+ pid2 = fork (); /* Double fork to let init take over the new child. */
+ if (pid2 == (pid_t)(-1))
+ _exit (1);
+ if (pid2)
+ _exit (0); /* Let the parent exit immediately. */
+
+ if (envp)
+ for (i=0; envp[i]; i++)
+ putenv (xstrdup (envp[i]));
+
+ do_exec (pgmname, argv, -1, -1, -1, NULL, NULL, 0);
+
+ /*NOTREACHED*/
+ }
+
+ if (waitpid (pid, NULL, 0) == -1)
+ log_error ("waitpid failed in gnupg_spawn_process_detached: %s",
+ strerror (errno));
+
+ return 0;
+}
+
+
+/* Kill a process; that is send an appropriate signal to the process.
+ gnupg_wait_process must be called to actually remove the process
+ from the system. An invalid PID is ignored. */
+void
+gnupg_kill_process (pid_t pid)
+{
+ if (pid != (pid_t)(-1))
+ {
+ kill (pid, SIGTERM);
+ }
+}
diff --git a/common/exechelp-w32.c b/common/exechelp-w32.c
new file mode 100644
index 0000000..00cf3fc
--- /dev/null
+++ b/common/exechelp-w32.c
@@ -0,0 +1,1043 @@
+/* exechelp-w32.c - Fork and exec helpers for W32.
+ * Copyright (C) 2004, 2007, 2008, 2009,
+ * 2010 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#if !defined(HAVE_W32_SYSTEM) || defined (HAVE_W32CE_SYSTEM)
+#error This code is only used on W32.
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#ifdef HAVE_SIGNAL_H
+# include <signal.h>
+#endif
+#include <unistd.h>
+#include <fcntl.h>
+
+#ifdef WITHOUT_NPTH /* Give the Makefile a chance to build without Pth. */
+#undef HAVE_NPTH
+#undef USE_NPTH
+#endif
+
+#ifdef HAVE_NPTH
+#include <npth.h>
+#endif
+
+#ifdef HAVE_STAT
+# include <sys/stat.h>
+#endif
+
+
+#include "util.h"
+#include "i18n.h"
+#include "sysutils.h"
+#include "exechelp.h"
+
+/* Define to 1 do enable debugging. */
+#define DEBUG_W32_SPAWN 0
+
+
+/* It seems Vista doesn't grok X_OK and so fails access() tests.
+ Previous versions interpreted X_OK as F_OK anyway, so we'll just
+ use F_OK directly. */
+#undef X_OK
+#define X_OK F_OK
+
+/* We assume that a HANDLE can be represented by an int which should
+ be true for all i386 systems (HANDLE is defined as void *) and
+ these are the only systems for which Windows is available. Further
+ we assume that -1 denotes an invalid handle. */
+# define fd_to_handle(a) ((HANDLE)(a))
+# define handle_to_fd(a) ((int)(a))
+# define pid_to_handle(a) ((HANDLE)(a))
+# define handle_to_pid(a) ((int)(a))
+
+
+/* Helper */
+static inline gpg_error_t
+my_error_from_syserror (void)
+{
+ return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
+}
+
+static inline gpg_error_t
+my_error (int errcode)
+{
+ return gpg_err_make (default_errsource, errcode);
+}
+
+
+/* Return the maximum number of currently allowed open file
+ descriptors. Only useful on POSIX systems but returns a value on
+ other systems too. */
+int
+get_max_fds (void)
+{
+ int max_fds = -1;
+
+#ifdef OPEN_MAX
+ if (max_fds == -1)
+ max_fds = OPEN_MAX;
+#endif
+
+ if (max_fds == -1)
+ max_fds = 256; /* Arbitrary limit. */
+
+ return max_fds;
+}
+
+
+/* Under Windows this is a dummy function. */
+void
+close_all_fds (int first, int *except)
+{
+ (void)first;
+ (void)except;
+}
+
+
+/* Returns an array with all currently open file descriptors. The end
+ * of the array is marked by -1. The caller needs to release this
+ * array using the *standard free* and not with xfree. This allow the
+ * use of this function right at startup even before libgcrypt has
+ * been initialized. Returns NULL on error and sets ERRNO
+ * accordingly. Note that fstat prints a warning to DebugView for all
+ * invalid fds which is a bit annoying. We actually do not need this
+ * function in real code (close_all_fds is a dummy anyway) but we keep
+ * it for use by t-exechelp.c. */
+int *
+get_all_open_fds (void)
+{
+ int *array;
+ size_t narray;
+ int fd, max_fd, idx;
+#ifndef HAVE_STAT
+ array = calloc (1, sizeof *array);
+ if (array)
+ array[0] = -1;
+#else /*HAVE_STAT*/
+ struct stat statbuf;
+
+ max_fd = get_max_fds ();
+ narray = 32; /* If you change this change also t-exechelp.c. */
+ array = calloc (narray, sizeof *array);
+ if (!array)
+ return NULL;
+
+ /* Note: The list we return is ordered. */
+ for (idx=0, fd=0; fd < max_fd; fd++)
+ if (!(fstat (fd, &statbuf) == -1 && errno == EBADF))
+ {
+ if (idx+1 >= narray)
+ {
+ int *tmp;
+
+ narray += (narray < 256)? 32:256;
+ tmp = realloc (array, narray * sizeof *array);
+ if (!tmp)
+ {
+ free (array);
+ return NULL;
+ }
+ array = tmp;
+ }
+ array[idx++] = fd;
+ }
+ array[idx] = -1;
+#endif /*HAVE_STAT*/
+ return array;
+}
+
+
+/* Helper function to build_w32_commandline. */
+static char *
+build_w32_commandline_copy (char *buffer, const char *string)
+{
+ char *p = buffer;
+ const char *s;
+
+ if (!*string) /* Empty string. */
+ p = stpcpy (p, "\"\"");
+ else if (strpbrk (string, " \t\n\v\f\""))
+ {
+ /* Need to do some kind of quoting. */
+ p = stpcpy (p, "\"");
+ for (s=string; *s; s++)
+ {
+ *p++ = *s;
+ if (*s == '\"')
+ *p++ = *s;
+ }
+ *p++ = '\"';
+ *p = 0;
+ }
+ else
+ p = stpcpy (p, string);
+
+ return p;
+}
+
+/* Build a command line for use with W32's CreateProcess. On success
+ CMDLINE gets the address of a newly allocated string. */
+static gpg_error_t
+build_w32_commandline (const char *pgmname, const char * const *argv,
+ char **cmdline)
+{
+ int i, n;
+ const char *s;
+ char *buf, *p;
+
+ *cmdline = NULL;
+ n = 0;
+ s = pgmname;
+ n += strlen (s) + 1 + 2; /* (1 space, 2 quoting */
+ for (; *s; s++)
+ if (*s == '\"')
+ n++; /* Need to double inner quotes. */
+ for (i=0; (s=argv[i]); i++)
+ {
+ n += strlen (s) + 1 + 2; /* (1 space, 2 quoting */
+ for (; *s; s++)
+ if (*s == '\"')
+ n++; /* Need to double inner quotes. */
+ }
+ n++;
+
+ buf = p = xtrymalloc (n);
+ if (!buf)
+ return my_error_from_syserror ();
+
+ p = build_w32_commandline_copy (p, pgmname);
+ for (i=0; argv[i]; i++)
+ {
+ *p++ = ' ';
+ p = build_w32_commandline_copy (p, argv[i]);
+ }
+
+ *cmdline= buf;
+ return 0;
+}
+
+
+#define INHERIT_READ 1
+#define INHERIT_WRITE 2
+#define INHERIT_BOTH (INHERIT_READ|INHERIT_WRITE)
+
+/* Create pipe. FLAGS indicates which ends are inheritable. */
+static int
+create_inheritable_pipe (HANDLE filedes[2], int flags)
+{
+ HANDLE r, w;
+ SECURITY_ATTRIBUTES sec_attr;
+
+ memset (&sec_attr, 0, sizeof sec_attr );
+ sec_attr.nLength = sizeof sec_attr;
+ sec_attr.bInheritHandle = TRUE;
+
+ if (!CreatePipe (&r, &w, &sec_attr, 0))
+ return -1;
+
+ if ((flags & INHERIT_READ) == 0)
+ if (! SetHandleInformation (r, HANDLE_FLAG_INHERIT, 0))
+ goto fail;
+
+ if ((flags & INHERIT_WRITE) == 0)
+ if (! SetHandleInformation (w, HANDLE_FLAG_INHERIT, 0))
+ goto fail;
+
+ filedes[0] = r;
+ filedes[1] = w;
+ return 0;
+
+ fail:
+ log_error ("SetHandleInformation failed: %s\n", w32_strerror (-1));
+ CloseHandle (r);
+ CloseHandle (w);
+ return -1;
+}
+
+
+static HANDLE
+w32_open_null (int for_write)
+{
+ HANDLE hfile;
+
+ hfile = CreateFileW (L"nul",
+ for_write? GENERIC_WRITE : GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, OPEN_EXISTING, 0, NULL);
+ if (hfile == INVALID_HANDLE_VALUE)
+ log_debug ("can't open 'nul': %s\n", w32_strerror (-1));
+ return hfile;
+}
+
+
+static gpg_error_t
+create_pipe_and_estream (int filedes[2], int flags,
+ estream_t *r_fp, int outbound, int nonblock)
+{
+ gpg_error_t err = 0;
+ HANDLE fds[2];
+ es_syshd_t syshd;
+
+ filedes[0] = filedes[1] = -1;
+ err = my_error (GPG_ERR_GENERAL);
+ if (!create_inheritable_pipe (fds, flags))
+ {
+ filedes[0] = _open_osfhandle (handle_to_fd (fds[0]), O_RDONLY);
+ if (filedes[0] == -1)
+ {
+ log_error ("failed to translate osfhandle %p\n", fds[0]);
+ CloseHandle (fds[1]);
+ }
+ else
+ {
+ filedes[1] = _open_osfhandle (handle_to_fd (fds[1]), O_APPEND);
+ if (filedes[1] == -1)
+ {
+ log_error ("failed to translate osfhandle %p\n", fds[1]);
+ close (filedes[0]);
+ filedes[0] = -1;
+ CloseHandle (fds[1]);
+ }
+ else
+ err = 0;
+ }
+ }
+
+ if (! err && r_fp)
+ {
+ syshd.type = ES_SYSHD_HANDLE;
+ if (!outbound)
+ {
+ syshd.u.handle = fds[0];
+ *r_fp = es_sysopen (&syshd, nonblock? "r,nonblock" : "r");
+ }
+ else
+ {
+ syshd.u.handle = fds[1];
+ *r_fp = es_sysopen (&syshd, nonblock? "w,nonblock" : "w");
+ }
+ if (!*r_fp)
+ {
+ err = my_error_from_syserror ();
+ log_error (_("error creating a stream for a pipe: %s\n"),
+ gpg_strerror (err));
+ close (filedes[0]);
+ close (filedes[1]);
+ filedes[0] = filedes[1] = -1;
+ return err;
+ }
+ }
+
+ return err;
+}
+
+/* Portable function to create a pipe. Under Windows the write end is
+ inheritable. If R_FP is not NULL, an estream is created for the
+ read end and stored at R_FP. */
+gpg_error_t
+gnupg_create_inbound_pipe (int filedes[2], estream_t *r_fp, int nonblock)
+{
+ return create_pipe_and_estream (filedes, INHERIT_WRITE,
+ r_fp, 0, nonblock);
+}
+
+
+/* Portable function to create a pipe. Under Windows the read end is
+ inheritable. If R_FP is not NULL, an estream is created for the
+ write end and stored at R_FP. */
+gpg_error_t
+gnupg_create_outbound_pipe (int filedes[2], estream_t *r_fp, int nonblock)
+{
+ return create_pipe_and_estream (filedes, INHERIT_READ,
+ r_fp, 1, nonblock);
+}
+
+
+/* Portable function to create a pipe. Under Windows both ends are
+ inheritable. */
+gpg_error_t
+gnupg_create_pipe (int filedes[2])
+{
+ return create_pipe_and_estream (filedes, INHERIT_BOTH,
+ NULL, 0, 0);
+}
+
+
+/* Fork and exec the PGMNAME, see exechelp.h for details. */
+gpg_error_t
+gnupg_spawn_process (const char *pgmname, const char *argv[],
+ int *except, void (*preexec)(void), unsigned int flags,
+ estream_t *r_infp,
+ estream_t *r_outfp,
+ estream_t *r_errfp,
+ pid_t *pid)
+{
+ gpg_error_t err;
+ SECURITY_ATTRIBUTES sec_attr;
+ PROCESS_INFORMATION pi =
+ {
+ NULL, /* Returns process handle. */
+ 0, /* Returns primary thread handle. */
+ 0, /* Returns pid. */
+ 0 /* Returns tid. */
+ };
+ STARTUPINFOW si;
+ int cr_flags;
+ char *cmdline;
+ wchar_t *wcmdline = NULL;
+ wchar_t *wpgmname = NULL;
+ HANDLE inpipe[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE};
+ HANDLE outpipe[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE};
+ HANDLE errpipe[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE};
+ estream_t infp = NULL;
+ estream_t outfp = NULL;
+ estream_t errfp = NULL;
+ HANDLE nullhd[3] = {INVALID_HANDLE_VALUE,
+ INVALID_HANDLE_VALUE,
+ INVALID_HANDLE_VALUE};
+ int i, rc;
+ es_syshd_t syshd;
+ gpg_err_source_t errsource = default_errsource;
+ int nonblock = !!(flags & GNUPG_SPAWN_NONBLOCK);
+
+ (void)except; /* Not yet used. */
+
+ if (r_infp)
+ *r_infp = NULL;
+ if (r_outfp)
+ *r_outfp = NULL;
+ if (r_errfp)
+ *r_errfp = NULL;
+ *pid = (pid_t)(-1); /* Always required. */
+
+ if (r_infp)
+ {
+ if (create_inheritable_pipe (inpipe, INHERIT_READ))
+ {
+ err = gpg_err_make (errsource, GPG_ERR_GENERAL);
+ log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
+ return err;
+ }
+
+ syshd.type = ES_SYSHD_HANDLE;
+ syshd.u.handle = inpipe[1];
+ infp = es_sysopen (&syshd, nonblock? "w,nonblock" : "w");
+ if (!infp)
+ {
+ err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
+ log_error (_("error creating a stream for a pipe: %s\n"),
+ gpg_strerror (err));
+ CloseHandle (inpipe[0]);
+ CloseHandle (inpipe[1]);
+ inpipe[0] = inpipe[1] = INVALID_HANDLE_VALUE;
+ return err;
+ }
+ }
+
+ if (r_outfp)
+ {
+ if (create_inheritable_pipe (outpipe, INHERIT_WRITE))
+ {
+ err = gpg_err_make (errsource, GPG_ERR_GENERAL);
+ log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
+ return err;
+ }
+
+ syshd.type = ES_SYSHD_HANDLE;
+ syshd.u.handle = outpipe[0];
+ outfp = es_sysopen (&syshd, nonblock? "r,nonblock" : "r");
+ if (!outfp)
+ {
+ err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
+ log_error (_("error creating a stream for a pipe: %s\n"),
+ gpg_strerror (err));
+ CloseHandle (outpipe[0]);
+ CloseHandle (outpipe[1]);
+ outpipe[0] = outpipe[1] = INVALID_HANDLE_VALUE;
+ if (infp)
+ es_fclose (infp);
+ else if (inpipe[1] != INVALID_HANDLE_VALUE)
+ CloseHandle (inpipe[1]);
+ if (inpipe[0] != INVALID_HANDLE_VALUE)
+ CloseHandle (inpipe[0]);
+ return err;
+ }
+ }
+
+ if (r_errfp)
+ {
+ if (create_inheritable_pipe (errpipe, INHERIT_WRITE))
+ {
+ err = gpg_err_make (errsource, GPG_ERR_GENERAL);
+ log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
+ return err;
+ }
+
+ syshd.type = ES_SYSHD_HANDLE;
+ syshd.u.handle = errpipe[0];
+ errfp = es_sysopen (&syshd, nonblock? "r,nonblock" : "r");
+ if (!errfp)
+ {
+ err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
+ log_error (_("error creating a stream for a pipe: %s\n"),
+ gpg_strerror (err));
+ CloseHandle (errpipe[0]);
+ CloseHandle (errpipe[1]);
+ errpipe[0] = errpipe[1] = INVALID_HANDLE_VALUE;
+ if (outfp)
+ es_fclose (outfp);
+ else if (outpipe[0] != INVALID_HANDLE_VALUE)
+ CloseHandle (outpipe[0]);
+ if (outpipe[1] != INVALID_HANDLE_VALUE)
+ CloseHandle (outpipe[1]);
+ if (infp)
+ es_fclose (infp);
+ else if (inpipe[1] != INVALID_HANDLE_VALUE)
+ CloseHandle (inpipe[1]);
+ if (inpipe[0] != INVALID_HANDLE_VALUE)
+ CloseHandle (inpipe[0]);
+ return err;
+ }
+ }
+
+ /* Prepare security attributes. */
+ memset (&sec_attr, 0, sizeof sec_attr );
+ sec_attr.nLength = sizeof sec_attr;
+ sec_attr.bInheritHandle = FALSE;
+
+ /* Build the command line. */
+ err = build_w32_commandline (pgmname, argv, &cmdline);
+ if (err)
+ return err;
+
+ if (inpipe[0] == INVALID_HANDLE_VALUE)
+ nullhd[0] = ((flags & GNUPG_SPAWN_KEEP_STDIN)?
+ GetStdHandle (STD_INPUT_HANDLE) : w32_open_null (0));
+ if (outpipe[1] == INVALID_HANDLE_VALUE)
+ nullhd[1] = ((flags & GNUPG_SPAWN_KEEP_STDOUT)?
+ GetStdHandle (STD_OUTPUT_HANDLE) : w32_open_null (1));
+ if (errpipe[1] == INVALID_HANDLE_VALUE)
+ nullhd[2] = ((flags & GNUPG_SPAWN_KEEP_STDOUT)?
+ GetStdHandle (STD_ERROR_HANDLE) : w32_open_null (1));
+
+ /* Start the process. Note that we can't run the PREEXEC function
+ because this might change our own environment. */
+ (void)preexec;
+
+ memset (&si, 0, sizeof si);
+ si.cb = sizeof (si);
+ si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
+ si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_HIDE;
+ si.hStdInput = inpipe[0] == INVALID_HANDLE_VALUE? nullhd[0] : inpipe[0];
+ si.hStdOutput = outpipe[1] == INVALID_HANDLE_VALUE? nullhd[1] : outpipe[1];
+ si.hStdError = errpipe[1] == INVALID_HANDLE_VALUE? nullhd[2] : errpipe[1];
+
+ cr_flags = (CREATE_DEFAULT_ERROR_MODE
+ | ((flags & GNUPG_SPAWN_DETACHED)? DETACHED_PROCESS : 0)
+ | GetPriorityClass (GetCurrentProcess ())
+ | CREATE_SUSPENDED);
+ /* log_debug ("CreateProcess, path='%s' cmdline='%s'\n", */
+ /* pgmname, cmdline); */
+ /* Take care: CreateProcessW may modify wpgmname */
+ if (!(wpgmname = utf8_to_wchar (pgmname)))
+ rc = 0;
+ else if (!(wcmdline = utf8_to_wchar (cmdline)))
+ rc = 0;
+ else
+ rc = CreateProcessW (wpgmname, /* Program to start. */
+ wcmdline, /* Command line arguments. */
+ &sec_attr, /* Process security attributes. */
+ &sec_attr, /* Thread security attributes. */
+ TRUE, /* Inherit handles. */
+ cr_flags, /* Creation flags. */
+ NULL, /* Environment. */
+ NULL, /* Use current drive/directory. */
+ &si, /* Startup information. */
+ &pi /* Returns process information. */
+ );
+ if (!rc)
+ {
+ if (!wpgmname || !wcmdline)
+ log_error ("CreateProcess failed (utf8_to_wchar): %s\n",
+ strerror (errno));
+ else
+ log_error ("CreateProcess failed: %s\n", w32_strerror (-1));
+ xfree (wpgmname);
+ xfree (wcmdline);
+ xfree (cmdline);
+ if (infp)
+ es_fclose (infp);
+ else if (inpipe[1] != INVALID_HANDLE_VALUE)
+ CloseHandle (outpipe[1]);
+ if (inpipe[0] != INVALID_HANDLE_VALUE)
+ CloseHandle (inpipe[0]);
+ if (outfp)
+ es_fclose (outfp);
+ else if (outpipe[0] != INVALID_HANDLE_VALUE)
+ CloseHandle (outpipe[0]);
+ if (outpipe[1] != INVALID_HANDLE_VALUE)
+ CloseHandle (outpipe[1]);
+ if (errfp)
+ es_fclose (errfp);
+ else if (errpipe[0] != INVALID_HANDLE_VALUE)
+ CloseHandle (errpipe[0]);
+ if (errpipe[1] != INVALID_HANDLE_VALUE)
+ CloseHandle (errpipe[1]);
+ return gpg_err_make (errsource, GPG_ERR_GENERAL);
+ }
+ xfree (wpgmname);
+ xfree (wcmdline);
+ xfree (cmdline);
+ cmdline = NULL;
+
+ /* Close the inherited handles to /dev/null. */
+ for (i=0; i < DIM (nullhd); i++)
+ if (nullhd[i] != INVALID_HANDLE_VALUE)
+ CloseHandle (nullhd[i]);
+
+ /* Close the inherited ends of the pipes. */
+ if (inpipe[0] != INVALID_HANDLE_VALUE)
+ CloseHandle (inpipe[0]);
+ if (outpipe[1] != INVALID_HANDLE_VALUE)
+ CloseHandle (outpipe[1]);
+ if (errpipe[1] != INVALID_HANDLE_VALUE)
+ CloseHandle (errpipe[1]);
+
+ /* log_debug ("CreateProcess ready: hProcess=%p hThread=%p" */
+ /* " dwProcessID=%d dwThreadId=%d\n", */
+ /* pi.hProcess, pi.hThread, */
+ /* (int) pi.dwProcessId, (int) pi.dwThreadId); */
+ /* log_debug (" outfp=%p errfp=%p\n", outfp, errfp); */
+
+ /* Fixme: For unknown reasons AllowSetForegroundWindow returns an
+ invalid argument error if we pass it the correct processID. As a
+ workaround we use -1 (ASFW_ANY). */
+ if ((flags & GNUPG_SPAWN_RUN_ASFW))
+ gnupg_allow_set_foregound_window ((pid_t)(-1)/*pi.dwProcessId*/);
+
+ /* Process has been created suspended; resume it now. */
+ ResumeThread (pi.hThread);
+ CloseHandle (pi.hThread);
+
+ if (r_infp)
+ *r_infp = infp;
+ if (r_outfp)
+ *r_outfp = outfp;
+ if (r_errfp)
+ *r_errfp = errfp;
+
+ *pid = handle_to_pid (pi.hProcess);
+ return 0;
+
+}
+
+
+
+/* Simplified version of gnupg_spawn_process. This function forks and
+ then execs PGMNAME, while connecting INFD to stdin, OUTFD to stdout
+ and ERRFD to stderr (any of them may be -1 to connect them to
+ /dev/null). The arguments for the process are expected in the NULL
+ terminated array ARGV. The program name itself should not be
+ included there. Calling gnupg_wait_process is required.
+
+ Returns 0 on success or an error code. */
+gpg_error_t
+gnupg_spawn_process_fd (const char *pgmname, const char *argv[],
+ int infd, int outfd, int errfd, pid_t *pid)
+{
+ gpg_error_t err;
+ SECURITY_ATTRIBUTES sec_attr;
+ PROCESS_INFORMATION pi = { NULL, 0, 0, 0 };
+ STARTUPINFOW si;
+ char *cmdline;
+ wchar_t *wcmdline = NULL;
+ wchar_t *wpgmname = NULL;
+ int i, rc;
+ HANDLE stdhd[3];
+
+ /* Setup return values. */
+ *pid = (pid_t)(-1);
+
+ /* Prepare security attributes. */
+ memset (&sec_attr, 0, sizeof sec_attr );
+ sec_attr.nLength = sizeof sec_attr;
+ sec_attr.bInheritHandle = FALSE;
+
+ /* Build the command line. */
+ err = build_w32_commandline (pgmname, argv, &cmdline);
+ if (err)
+ return err;
+
+ memset (&si, 0, sizeof si);
+ si.cb = sizeof (si);
+ si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
+ si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE;
+ stdhd[0] = infd == -1? w32_open_null (0) : INVALID_HANDLE_VALUE;
+ stdhd[1] = outfd == -1? w32_open_null (1) : INVALID_HANDLE_VALUE;
+ stdhd[2] = errfd == -1? w32_open_null (1) : INVALID_HANDLE_VALUE;
+ si.hStdInput = infd == -1? stdhd[0] : (void*)_get_osfhandle (infd);
+ si.hStdOutput = outfd == -1? stdhd[1] : (void*)_get_osfhandle (outfd);
+ si.hStdError = errfd == -1? stdhd[2] : (void*)_get_osfhandle (errfd);
+
+/* log_debug ("CreateProcess, path='%s' cmdline='%s'\n", pgmname, cmdline); */
+ /* Take care: CreateProcessW may modify wpgmname */
+ if (!(wpgmname = utf8_to_wchar (pgmname)))
+ rc = 0;
+ else if (!(wcmdline = utf8_to_wchar (cmdline)))
+ rc = 0;
+ else
+ rc = CreateProcessW (wpgmname, /* Program to start. */
+ wcmdline, /* Command line arguments. */
+ &sec_attr, /* Process security attributes. */
+ &sec_attr, /* Thread security attributes. */
+ TRUE, /* Inherit handles. */
+ (CREATE_DEFAULT_ERROR_MODE
+ | GetPriorityClass (GetCurrentProcess ())
+ | CREATE_SUSPENDED | DETACHED_PROCESS),
+ NULL, /* Environment. */
+ NULL, /* Use current drive/directory. */
+ &si, /* Startup information. */
+ &pi /* Returns process information. */
+ );
+ if (!rc)
+ {
+ if (!wpgmname || !wcmdline)
+ log_error ("CreateProcess failed (utf8_to_wchar): %s\n",
+ strerror (errno));
+ else
+ log_error ("CreateProcess failed: %s\n", w32_strerror (-1));
+ err = my_error (GPG_ERR_GENERAL);
+ }
+ else
+ err = 0;
+ xfree (wpgmname);
+ xfree (wcmdline);
+ xfree (cmdline);
+ for (i=0; i < 3; i++)
+ if (stdhd[i] != INVALID_HANDLE_VALUE)
+ CloseHandle (stdhd[i]);
+ if (err)
+ return err;
+
+/* log_debug ("CreateProcess ready: hProcess=%p hThread=%p" */
+/* " dwProcessID=%d dwThreadId=%d\n", */
+/* pi.hProcess, pi.hThread, */
+/* (int) pi.dwProcessId, (int) pi.dwThreadId); */
+
+ /* Process has been created suspended; resume it now. */
+ ResumeThread (pi.hThread);
+ CloseHandle (pi.hThread);
+
+ *pid = handle_to_pid (pi.hProcess);
+ return 0;
+
+}
+
+
+/* See exechelp.h for a description. */
+gpg_error_t
+gnupg_wait_process (const char *pgmname, pid_t pid, int hang, int *r_exitcode)
+{
+ return gnupg_wait_processes (&pgmname, &pid, 1, hang, r_exitcode);
+}
+
+/* See exechelp.h for a description. */
+gpg_error_t
+gnupg_wait_processes (const char **pgmnames, pid_t *pids, size_t count,
+ int hang, int *r_exitcodes)
+{
+ gpg_err_code_t ec = 0;
+ size_t i;
+ HANDLE *procs;
+ int code;
+
+ procs = xtrycalloc (count, sizeof *procs);
+ if (procs == NULL)
+ return my_error_from_syserror ();
+
+ for (i = 0; i < count; i++)
+ {
+ if (r_exitcodes)
+ r_exitcodes[i] = -1;
+
+ if (pids[i] == (pid_t)(-1))
+ return my_error (GPG_ERR_INV_VALUE);
+
+ procs[i] = fd_to_handle (pids[i]);
+ }
+
+ /* FIXME: We should do a pth_waitpid here. However this has not yet
+ been implemented. A special W32 pth system call would even be
+ better. */
+ code = WaitForMultipleObjects (count, procs, TRUE, hang? INFINITE : 0);
+ switch (code)
+ {
+ case WAIT_TIMEOUT:
+ ec = GPG_ERR_TIMEOUT;
+ goto leave;
+
+ case WAIT_FAILED:
+ log_error (_("waiting for processes to terminate failed: %s\n"),
+ w32_strerror (-1));
+ ec = GPG_ERR_GENERAL;
+ goto leave;
+
+ case WAIT_OBJECT_0:
+ for (i = 0; i < count; i++)
+ {
+ DWORD exc;
+
+ if (! GetExitCodeProcess (procs[i], &exc))
+ {
+ log_error (_("error getting exit code of process %d: %s\n"),
+ (int) pids[i], w32_strerror (-1) );
+ ec = GPG_ERR_GENERAL;
+ }
+ else if (exc)
+ {
+ if (!r_exitcodes)
+ log_error (_("error running '%s': exit status %d\n"),
+ pgmnames[i], (int)exc);
+ else
+ r_exitcodes[i] = (int)exc;
+ ec = GPG_ERR_GENERAL;
+ }
+ else
+ {
+ if (r_exitcodes)
+ r_exitcodes[i] = 0;
+ }
+ }
+ break;
+
+ default:
+ log_error ("WaitForMultipleObjects returned unexpected "
+ "code %d\n", code);
+ ec = GPG_ERR_GENERAL;
+ break;
+ }
+
+ leave:
+ return gpg_err_make (GPG_ERR_SOURCE_DEFAULT, ec);
+}
+
+
+
+void
+gnupg_release_process (pid_t pid)
+{
+ if (pid != (pid_t)INVALID_HANDLE_VALUE)
+ {
+ HANDLE process = (HANDLE)pid;
+
+ CloseHandle (process);
+ }
+}
+
+
+/* Spawn a new process and immediately detach from it. The name of
+ the program to exec is PGMNAME and its arguments are in ARGV (the
+ programname is automatically passed as first argument).
+ Environment strings in ENVP are set. An error is returned if
+ pgmname is not executable; to make this work it is necessary to
+ provide an absolute file name. All standard file descriptors are
+ connected to /dev/null. */
+gpg_error_t
+gnupg_spawn_process_detached (const char *pgmname, const char *argv[],
+ const char *envp[] )
+{
+ gpg_error_t err;
+ SECURITY_ATTRIBUTES sec_attr;
+ PROCESS_INFORMATION pi =
+ {
+ NULL, /* Returns process handle. */
+ 0, /* Returns primary thread handle. */
+ 0, /* Returns pid. */
+ 0 /* Returns tid. */
+ };
+ STARTUPINFOW si;
+ int cr_flags;
+ char *cmdline;
+ wchar_t *wcmdline = NULL;
+ wchar_t *wpgmname = NULL;
+ BOOL in_job = FALSE;
+ gpg_err_code_t ec;
+ int rc;
+ int jobdebug;
+
+ /* We don't use ENVP. */
+ (void)envp;
+
+ cmdline = getenv ("GNUPG_EXEC_DEBUG_FLAGS");
+ jobdebug = (cmdline && (atoi (cmdline) & 1));
+
+ if ((ec = gnupg_access (pgmname, X_OK)))
+ return gpg_err_make (default_errsource, ec);
+
+ /* Prepare security attributes. */
+ memset (&sec_attr, 0, sizeof sec_attr );
+ sec_attr.nLength = sizeof sec_attr;
+ sec_attr.bInheritHandle = FALSE;
+
+ /* Build the command line. */
+ err = build_w32_commandline (pgmname, argv, &cmdline);
+ if (err)
+ return err;
+
+ /* Start the process. */
+ memset (&si, 0, sizeof si);
+ si.cb = sizeof (si);
+ si.dwFlags = STARTF_USESHOWWINDOW;
+ si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE;
+
+ cr_flags = (CREATE_DEFAULT_ERROR_MODE
+ | GetPriorityClass (GetCurrentProcess ())
+ | CREATE_NEW_PROCESS_GROUP
+ | DETACHED_PROCESS);
+
+ /* Check if we were spawned as part of a Job.
+ * In a job we need to add CREATE_BREAKAWAY_FROM_JOB
+ * to the cr_flags, otherwise our child processes
+ * are killed when we terminate. */
+ if (!IsProcessInJob (GetCurrentProcess(), NULL, &in_job))
+ {
+ log_error ("IsProcessInJob() failed: %s\n", w32_strerror (-1));
+ in_job = FALSE;
+ }
+
+ if (in_job)
+ {
+ /* Only try to break away from job if it is allowed, otherwise
+ * CreateProcess() would fail with an "Access is denied" error. */
+ JOBOBJECT_EXTENDED_LIMIT_INFORMATION info;
+ if (!QueryInformationJobObject (NULL, JobObjectExtendedLimitInformation,
+ &info, sizeof info, NULL))
+ {
+ log_error ("QueryInformationJobObject() failed: %s\n",
+ w32_strerror (-1));
+ }
+ else if ((info.BasicLimitInformation.LimitFlags &
+ JOB_OBJECT_LIMIT_BREAKAWAY_OK))
+ {
+ if (jobdebug)
+ log_debug ("Using CREATE_BREAKAWAY_FROM_JOB flag\n");
+ cr_flags |= CREATE_BREAKAWAY_FROM_JOB;
+ }
+ else if ((info.BasicLimitInformation.LimitFlags &
+ JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK))
+ {
+ /* The child process should automatically detach from the job. */
+ if (jobdebug)
+ log_debug ("Not using CREATE_BREAKAWAY_FROM_JOB flag; "
+ "JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK is set\n");
+ }
+ else
+ {
+ /* It seems that the child process must remain in the job.
+ * This is not necessarily an error, although it can cause premature
+ * termination of the child process when the job is closed. */
+ if (jobdebug)
+ log_debug ("Not using CREATE_BREAKAWAY_FROM_JOB flag\n");
+ }
+ }
+ else
+ {
+ if (jobdebug)
+ log_debug ("Process is not in a Job\n");
+ }
+
+ /* log_debug ("CreateProcess(detached), path='%s' cmdline='%s'\n", */
+ /* pgmname, cmdline); */
+ /* Take care: CreateProcessW may modify wpgmname */
+ if (!(wpgmname = utf8_to_wchar (pgmname)))
+ rc = 0;
+ else if (!(wcmdline = utf8_to_wchar (cmdline)))
+ rc = 0;
+ else
+ rc = CreateProcessW (wpgmname, /* Program to start. */
+ wcmdline, /* Command line arguments. */
+ &sec_attr, /* Process security attributes. */
+ &sec_attr, /* Thread security attributes. */
+ FALSE, /* Inherit handles. */
+ cr_flags, /* Creation flags. */
+ NULL, /* Environment. */
+ NULL, /* Use current drive/directory. */
+ &si, /* Startup information. */
+ &pi /* Returns process information. */
+ );
+ if (!rc)
+ {
+ if (!wpgmname || !wcmdline)
+ log_error ("CreateProcess failed (utf8_to_wchar): %s\n",
+ strerror (errno));
+ else
+ log_error ("CreateProcess(detached) failed: %s\n", w32_strerror (-1));
+ xfree (wpgmname);
+ xfree (wcmdline);
+ xfree (cmdline);
+ return my_error (GPG_ERR_GENERAL);
+ }
+ xfree (wpgmname);
+ xfree (wcmdline);
+ xfree (cmdline);
+ cmdline = NULL;
+
+/* log_debug ("CreateProcess(detached) ready: hProcess=%p hThread=%p" */
+/* " dwProcessID=%d dwThreadId=%d\n", */
+/* pi.hProcess, pi.hThread, */
+/* (int) pi.dwProcessId, (int) pi.dwThreadId); */
+
+ CloseHandle (pi.hThread);
+ CloseHandle (pi.hProcess);
+
+ return 0;
+}
+
+
+/* Kill a process; that is send an appropriate signal to the process.
+ gnupg_wait_process must be called to actually remove the process
+ from the system. An invalid PID is ignored. */
+void
+gnupg_kill_process (pid_t pid)
+{
+ if (pid != (pid_t) INVALID_HANDLE_VALUE)
+ {
+ HANDLE process = (HANDLE) pid;
+
+ /* Arbitrary error code. */
+ TerminateProcess (process, 1);
+ }
+}
diff --git a/common/exechelp-w32ce.c b/common/exechelp-w32ce.c
new file mode 100644
index 0000000..ec9f014
--- /dev/null
+++ b/common/exechelp-w32ce.c
@@ -0,0 +1,886 @@
+/* exechelp-w32.c - Fork and exec helpers for W32CE.
+ * Copyright (C) 2004, 2007, 2008, 2009,
+ * 2010 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#if !defined(HAVE_W32_SYSTEM) && !defined (HAVE_W32CE_SYSTEM)
+#error This code is only used on W32CE.
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#ifdef HAVE_SIGNAL_H
+# include <signal.h>
+#endif
+#include <unistd.h>
+#include <fcntl.h>
+
+#ifdef WITHOUT_NPTH /* Give the Makefile a chance to build without Pth. */
+#undef HAVE_NPTH
+#undef USE_NPTH
+#endif
+
+#ifdef HAVE_NPTH
+#include <npth.h>
+#endif
+
+#ifdef HAVE_STAT
+# include <sys/stat.h>
+#endif
+
+#include <assuan.h>
+
+#include "util.h"
+#include "i18n.h"
+#include "sysutils.h"
+#include "exechelp.h"
+
+
+/* It seems Vista doesn't grok X_OK and so fails access() tests.
+ Previous versions interpreted X_OK as F_OK anyway, so we'll just
+ use F_OK directly. */
+#undef X_OK
+#define X_OK F_OK
+
+
+/* We assume that a HANDLE can be represented by an int which should
+ be true for all i386 systems (HANDLE is defined as void *) and
+ these are the only systems for which Windows is available. Further
+ we assume that -1 denotes an invalid handle. */
+#define fd_to_handle(a) ((HANDLE)(a))
+#define handle_to_fd(a) ((int)(a))
+#define pid_to_handle(a) ((HANDLE)(a))
+#define handle_to_pid(a) ((int)(a))
+
+
+#ifdef USE_NPTH
+/* The data passed to the feeder_thread. */
+struct feeder_thread_parms
+{
+ estream_t stream;
+ volatile int stream_valid;
+ HANDLE hd;
+ int direction;
+};
+
+
+/* The thread started by start_feede3. */
+static void *
+feeder_thread (void *arg)
+{
+ struct feeder_thread_parms *parm = arg;
+ char buffer[4096];
+ int rc;
+
+ if (parm->direction)
+ {
+ size_t nread = 0;
+ DWORD nwritten;
+
+ log_debug ("feeder_thread estream->pipe: stream=%p pipe=%p\n",
+ parm->stream, parm->hd);
+ while (parm->stream_valid
+ && !es_read (parm->stream, buffer, sizeof buffer, &nread))
+ {
+ do
+ {
+ pth_enter ();
+ rc = WriteFile (parm->hd, buffer, nread, &nwritten, NULL);
+ pth_leave ();
+ if (!rc)
+ {
+ log_debug ("feeder(%p): WriteFile error: rc=%d\n",
+ parm->hd, (int)GetLastError ());
+ goto leave;
+ }
+ nread -= nwritten;
+ }
+ while (nread);
+ }
+ if (!parm->stream_valid)
+ log_debug ("feeder(%p): closed by other thread\n", parm->hd);
+ else if (nread)
+ log_debug ("feeder(%p): es_read error: %s\n",
+ parm->hd, strerror (errno));
+ }
+ else
+ {
+ DWORD nread = 0;
+ size_t nwritten;
+
+ log_debug ("feeder_thread pipe->estream: stream=%p pipe=%p\n",
+ parm->stream, parm->hd);
+ while ( (pth_enter (),
+ (rc = ReadFile (parm->hd, buffer, sizeof buffer, &nread, NULL)),
+ pth_leave (),
+ rc) && nread)
+ {
+ log_debug ("feeder_thread pipe->estream: read %d bytes\n",
+ (int)nread);
+ do
+ {
+ if (parm->stream_valid
+ && es_write (parm->stream, buffer, nread, &nwritten))
+ {
+ log_debug ("feeder(%p): es_write error: %s\n",
+ parm->hd, strerror (errno));
+ goto leave;
+ }
+ log_debug ("feeder_thread pipe->estream: es_wrote %d bytes\n",
+ (int)nwritten);
+ nread -= nwritten;
+ }
+ while (nread && parm->stream_valid);
+ }
+ if (!parm->stream_valid)
+ log_debug ("feeder(%p): closed by other thread\n", parm->hd);
+ else if (nread)
+ log_debug ("feeder(%p): ReadFile error: rc=%d\n",
+ parm->hd, (int)GetLastError ());
+ else
+ log_debug ("feeder(%p): eof\n", parm->hd);
+ }
+
+leave:
+ log_debug ("feeder(%p): waiting for es_fclose\n", parm->hd);
+ while (parm->stream_valid)
+ pth_yield (NULL);
+ log_debug ("feeder(%p): about to close the pipe handle\n", parm->hd);
+ CloseHandle (parm->hd);
+ log_debug ("feeder(%p): pipe handle closed\n", parm->hd);
+ xfree (parm);
+ return NULL;
+}
+#endif /*USE_NPTH*/
+
+#ifdef USE_NPTH
+static void
+feeder_onclose_notification (estream_t stream, void *opaque)
+{
+ struct feeder_thread_parms *parm = opaque;
+ (void)stream;
+ log_debug ("feeder(%p): received onclose note\n", parm->hd);
+ parm->stream_valid = 0;
+}
+#endif /*USE_NPTH*/
+
+/* Fire up a thread to copy data between STREAM and a pipe's
+ descriptor FD. With DIRECTION set to true the copy takes place
+ from the stream to the pipe, otherwise from the pipe to the
+ stream. */
+static gpg_error_t
+start_feeder (estream_t stream, HANDLE hd, int direction)
+{
+#ifdef USE_NPTH
+ gpg_error_t err;
+ struct feeder_thread_parms *parm;
+ pth_attr_t tattr;
+
+ parm = xtrymalloc (sizeof *parm);
+ if (!parm)
+ return gpg_error_from_syserror ();
+ parm->stream = stream;
+ parm->stream_valid = 1;
+ parm->hd = hd;
+ parm->direction = direction;
+
+ if (es_onclose (stream, 1, feeder_onclose_notification, parm))
+ {
+ err = gpg_error_from_syserror ();
+ xfree (parm);
+ return err;
+ }
+
+ tattr = pth_attr_new ();
+ pth_attr_set (tattr, PTH_ATTR_JOINABLE, 0);
+ pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 64*1024);
+ pth_attr_set (tattr, PTH_ATTR_NAME, "exec-feeder");
+
+ log_debug ("spawning new feeder(%p, %p, %d)\n", stream, hd, direction);
+ if(!pth_spawn (tattr, feeder_thread, parm))
+ {
+ err = gpg_error_from_syserror ();
+ es_onclose (stream, 0, feeder_onclose_notification, parm);
+ xfree (parm);
+ }
+ else
+ err = 0;
+ pth_attr_destroy (tattr);
+
+ return err;
+#else
+ (void)stream;
+ (void)hd;
+ (void)direction;
+ return gpg_error (GPG_ERR_NOT_IMPLEMENTED); /* No Pth. */
+#endif
+}
+
+
+
+/* Return the maximum number of currently allowed open file
+ descriptors. Only useful on POSIX systems but returns a value on
+ other systems too. */
+int
+get_max_fds (void)
+{
+ int max_fds = -1;
+
+#ifdef OPEN_MAX
+ if (max_fds == -1)
+ max_fds = OPEN_MAX;
+#endif
+
+ if (max_fds == -1)
+ max_fds = 256; /* Arbitrary limit. */
+
+ return max_fds;
+}
+
+
+/* Under Windows this is a dummy function. */
+void
+close_all_fds (int first, int *except)
+{
+ (void)first;
+ (void)except;
+}
+
+
+/* Returns an array with all currently open file descriptors. The end
+ of the array is marked by -1. The caller needs to release this
+ array using the *standard free* and not with xfree. This allow the
+ use of this function right at startup even before libgcrypt has
+ been initialized. Returns NULL on error and sets ERRNO
+ accordingly. */
+int *
+get_all_open_fds (void)
+{
+ int *array;
+ size_t narray;
+ int fd, max_fd, idx;
+#ifndef HAVE_STAT
+ array = calloc (1, sizeof *array);
+ if (array)
+ array[0] = -1;
+#else /*HAVE_STAT*/
+ struct stat statbuf;
+
+ max_fd = get_max_fds ();
+ narray = 32; /* If you change this change also t-exechelp.c. */
+ array = calloc (narray, sizeof *array);
+ if (!array)
+ return NULL;
+
+ /* Note: The list we return is ordered. */
+ for (idx=0, fd=0; fd < max_fd; fd++)
+ if (!(fstat (fd, &statbuf) == -1 && errno == EBADF))
+ {
+ if (idx+1 >= narray)
+ {
+ int *tmp;
+
+ narray += (narray < 256)? 32:256;
+ tmp = realloc (array, narray * sizeof *array);
+ if (!tmp)
+ {
+ free (array);
+ return NULL;
+ }
+ array = tmp;
+ }
+ array[idx++] = fd;
+ }
+ array[idx] = -1;
+#endif /*HAVE_STAT*/
+ return array;
+}
+
+
+
+static char *
+copy_quoted (char *p, const char *string)
+{
+ const char *s;
+
+ if (!*string) /* Empty string. */
+ p = stpcpy (p, "\"\"");
+ else if (strpbrk (string, " \t\n\v\f\"")) /* Need quotes. */
+ {
+ p = stpcpy (p, "\"");
+ for (s = string; *s; s++)
+ {
+ *p++ = *s;
+ if (*s == '\"')
+ *p++ = *s;
+ }
+ *p++ = '\"';
+ *p = 0;
+ }
+ else /* Copy verbatim. */
+ p = stpcpy (p, string);
+
+ return p;
+}
+
+
+/* Build a command line for use with W32's CreateProcess. On success
+ CMDLINE gets the address of a newly allocated string. */
+static int
+build_w32_commandline (const char * const *argv,
+ int rvid0, int rvid1, int rvid2,
+ char **cmdline)
+{
+ int i, n;
+ const char *s;
+ char *buf, *p;
+ char fdbuf[3*30];
+
+ p = fdbuf;
+ *p = 0;
+
+ if (rvid0)
+ snprintf (p, 25, "-&S0=%d ", rvid0);
+ else
+ strcpy (p, "-&S0=null ");
+ p += strlen (p);
+
+ if (rvid1)
+ snprintf (p, 25, "-&S1=%d ", rvid1);
+ else
+ strcpy (p, "-&S1=null ");
+ p += strlen (p);
+
+ if (rvid2)
+ snprintf (p, 25, "-&S2=%d ", rvid2);
+ else
+ strcpy (p, "-&S2=null ");
+ p += strlen (p);
+
+ *cmdline = NULL;
+ n = strlen (fdbuf);
+ for (i=0; (s = argv[i]); i++)
+ {
+ n += strlen (s) + 1 + 2; /* (1 space, 2 quoting) */
+ for (; *s; s++)
+ if (*s == '\"')
+ n++; /* Need to double inner quotes. */
+ }
+ n++;
+
+ buf = p = xtrymalloc (n);
+ if (! buf)
+ return -1;
+
+ p = stpcpy (p, fdbuf);
+ for (i = 0; argv[i]; i++)
+ {
+ *p++ = ' ';
+ p = copy_quoted (p, argv[i]);
+ }
+
+ *cmdline = buf;
+ return 0;
+}
+
+
+/* Create pipe where one end is inheritable: With an INHERIT_IDX of 0
+ the read end is inheritable, with 1 the write end is inheritable.
+ Note that the inheritable ends are rendezvous ids and no file
+ descriptors or handles. */
+static gpg_error_t
+create_inheritable_pipe (int filedes[2], int inherit_idx)
+{
+ HANDLE hd;
+ int rvid;
+
+ filedes[0] = filedes[1] = -1;
+ hd = _assuan_w32ce_prepare_pipe (&rvid, !inherit_idx);
+ if (hd == INVALID_HANDLE_VALUE)
+ {
+ log_error ("_assuan_w32ce_prepare_pipe failed: %s\n", w32_strerror (-1));
+ gpg_err_set_errno (EIO);
+ return gpg_error_from_syserror ();
+ }
+
+ if (inherit_idx)
+ {
+ filedes[0] = handle_to_fd (hd);
+ filedes[1] = rvid;
+ }
+ else
+ {
+ filedes[0] = rvid;
+ filedes[1] = handle_to_fd (hd);
+ }
+ return 0;
+}
+
+
+/* Portable function to create a pipe. Under Windows the write end is
+ inheritable (i.e. an rendezvous id). */
+gpg_error_t
+gnupg_create_inbound_pipe (int filedes[2], estream_t *r_fp, int nonblock)
+{
+ if (r_fp)
+ return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+ else
+ return create_inheritable_pipe (filedes, 1);
+}
+
+
+/* Portable function to create a pipe. Under Windows the read end is
+ inheritable (i.e. an rendezvous id). */
+gpg_error_t
+gnupg_create_outbound_pipe (int filedes[2], estream_t *r_fp, int nonblock)
+{
+ if (r_fp)
+ return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+ else
+ return create_inheritable_pipe (filedes, 0);
+}
+
+
+/* Portable function to create a pipe. Under Windows both ends are
+ inheritable. */
+gpg_error_t
+gnupg_create_pipe (int filedes[2])
+{
+ return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+}
+
+
+static int
+create_process (const char *pgmname, const char *cmdline,
+ PROCESS_INFORMATION *pi)
+{
+ int res;
+ wchar_t *wpgmname, *wcmdline;
+
+ wpgmname = utf8_to_wchar (pgmname);
+ if (!wpgmname)
+ return 0;
+ wcmdline = utf8_to_wchar (cmdline);
+ if (!wcmdline)
+ {
+ xfree (wpgmname);
+ return 0;
+ }
+ res = CreateProcess (wpgmname, /* Program to start. */
+ wcmdline, /* Command line arguments. */
+ NULL, /* Process security attributes. */
+ NULL, /* Thread security attributes. */
+ FALSE, /* Inherit handles. */
+ CREATE_SUSPENDED, /* Creation flags. */
+ NULL, /* Environment. */
+ NULL, /* Use current drive/directory. */
+ NULL, /* Startup information. */
+ pi); /* Returns process information. */
+ xfree (wcmdline);
+ xfree (wpgmname);
+ return res;
+}
+
+
+/* Fork and exec the PGMNAME, see exechelp.h for details. */
+gpg_error_t
+gnupg_spawn_process (const char *pgmname, const char *argv[],
+ int *except, void (*preexec)(void), unsigned int flags,
+ estream_t *r_infp,
+ estream_t *r_outfp,
+ estream_t *r_errfp,
+ pid_t *pid)
+{
+ gpg_error_t err;
+ PROCESS_INFORMATION pi = {NULL };
+ char *cmdline;
+ es_syshd_t syshd;
+ struct {
+ HANDLE hd;
+ int rvid;
+ } inpipe = {INVALID_HANDLE_VALUE, 0};
+ struct {
+ HANDLE hd;
+ int rvid;
+ } outpipe = {INVALID_HANDLE_VALUE, 0};
+ struct {
+ HANDLE hd;
+ int rvid;
+ } errpipe = {INVALID_HANDLE_VALUE, 0};
+ estream_t outfp = NULL;
+ estream_t errfp = NULL;
+ gpg_err_source_t errsource = default_errsource;
+
+ (void)except; /* Not yet used. */
+ (void)preexec;
+ (void)flags;
+
+ /* Setup return values. */
+ if (r_outfp)
+ *r_outfp = NULL;
+ if (r_errfp)
+ *r_errfp = NULL;
+ *pid = (pid_t)(-1); /* Always required. */
+
+ log_debug ("%s: enter\n", __func__);
+ if (infp)
+ {
+ es_fflush (infp);
+ es_rewind (infp);
+
+ /* Create a pipe to copy our infile to the stdin of the child
+ process. On success inpipe.hd is owned by the feeder. */
+ inpipe.hd = _assuan_w32ce_prepare_pipe (&inpipe.rvid, 1);
+ if (inpipe.hd == INVALID_HANDLE_VALUE)
+ {
+ log_error ("_assuan_w32ce_prepare_pipe failed: %s\n",
+ w32_strerror (-1));
+ gpg_err_set_errno (EIO);
+ return gpg_error_from_syserror ();
+ }
+ log_debug ("%s: inpipe %p created; hd=%p rvid=%d\n", __func__,
+ infp, inpipe.hd, inpipe.rvid);
+ err = start_feeder (infp, inpipe.hd, 1);
+ if (err)
+ {
+ log_error ("error spawning feeder: %s\n", gpg_strerror (err));
+ CloseHandle (inpipe.hd);
+ return err;
+ }
+ inpipe.hd = INVALID_HANDLE_VALUE; /* Now owned by the feeder. */
+ log_debug ("%s: inpipe %p created; feeder started\n", __func__,
+ infp);
+ }
+
+ if (r_outfp)
+ {
+ /* Create a pipe to make the stdout of the child process
+ available as a stream. */
+ outpipe.hd = _assuan_w32ce_prepare_pipe (&outpipe.rvid, 0);
+ if (outpipe.hd == INVALID_HANDLE_VALUE)
+ {
+ log_error ("_assuan_w32ce_prepare_pipe failed: %s\n",
+ w32_strerror (-1));
+ gpg_err_set_errno (EIO);
+ /* Fixme release other stuff/kill feeder. */
+ return gpg_error_from_syserror ();
+ }
+ syshd.type = ES_SYSHD_HANDLE;
+ syshd.u.handle = outpipe.hd;
+ err = 0;
+ outfp = es_sysopen (&syshd, "r");
+ if (!outfp)
+ {
+ err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
+ log_error ("error opening pipe stream: %s\n", gpg_strerror (err));
+ CloseHandle (outpipe.hd);
+ return err;
+ }
+ log_debug ("%s: outpipe %p created; hd=%p rvid=%d\n", __func__,
+ outfp, outpipe.hd, outpipe.rvid);
+ outpipe.hd = INVALID_HANDLE_VALUE; /* Now owned by the OUTFP. */
+ }
+
+ if (r_errfp)
+ {
+ /* Create a pipe to make the stderr of the child process
+ available as a stream. */
+ errpipe.hd = _assuan_w32ce_prepare_pipe (&errpipe.rvid, 0);
+ if (errpipe.hd == INVALID_HANDLE_VALUE)
+ {
+ log_error ("_assuan_w32ce_prepare_pipe failed: %s\n",
+ w32_strerror (-1));
+ gpg_err_set_errno (EIO);
+ /* Fixme release other stuff/kill feeder. */
+ return gpg_error_from_syserror ();
+ }
+ syshd.type = ES_SYSHD_HANDLE;
+ syshd.u.handle = errpipe.hd;
+ err = 0;
+ errfp = es_sysopen (&syshd, "r");
+ if (!errfp)
+ {
+ err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
+ log_error ("error opening pipe stream: %s\n", gpg_strerror (err));
+ CloseHandle (errpipe.hd);
+ return err;
+ }
+ log_debug ("%s: errpipe %p created; hd=%p rvid=%d\n", __func__,
+ errfp, errpipe.hd, errpipe.rvid);
+ errpipe.hd = INVALID_HANDLE_VALUE; /* Now owned by the ERRFP. */
+ }
+
+
+
+ /* Build the command line. */
+ err = build_w32_commandline (argv, inpipe.rvid, outpipe.rvid, errpipe.rvid,
+ &cmdline);
+ if (err)
+ {
+ /* Fixme release other stuff/kill feeder. */
+ CloseHandle (errpipe.hd);
+ return err;
+ }
+
+ log_debug ("CreateProcess, path='%s' cmdline='%s'\n", pgmname, cmdline);
+ if (!create_process (pgmname, cmdline, &pi))
+ {
+ log_error ("CreateProcess failed: %s\n", w32_strerror (-1));
+ xfree (cmdline);
+ /* Fixme release other stuff/kill feeder. */
+ CloseHandle (errpipe.hd);
+ return gpg_error (GPG_ERR_GENERAL);
+ }
+ xfree (cmdline);
+ cmdline = NULL;
+
+ /* Note: The other end of the pipe is a rendezvous id and thus there
+ is no need for a close. */
+
+ log_debug ("CreateProcess ready: hProcess=%p hThread=%p"
+ " dwProcessID=%d dwThreadId=%d\n",
+ pi.hProcess, pi.hThread,
+ (int) pi.dwProcessId, (int) pi.dwThreadId);
+
+
+ /* Process has been created suspended; resume it now. */
+ ResumeThread (pi.hThread);
+ CloseHandle (pi.hThread);
+
+ if (r_outfp)
+ *r_outfp = outfp;
+ if (r_errfp)
+ *r_errfp = errfp;
+ *pid = handle_to_pid (pi.hProcess);
+ return 0;
+}
+
+
+
+/* Simplified version of gnupg_spawn_process. This function forks and
+ then execs PGMNAME, while connecting INFD to stdin, OUTFD to stdout
+ and ERRFD to stderr (any of them may be -1 to connect them to
+ /dev/null). The arguments for the process are expected in the NULL
+ terminated array ARGV. The program name itself should not be
+ included there. Calling gnupg_wait_process is required.
+
+ Returns 0 on success or an error code. */
+gpg_error_t
+gnupg_spawn_process_fd (const char *pgmname, const char *argv[],
+ int infd, int outfd, int errfd, pid_t *pid)
+{
+ gpg_error_t err;
+ PROCESS_INFORMATION pi = {NULL};
+ char *cmdline;
+
+ /* Setup return values. */
+ *pid = (pid_t)(-1);
+
+ if (infd != -1 || outfd != -1 || errfd != -1)
+ return gpg_error (GPG_ERR_NOT_SUPPORTED);
+
+ /* Build the command line. */
+ err = build_w32_commandline (argv, 0, 0, 0, &cmdline);
+ if (err)
+ return err;
+
+ log_debug ("CreateProcess, path='%s' cmdline='%s'\n", pgmname, cmdline);
+ if (!create_process (pgmname, cmdline, &pi))
+ {
+ log_error ("CreateProcess(fd) failed: %s\n", w32_strerror (-1));
+ xfree (cmdline);
+ return gpg_error (GPG_ERR_GENERAL);
+ }
+ xfree (cmdline);
+ cmdline = NULL;
+
+ log_debug ("CreateProcess(fd) ready: hProcess=%p hThread=%p"
+ " dwProcessID=%d dwThreadId=%d\n",
+ pi.hProcess, pi.hThread,
+ (int) pi.dwProcessId, (int) pi.dwThreadId);
+
+ /* Process has been created suspended; resume it now. */
+ ResumeThread (pi.hThread);
+ CloseHandle (pi.hThread);
+
+ *pid = handle_to_pid (pi.hProcess);
+ return 0;
+}
+
+
+/* See exechelp.h for a description. */
+gpg_error_t
+gnupg_wait_process (const char *pgmname, pid_t pid, int hang, int *exitcode)
+{
+ gpg_err_code_t ec;
+ HANDLE proc = fd_to_handle (pid);
+ int code;
+ DWORD exc;
+
+ if (exitcode)
+ *exitcode = -1;
+
+ if (pid == (pid_t)(-1))
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ /* FIXME: We should do a pth_waitpid here. However this has not yet
+ been implemented. A special W32 pth system call would even be
+ better. */
+ code = WaitForSingleObject (proc, hang? INFINITE : 0);
+ switch (code)
+ {
+ case WAIT_TIMEOUT:
+ ec = GPG_ERR_TIMEOUT;
+ break;
+
+ case WAIT_FAILED:
+ log_error (_("waiting for process %d to terminate failed: %s\n"),
+ (int)pid, w32_strerror (-1));
+ ec = GPG_ERR_GENERAL;
+ break;
+
+ case WAIT_OBJECT_0:
+ if (!GetExitCodeProcess (proc, &exc))
+ {
+ log_error (_("error getting exit code of process %d: %s\n"),
+ (int)pid, w32_strerror (-1) );
+ ec = GPG_ERR_GENERAL;
+ }
+ else if (exc)
+ {
+ log_error (_("error running '%s': exit status %d\n"),
+ pgmname, (int)exc );
+ if (exitcode)
+ *exitcode = (int)exc;
+ ec = GPG_ERR_GENERAL;
+ }
+ else
+ {
+ if (exitcode)
+ *exitcode = 0;
+ ec = 0;
+ }
+ break;
+
+ default:
+ log_error ("WaitForSingleObject returned unexpected "
+ "code %d for pid %d\n", code, (int)pid );
+ ec = GPG_ERR_GENERAL;
+ break;
+ }
+
+ return gpg_err_make (GPG_ERR_SOURCE_DEFAULT, ec);
+}
+
+
+/* See exechelp.h for a description. */
+gpg_error_t
+gnupg_wait_processes (const char **pgmnames, pid_t *pids, size_t count,
+ int hang, int *r_exitcodes)
+{
+ return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+}
+
+
+void
+gnupg_release_process (pid_t pid)
+{
+ if (pid != (pid_t)INVALID_HANDLE_VALUE)
+ {
+ HANDLE process = (HANDLE)pid;
+
+ CloseHandle (process);
+ }
+}
+
+
+/* Spawn a new process and immediately detach from it. The name of
+ the program to exec is PGMNAME and its arguments are in ARGV (the
+ programname is automatically passed as first argument).
+ Environment strings in ENVP are set. An error is returned if
+ pgmname is not executable; to make this work it is necessary to
+ provide an absolute file name. All standard file descriptors are
+ connected to /dev/null. */
+gpg_error_t
+gnupg_spawn_process_detached (const char *pgmname, const char *argv[],
+ const char *envp[] )
+{
+ gpg_error_t err;
+ char *cmdline;
+ PROCESS_INFORMATION pi = {NULL };
+
+ (void)envp;
+
+ /* Build the command line. */
+ err = build_w32_commandline (argv, 0, 0, 0, &cmdline);
+ if (err)
+ return err;
+
+ /* Note: There is no detached flag under CE. */
+ log_debug ("CreateProcess, path='%s' cmdline='%s'\n", pgmname, cmdline);
+ if (!create_process (pgmname, cmdline, &pi))
+ {
+ log_error ("CreateProcess(detached) failed: %s\n", w32_strerror (-1));
+ xfree (cmdline);
+ return gpg_error (GPG_ERR_GENERAL);
+ }
+ xfree (cmdline);
+ cmdline = NULL;
+
+ log_debug ("CreateProcess(detached) ready: hProcess=%p hThread=%p"
+ " dwProcessID=%d dwThreadId=%d\n",
+ pi.hProcess, pi.hThread,
+ (int) pi.dwProcessId, (int) pi.dwThreadId);
+
+ /* Process has been created suspended; resume it now. */
+ ResumeThread (pi.hThread);
+ CloseHandle (pi.hThread);
+
+ return 0;
+}
+
+
+/* Kill a process; that is send an appropriate signal to the process.
+ gnupg_wait_process must be called to actually remove the process
+ from the system. An invalid PID is ignored. */
+void
+gnupg_kill_process (pid_t pid)
+{
+ if (pid != (pid_t) INVALID_HANDLE_VALUE)
+ {
+ HANDLE process = (HANDLE) pid;
+
+ /* Arbitrary error code. */
+ TerminateProcess (process, 1);
+ }
+}
diff --git a/common/exechelp.h b/common/exechelp.h
new file mode 100644
index 0000000..1240fde
--- /dev/null
+++ b/common/exechelp.h
@@ -0,0 +1,207 @@
+/* exechelp.h - Definitions for the fork and exec helpers
+ * Copyright (C) 2004, 2009, 2010 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_COMMON_EXECHELP_H
+#define GNUPG_COMMON_EXECHELP_H
+
+
+/* Return the maximum number of currently allowed file descriptors.
+ Only useful on POSIX systems. */
+int get_max_fds (void);
+
+
+/* Close all file descriptors starting with descriptor FIRST. If
+ EXCEPT is not NULL, it is expected to be a list of file descriptors
+ which are not to close. This list shall be sorted in ascending
+ order with its end marked by -1. */
+void close_all_fds (int first, int *except);
+
+
+/* Returns an array with all currently open file descriptors. The end
+ of the array is marked by -1. The caller needs to release this
+ array using the *standard free* and not with xfree. This allow the
+ use of this function right at startup even before libgcrypt has
+ been initialized. Returns NULL on error and sets ERRNO accordingly. */
+int *get_all_open_fds (void);
+
+
+/* Portable function to create a pipe. Under Windows the write end is
+ inheritable. If R_FP is not NULL, an estream is created for the
+ write end and stored at R_FP. */
+gpg_error_t gnupg_create_inbound_pipe (int filedes[2],
+ estream_t *r_fp, int nonblock);
+
+/* Portable function to create a pipe. Under Windows the read end is
+ inheritable. If R_FP is not NULL, an estream is created for the
+ write end and stored at R_FP. */
+gpg_error_t gnupg_create_outbound_pipe (int filedes[2],
+ estream_t *r_fp, int nonblock);
+
+/* Portable function to create a pipe. Under Windows both ends are
+ inheritable. */
+gpg_error_t gnupg_create_pipe (int filedes[2]);
+
+
+#define GNUPG_SPAWN_NONBLOCK 16
+#define GNUPG_SPAWN_RUN_ASFW 64
+#define GNUPG_SPAWN_DETACHED 128
+#define GNUPG_SPAWN_KEEP_STDIN 256
+#define GNUPG_SPAWN_KEEP_STDOUT 512
+#define GNUPG_SPAWN_KEEP_STDERR 1024
+
+/* Fork and exec the program PGMNAME.
+
+ If R_INFP is NULL connect stdin of the new process to /dev/null; if
+ it is not NULL store the address of a pointer to a new estream
+ there. If R_OUTFP is NULL connect stdout of the new process to
+ /dev/null; if it is not NULL store the address of a pointer to a
+ new estream there. If R_ERRFP is NULL connect stderr of the new
+ process to /dev/null; if it is not NULL store the address of a
+ pointer to a new estream there. On success the pid of the new
+ process is stored at PID. On error -1 is stored at PID and if
+ R_OUTFP or R_ERRFP are not NULL, NULL is stored there.
+
+ The arguments for the process are expected in the NULL terminated
+ array ARGV. The program name itself should not be included there.
+ If PREEXEC is not NULL, the given function will be called right
+ before the exec.
+
+ IF EXCEPT is not NULL, it is expected to be an ordered list of file
+ descriptors, terminated by an entry with the value (-1). These
+ file descriptors won't be closed before spawning a new program.
+
+ Returns 0 on success or an error code. Calling gnupg_wait_process
+ and gnupg_release_process is required if the function succeeded.
+
+ FLAGS is a bit vector:
+
+ GNUPG_SPAWN_NONBLOCK
+ If set the two output streams are created in non-blocking
+ mode and the input stream is switched to non-blocking mode.
+ This is merely a convenience feature because the caller
+ could do the same with gpgrt_set_nonblock. Does not yet
+ work for Windows.
+
+ GNUPG_SPAWN_DETACHED
+ If set the process will be started as a background process.
+ This flag is only useful under W32 (but not W32CE) systems,
+ so that no new console is created and pops up a console
+ window when starting the server. Does not work on W32CE.
+
+ GNUPG_SPAWN_RUN_ASFW
+ On W32 (but not on W32CE) run AllowSetForegroundWindow for
+ the child. Note that due to unknown problems this actually
+ allows SetForegroundWindow for all children of this process.
+
+ GNUPG_SPAWN_KEEP_STDIN
+ GNUPG_SPAWN_KEEP_STDOUT
+ GNUPG_SPAWN_KEEP_STDERR
+ Do not assign /dev/null to a non-required standard file
+ descriptor.
+
+ */
+gpg_error_t
+gnupg_spawn_process (const char *pgmname, const char *argv[],
+ int *execpt, void (*preexec)(void), unsigned int flags,
+ estream_t *r_infp,
+ estream_t *r_outfp,
+ estream_t *r_errfp,
+ pid_t *pid);
+
+
+/* Simplified version of gnupg_spawn_process. This function forks and
+ then execs PGMNAME, while connecting INFD to stdin, OUTFD to stdout
+ and ERRFD to stderr (any of them may be -1 to connect them to
+ /dev/null). The arguments for the process are expected in the NULL
+ terminated array ARGV. The program name itself should not be
+ included there. Calling gnupg_wait_process and
+ gnupg_release_process is required. Returns 0 on success or an
+ error code. */
+gpg_error_t gnupg_spawn_process_fd (const char *pgmname,
+ const char *argv[],
+ int infd, int outfd, int errfd,
+ pid_t *pid);
+
+
+/* If HANG is true, waits for the process identified by PID to exit;
+ if HANG is false, checks whether the process has terminated.
+ PGMNAME should be the same as supplied to the spawn function and is
+ only used for diagnostics. Return values:
+
+ 0
+ The process exited successful. 0 is stored at R_EXITCODE.
+
+ GPG_ERR_GENERAL
+ The process exited without success. The exit code of process
+ is then stored at R_EXITCODE. An exit code of -1 indicates
+ that the process terminated abnormally (e.g. due to a signal).
+
+ GPG_ERR_TIMEOUT
+ The process is still running (returned only if HANG is false).
+
+ GPG_ERR_INV_VALUE
+ An invalid PID has been specified.
+
+ Other error codes may be returned as well. Unless otherwise noted,
+ -1 will be stored at R_EXITCODE. R_EXITCODE may be passed as NULL
+ if the exit code is not required (in that case an error message will
+ be printed). Note that under Windows PID is not the process id but
+ the handle of the process. */
+gpg_error_t gnupg_wait_process (const char *pgmname, pid_t pid, int hang,
+ int *r_exitcode);
+
+/* Like gnupg_wait_process, but for COUNT processes. */
+gpg_error_t gnupg_wait_processes (const char **pgmnames, pid_t *pids,
+ size_t count, int hang, int *r_exitcodes);
+
+
+/* Kill a process; that is send an appropriate signal to the process.
+ gnupg_wait_process must be called to actually remove the process
+ from the system. An invalid PID is ignored. */
+void gnupg_kill_process (pid_t pid);
+
+/* Release the process identified by PID. This function is actually
+ only required for Windows but it does not harm to always call it.
+ It is a nop if PID is invalid. */
+void gnupg_release_process (pid_t pid);
+
+
+/* Spawn a new process and immediately detach from it. The name of
+ the program to exec is PGMNAME and its arguments are in ARGV (the
+ programname is automatically passed as first argument).
+ Environment strings in ENVP are set. An error is returned if
+ pgmname is not executable; to make this work it is necessary to
+ provide an absolute file name. */
+gpg_error_t gnupg_spawn_process_detached (const char *pgmname,
+ const char *argv[],
+ const char *envp[] );
+
+
+
+#endif /*GNUPG_COMMON_EXECHELP_H*/
diff --git a/common/exectool.c b/common/exectool.c
new file mode 100644
index 0000000..3458de4
--- /dev/null
+++ b/common/exectool.c
@@ -0,0 +1,650 @@
+/* exectool.c - Utility functions to execute a helper tool
+ * Copyright (C) 2015 Werner Koch
+ * Copyright (C) 2016 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <assert.h>
+#include <gpg-error.h>
+
+#include <assuan.h>
+#include "i18n.h"
+#include "logging.h"
+#include "membuf.h"
+#include "mischelp.h"
+#include "exechelp.h"
+#include "sysutils.h"
+#include "util.h"
+#include "exectool.h"
+
+typedef struct
+{
+ const char *pgmname;
+ exec_tool_status_cb_t status_cb;
+ void *status_cb_value;
+ int cont;
+ size_t used;
+ size_t buffer_size;
+ char *buffer;
+} read_and_log_buffer_t;
+
+
+static inline gpg_error_t
+my_error_from_syserror (void)
+{
+ return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
+}
+
+
+static void
+read_and_log_stderr (read_and_log_buffer_t *state, es_poll_t *fderr)
+{
+ gpg_error_t err;
+ int c;
+
+ if (!fderr)
+ {
+ /* Flush internal buffer. */
+ if (state->used)
+ {
+ const char *pname;
+ int len;
+
+ state->buffer[state->used] = 0;
+ state->used = 0;
+
+ pname = strrchr (state->pgmname, '/');
+ if (pname && pname != state->pgmname && pname[1])
+ pname++;
+ else
+ pname = state->pgmname;
+ len = strlen (pname);
+
+ if (state->status_cb
+ && !strncmp (state->buffer, "[GNUPG:] ", 9)
+ && state->buffer[9] >= 'A' && state->buffer[9] <= 'Z')
+ {
+ char *rest;
+
+ rest = strchr (state->buffer + 9, ' ');
+ if (!rest)
+ {
+ /* Set REST to an empty string. */
+ rest = state->buffer + strlen (state->buffer);
+ }
+ else
+ {
+ *rest++ = 0;
+ trim_spaces (rest);
+ }
+ state->status_cb (state->status_cb_value,
+ state->buffer + 9, rest);
+ }
+ else if (!state->cont
+ && !strncmp (state->buffer, pname, len)
+ && strlen (state->buffer) > strlen (pname)
+ && state->buffer[len] == ':' )
+ {
+ /* PGMNAME plus colon is identical to the start of
+ the output: print only the output. */
+ log_info ("%s\n", state->buffer);
+ }
+ else
+ log_info ("%s%c %s\n",
+ pname, state->cont? '+':':', state->buffer);
+ }
+ state->cont = 0;
+ return;
+ }
+ for (;;)
+ {
+ c = es_fgetc (fderr->stream);
+ if (c == EOF)
+ {
+ if (es_feof (fderr->stream))
+ {
+ fderr->ignore = 1; /* Not anymore needed. */
+ }
+ else if (es_ferror (fderr->stream))
+ {
+ err = my_error_from_syserror ();
+ log_error ("error reading stderr of '%s': %s\n",
+ state->pgmname, gpg_strerror (err));
+ fderr->ignore = 1; /* Disable. */
+ }
+
+ break;
+ }
+ else if (c == '\n')
+ {
+ read_and_log_stderr (state, NULL);
+ }
+ else
+ {
+ if (state->used >= state->buffer_size - 1)
+ {
+ if (state->status_cb)
+ {
+ /* A status callback requires that we have a full
+ * line. Thus we need to enlarget the buffer in
+ * this case. */
+ char *newbuffer;
+ size_t newsize = state->buffer_size + 256;
+
+ newbuffer = xtrymalloc (newsize);
+ if (!newbuffer)
+ {
+ log_error ("error allocating memory for status cb: %s\n",
+ gpg_strerror (my_error_from_syserror ()));
+ /* We better disable the status CB in this case. */
+ state->status_cb = NULL;
+ read_and_log_stderr (state, NULL);
+ state->cont = 1;
+ }
+ else
+ {
+ memcpy (newbuffer, state->buffer, state->used);
+ xfree (state->buffer);
+ state->buffer = newbuffer;
+ state->buffer_size = newsize;
+ }
+ }
+ else
+ {
+ read_and_log_stderr (state, NULL);
+ state->cont = 1;
+ }
+ }
+ state->buffer[state->used++] = c;
+ }
+ }
+}
+
+
+
+/* A buffer to copy from one stream to another. */
+struct copy_buffer
+{
+ char buffer[4096];
+ char *writep;
+ size_t nread;
+};
+
+
+/* Initialize a copy buffer. */
+static void
+copy_buffer_init (struct copy_buffer *c)
+{
+ c->writep = c->buffer;
+ c->nread = 0;
+}
+
+
+/* Securely wipe a copy buffer. */
+static void
+copy_buffer_shred (struct copy_buffer *c)
+{
+ if (c == NULL)
+ return;
+ wipememory (c->buffer, sizeof c->buffer);
+ c->writep = NULL;
+ c->nread = ~0U;
+}
+
+
+/* Copy data from SOURCE to SINK using copy buffer C. */
+static gpg_error_t
+copy_buffer_do_copy (struct copy_buffer *c, estream_t source, estream_t sink)
+{
+ gpg_error_t err;
+ size_t nwritten = 0;
+
+ if (c->nread == 0)
+ {
+ c->writep = c->buffer;
+ if (es_read (source, c->buffer, sizeof c->buffer, &c->nread))
+ {
+ err = my_error_from_syserror ();
+ if (gpg_err_code (err) == GPG_ERR_EAGAIN)
+ return 0; /* We will just retry next time. */
+
+ return err;
+ }
+
+ log_assert (c->nread <= sizeof c->buffer);
+ }
+
+ if (c->nread == 0)
+ return 0; /* Done copying. */
+
+ nwritten = 0;
+ if (sink && es_write (sink, c->writep, c->nread, &nwritten))
+ err = my_error_from_syserror ();
+ else
+ err = 0;
+
+ log_assert (nwritten <= c->nread);
+ c->writep += nwritten;
+ c->nread -= nwritten;
+ log_assert (c->writep - c->buffer <= sizeof c->buffer);
+
+ if (err)
+ {
+ if (gpg_err_code (err) == GPG_ERR_EAGAIN)
+ return 0; /* We will just retry next time. */
+
+ return err;
+ }
+
+ if (sink && es_fflush (sink) && errno != EAGAIN)
+ err = my_error_from_syserror ();
+
+ return err;
+}
+
+
+/* Flush the remaining data to SINK. */
+static gpg_error_t
+copy_buffer_flush (struct copy_buffer *c, estream_t sink)
+{
+ gpg_error_t err = 0;
+ size_t nwritten = 0;
+
+ if (es_write (sink, c->writep, c->nread, &nwritten))
+ err = my_error_from_syserror ();
+
+ log_assert (nwritten <= c->nread);
+ c->writep += nwritten;
+ c->nread -= nwritten;
+ log_assert (c->writep - c->buffer <= sizeof c->buffer);
+
+ if (err)
+ return err;
+
+ if (es_fflush (sink))
+ err = my_error_from_syserror ();
+
+ return err;
+}
+
+
+
+/* Run the program PGMNAME with the command line arguments given in
+ * the NULL terminates array ARGV. If INPUT is not NULL it will be
+ * fed to stdin of the process. stderr is logged using log_info and
+ * the process' stdout is written to OUTPUT. If OUTPUT is NULL the
+ * output is discarded. If INEXTRA is given, an additional input
+ * stream will be passed to the child; to tell the child about this
+ * ARGV is scanned and the first occurrence of an argument
+ * "-&@INEXTRA@" is replaced by the concatenation of "-&" and the
+ * child's file descriptor of the pipe created for the INEXTRA stream.
+ *
+ * On error a diagnostic is printed and an error code returned. */
+gpg_error_t
+gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
+ estream_t input, estream_t inextra,
+ estream_t output,
+ exec_tool_status_cb_t status_cb,
+ void *status_cb_value)
+{
+ gpg_error_t err;
+ pid_t pid = (pid_t) -1;
+ estream_t infp = NULL;
+ estream_t extrafp = NULL;
+ estream_t outfp = NULL, errfp = NULL;
+ es_poll_t fds[4];
+ int exceptclose[2];
+ int extrapipe[2] = {-1, -1};
+ char extrafdbuf[20];
+ const char *argsave = NULL;
+ int argsaveidx;
+ int count;
+ read_and_log_buffer_t fderrstate;
+ struct copy_buffer *cpbuf_in = NULL, *cpbuf_out = NULL, *cpbuf_extra = NULL;
+
+ memset (fds, 0, sizeof fds);
+ memset (&fderrstate, 0, sizeof fderrstate);
+
+ cpbuf_in = xtrymalloc (sizeof *cpbuf_in);
+ if (cpbuf_in == NULL)
+ {
+ err = my_error_from_syserror ();
+ goto leave;
+ }
+ copy_buffer_init (cpbuf_in);
+
+ cpbuf_out = xtrymalloc (sizeof *cpbuf_out);
+ if (cpbuf_out == NULL)
+ {
+ err = my_error_from_syserror ();
+ goto leave;
+ }
+ copy_buffer_init (cpbuf_out);
+
+ cpbuf_extra = xtrymalloc (sizeof *cpbuf_extra);
+ if (cpbuf_extra == NULL)
+ {
+ err = my_error_from_syserror ();
+ goto leave;
+ }
+ copy_buffer_init (cpbuf_extra);
+
+ fderrstate.pgmname = pgmname;
+ fderrstate.status_cb = status_cb;
+ fderrstate.status_cb_value = status_cb_value;
+ fderrstate.buffer_size = 256;
+ fderrstate.buffer = xtrymalloc (fderrstate.buffer_size);
+ if (!fderrstate.buffer)
+ {
+ err = my_error_from_syserror ();
+ goto leave;
+ }
+
+ if (inextra)
+ {
+ err = gnupg_create_outbound_pipe (extrapipe, &extrafp, 1);
+ if (err)
+ {
+ log_error ("error running outbound pipe for extra fp: %s\n",
+ gpg_strerror (err));
+ goto leave;
+ }
+ exceptclose[0] = extrapipe[0]; /* Do not close in child. */
+ exceptclose[1] = -1;
+ /* Now find the argument marker and replace by the pipe's fd.
+ Yeah, that is an ugly non-thread safe hack but it safes us to
+ create a copy of the array. */
+#ifdef HAVE_W32_SYSTEM
+ snprintf (extrafdbuf, sizeof extrafdbuf, "-&%lu",
+ (unsigned long)(void*)_get_osfhandle (extrapipe[0]));
+#else
+ snprintf (extrafdbuf, sizeof extrafdbuf, "-&%d", extrapipe[0]);
+#endif
+ for (argsaveidx=0; argv[argsaveidx]; argsaveidx++)
+ if (!strcmp (argv[argsaveidx], "-&@INEXTRA@"))
+ {
+ argsave = argv[argsaveidx];
+ argv[argsaveidx] = extrafdbuf;
+ break;
+ }
+ }
+ else
+ exceptclose[0] = -1;
+
+ err = gnupg_spawn_process (pgmname, argv,
+ exceptclose, NULL, GNUPG_SPAWN_NONBLOCK,
+ input? &infp : NULL,
+ &outfp, &errfp, &pid);
+ if (extrapipe[0] != -1)
+ close (extrapipe[0]);
+ if (argsave)
+ argv[argsaveidx] = argsave;
+ if (err)
+ {
+ log_error ("error running '%s': %s\n", pgmname, gpg_strerror (err));
+ goto leave;
+ }
+
+ fds[0].stream = infp;
+ fds[0].want_write = 1;
+ if (!input)
+ fds[0].ignore = 1;
+ fds[1].stream = outfp;
+ fds[1].want_read = 1;
+ fds[2].stream = errfp;
+ fds[2].want_read = 1;
+ fds[3].stream = extrafp;
+ fds[3].want_write = 1;
+ if (!inextra)
+ fds[3].ignore = 1;
+
+ /* Now read as long as we have something to poll. We continue
+ reading even after EOF or error on stdout so that we get the
+ other error messages or remaining output. */
+ while (! (fds[1].ignore && fds[2].ignore))
+ {
+ count = es_poll (fds, DIM(fds), -1);
+ if (count == -1)
+ {
+ err = my_error_from_syserror ();
+ log_error ("error polling '%s': %s\n", pgmname, gpg_strerror (err));
+ goto leave;
+ }
+ if (!count)
+ {
+ log_debug ("unexpected timeout while polling '%s'\n", pgmname);
+ break;
+ }
+
+ if (fds[0].got_write)
+ {
+ err = copy_buffer_do_copy (cpbuf_in, input, fds[0].stream);
+ if (err)
+ {
+ log_error ("error feeding data to '%s': %s\n",
+ pgmname, gpg_strerror (err));
+ goto leave;
+ }
+
+ if (es_feof (input))
+ {
+ err = copy_buffer_flush (cpbuf_in, fds[0].stream);
+ if (gpg_err_code (err) == GPG_ERR_EAGAIN)
+ continue; /* Retry next time. */
+ if (err)
+ {
+ log_error ("error feeding data to '%s': %s\n",
+ pgmname, gpg_strerror (err));
+ goto leave;
+ }
+
+ fds[0].ignore = 1; /* ready. */
+ es_fclose (infp); infp = NULL;
+ }
+ }
+
+ if (fds[3].got_write)
+ {
+ log_assert (inextra);
+ err = copy_buffer_do_copy (cpbuf_extra, inextra, fds[3].stream);
+ if (err)
+ {
+ log_error ("error feeding data to '%s': %s\n",
+ pgmname, gpg_strerror (err));
+ goto leave;
+ }
+
+ if (es_feof (inextra))
+ {
+ err = copy_buffer_flush (cpbuf_extra, fds[3].stream);
+ if (gpg_err_code (err) == GPG_ERR_EAGAIN)
+ continue; /* Retry next time. */
+ if (err)
+ {
+ log_error ("error feeding data to '%s': %s\n",
+ pgmname, gpg_strerror (err));
+ goto leave;
+ }
+
+ fds[3].ignore = 1; /* ready. */
+ es_fclose (extrafp); extrafp = NULL;
+ }
+ }
+
+ if (fds[1].got_read)
+ {
+ err = copy_buffer_do_copy (cpbuf_out, fds[1].stream, output);
+ if (err)
+ {
+ log_error ("error reading data from '%s': %s\n",
+ pgmname, gpg_strerror (err));
+ goto leave;
+ }
+
+ if (es_feof (fds[1].stream))
+ {
+ err = copy_buffer_flush (cpbuf_out, output);
+ if (err)
+ {
+ log_error ("error reading data from '%s': %s\n",
+ pgmname, gpg_strerror (err));
+ goto leave;
+ }
+
+ fds[1].ignore = 1; /* ready. */
+ }
+ }
+
+ if (fds[2].got_read)
+ read_and_log_stderr (&fderrstate, fds + 2);
+ }
+
+ read_and_log_stderr (&fderrstate, NULL); /* Flush. */
+ es_fclose (infp); infp = NULL;
+ es_fclose (extrafp); extrafp = NULL;
+ es_fclose (outfp); outfp = NULL;
+ es_fclose (errfp); errfp = NULL;
+
+ err = gnupg_wait_process (pgmname, pid, 1, NULL);
+ pid = (pid_t)(-1);
+
+ leave:
+ if (err && pid != (pid_t) -1)
+ gnupg_kill_process (pid);
+
+ es_fclose (infp);
+ es_fclose (extrafp);
+ es_fclose (outfp);
+ es_fclose (errfp);
+ if (pid != (pid_t)(-1))
+ gnupg_wait_process (pgmname, pid, 1, NULL);
+ gnupg_release_process (pid);
+
+ copy_buffer_shred (cpbuf_in);
+ xfree (cpbuf_in);
+ copy_buffer_shred (cpbuf_out);
+ xfree (cpbuf_out);
+ copy_buffer_shred (cpbuf_extra);
+ xfree (cpbuf_extra);
+ xfree (fderrstate.buffer);
+ return err;
+}
+
+
+/* A dummy free function to pass to 'es_mopen'. */
+static void
+nop_free (void *ptr)
+{
+ (void) ptr;
+}
+
+/* Run the program PGMNAME with the command line arguments given in
+ the NULL terminates array ARGV. If INPUT_STRING is not NULL it
+ will be fed to stdin of the process. stderr is logged using
+ log_info and the process' stdout is returned in a newly malloced
+ buffer RESULT with the length stored at RESULTLEN if not given as
+ NULL. A hidden Nul is appended to the output. On error NULL is
+ stored at RESULT, a diagnostic is printed, and an error code
+ returned. */
+gpg_error_t
+gnupg_exec_tool (const char *pgmname, const char *argv[],
+ const char *input_string,
+ char **result, size_t *resultlen)
+{
+ gpg_error_t err;
+ estream_t input = NULL;
+ estream_t output;
+ size_t len;
+ size_t nread;
+
+ *result = NULL;
+ if (resultlen)
+ *resultlen = 0;
+
+ if (input_string)
+ {
+ len = strlen (input_string);
+ input = es_mopen ((char *) input_string, len, len,
+ 0 /* don't grow */, NULL, nop_free, "rb");
+ if (! input)
+ return my_error_from_syserror ();
+ }
+
+ output = es_fopenmem (0, "wb");
+ if (! output)
+ {
+ err = my_error_from_syserror ();
+ goto leave;
+ }
+
+ err = gnupg_exec_tool_stream (pgmname, argv, input, NULL, output, NULL, NULL);
+ if (err)
+ goto leave;
+
+ len = es_ftello (output);
+ err = es_fseek (output, 0, SEEK_SET);
+ if (err)
+ goto leave;
+
+ *result = xtrymalloc (len + 1);
+ if (!*result)
+ {
+ err = my_error_from_syserror ();
+ goto leave;
+ }
+
+ if (len)
+ {
+ if (es_read (output, *result, len, &nread))
+ {
+ err = my_error_from_syserror ();
+ goto leave;
+ }
+ if (nread != len)
+ log_fatal ("%s: short read from memstream\n", __func__);
+ }
+ (*result)[len] = 0;
+
+ if (resultlen)
+ *resultlen = len;
+
+ leave:
+ es_fclose (input);
+ es_fclose (output);
+ if (err)
+ {
+ xfree (*result);
+ *result = NULL;
+ }
+ return err;
+}
diff --git a/common/exectool.h b/common/exectool.h
new file mode 100644
index 0000000..27bbfc9
--- /dev/null
+++ b/common/exectool.h
@@ -0,0 +1,69 @@
+/* sh-exectool.h - Utility functions to execute a helper tool
+ * Copyright (C) 2015 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_COMMON_EXECTOOL_H
+#define GNUPG_COMMON_EXECTOOL_H
+
+#include <gpg-error.h>
+
+/* This callback can be used to process --status-fd outputs of GnuPG
+ * tools. OPAQUE can be used to communicate between the caller of the
+ * function and the callback. KEYWORD is the status keyword (see
+ * doc/DETAILS); it is never NULL. ARGS are the arguments of the
+ * status line and will also never be NULL; the caller may modify this
+ * string. */
+typedef void (*exec_tool_status_cb_t) (void *opaque,
+ const char *keyword,
+ char *args);
+
+
+/* Run the program PGMNAME with the command line arguments given in
+ the NULL terminates array ARGV. If INPUT_STRING is not NULL it
+ will be fed to stdin of the process. stderr is logged using
+ log_info and the process' stdout is returned in a newly malloced
+ buffer RESULT with the length stored at RESULTLEN if not given as
+ NULL. A hidden Nul is appended to the output. On error NULL is
+ stored at RESULT, a diagnostic is printed, and an error code
+ returned. */
+gpg_error_t gnupg_exec_tool (const char *pgmname, const char *argv[],
+ const char *input_string,
+ char **result, size_t *resultlen);
+
+/* Run the program PGMNAME with the command line arguments given in
+ the NULL terminates array ARGV. If INPUT is not NULL it will be
+ fed to stdin of the process. stderr is logged using log_info and
+ the process' stdout is written to OUTPUT. On error a diagnostic is
+ printed, and an error code returned. INEXTRA is reserved. */
+gpg_error_t gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
+ estream_t input, estream_t inextra,
+ estream_t output,
+ exec_tool_status_cb_t status_cb,
+ void *status_cb_value);
+
+#endif /* GNUPG_COMMON_EXECTOOL_H */
diff --git a/common/exstatus.awk b/common/exstatus.awk
new file mode 100644
index 0000000..fb13819
--- /dev/null
+++ b/common/exstatus.awk
@@ -0,0 +1,39 @@
+# exstatus.awk - Extract status codes from status.h
+# Copyright (C) 2007 Free Software Foundation, Inc.
+#
+# This file is part of GnuPG.
+#
+# GnuPG is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# GnuPG is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+BEGIN {
+ print "# Created by exstatus.awk - DO NOT EDIT."
+ topheader = 0;
+ code = 0;
+}
+
+topheader == 0 && /^\/\*/ { topheader = 1 }
+topheader == 1 { print $0 }
+topheader == 1 && /\*\// { topheader = 2; print "" }
+
+/^[ \t]+STATUS_[A-Za-z_]+/ {
+ sub (/[,\/\*]+/, "", $1);
+ desc = substr($1,8);
+ printf "%d\t%s\t%s\n", code, $1, desc;
+ code++;
+}
+
+
+END {
+ print "# end of status codes."
+}
diff --git a/common/fwddecl.h b/common/fwddecl.h
new file mode 100644
index 0000000..b945406
--- /dev/null
+++ b/common/fwddecl.h
@@ -0,0 +1,39 @@
+/* fwddecl.h - Forward declarations
+ * Copyright (C) 2015 Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_COMMON_FWDDECL_H
+#define GNUPG_COMMON_FWDDECL_H
+
+
+/*-- Forward declaration of the commonly used server control structure. */
+struct server_control_s;
+typedef struct server_control_s *ctrl_t;
+
+
+#endif /*GNUPG_COMMON_FWDDECL_H*/
diff --git a/common/gc-opt-flags.h b/common/gc-opt-flags.h
new file mode 100644
index 0000000..8458aa0
--- /dev/null
+++ b/common/gc-opt-flags.h
@@ -0,0 +1,42 @@
+/* gc-opt-flags.h - gpgconf constants used by the backends.
+ * Copyright (C) 2004, 2007 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.
+ */
+
+#ifndef GNUPG_GC_OPT_FLAGS_H
+#define GNUPG_GC_OPT_FLAGS_H
+
+/* Public option flags. YOU MUST NOT CHANGE THE NUMBERS OF THE
+ EXISTING FLAGS, AS THEY ARE PART OF THE EXTERNAL INTERFACE. See
+ gnupg/tools/gpgconf-comp.c for details. */
+
+#define GC_OPT_FLAG_NONE 0UL
+
+/* 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)
+
+/* The NO_CHANGE flag for an option indicates that the user should not
+ be allowed to change this option using the standard gpgconf method.
+ Frontends using gpgconf should grey out such options, so that only
+ the current value is displayed. */
+#define GC_OPT_FLAG_NO_CHANGE (1UL <<7)
+
+
+#endif /*GNUPG_GC_OPT_FLAGS_H*/
diff --git a/common/get-passphrase.c b/common/get-passphrase.c
new file mode 100644
index 0000000..c24b40e
--- /dev/null
+++ b/common/get-passphrase.c
@@ -0,0 +1,255 @@
+/* get-passphrase.c - Ask for a passphrase via the agent
+ * Copyright (C) 2009 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <assuan.h>
+
+#include "util.h"
+#include "i18n.h"
+#include "asshelp.h"
+#include "membuf.h"
+#include "sysutils.h"
+#include "get-passphrase.h"
+
+/* The context used by this process to ask for the passphrase. */
+static assuan_context_t agent_ctx;
+static struct
+{
+ gpg_err_source_t errsource;
+ int verbosity;
+ const char *agent_program;
+ const char *lc_ctype;
+ const char *lc_messages;
+ session_env_t session_env;
+ const char *pinentry_user_data;
+} agentargs;
+
+
+/* Set local variable to be used for a possible agent startup. Note
+ that the strings are just pointers and should not anymore be
+ modified by the caller. */
+void
+gnupg_prepare_get_passphrase (gpg_err_source_t errsource,
+ int verbosity,
+ const char *agent_program,
+ const char *opt_lc_ctype,
+ const char *opt_lc_messages,
+ session_env_t session_env)
+{
+ agentargs.errsource = errsource;
+ agentargs.verbosity = verbosity;
+ agentargs.agent_program = agent_program;
+ agentargs.lc_ctype = opt_lc_ctype;
+ agentargs.lc_messages = opt_lc_messages;
+ agentargs.session_env = session_env;
+}
+
+
+/* Try to connect to the agent via socket or fork it off and work by
+ pipes. Handle the server's initial greeting. */
+static gpg_error_t
+start_agent (void)
+{
+ gpg_error_t err;
+
+ /* Fixme: This code is not thread safe, thus we don't build it with
+ pth. We will need a context for each thread or serialize the
+ access to the agent. */
+ if (agent_ctx)
+ return 0;
+
+ err = start_new_gpg_agent (&agent_ctx,
+ agentargs.errsource,
+ agentargs.agent_program,
+ agentargs.lc_ctype,
+ agentargs.lc_messages,
+ agentargs.session_env,
+ 1, agentargs.verbosity, 0, NULL, NULL);
+ if (!err)
+ {
+ /* Tell the agent that we support Pinentry notifications. No
+ error checking so that it will work with older agents. */
+ assuan_transact (agent_ctx, "OPTION allow-pinentry-notify",
+ NULL, NULL, NULL, NULL, NULL, NULL);
+ }
+
+ return err;
+}
+
+
+/* This is the default inquiry callback. It merely handles the
+ Pinentry notification. */
+static gpg_error_t
+default_inq_cb (void *opaque, const char *line)
+{
+ (void)opaque;
+
+ if (!strncmp (line, "PINENTRY_LAUNCHED", 17) && (line[17]==' '||!line[17]))
+ {
+ gnupg_allow_set_foregound_window ((pid_t)strtoul (line+17, NULL, 10));
+ /* We do not return errors to avoid breaking other code. */
+ }
+ else
+ log_debug ("ignoring gpg-agent inquiry '%s'\n", line);
+
+ return 0;
+}
+
+
+/* Ask for a passphrase via gpg-agent. On success the caller needs to
+ free the string stored at R_PASSPHRASE. On error NULL will be
+ stored at R_PASSPHRASE and an appropriate gpg error code is
+ returned. With REPEAT set to 1, gpg-agent will ask the user to
+ repeat the just entered passphrase. CACHE_ID is a gpg-agent style
+ passphrase cache id or NULL. ERR_MSG is a error message to be
+ presented to the user (e.g. "bad passphrase - try again") or NULL.
+ PROMPT is the prompt string to label the entry box, it may be NULL
+ for a default one. DESC_MSG is a longer description to be
+ displayed above the entry box, if may be NULL for a default one.
+ If USE_SECMEM is true, the returned passphrase is returned in
+ secure memory. The length of all these strings is limited; they
+ need to fit in their encoded form into a standard Assuan line (i.e
+ less then about 950 characters). All strings shall be UTF-8. */
+gpg_error_t
+gnupg_get_passphrase (const char *cache_id,
+ const char *err_msg,
+ const char *prompt,
+ const char *desc_msg,
+ int repeat,
+ int check_quality,
+ int use_secmem,
+ char **r_passphrase)
+{
+ gpg_error_t err;
+ char line[ASSUAN_LINELENGTH];
+ const char *arg1 = NULL;
+ char *arg2 = NULL;
+ char *arg3 = NULL;
+ char *arg4 = NULL;
+ membuf_t data;
+
+ *r_passphrase = NULL;
+
+ err = start_agent ();
+ if (err)
+ return err;
+
+ /* Check that the gpg-agent understands the repeat option. */
+ if (assuan_transact (agent_ctx,
+ "GETINFO cmd_has_option GET_PASSPHRASE repeat",
+ NULL, NULL, NULL, NULL, NULL, NULL))
+ return gpg_error (GPG_ERR_NOT_SUPPORTED);
+
+ arg1 = cache_id && *cache_id? cache_id:NULL;
+ if (err_msg && *err_msg)
+ if (!(arg2 = percent_plus_escape (err_msg)))
+ goto no_mem;
+ if (prompt && *prompt)
+ if (!(arg3 = percent_plus_escape (prompt)))
+ goto no_mem;
+ if (desc_msg && *desc_msg)
+ if (!(arg4 = percent_plus_escape (desc_msg)))
+ goto no_mem;
+
+ snprintf (line, DIM(line),
+ "GET_PASSPHRASE --data %s--repeat=%d -- %s %s %s %s",
+ check_quality? "--check ":"",
+ repeat,
+ arg1? arg1:"X",
+ arg2? arg2:"X",
+ arg3? arg3:"X",
+ arg4? arg4:"X");
+ xfree (arg2);
+ xfree (arg3);
+ xfree (arg4);
+
+ if (use_secmem)
+ init_membuf_secure (&data, 64);
+ else
+ init_membuf (&data, 64);
+ err = assuan_transact (agent_ctx, line,
+ put_membuf_cb, &data,
+ default_inq_cb, NULL, NULL, NULL);
+
+ /* Older Pinentries return the old assuan error code for canceled
+ which gets translated by libassuan to GPG_ERR_ASS_CANCELED and
+ not to the code for a user cancel. Fix this here. */
+ if (err && gpg_err_source (err)
+ && gpg_err_code (err) == GPG_ERR_ASS_CANCELED)
+ err = gpg_err_make (gpg_err_source (err), GPG_ERR_CANCELED);
+
+ if (err)
+ {
+ void *p;
+ size_t n;
+
+ p = get_membuf (&data, &n);
+ if (p)
+ wipememory (p, n);
+ xfree (p);
+ }
+ else
+ {
+ put_membuf (&data, "", 1);
+ *r_passphrase = get_membuf (&data, NULL);
+ if (!*r_passphrase)
+ err = gpg_error_from_syserror ();
+ }
+ return err;
+ no_mem:
+ err = gpg_error_from_syserror ();
+ xfree (arg2);
+ xfree (arg3);
+ xfree (arg4);
+ return err;
+}
+
+
+/* Flush the passphrase cache with Id CACHE_ID. */
+gpg_error_t
+gnupg_clear_passphrase (const char *cache_id)
+{
+ gpg_error_t err;
+ char line[ASSUAN_LINELENGTH];
+
+ if (!cache_id || !*cache_id)
+ return 0;
+
+ err = start_agent ();
+ if (err)
+ return err;
+
+ snprintf (line, DIM(line), "CLEAR_PASSPHRASE %s", cache_id);
+ return assuan_transact (agent_ctx, line, NULL, NULL,
+ default_inq_cb, NULL, NULL, NULL);
+}
diff --git a/common/get-passphrase.h b/common/get-passphrase.h
new file mode 100644
index 0000000..afdbe78
--- /dev/null
+++ b/common/get-passphrase.h
@@ -0,0 +1,54 @@
+/* get-passphrase.h - Definitions to ask for a passphrase via the agent.
+ * Copyright (C) 2009 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_COMMON_GET_PASSPHRASE_H
+#define GNUPG_COMMON_GET_PASSPHRASE_H
+
+#include "session-env.h"
+
+void gnupg_prepare_get_passphrase (gpg_err_source_t errsource,
+ int verbosity,
+ const char *agent_program,
+ const char *opt_lc_ctype,
+ const char *opt_lc_messages,
+ session_env_t session_env);
+
+gpg_error_t gnupg_get_passphrase (const char *cache_id,
+ const char *err_msg,
+ const char *prompt,
+ const char *desc_msg,
+ int repeat,
+ int check_quality,
+ int use_secmem,
+ char **r_passphrase);
+
+gpg_error_t gnupg_clear_passphrase (const char *cache_id);
+
+
+#endif /*GNUPG_COMMON_GET_PASSPHRASE_H*/
diff --git a/common/gettime.c b/common/gettime.c
new file mode 100644
index 0000000..3fe30ce
--- /dev/null
+++ b/common/gettime.c
@@ -0,0 +1,1064 @@
+/* gettime.c - Wrapper for time functions
+ * Copyright (C) 1998, 2002, 2007, 2011 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <time.h>
+#include <ctype.h>
+#ifdef HAVE_LOCALE_H
+#include <locale.h>
+#endif
+#ifdef HAVE_LANGINFO_H
+#include <langinfo.h>
+#endif
+
+#include "util.h"
+#include "i18n.h"
+#include "gettime.h"
+
+#ifdef HAVE_UNSIGNED_TIME_T
+# define IS_INVALID_TIME_T(a) ((a) == (time_t)(-1))
+#else
+ /* Error or 32 bit time_t and value after 2038-01-19. */
+# define IS_INVALID_TIME_T(a) ((a) < 0)
+#endif
+
+
+static unsigned long timewarp;
+static enum { NORMAL = 0, FROZEN, FUTURE, PAST } timemode;
+
+/* Correction used to map to real Julian days. */
+#define JD_DIFF 1721060L
+
+
+/* Wrapper for the time(3). We use this here so we can fake the time
+ for tests */
+time_t
+gnupg_get_time ()
+{
+ time_t current = time (NULL);
+ if (current == (time_t)(-1))
+ log_fatal ("time() failed\n");
+
+ if (timemode == NORMAL)
+ return current;
+ else if (timemode == FROZEN)
+ return timewarp;
+ else if (timemode == FUTURE)
+ return current + timewarp;
+ else
+ return current - timewarp;
+}
+
+
+/* Wrapper around gmtime_r.
+
+ On systems without gmtime_r this implementation works within gnupg
+ because we use only one thread a time. FIXME: An independent
+ library may use gmtime in one of its own thread (or via
+ npth_enter/npth_leave) - in this case we run into a problem. The
+ solution would be to use a mutex here. */
+struct tm *
+gnupg_gmtime (const time_t *timep, struct tm *result)
+{
+#ifdef HAVE_GMTIME_R
+ return gmtime_r (timep, result);
+#else
+ struct tm *tp;
+
+ tp = gmtime (timep);
+ if (tp)
+ memcpy (result, tp, sizeof *result);
+ return tp;
+#endif
+}
+
+
+/* Return the current time (possibly faked) in ISO format. */
+void
+gnupg_get_isotime (gnupg_isotime_t timebuf)
+{
+ time_t atime = gnupg_get_time ();
+ struct tm *tp;
+ struct tm tmbuf;
+
+ tp = gnupg_gmtime (&atime, &tmbuf);
+ if (!tp)
+ *timebuf = 0;
+ else
+ snprintf (timebuf, 16, "%04d%02d%02dT%02d%02d%02d",
+ 1900 + tp->tm_year, tp->tm_mon+1, tp->tm_mday,
+ tp->tm_hour, tp->tm_min, tp->tm_sec);
+}
+
+
+/* Set the time to NEWTIME so that gnupg_get_time returns a time
+ starting with this one. With FREEZE set to 1 the returned time
+ will never change. Just for completeness, a value of (time_t)-1
+ for NEWTIME gets you back to reality. Note that this is obviously
+ not thread-safe but this is not required. */
+void
+gnupg_set_time (time_t newtime, int freeze)
+{
+ time_t current = time (NULL);
+
+ if ( newtime == (time_t)-1 || current == newtime)
+ {
+ timemode = NORMAL;
+ timewarp = 0;
+ }
+ else if (freeze)
+ {
+ timemode = FROZEN;
+ timewarp = newtime == (time_t)-1 ? current : newtime;
+ }
+ else if (newtime > current)
+ {
+ timemode = FUTURE;
+ timewarp = newtime - current;
+ }
+ else
+ {
+ timemode = PAST;
+ timewarp = current - newtime;
+ }
+}
+
+/* Returns true when we are in timewarp mode */
+int
+gnupg_faked_time_p (void)
+{
+ return timemode;
+}
+
+
+/* This function is used by gpg because OpenPGP defines the timestamp
+ as an unsigned 32 bit value. */
+u32
+make_timestamp (void)
+{
+ time_t t = gnupg_get_time ();
+ return (u32)t;
+}
+
+
+
+/****************
+ * Scan a date string and return a timestamp.
+ * The only supported format is "yyyy-mm-dd"
+ * Returns 0 for an invalid date.
+ */
+u32
+scan_isodatestr( const char *string )
+{
+ int year, month, day;
+ struct tm tmbuf;
+ time_t stamp;
+ int i;
+
+ if( strlen(string) != 10 || string[4] != '-' || string[7] != '-' )
+ return 0;
+ for( i=0; i < 4; i++ )
+ if( !digitp (string+i) )
+ return 0;
+ if( !digitp (string+5) || !digitp(string+6) )
+ return 0;
+ if( !digitp(string+8) || !digitp(string+9) )
+ return 0;
+ year = atoi(string);
+ month = atoi(string+5);
+ day = atoi(string+8);
+ /* some basic checks */
+ if( year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 )
+ return 0;
+ memset( &tmbuf, 0, sizeof tmbuf );
+ tmbuf.tm_mday = day;
+ tmbuf.tm_mon = month-1;
+ tmbuf.tm_year = year - 1900;
+ tmbuf.tm_isdst = -1;
+ stamp = mktime( &tmbuf );
+ if( stamp == (time_t)-1 )
+ return 0;
+ return stamp;
+}
+
+
+int
+isotime_p (const char *string)
+{
+ const char *s;
+ int i;
+
+ if (!*string)
+ return 0;
+ for (s=string, i=0; i < 8; i++, s++)
+ if (!digitp (s))
+ return 0;
+ if (*s != 'T')
+ return 0;
+ for (s++, i=9; i < 15; i++, s++)
+ if (!digitp (s))
+ return 0;
+ if (*s == 'Z')
+ s++;
+ if ( !(!*s || (isascii (*s) && isspace(*s)) || *s == ':' || *s == ','))
+ return 0; /* Wrong delimiter. */
+
+ return 1;
+}
+
+
+/* Scan a string and return true if the string represents the human
+ readable format of an ISO time. This format is:
+ yyyy-mm-dd[ hh[:mm[:ss]]]
+ Scanning stops at the second space or at a comma. If DATE_ONLY is
+ true the time part is not expected and the scanning stops at the
+ first space or at a comma. */
+int
+isotime_human_p (const char *string, int date_only)
+{
+ const char *s;
+ int i;
+
+ if (!*string)
+ return 0;
+ for (s=string, i=0; i < 4; i++, s++)
+ if (!digitp (s))
+ return 0;
+ if (*s != '-')
+ return 0;
+ s++;
+ if (!digitp (s) || !digitp (s+1) || s[2] != '-')
+ return 0;
+ i = atoi_2 (s);
+ if (i < 1 || i > 12)
+ return 0;
+ s += 3;
+ if (!digitp (s) || !digitp (s+1))
+ return 0;
+ i = atoi_2 (s);
+ if (i < 1 || i > 31)
+ return 0;
+ s += 2;
+ if (!*s || *s == ',')
+ return 1; /* Okay; only date given. */
+ if (!spacep (s))
+ return 0;
+ if (date_only)
+ return 1; /* Okay; only date was requested. */
+ s++;
+ if (spacep (s))
+ return 1; /* Okay, second space stops scanning. */
+ if (!digitp (s) || !digitp (s+1))
+ return 0;
+ i = atoi_2 (s);
+ if (i < 0 || i > 23)
+ return 0;
+ s += 2;
+ if (!*s || *s == ',')
+ return 1; /* Okay; only date and hour given. */
+ if (*s != ':')
+ return 0;
+ s++;
+ if (!digitp (s) || !digitp (s+1))
+ return 0;
+ i = atoi_2 (s);
+ if (i < 0 || i > 59)
+ return 0;
+ s += 2;
+ if (!*s || *s == ',')
+ return 1; /* Okay; only date, hour and minute given. */
+ if (*s != ':')
+ return 0;
+ s++;
+ if (!digitp (s) || !digitp (s+1))
+ return 0;
+ i = atoi_2 (s);
+ if (i < 0 || i > 60)
+ return 0;
+ s += 2;
+ if (!*s || *s == ',' || spacep (s))
+ return 1; /* Okay; date, hour and minute and second given. */
+
+ return 0; /* Unexpected delimiter. */
+}
+
+/* Convert a standard isotime or a human readable variant into an
+ isotime structure. The allowed formats are those described by
+ isotime_p and isotime_human_p. The function returns 0 on failure
+ or the length of the scanned string on success. */
+size_t
+string2isotime (gnupg_isotime_t atime, const char *string)
+{
+ gnupg_isotime_t dummyatime;
+
+ if (!atime)
+ atime = dummyatime;
+
+ atime[0] = 0;
+ if (isotime_p (string))
+ {
+ memcpy (atime, string, 15);
+ atime[15] = 0;
+ return 15;
+ }
+ if (!isotime_human_p (string, 0))
+ return 0;
+ atime[0] = string[0];
+ atime[1] = string[1];
+ atime[2] = string[2];
+ atime[3] = string[3];
+ atime[4] = string[5];
+ atime[5] = string[6];
+ atime[6] = string[8];
+ atime[7] = string[9];
+ atime[8] = 'T';
+ memset (atime+9, '0', 6);
+ atime[15] = 0;
+ if (!spacep (string+10))
+ return 10;
+ if (spacep (string+11))
+ return 11; /* As per def, second space stops scanning. */
+ atime[9] = string[11];
+ atime[10] = string[12];
+ if (string[13] != ':')
+ return 13;
+ atime[11] = string[14];
+ atime[12] = string[15];
+ if (string[16] != ':')
+ return 16;
+ atime[13] = string[17];
+ atime[14] = string[18];
+ return 19;
+}
+
+
+/* Scan an ISO timestamp and return an Epoch based timestamp. The
+ only supported format is "yyyymmddThhmmss[Z]" delimited by white
+ space, nul, a colon or a comma. Returns (time_t)(-1) for an
+ invalid string. */
+time_t
+isotime2epoch (const char *string)
+{
+ int year, month, day, hour, minu, sec;
+ struct tm tmbuf;
+
+ if (!isotime_p (string))
+ return (time_t)(-1);
+
+ year = atoi_4 (string);
+ month = atoi_2 (string + 4);
+ day = atoi_2 (string + 6);
+ hour = atoi_2 (string + 9);
+ minu = atoi_2 (string + 11);
+ sec = atoi_2 (string + 13);
+
+ /* Basic checks. */
+ if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31
+ || hour > 23 || minu > 59 || sec > 61 )
+ return (time_t)(-1);
+
+ memset (&tmbuf, 0, sizeof tmbuf);
+ tmbuf.tm_sec = sec;
+ tmbuf.tm_min = minu;
+ tmbuf.tm_hour = hour;
+ tmbuf.tm_mday = day;
+ tmbuf.tm_mon = month-1;
+ tmbuf.tm_year = year - 1900;
+ tmbuf.tm_isdst = -1;
+ return timegm (&tmbuf);
+}
+
+
+/* Convert an Epoch time to an iso time stamp. */
+void
+epoch2isotime (gnupg_isotime_t timebuf, time_t atime)
+{
+ if (atime == (time_t)(-1))
+ *timebuf = 0;
+ else
+ {
+ struct tm *tp;
+#ifdef HAVE_GMTIME_R
+ struct tm tmbuf;
+
+ tp = gmtime_r (&atime, &tmbuf);
+#else
+ tp = gmtime (&atime);
+#endif
+ snprintf (timebuf, 16, "%04d%02d%02dT%02d%02d%02d",
+ 1900 + tp->tm_year, tp->tm_mon+1, tp->tm_mday,
+ tp->tm_hour, tp->tm_min, tp->tm_sec);
+ }
+}
+
+
+/* Parse a short ISO date string (YYYY-MM-DD) into a TM structure.
+ Returns 0 on success. */
+int
+isodate_human_to_tm (const char *string, struct tm *t)
+{
+ int year, month, day;
+
+ if (!isotime_human_p (string, 1))
+ return -1;
+
+ year = atoi_4 (string);
+ month = atoi_2 (string + 5);
+ day = atoi_2 (string + 8);
+
+ /* Basic checks. */
+ if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31)
+ return -1;
+
+ memset (t, 0, sizeof *t);
+ t->tm_sec = 0;
+ t->tm_min = 0;
+ t->tm_hour = 0;
+ t->tm_mday = day;
+ t->tm_mon = month-1;
+ t->tm_year = year - 1900;
+ t->tm_isdst = -1;
+ return 0;
+}
+
+
+/* This function is a copy of gpgme/src/conversion.c:_gpgme_timegm.
+ If you change it, then update the other one too. */
+#ifdef HAVE_W32_SYSTEM
+static time_t
+_win32_timegm (struct tm *tm)
+{
+ /* This one is thread safe. */
+ SYSTEMTIME st;
+ FILETIME ft;
+ unsigned long long cnsecs;
+
+ st.wYear = tm->tm_year + 1900;
+ st.wMonth = tm->tm_mon + 1;
+ st.wDay = tm->tm_mday;
+ st.wHour = tm->tm_hour;
+ st.wMinute = tm->tm_min;
+ st.wSecond = tm->tm_sec;
+ st.wMilliseconds = 0; /* Not available. */
+ st.wDayOfWeek = 0; /* Ignored. */
+
+ /* System time is UTC thus the conversion is pretty easy. */
+ if (!SystemTimeToFileTime (&st, &ft))
+ {
+ gpg_err_set_errno (EINVAL);
+ return (time_t)(-1);
+ }
+
+ cnsecs = (((unsigned long long)ft.dwHighDateTime << 32)
+ | ft.dwLowDateTime);
+ cnsecs -= 116444736000000000ULL; /* The filetime epoch is 1601-01-01. */
+ return (time_t)(cnsecs / 10000000ULL);
+}
+#endif
+
+
+/* Parse the string TIMESTAMP into a time_t. The string may either be
+ seconds since Epoch or in the ISO 8601 format like
+ "20390815T143012". Returns 0 for an empty string or seconds since
+ Epoch. Leading spaces are skipped. If ENDP is not NULL, it will
+ point to the next non-parsed character in TIMESTRING.
+
+ This function is a copy of
+ gpgme/src/conversion.c:_gpgme_parse_timestamp. If you change it,
+ then update the other one too. */
+time_t
+parse_timestamp (const char *timestamp, char **endp)
+{
+ /* Need to skip leading spaces, because that is what strtoul does
+ but not our ISO 8601 checking code. */
+ while (*timestamp && *timestamp== ' ')
+ timestamp++;
+ if (!*timestamp)
+ return 0;
+
+ if (strlen (timestamp) >= 15 && timestamp[8] == 'T')
+ {
+ struct tm buf;
+ int year;
+
+ year = atoi_4 (timestamp);
+ if (year < 1900)
+ return (time_t)(-1);
+
+ if (endp)
+ *endp = (char*)(timestamp + 15);
+
+ /* Fixme: We would better use a configure test to see whether
+ mktime can handle dates beyond 2038. */
+ if (sizeof (time_t) <= 4 && year >= 2038)
+ return (time_t)2145914603; /* 2037-12-31 23:23:23 */
+
+ memset (&buf, 0, sizeof buf);
+ buf.tm_year = year - 1900;
+ buf.tm_mon = atoi_2 (timestamp+4) - 1;
+ buf.tm_mday = atoi_2 (timestamp+6);
+ buf.tm_hour = atoi_2 (timestamp+9);
+ buf.tm_min = atoi_2 (timestamp+11);
+ buf.tm_sec = atoi_2 (timestamp+13);
+
+#ifdef HAVE_W32_SYSTEM
+ return _win32_timegm (&buf);
+#else
+#ifdef HAVE_TIMEGM
+ return timegm (&buf);
+#else
+ {
+ time_t tim;
+
+ putenv ("TZ=UTC");
+ tim = mktime (&buf);
+#ifdef __GNUC__
+#warning fixme: we must somehow reset TZ here. It is not threadsafe anyway.
+#endif
+ return tim;
+ }
+#endif /* !HAVE_TIMEGM */
+#endif /* !HAVE_W32_SYSTEM */
+ }
+ else
+ return (time_t)strtoul (timestamp, endp, 10);
+}
+
+
+
+u32
+add_days_to_timestamp( u32 stamp, u16 days )
+{
+ return stamp + days*86400L;
+}
+
+
+/****************
+ * Return a string with a time value in the form: x Y, n D, n H
+ */
+
+const char *
+strtimevalue( u32 value )
+{
+ static char buffer[30];
+ unsigned int years, days, hours, minutes;
+
+ value /= 60;
+ minutes = value % 60;
+ value /= 60;
+ hours = value % 24;
+ value /= 24;
+ days = value % 365;
+ value /= 365;
+ years = value;
+
+ sprintf(buffer,"%uy%ud%uh%um", years, days, hours, minutes );
+ if( years )
+ return buffer;
+ if( days )
+ return strchr( buffer, 'y' ) + 1;
+ return strchr( buffer, 'd' ) + 1;
+}
+
+
+
+/* Return a malloced string with the time elapsed between NOW and
+ SINCE. May return NULL on error. */
+char *
+elapsed_time_string (time_t since, time_t now)
+{
+ char *result;
+ double diff;
+ unsigned long value;
+ unsigned int days, hours, minutes, seconds;
+
+ if (!now)
+ now = gnupg_get_time ();
+
+ diff = difftime (now, since);
+ if (diff < 0)
+ return xtrystrdup ("time-warp");
+
+ seconds = (unsigned long)diff % 60;
+ value = (unsigned long)(diff / 60);
+ minutes = value % 60;
+ value /= 60;
+ hours = value % 24;
+ value /= 24;
+ days = value % 365;
+
+ if (days)
+ result = xtryasprintf ("%ud%uh%um%us", days, hours, minutes, seconds);
+ else if (hours)
+ result = xtryasprintf ("%uh%um%us", hours, minutes, seconds);
+ else if (minutes)
+ result = xtryasprintf ("%um%us", minutes, seconds);
+ else
+ result = xtryasprintf ("%us", seconds);
+
+ return result;
+}
+
+
+/*
+ * Note: this function returns GMT
+ */
+const char *
+strtimestamp (u32 stamp)
+{
+ static char buffer[11+5];
+ struct tm *tp;
+ time_t atime = stamp;
+
+ if (IS_INVALID_TIME_T (atime))
+ {
+ strcpy (buffer, "????" "-??" "-??");
+ }
+ else
+ {
+ tp = gmtime( &atime );
+ snprintf (buffer, sizeof buffer, "%04d-%02d-%02d",
+ 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday );
+ }
+ return buffer;
+}
+
+
+/*
+ * Note: this function returns GMT
+ */
+const char *
+isotimestamp (u32 stamp)
+{
+ static char buffer[25+5];
+ struct tm *tp;
+ time_t atime = stamp;
+
+ if (IS_INVALID_TIME_T (atime))
+ {
+ strcpy (buffer, "????" "-??" "-??" " " "??" ":" "??" ":" "??");
+ }
+ else
+ {
+ tp = gmtime ( &atime );
+ snprintf (buffer, sizeof buffer, "%04d-%02d-%02d %02d:%02d:%02d",
+ 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday,
+ tp->tm_hour, tp->tm_min, tp->tm_sec);
+ }
+ return buffer;
+}
+
+
+/* Windows version of strftime returning the string as utf-8. */
+#ifdef HAVE_W32_SYSTEM
+
+#define strftime(a,b,c,d) w32_strftime ((a),(b),(c),(d))
+
+static size_t
+w32_strftime (char *s, size_t max, const char *format, const struct tm *tm)
+{
+ wchar_t *wformatbuf = NULL;
+ const wchar_t *wformat = L"%c %Z";
+ wchar_t wbuf[200];
+ size_t n;
+ char *buf;
+
+ if (strcmp (format, "%c %Z"))
+ {
+ log_debug (" comverted\n");
+ wformatbuf = utf8_to_wchar (format);
+ if (wformatbuf)
+ wformat = wformatbuf;
+ }
+
+ n = wcsftime (wbuf, sizeof wbuf, wformat, tm);
+ xfree (wformatbuf);
+ if (!n)
+ {
+ /* Most likely the buffer is too short - try ISO format instead. */
+ n = wcsftime (wbuf, sizeof wbuf, L"%Y-%m-%d %H:%M:%S", tm);
+ if (!n)
+ wcscpy (wbuf, L"[????" "-??" "-??]");
+ }
+ buf = wchar_to_utf8 (wbuf);
+ mem2str (s, buf? buf : "[????" "-??" "-??]", max);
+ xfree (buf);
+ return strlen (s) + 1;
+}
+#endif /*HAVE_W32_SYSTEM*/
+
+
+
+/****************
+ * Note: this function returns local time
+ */
+const char *
+asctimestamp (u32 stamp)
+{
+ static char buffer[80];
+#if defined (HAVE_STRFTIME) && defined (HAVE_NL_LANGINFO)
+ static char fmt[80];
+#endif
+ struct tm *tp;
+ time_t atime = stamp;
+
+ if (IS_INVALID_TIME_T (atime))
+ {
+ strcpy (buffer, "????" "-??" "-??");
+ return buffer;
+ }
+ tp = localtime( &atime );
+#ifdef HAVE_STRFTIME
+# if defined(HAVE_NL_LANGINFO)
+ mem2str( fmt, nl_langinfo(D_T_FMT), DIM(fmt)-3 );
+ if (!strstr( fmt, "%Z" ))
+ strcat( fmt, " %Z");
+ /* NOTE: gcc -Wformat-noliteral will complain here. I have found no
+ way to suppress this warning. */
+ strftime (buffer, DIM(buffer)-1, fmt, tp);
+# elif defined(HAVE_W32CE_SYSTEM)
+ /* tzset is not available but %Z nevertheless prints a default
+ nonsense timezone ("WILDABBR"). Thus we don't print the time
+ zone at all. */
+ strftime (buffer, DIM(buffer)-1, "%c", tp);
+# else
+# if HAVE_W32_SYSTEM
+ {
+ static int done;
+
+ if (!done)
+ {
+ /* The locale names as used by Windows are in the form
+ * "German_Germany.1252" or "German_Austria.1252" with
+ * alternate names similar to Unix, e.g. "de-DE". However
+ * that is the theory. On current Windows and Mingw the
+ * alternate names do not work. We would need a table to map
+ * them from the short names as provided by gpgrt to the long
+ * names and append some code page. For now we use "" and
+ * take the locale from the user's system settings. Thus the
+ * standard Unix envvars don't work for time and may mismatch
+ * with the string translations. The new UCRT available since
+ * 2018 has a lot of additional support but that will for sure
+ * break other things. We should move to ISO strings to get
+ * rid of such problems. */
+ setlocale (LC_TIME, "");
+ done = 1;
+ /* log_debug ("LC_ALL now '%s'\n", setlocale (LC_ALL, NULL)); */
+ /* log_debug ("LC_TIME now '%s'\n", setlocale (LC_TIME, NULL)); */
+ }
+ }
+# endif
+ /* FIXME: we should check whether the locale appends a " %Z" These
+ * locales from glibc don't put the " %Z": fi_FI hr_HR ja_JP lt_LT
+ * lv_LV POSIX ru_RU ru_SU sv_FI sv_SE zh_CN. */
+ strftime (buffer, DIM(buffer)-1, "%c %Z", tp);
+# endif
+ buffer[DIM(buffer)-1] = 0;
+#else
+ mem2str( buffer, asctime(tp), DIM(buffer) );
+#endif
+ return buffer;
+}
+
+
+/* Return the timestamp STAMP in RFC-2822 format. This is always done
+ * in the C locale. We return the gmtime to avoid computing the
+ * timezone. The caller must release the returned string.
+ *
+ * Example: "Mon, 27 Jun 2016 1:42:00 +0000".
+ */
+char *
+rfctimestamp (u32 stamp)
+{
+ time_t atime = stamp;
+ struct tm tmbuf, *tp;
+
+
+ if (IS_INVALID_TIME_T (atime))
+ {
+ gpg_err_set_errno (EINVAL);
+ return NULL;
+ }
+
+ tp = gnupg_gmtime (&atime, &tmbuf);
+ if (!tp)
+ return NULL;
+ return xtryasprintf ("%.3s, %02d %.3s %04d %02d:%02d:%02d +0000",
+ &"SunMonTueWedThuFriSat"[(tp->tm_wday%7)*3],
+ tp->tm_mday,
+ &"JanFebMarAprMayJunJulAugSepOctNovDec"
+ [(tp->tm_mon%12)*3],
+ tp->tm_year + 1900,
+ tp->tm_hour,
+ tp->tm_min,
+ tp->tm_sec);
+}
+
+
+static int
+days_per_year (int y)
+{
+ int s ;
+
+ s = !(y % 4);
+ if ( !(y % 100))
+ if ((y%400))
+ s = 0;
+ return s ? 366 : 365;
+}
+
+static int
+days_per_month (int y, int m)
+{
+ int s;
+
+ switch(m)
+ {
+ case 1: case 3: case 5: case 7: case 8: case 10: case 12:
+ return 31 ;
+ case 2:
+ s = !(y % 4);
+ if (!(y % 100))
+ if ((y % 400))
+ s = 0;
+ return s? 29 : 28 ;
+ case 4: case 6: case 9: case 11:
+ return 30;
+ }
+ BUG();
+}
+
+
+/* Convert YEAR, MONTH and DAY into the Julian date. We assume that
+ it is already noon. We do not support dates before 1582-10-15. */
+static unsigned long
+date2jd (int year, int month, int day)
+{
+ unsigned long jd;
+
+ jd = 365L * year + 31 * (month-1) + day + JD_DIFF;
+ if (month < 3)
+ year-- ;
+ else
+ jd -= (4 * month + 23) / 10;
+
+ jd += year / 4 - ((year / 100 + 1) *3) / 4;
+
+ return jd ;
+}
+
+/* Convert a Julian date back to YEAR, MONTH and DAY. Return day of
+ the year or 0 on error. This function uses some more or less
+ arbitrary limits, most important is that days before 1582 are not
+ supported. */
+static int
+jd2date (unsigned long jd, int *year, int *month, int *day)
+{
+ int y, m, d;
+ long delta;
+
+ if (!jd)
+ return 0 ;
+ if (jd < 1721425 || jd > 2843085)
+ return 0;
+
+ y = (jd - JD_DIFF) / 366;
+ d = m = 1;
+
+ while ((delta = jd - date2jd (y, m, d)) > days_per_year (y))
+ y++;
+
+ m = (delta / 31) + 1;
+ while( (delta = jd - date2jd (y, m, d)) > days_per_month (y,m))
+ if (++m > 12)
+ {
+ m = 1;
+ y++;
+ }
+
+ d = delta + 1 ;
+ if (d > days_per_month (y, m))
+ {
+ d = 1;
+ m++;
+ }
+ if (m > 12)
+ {
+ m = 1;
+ y++;
+ }
+
+ if (year)
+ *year = y;
+ if (month)
+ *month = m;
+ if (day)
+ *day = d ;
+
+ return (jd - date2jd (y, 1, 1)) + 1;
+}
+
+
+/* Check that the 15 bytes in ATIME represent a valid ISO time. Note
+ that this function does not expect a string but a plain 15 byte
+ isotime buffer. */
+gpg_error_t
+check_isotime (const gnupg_isotime_t atime)
+{
+ int i;
+ const char *s;
+
+ if (!*atime)
+ return gpg_error (GPG_ERR_NO_VALUE);
+
+ for (s=atime, i=0; i < 8; i++, s++)
+ if (!digitp (s))
+ return gpg_error (GPG_ERR_INV_TIME);
+ if (*s != 'T')
+ return gpg_error (GPG_ERR_INV_TIME);
+ for (s++, i=9; i < 15; i++, s++)
+ if (!digitp (s))
+ return gpg_error (GPG_ERR_INV_TIME);
+ return 0;
+}
+
+
+/* Dump the ISO time T to the log stream without a LF. */
+void
+dump_isotime (const gnupg_isotime_t t)
+{
+ if (!t || !*t)
+ log_printf ("%s", _("[none]"));
+ else
+ log_printf ("%.4s-%.2s-%.2s %.2s:%.2s:%s",
+ t, t+4, t+6, t+9, t+11, t+13);
+}
+
+
+/* Copy one ISO date to another, this is inline so that we can do a
+ minimal sanity check. A null date (empty string) is allowed. */
+void
+gnupg_copy_time (gnupg_isotime_t d, const gnupg_isotime_t s)
+{
+ if (*s)
+ {
+ if ((strlen (s) != 15 || s[8] != 'T'))
+ BUG();
+ memcpy (d, s, 15);
+ d[15] = 0;
+ }
+ else
+ *d = 0;
+}
+
+
+/* Add SECONDS to ATIME. SECONDS may not be negative and is limited
+ to about the equivalent of 62 years which should be more then
+ enough for our purposes. */
+gpg_error_t
+add_seconds_to_isotime (gnupg_isotime_t atime, int nseconds)
+{
+ gpg_error_t err;
+ int year, month, day, hour, minute, sec, ndays;
+ unsigned long jd;
+
+ err = check_isotime (atime);
+ if (err)
+ return err;
+
+ if (nseconds < 0 || nseconds >= (0x7fffffff - 61) )
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ year = atoi_4 (atime+0);
+ month = atoi_2 (atime+4);
+ day = atoi_2 (atime+6);
+ hour = atoi_2 (atime+9);
+ minute= atoi_2 (atime+11);
+ sec = atoi_2 (atime+13);
+
+ if (year <= 1582) /* The julian date functions don't support this. */
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ sec += nseconds;
+ minute += sec/60;
+ sec %= 60;
+ hour += minute/60;
+ minute %= 60;
+ ndays = hour/24;
+ hour %= 24;
+
+ jd = date2jd (year, month, day) + ndays;
+ jd2date (jd, &year, &month, &day);
+
+ if (year > 9999 || month > 12 || day > 31
+ || year < 0 || month < 1 || day < 1)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ snprintf (atime, 16, "%04d%02d%02dT%02d%02d%02d",
+ year, month, day, hour, minute, sec);
+ return 0;
+}
+
+
+gpg_error_t
+add_days_to_isotime (gnupg_isotime_t atime, int ndays)
+{
+ gpg_error_t err;
+ int year, month, day, hour, minute, sec;
+ unsigned long jd;
+
+ err = check_isotime (atime);
+ if (err)
+ return err;
+
+ if (ndays < 0 || ndays >= 9999*366 )
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ year = atoi_4 (atime+0);
+ month = atoi_2 (atime+4);
+ day = atoi_2 (atime+6);
+ hour = atoi_2 (atime+9);
+ minute= atoi_2 (atime+11);
+ sec = atoi_2 (atime+13);
+
+ if (year <= 1582) /* The julian date functions don't support this. */
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ jd = date2jd (year, month, day) + ndays;
+ jd2date (jd, &year, &month, &day);
+
+ if (year > 9999 || month > 12 || day > 31
+ || year < 0 || month < 1 || day < 1)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ snprintf (atime, 16, "%04d%02d%02dT%02d%02d%02d",
+ year, month, day, hour, minute, sec);
+ return 0;
+}
diff --git a/common/gettime.h b/common/gettime.h
new file mode 100644
index 0000000..73f1886
--- /dev/null
+++ b/common/gettime.h
@@ -0,0 +1,70 @@
+/* gettime.h - Wrapper for time functions
+ * Copyright (C) 2010, 2012 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_COMMON_GETTIME_H
+#define GNUPG_COMMON_GETTIME_H
+
+#include <time.h> /* We need time_t. */
+#include <gpg-error.h> /* We need gpg_error_t. */
+
+
+/* A type to hold the ISO time. Note that this is the same as
+ the KSBA type ksba_isotime_t. */
+typedef char gnupg_isotime_t[16];
+
+time_t gnupg_get_time (void);
+struct tm *gnupg_gmtime (const time_t *timep, struct tm *result);
+void gnupg_get_isotime (gnupg_isotime_t timebuf);
+void gnupg_set_time (time_t newtime, int freeze);
+int gnupg_faked_time_p (void);
+u32 make_timestamp (void);
+char *elapsed_time_string (time_t since, time_t now);
+
+u32 scan_isodatestr (const char *string);
+int isotime_p (const char *string);
+int isotime_human_p (const char *string, int date_only);
+size_t string2isotime (gnupg_isotime_t atime, const char *string);
+time_t isotime2epoch (const char *string);
+void epoch2isotime (gnupg_isotime_t timebuf, time_t atime);
+int isodate_human_to_tm (const char *string, struct tm *t);
+time_t parse_timestamp (const char *timestamp, char **endp);
+u32 add_days_to_timestamp (u32 stamp, u16 days);
+const char *strtimevalue (u32 stamp);
+const char *strtimestamp (u32 stamp); /* GMT */
+const char *isotimestamp (u32 stamp); /* GMT */
+const char *asctimestamp (u32 stamp); /* localized */
+char *rfctimestamp (u32 stamp); /* RFC format, malloced. */
+gpg_error_t add_seconds_to_isotime (gnupg_isotime_t atime, int nseconds);
+gpg_error_t add_days_to_isotime (gnupg_isotime_t atime, int ndays);
+gpg_error_t check_isotime (const gnupg_isotime_t atime);
+void dump_isotime (const gnupg_isotime_t atime);
+void gnupg_copy_time (gnupg_isotime_t d, const gnupg_isotime_t s);
+
+
+#endif /*GNUPG_COMMON_GETTIME_H*/
diff --git a/common/gnupg.ico b/common/gnupg.ico
new file mode 100644
index 0000000..4c4bae0
--- /dev/null
+++ b/common/gnupg.ico
Binary files differ
diff --git a/common/gpgrlhelp.c b/common/gpgrlhelp.c
new file mode 100644
index 0000000..680d999
--- /dev/null
+++ b/common/gpgrlhelp.c
@@ -0,0 +1,97 @@
+/* gpgrlhelp.c - A readline wrapper.
+ * Copyright (C) 2006 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+/* This module may by used by applications to initializes readline
+ support. It is required so that we can have hooks in other parts
+ of libcommon without actually requiring to link against
+ libreadline. It works along with ttyio.c which is a proper part of
+ libcommon. */
+
+#include <config.h>
+#include <stdlib.h>
+#include <stddef.h>
+
+#ifdef HAVE_LIBREADLINE
+#define GNUPG_LIBREADLINE_H_INCLUDED
+#include <stdio.h>
+#include <readline/readline.h>
+#include <readline/history.h>
+#endif
+
+#include "util.h"
+#include "common-defs.h"
+
+
+#ifdef HAVE_LIBREADLINE
+static void
+set_completer (rl_completion_func_t *completer)
+{
+ rl_attempted_completion_function = completer;
+ rl_inhibit_completion = 0;
+}
+
+static void
+inhibit_completion (int value)
+{
+ rl_inhibit_completion = value;
+}
+
+static void
+cleanup_after_signal (void)
+{
+ rl_free_line_state ();
+ rl_cleanup_after_signal ();
+}
+
+static void
+init_stream (FILE *fp)
+{
+ rl_catch_signals = 0;
+ rl_instream = rl_outstream = fp;
+ rl_inhibit_completion = 1;
+}
+
+#endif /*HAVE_LIBREADLINE*/
+
+
+/* Initialize our readline code. This should be called as early as
+ possible as it is actually a constructur. */
+void
+gnupg_rl_initialize (void)
+{
+#ifdef HAVE_LIBREADLINE
+ tty_private_set_rl_hooks (init_stream,
+ set_completer,
+ inhibit_completion,
+ cleanup_after_signal,
+ readline,
+ add_history);
+ rl_readline_name = GNUPG_NAME;
+#endif
+}
diff --git a/common/helpfile.c b/common/helpfile.c
new file mode 100644
index 0000000..7a7a235
--- /dev/null
+++ b/common/helpfile.c
@@ -0,0 +1,272 @@
+/* helpfile.c - GnuPG's helpfile feature
+ * Copyright (C) 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+
+
+#include "util.h"
+#include "i18n.h"
+#include "membuf.h"
+
+
+/* Try to find KEY in the file FNAME. */
+static char *
+findkey_fname (const char *key, const char *fname)
+{
+ gpg_error_t err = 0;
+ estream_t fp;
+ int lnr = 0;
+ int c;
+ char *p, line[256];
+ int in_item = 0;
+ membuf_t mb = MEMBUF_ZERO;
+
+ fp = es_fopen (fname, "r");
+ if (!fp)
+ {
+ if (errno != ENOENT)
+ {
+ err = gpg_error_from_syserror ();
+ log_error (_("can't open '%s': %s\n"), fname, gpg_strerror (err));
+ }
+ return NULL;
+ }
+
+ while (es_fgets (line, DIM(line)-1, fp))
+ {
+ lnr++;
+
+ if (!*line || line[strlen(line)-1] != '\n')
+ {
+ /* Eat until end of line. */
+ while ((c = es_getc (fp)) != EOF && c != '\n')
+ ;
+ err = gpg_error (*line? GPG_ERR_LINE_TOO_LONG
+ : GPG_ERR_INCOMPLETE_LINE);
+ log_error (_("file '%s', line %d: %s\n"),
+ fname, lnr, gpg_strerror (err));
+ }
+ else
+ line[strlen(line)-1] = 0; /* Chop the LF. */
+
+ again:
+ if (!in_item)
+ {
+ /* Allow for empty lines and spaces while not in an item. */
+ for (p=line; spacep (p); p++)
+ ;
+ if (!*p || *p == '#')
+ continue;
+ if (*line != '.' || spacep(line+1))
+ {
+ log_info (_("file '%s', line %d: %s\n"),
+ fname, lnr, _("ignoring garbage line"));
+ continue;
+ }
+ trim_trailing_spaces (line);
+ in_item = 1;
+ if (!strcmp (line+1, key))
+ {
+ /* Found. Start collecting. */
+ init_membuf (&mb, 1024);
+ }
+ continue;
+ }
+
+ /* If in an item only allow for comments in the first column
+ and provide ". " as an escape sequence to allow for
+ leading dots and hash marks in the actual text. */
+ if (*line == '#')
+ continue;
+ if (*line == '.')
+ {
+ if (spacep(line+1))
+ p = line + 2;
+ else
+ {
+ trim_trailing_spaces (line);
+ in_item = 0;
+ if (is_membuf_ready (&mb))
+ break; /* Yep, found and collected the item. */
+ if (!line[1])
+ continue; /* Just an end of text dot. */
+ goto again; /* A new key line. */
+ }
+ }
+ else
+ p = line;
+
+ if (is_membuf_ready (&mb))
+ {
+ put_membuf_str (&mb, p);
+ put_membuf (&mb, "\n", 1);
+ }
+
+ }
+ if ( !err && es_ferror (fp) )
+ {
+ err = gpg_error_from_syserror ();
+ log_error (_("error reading '%s', line %d: %s\n"),
+ fname, lnr, gpg_strerror (err));
+ }
+
+ es_fclose (fp);
+ if (is_membuf_ready (&mb))
+ {
+ /* We have collected something. */
+ if (err)
+ {
+ xfree (get_membuf (&mb, NULL));
+ return NULL;
+ }
+ else
+ {
+ put_membuf (&mb, "", 1); /* Terminate string. */
+ return get_membuf (&mb, NULL);
+ }
+ }
+ else
+ return NULL;
+}
+
+
+/* Try the help files depending on the locale. */
+static char *
+findkey_locale (const char *key, const char *locname,
+ int only_current_locale, const char *dirname)
+{
+ const char *s;
+ char *fname, *ext, *p;
+ char *result;
+
+ fname = xtrymalloc (strlen (dirname) + 6 + strlen (locname) + 4 + 1);
+ if (!fname)
+ return NULL;
+ ext = stpcpy (stpcpy (fname, dirname), "/help.");
+ /* Search with locale name and territory. ("help.LL_TT.txt") */
+ if (strchr (locname, '_'))
+ {
+ strcpy (stpcpy (ext, locname), ".txt");
+ result = findkey_fname (key, fname);
+ }
+ else
+ result = NULL; /* No territory. */
+
+ if (!result)
+ {
+ /* Search with just the locale name - if any. ("help.LL.txt") */
+ if (*locname)
+ {
+ for (p=ext, s=locname; *s && *s != '_';)
+ *p++ = *s++;
+ strcpy (p, ".txt");
+ result = findkey_fname (key, fname);
+ }
+ else
+ result = NULL;
+ }
+
+ if (!result && (!only_current_locale || !*locname) )
+ {
+ /* Last try: Search in file without any locale info. ("help.txt") */
+ strcpy (ext, "txt");
+ result = findkey_fname (key, fname);
+ }
+
+ xfree (fname);
+ return result;
+}
+
+
+/* Return a malloced help text as identified by KEY. The system takes
+ the string from an UTF-8 encoded file to be created by an
+ administrator or as distributed with GnuPG. On a GNU or Unix
+ system the entry is searched in these files:
+
+ /etc/gnupg/help.LL.txt
+ /etc/gnupg/help.txt
+ /usr/share/gnupg/help.LL.txt
+ /usr/share/gnupg/help.txt
+
+ Here LL denotes the two digit language code of the current locale.
+ If ONLY_CURRENT_LOCALE is set, the function won't fallback to the
+ english valiant ("help.txt") unless that locale has been requested.
+
+ The help file needs to be encoded in UTF-8, lines with a '#' in the
+ first column are comment lines and entirely ignored. Help keys are
+ identified by a key consisting of a single word with a single dot
+ as the first character. All key lines listed without any
+ intervening lines (except for comment lines) lead to the same help
+ text. Lines following the key lines make up the actual hep texts.
+
+*/
+
+char *
+gnupg_get_help_string (const char *key, int only_current_locale)
+{
+ static const char *locname;
+ char *result;
+
+ if (!locname)
+ {
+ char *buffer, *p;
+ int count = 0;
+ const char *s = gnupg_messages_locale_name ();
+ buffer = xtrystrdup (s);
+ if (!buffer)
+ locname = "";
+ else
+ {
+ for (p = buffer; *p; p++)
+ if (*p == '.' || *p == '@' || *p == '/' /*(safeguard)*/)
+ *p = 0;
+ else if (*p == '_')
+ {
+ if (count++)
+ *p = 0; /* Also cut at a underscore in the territory. */
+ }
+ locname = buffer;
+ }
+ }
+
+ if (!key || !*key)
+ return NULL;
+
+ result = findkey_locale (key, locname, only_current_locale,
+ gnupg_sysconfdir ());
+ if (!result)
+ result = findkey_locale (key, locname, only_current_locale,
+ gnupg_datadir ());
+
+ if (result)
+ trim_trailing_spaces (result);
+
+ return result;
+}
diff --git a/common/homedir.c b/common/homedir.c
new file mode 100644
index 0000000..9788c22
--- /dev/null
+++ b/common/homedir.c
@@ -0,0 +1,1536 @@
+/* homedir.c - Setup the home directory.
+ * Copyright (C) 2004, 2006, 2007, 2010 Free Software Foundation, Inc.
+ * Copyright (C) 2013, 2016 Werner Koch
+ * Copyright (C) 2021 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: (LGPL-3.0-or-later OR GPL-2.0-or-later)
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#ifdef HAVE_W32_SYSTEM
+#include <winsock2.h> /* Due to the stupid mingw64 requirement to
+ include this header before windows.h which
+ is often implicitly included. */
+#include <shlobj.h>
+#ifndef CSIDL_APPDATA
+#define CSIDL_APPDATA 0x001a
+#endif
+#ifndef CSIDL_LOCAL_APPDATA
+#define CSIDL_LOCAL_APPDATA 0x001c
+#endif
+#ifndef CSIDL_COMMON_APPDATA
+#define CSIDL_COMMON_APPDATA 0x0023
+#endif
+#ifndef CSIDL_FLAG_CREATE
+#define CSIDL_FLAG_CREATE 0x8000
+#endif
+#endif /*HAVE_W32_SYSTEM*/
+
+#ifdef HAVE_STAT
+#include <sys/stat.h> /* for stat() */
+#endif
+
+#include "util.h"
+#include "sysutils.h"
+#include "i18n.h"
+#include "zb32.h"
+
+/* The name of the symbolic link to the file from which the process
+ * text was read. */
+#if __linux__
+# define MYPROC_SELF_EXE "/proc/self/exe"
+#elif defined(__NetBSD__)
+# define MYPROC_SELF_EXE "/proc/curproc/exe"
+#elif defined(__illumos__) || defined(__sun)
+# define MYPROC_SELF_EXE "/proc/self/path/a.out"
+#else /* Assume other BSDs */
+# define MYPROC_SELF_EXE "/proc/curproc/file"
+#endif
+
+
+/* The GnuPG homedir. This is only accessed by the functions
+ * gnupg_homedir and gnupg_set_homedir. Malloced. */
+static char *the_gnupg_homedir;
+
+/* Flag indicating that home directory is not the default one. */
+static byte non_default_homedir;
+
+
+#ifdef HAVE_W32_SYSTEM
+/* A flag used to indicate that a control file for gpgconf has been
+ * detected. Under Windows the presence of this file indicates a
+ * portable installations and triggers several changes:
+ *
+ * - The GNUGHOME directory is fixed relative to installation
+ * directory. All other means to set the home directory are ignored.
+ *
+ * - All registry variables will be ignored.
+ *
+ * This flag is not used on Unix systems.
+ */
+static byte w32_portable_app;
+#endif /*HAVE_W32_SYSTEM*/
+
+#ifdef HAVE_W32_SYSTEM
+/* This flag is true if this process' binary has been installed under
+ bin and not in the root directory as often used before GnuPG 2.1. */
+static byte w32_bin_is_bin;
+#endif /*HAVE_W32_SYSTEM*/
+
+
+#ifdef HAVE_W32_SYSTEM
+static const char *w32_rootdir (void);
+#endif
+
+
+/* This is a helper function to load and call a Windows function from
+ * either of one DLLs. On success an UTF-8 file name is returned.
+ * ERRNO is _not_ set on error. */
+#ifdef HAVE_W32_SYSTEM
+static char *
+w32_shgetfolderpath (HWND a, int b, HANDLE c, DWORD d)
+{
+ static int initialized;
+ static HRESULT (WINAPI * func)(HWND,int,HANDLE,DWORD,LPWSTR);
+ wchar_t wfname[MAX_PATH];
+
+ if (!initialized)
+ {
+ static char *dllnames[] = { "shell32.dll", "shfolder.dll", NULL };
+ void *handle;
+ int i;
+
+ initialized = 1;
+
+ for (i=0, handle = NULL; !handle && dllnames[i]; i++)
+ {
+ handle = dlopen (dllnames[i], RTLD_LAZY);
+ if (handle)
+ {
+ func = dlsym (handle, "SHGetFolderPathW");
+ if (!func)
+ {
+ dlclose (handle);
+ handle = NULL;
+ }
+ }
+ }
+ }
+
+ if (func && func (a,b,c,d,wfname) >= 0)
+ return wchar_to_utf8 (wfname);
+ else
+ return NULL;
+}
+#endif /*HAVE_W32_SYSTEM*/
+
+
+/* Check whether DIR is the default homedir. */
+static int
+is_gnupg_default_homedir (const char *dir)
+{
+ int result;
+ char *a = make_absfilename (dir, NULL);
+ char *b = make_absfilename (standard_homedir (), NULL);
+ result = !compare_filenames (a, b);
+ xfree (b);
+ xfree (a);
+ return result;
+}
+
+
+/* Helper to remove trailing slashes from NEWDIR. Return a new
+ * allocated string if that has been done or NULL if there are no
+ * slashes to remove. Also inserts a missing slash after a Windows
+ * drive letter. */
+static char *
+copy_dir_with_fixup (const char *newdir)
+{
+ char *result = NULL;
+ char *p;
+
+ if (!*newdir)
+ return NULL;
+
+#ifdef HAVE_W32_SYSTEM
+ if (newdir[0] && newdir[1] == ':'
+ && !(newdir[2] == '/' || newdir[2] == '\\'))
+ {
+ /* Drive letter with missing leading slash. */
+ p = result = xmalloc (strlen (newdir) + 1 + 1);
+ *p++ = newdir[0];
+ *p++ = newdir[1];
+ *p++ = '\\';
+ strcpy (p, newdir+2);
+
+ /* Remove trailing slashes. */
+ p = result + strlen (result) - 1;
+ while (p > result+2 && (*p == '/' || *p == '\\'))
+ *p-- = 0;
+ }
+ else if (newdir[strlen (newdir)-1] == '/'
+ || newdir[strlen (newdir)-1] == '\\' )
+ {
+ result = xstrdup (newdir);
+ p = result + strlen (result) - 1;
+ while (p > result
+ && (*p == '/' || *p == '\\')
+ && (p-1 > result && p[-1] != ':')) /* We keep "c:/". */
+ *p-- = 0;
+ }
+
+#else /*!HAVE_W32_SYSTEM*/
+
+ if (newdir[strlen (newdir)-1] == '/')
+ {
+ result = xstrdup (newdir);
+ p = result + strlen (result) - 1;
+ while (p > result && *p == '/')
+ *p-- = 0;
+ }
+
+#endif /*!HAVE_W32_SYSTEM*/
+
+ return result;
+}
+
+
+/* Get the standard home directory. In general this function should
+ not be used as it does not consider a registry value (under W32) or
+ the GNUPGHOME environment variable. It is better to use
+ default_homedir(). */
+const char *
+standard_homedir (void)
+{
+#ifdef HAVE_W32_SYSTEM
+ static const char *dir;
+
+ if (!dir)
+ {
+ const char *rdir;
+
+ rdir = w32_rootdir ();
+ if (w32_portable_app)
+ {
+ dir = xstrconcat (rdir, DIRSEP_S "home", NULL);
+ }
+ else
+ {
+ char *path;
+
+ path = w32_shgetfolderpath (NULL, CSIDL_APPDATA|CSIDL_FLAG_CREATE,
+ NULL, 0);
+ if (path)
+ {
+ dir = xstrconcat (path, "\\gnupg", NULL);
+ xfree (path);
+
+ /* Try to create the directory if it does not yet exists. */
+ if (gnupg_access (dir, F_OK))
+ gnupg_mkdir (dir, "-rwx");
+ }
+ else
+ dir = GNUPG_DEFAULT_HOMEDIR;
+ }
+ }
+ return dir;
+#else/*!HAVE_W32_SYSTEM*/
+ return GNUPG_DEFAULT_HOMEDIR;
+#endif /*!HAVE_W32_SYSTEM*/
+}
+
+/* Set up the default home directory. The usual --homedir option
+ should be parsed later. */
+const char *
+default_homedir (void)
+{
+ const char *dir;
+
+#ifdef HAVE_W32_SYSTEM
+ /* For a portable application we only use the standard homedir. */
+ w32_rootdir ();
+ if (w32_portable_app)
+ return standard_homedir ();
+#endif /*HAVE_W32_SYSTEM*/
+
+ dir = getenv ("GNUPGHOME");
+#ifdef HAVE_W32_SYSTEM
+ if (!dir || !*dir)
+ {
+ static const char *saved_dir;
+
+ if (!saved_dir)
+ {
+ if (!dir || !*dir)
+ {
+ char *tmp, *p;
+
+ /* This is deprecated; gpgconf --list-dirs prints a
+ * warning if the homedir has been taken from the
+ * registry. */
+ tmp = read_w32_registry_string (NULL,
+ GNUPG_REGISTRY_DIR,
+ "HomeDir");
+ if (tmp && !*tmp)
+ {
+ xfree (tmp);
+ tmp = NULL;
+ }
+ if (tmp)
+ {
+ /* Strip trailing backslashes. */
+ p = tmp + strlen (tmp) - 1;
+ while (p > tmp && *p == '\\')
+ *p-- = 0;
+ saved_dir = tmp;
+ }
+ }
+
+ if (!saved_dir)
+ saved_dir = standard_homedir ();
+ }
+ dir = saved_dir;
+ }
+#endif /*HAVE_W32_SYSTEM*/
+
+ if (!dir || !*dir)
+ dir = GNUPG_DEFAULT_HOMEDIR;
+ else
+ {
+ char *p;
+
+ p = copy_dir_with_fixup (dir);
+ if (p)
+ dir = p;
+
+ if (!is_gnupg_default_homedir (dir))
+ non_default_homedir = 1;
+ }
+
+ return dir;
+}
+
+
+#ifdef HAVE_W32_SYSTEM
+/* Check whether gpgconf is installed and if so read the gpgconf.ctl
+ file. */
+static void
+check_portable_app (const char *dir)
+{
+ char *fname;
+
+ fname = xstrconcat (dir, DIRSEP_S "gpgconf.exe", NULL);
+ if (!gnupg_access (fname, F_OK))
+ {
+ strcpy (fname + strlen (fname) - 3, "ctl");
+ if (!gnupg_access (fname, F_OK))
+ {
+ /* gpgconf.ctl file found. Record this fact. */
+ w32_portable_app = 1;
+ {
+ unsigned int flags;
+ log_get_prefix (&flags);
+ log_set_prefix (NULL, (flags | GPGRT_LOG_NO_REGISTRY));
+ }
+ /* FIXME: We should read the file to detect special flags
+ and print a warning if we don't understand them */
+ }
+ }
+ xfree (fname);
+}
+#endif /*HAVE_W32_SYSTEM*/
+
+
+#ifdef HAVE_W32_SYSTEM
+/* Determine the root directory of the gnupg installation on Windows. */
+static const char *
+w32_rootdir (void)
+{
+ static int got_dir;
+ static char dir[MAX_PATH+5];
+
+ if (!got_dir)
+ {
+ char *p;
+ int rc;
+ wchar_t wdir [MAX_PATH+5];
+
+ rc = GetModuleFileNameW (NULL, wdir, MAX_PATH);
+ if (rc && WideCharToMultiByte (CP_UTF8, 0, wdir, -1, dir, MAX_PATH-4,
+ NULL, NULL) < 0)
+ rc = 0;
+ if (!rc)
+ {
+ log_debug ("GetModuleFileName failed: %s\n", w32_strerror (-1));
+ *dir = 0;
+ }
+ got_dir = 1;
+ p = strrchr (dir, DIRSEP_C);
+ if (p)
+ {
+ *p = 0;
+
+ check_portable_app (dir);
+
+ /* If we are installed below "bin" we strip that and use
+ the top directory instead. */
+ p = strrchr (dir, DIRSEP_C);
+ if (p && !strcmp (p+1, "bin"))
+ {
+ *p = 0;
+ w32_bin_is_bin = 1;
+ }
+ }
+ if (!p)
+ {
+ log_debug ("bad filename '%s' returned for this process\n", dir);
+ *dir = 0;
+ }
+ }
+
+ if (*dir)
+ return dir;
+ /* Fallback to the hardwired value. */
+ return GNUPG_LIBEXECDIR;
+}
+#endif /*HAVE_W32_SYSTEM*/
+
+
+#ifndef HAVE_W32_SYSTEM /* Unix */
+/* Determine the root directory of the gnupg installation on Unix.
+ * The standard case is that this function returns NULL so that the
+ * root directory as configured at build time is used. However, it
+ * may return a static string with a different root directory, similar
+ * to what we do on Windows. That second mode is triggered by the
+ * existence of a file gpgconf.ctl installed side-by-side to gpgconf.
+ * This file is parsed for keywords describing the actually to be used
+ * root directory. There is no solid standard on Unix to locate the
+ * binary used to create the process, thus we support this currently
+ * only on Linux and BSD where we can look this info up using the proc
+ * file system. If WANT_SYSCONFDIR is true the optional sysconfdir
+ * entry is returned. */
+static const char *
+unix_rootdir (int want_sysconfdir)
+{
+ static int checked;
+ static char *dir; /* for the rootdir */
+ static char *sdir; /* for the sysconfdir */
+
+ if (!checked)
+ {
+ char *p;
+ char *buffer;
+ size_t bufsize = 256-1;
+ int nread;
+ gpg_error_t err;
+ char *line;
+ size_t linelen;
+ ssize_t length;
+ estream_t fp;
+ char *rootdir;
+ char *sysconfdir;
+ const char *name;
+
+ for (;;)
+ {
+ buffer = xmalloc (bufsize+1);
+ nread = readlink (MYPROC_SELF_EXE, buffer, bufsize);
+ if (nread < 0)
+ {
+ err = gpg_error_from_syserror ();
+ buffer[0] = 0;
+ if ((name = getenv ("GNUPG_BUILD_ROOT")) && *name == '/')
+ {
+ /* Try a fallback for systems w/o a supported /proc
+ * file system if we are running a regression test. */
+ log_info ("error reading symlink '%s': %s\n",
+ MYPROC_SELF_EXE, gpg_strerror (err));
+ xfree (buffer);
+ buffer = xstrconcat (name, "/bin/gpgconf", NULL);
+ log_info ("trying fallback '%s'\n", buffer);
+ }
+ break;
+ }
+ else if (nread < bufsize)
+ {
+ buffer[nread] = 0;
+ break; /* Got it. */
+ }
+ else if (bufsize >= 4095)
+ {
+ buffer[0] = 0;
+ log_info ("error reading symlink '%s': %s\n",
+ MYPROC_SELF_EXE, "value too large");
+ break;
+ }
+ xfree (buffer);
+ bufsize += 256;
+ }
+ if (!*buffer)
+ {
+ xfree (buffer);
+ checked = 1;
+ return NULL; /* Error - assume no gpgconf.ctl. */
+ }
+
+ p = strrchr (buffer, '/');
+ if (!p)
+ {
+ xfree (buffer);
+ checked = 1;
+ return NULL; /* Erroneous /proc - assume no gpgconf.ctl. */
+ }
+ *p = 0; /* BUFFER has the directory. */
+ if ((p = strrchr (buffer, '/')))
+ {
+ /* Strip one part and expect the file below a bin dir. */
+ *p = 0;
+ p = xstrconcat (buffer, "/bin/gpgconf.ctl", NULL);
+ xfree (buffer);
+ buffer = p;
+ }
+ else /* !p */
+ {
+ /* Installed in the root which is not a good idea. Assume
+ * no gpgconf.ctl. */
+ xfree (buffer);
+ checked = 1;
+ return NULL;
+ }
+
+ if (gnupg_access (buffer, F_OK))
+ {
+ /* No gpgconf.ctl file. */
+ xfree (buffer);
+ checked = 1;
+ return NULL;
+ }
+ /* log_info ("detected '%s'\n", buffer); */
+ fp = es_fopen (buffer, "r");
+ if (!fp)
+ {
+ err = gpg_error_from_syserror ();
+ log_info ("error opening '%s': %s\n", buffer, gpg_strerror (err));
+ xfree (buffer);
+ checked = 1;
+ return NULL;
+ }
+
+ line = NULL;
+ linelen = 0;
+ rootdir = NULL;
+ sysconfdir = NULL;
+ while ((length = es_read_line (fp, &line, &linelen, NULL)) > 0)
+ {
+ /* Strip NL and CR, if present. */
+ while (length > 0
+ && (line[length - 1] == '\n' || line[length - 1] == '\r'))
+ line[--length] = 0;
+ trim_spaces (line);
+ if (!strncmp (line, "rootdir=", 8))
+ {
+ name = "rootdir";
+ p = line + 8;
+ }
+ else if (!strncmp (line, "rootdir =", 9)) /* (What a kludge) */
+ {
+ name = "rootdir";
+ p = line + 9;
+ }
+ else if (!strncmp (line, "sysconfdir=", 11))
+ {
+ name = "sysconfdir";
+ p = line + 11;
+ }
+ else if (!strncmp (line, "sysconfdir =", 12)) /* (What a kludge) */
+ {
+ name = "sysconfdir";
+ p = line + 12;
+ }
+ else
+ continue;
+ trim_spaces (p);
+ p = substitute_envvars (p);
+ if (!p)
+ {
+ err = gpg_error_from_syserror ();
+ log_info ("error getting %s from gpgconf.ctl: %s\n",
+ name, gpg_strerror (err));
+ }
+ else if (!strcmp (name, "sysconfdir"))
+ {
+ xfree (sysconfdir);
+ sysconfdir = p;
+ }
+ else
+ {
+ xfree (rootdir);
+ rootdir = p;
+ }
+ }
+ if (es_ferror (fp))
+ {
+ err = gpg_error_from_syserror ();
+ log_info ("error reading '%s': %s\n", buffer, gpg_strerror (err));
+ es_fclose (fp);
+ xfree (buffer);
+ xfree (line);
+ checked = 1;
+ return NULL;
+ }
+ es_fclose (fp);
+ xfree (buffer);
+ xfree (line);
+
+ if (!rootdir || !*rootdir || *rootdir != '/')
+ {
+ log_info ("invalid rootdir '%s' specified in gpgconf.ctl\n", rootdir);
+ xfree (rootdir);
+ xfree (sysconfdir);
+ dir = NULL;
+ }
+ else if (sysconfdir && (!*sysconfdir || *sysconfdir != '/'))
+ {
+ log_info ("invalid sysconfdir '%s' specified in gpgconf.ctl\n",
+ sysconfdir);
+ xfree (rootdir);
+ xfree (sysconfdir);
+ dir = NULL;
+ }
+ else
+ {
+ while (*rootdir && rootdir[strlen (rootdir)-1] == '/')
+ rootdir[strlen (rootdir)-1] = 0;
+ dir = rootdir;
+ gpgrt_annotate_leaked_object (dir);
+ /* log_info ("want rootdir '%s'\n", dir); */
+ if (sysconfdir)
+ {
+ while (*sysconfdir && sysconfdir[strlen (sysconfdir)-1] == '/')
+ sysconfdir[strlen (sysconfdir)-1] = 0;
+ sdir = sysconfdir;
+ gpgrt_annotate_leaked_object (sdir);
+ /* log_info ("want sysconfdir '%s'\n", sdir); */
+ }
+ }
+ checked = 1;
+ }
+
+ return want_sysconfdir? sdir : dir;
+}
+#endif /* Unix */
+
+
+#ifdef HAVE_W32_SYSTEM
+static const char *
+w32_commondir (void)
+{
+ static char *dir;
+
+ if (!dir)
+ {
+ const char *rdir;
+ char *path;
+
+ /* Make sure that w32_rootdir has been called so that we are
+ able to check the portable application flag. The common dir
+ is the identical to the rootdir. In that case there is also
+ no need to strdup its value. */
+ rdir = w32_rootdir ();
+ if (w32_portable_app)
+ return rdir;
+
+ path = w32_shgetfolderpath (NULL, CSIDL_COMMON_APPDATA, NULL, 0);
+ if (path)
+ {
+ dir = xstrconcat (path, "\\GNU", NULL);
+ /* No auto create of the directory. Either the installer or
+ * the admin has to create these directories. */
+ }
+ else
+ {
+ /* Folder not found or defined - probably an old Windows
+ * version. Use the installation directory instead. */
+ dir = xstrdup (rdir);
+ }
+ }
+
+ return dir;
+}
+#endif /*HAVE_W32_SYSTEM*/
+
+
+/* Change the homedir. Some care must be taken to set this early
+ * enough because previous calls to gnupg_homedir may else return a
+ * different string. */
+void
+gnupg_set_homedir (const char *newdir)
+{
+ char *tmp = NULL;
+
+ if (!newdir || !*newdir)
+ newdir = default_homedir ();
+ else
+ {
+ tmp = copy_dir_with_fixup (newdir);
+ if (tmp)
+ newdir = tmp;
+
+ if (!is_gnupg_default_homedir (newdir))
+ non_default_homedir = 1;
+ }
+ xfree (the_gnupg_homedir);
+ the_gnupg_homedir = make_absfilename (newdir, NULL);;
+ xfree (tmp);
+}
+
+
+/* Create the homedir directory only if the supplied directory name is
+ * the same as the default one. This way we avoid to create arbitrary
+ * directories when a non-default home directory is used. To cope
+ * with HOME, we do compare only the suffix if we see that the default
+ * homedir does start with a tilde. If the mkdir fails the function
+ * terminates the process. If QUIET is set not diagnostic is printed
+ * on homedir creation. */
+void
+gnupg_maybe_make_homedir (const char *fname, int quiet)
+{
+ const char *defhome = standard_homedir ();
+
+ if (
+#ifdef HAVE_W32_SYSTEM
+ ( !compare_filenames (fname, defhome) )
+#else
+ ( *defhome == '~'
+ && (strlen(fname) >= strlen (defhome+1)
+ && !strcmp(fname+strlen(fname)-strlen(defhome+1), defhome+1 ) ))
+ || (*defhome != '~' && !compare_filenames( fname, defhome ) )
+#endif
+ )
+ {
+ if (gnupg_mkdir (fname, "-rwx"))
+ log_fatal ( _("can't create directory '%s': %s\n"),
+ fname, strerror(errno) );
+ else if (!quiet )
+ log_info ( _("directory '%s' created\n"), fname );
+ }
+}
+
+
+/* Return the homedir. The returned string is valid until another
+ * gnupg-set-homedir call. This is always an absolute directory name.
+ * The function replaces the former global var opt.homedir. */
+const char *
+gnupg_homedir (void)
+{
+ /* If a homedir has not been set, set it to the default. */
+ if (!the_gnupg_homedir)
+ the_gnupg_homedir = make_absfilename (default_homedir (), NULL);
+ return the_gnupg_homedir;
+}
+
+
+/* Return whether the home dir is the default one. */
+int
+gnupg_default_homedir_p (void)
+{
+ return !non_default_homedir;
+}
+
+
+/* Return the directory name used by daemons for their current working
+ * directory. */
+const char *
+gnupg_daemon_rootdir (void)
+{
+#ifdef HAVE_W32_SYSTEM
+ static char *name;
+
+ if (!name)
+ {
+ char path[MAX_PATH];
+ size_t n;
+
+ n = GetSystemDirectoryA (path, sizeof path);
+ if (!n || n >= sizeof path)
+ name = xstrdup ("/"); /* Error - use the curret top dir instead. */
+ else
+ name = xstrdup (path);
+ }
+
+ return name;
+
+#else /*!HAVE_W32_SYSTEM*/
+ return "/";
+#endif /*!HAVE_W32_SYSTEM*/
+}
+
+
+/* Helper for gnupg-socketdir. This is a global function, so that
+ * gpgconf can use it for its --create-socketdir command. If
+ * SKIP_CHECKS is set permission checks etc. are not done. The
+ * function always returns a malloced directory name and stores these
+ * bit flags at R_INFO:
+ *
+ * 1 := Internal error, stat failed, out of core, etc.
+ * 2 := No /run/user directory.
+ * 4 := Directory not owned by the user, not a directory
+ * or wrong permissions.
+ * 8 := Same as 4 but for the subdir.
+ * 16 := mkdir failed
+ * 32 := Non default homedir; checking subdir.
+ * 64 := Subdir does not exist.
+ * 128 := Using homedir as fallback.
+ */
+char *
+_gnupg_socketdir_internal (int skip_checks, unsigned *r_info)
+{
+#if defined(HAVE_W32_SYSTEM)
+ char *name;
+
+ (void)skip_checks;
+
+ *r_info = 0;
+
+ /* First make sure that non_default_homedir and w32_portable_app can
+ * be set. */
+ gnupg_homedir ();
+
+ if (w32_portable_app)
+ {
+ name = xstrconcat (w32_rootdir (), DIRSEP_S, "gnupg", NULL);
+ }
+ else
+ {
+ char *path;
+
+ path = w32_shgetfolderpath (NULL,
+ CSIDL_LOCAL_APPDATA|CSIDL_FLAG_CREATE,
+ NULL, 0);
+ if (path)
+ {
+ name = xstrconcat (path, "\\gnupg", NULL);
+ xfree (path);
+ if (gnupg_access (name, F_OK))
+ gnupg_mkdir (name, "-rwx");
+ }
+ else
+ {
+ name = xstrdup (gnupg_homedir ());
+ }
+ }
+
+ /* If a non default homedir is used, we check whether an
+ * corresponding sub directory below the socket dir is available
+ * and use that. We hash the non default homedir to keep the new
+ * subdir short enough. */
+ if (non_default_homedir)
+ {
+ char sha1buf[20];
+ struct stat sb;
+ char *suffix;
+ char *p;
+
+ *r_info |= 32; /* Testing subdir. */
+
+ /* Canonicalize the name to avoid problems with mixed case
+ * names. Note that we use only 10 bytes of the hash because on
+ * Windows the account name is also part of the name. */
+ suffix = ascii_strlwr (xstrdup (gnupg_homedir ()));
+ for (p=suffix; *p; p++)
+ if ( *p == '\\')
+ *p = '/';
+ gcry_md_hash_buffer (GCRY_MD_SHA1, sha1buf, suffix, strlen (suffix));
+ xfree (suffix);
+ suffix = zb32_encode (sha1buf, 8*10);
+ if (!suffix)
+ {
+ *r_info |= 1; /* Out of core etc. */
+ goto leave_w32;
+ }
+ p = xstrconcat (name, "\\d.", suffix, NULL);
+ xfree (suffix);
+ xfree (name);
+ name = p;
+
+ /* Stat that directory and check constraints.
+ * The command
+ * gpgconf --remove-socketdir
+ * can be used to remove that directory. */
+ if (gnupg_stat (name, &sb))
+ {
+ if (errno != ENOENT)
+ *r_info |= 1; /* stat failed. */
+ else if (!skip_checks)
+ {
+ /* Try to create the directory and check again. */
+ if (gnupg_mkdir (name, "-rwx"))
+ *r_info |= 16; /* mkdir failed. */
+ else if (gnupg_stat (name, &sb))
+ {
+ if (errno != ENOENT)
+ *r_info |= 1; /* stat failed. */
+ else
+ *r_info |= 64; /* Subdir does not exist. */
+ }
+ else
+ goto leave_w32; /* Success! */
+ }
+ else
+ *r_info |= 64; /* Subdir does not exist. */
+ if (!skip_checks)
+ {
+ xfree (name);
+ name = NULL;
+ goto leave_w32;
+ }
+ }
+ }
+
+ leave_w32:
+ /* If nothing works - fall back to the homedir. */
+ if (!name)
+ {
+ *r_info |= 128; /* Fallback. */
+ name = xstrdup (gnupg_homedir ());
+ }
+
+#elif !defined(HAVE_STAT)
+ char *name;
+
+ (void)skip_checks;
+ *r_info = 0;
+ name = xstrdup (gnupg_homedir ());
+
+#else /* Unix and stat(2) available. */
+
+ static const char * const bases[] = {
+#ifdef USE_RUN_GNUPG_USER_SOCKET
+ "/run/gnupg",
+#endif
+ "/run",
+#ifdef USE_RUN_GNUPG_USER_SOCKET
+ "/var/run/gnupg",
+#endif
+ "/var/run",
+ NULL
+ };
+ int i;
+ struct stat sb;
+ char prefix[19 + 1 + 20 + 6 + 1];
+ const char *s;
+ char *name = NULL;
+
+ *r_info = 0;
+
+ /* First make sure that non_default_homedir can be set. */
+ gnupg_homedir ();
+
+ /* It has been suggested to first check XDG_RUNTIME_DIR envvar.
+ * However, the specs state that the lifetime of the directory MUST
+ * be bound to the user being logged in. Now GnuPG may also be run
+ * as a background process with no (desktop) user logged in. Thus
+ * we better don't do that. */
+
+ /* Check whether we have a /run/[gnupg/]user dir. */
+ for (i=0; bases[i]; i++)
+ {
+ snprintf (prefix, sizeof prefix, "%s/user/%u",
+ bases[i], (unsigned int)getuid ());
+ if (!stat (prefix, &sb) && S_ISDIR(sb.st_mode))
+ break;
+ }
+ if (!bases[i])
+ {
+ *r_info |= 2; /* No /run/user directory. */
+ goto leave;
+ }
+
+ if (sb.st_uid != getuid ())
+ {
+ *r_info |= 4; /* Not owned by the user. */
+ if (!skip_checks)
+ goto leave;
+ }
+
+ if (strlen (prefix) + 7 >= sizeof prefix)
+ {
+ *r_info |= 1; /* Ooops: Buffer too short to append "/gnupg". */
+ goto leave;
+ }
+ strcat (prefix, "/gnupg");
+
+ /* Check whether the gnupg sub directory has proper permissions. */
+ if (stat (prefix, &sb))
+ {
+ if (errno != ENOENT)
+ {
+ *r_info |= 1; /* stat failed. */
+ goto leave;
+ }
+
+ /* Try to create the directory and check again. */
+ if (gnupg_mkdir (prefix, "-rwx"))
+ {
+ *r_info |= 16; /* mkdir failed. */
+ goto leave;
+ }
+ if (stat (prefix, &sb))
+ {
+ *r_info |= 1; /* stat failed. */
+ goto leave;
+ }
+ }
+ /* Check that it is a directory, owned by the user, and only the
+ * user has permissions to use it. */
+ if (!S_ISDIR(sb.st_mode)
+ || sb.st_uid != getuid ()
+ || (sb.st_mode & (S_IRWXG|S_IRWXO)))
+ {
+ *r_info |= 4; /* Bad permissions or not a directory. */
+ if (!skip_checks)
+ goto leave;
+ }
+
+ /* If a non default homedir is used, we check whether an
+ * corresponding sub directory below the socket dir is available
+ * and use that. We hash the non default homedir to keep the new
+ * subdir short enough. */
+ if (non_default_homedir)
+ {
+ char sha1buf[20];
+ char *suffix;
+
+ *r_info |= 32; /* Testing subdir. */
+ s = gnupg_homedir ();
+ gcry_md_hash_buffer (GCRY_MD_SHA1, sha1buf, s, strlen (s));
+ suffix = zb32_encode (sha1buf, 8*15);
+ if (!suffix)
+ {
+ *r_info |= 1; /* Out of core etc. */
+ goto leave;
+ }
+ name = strconcat (prefix, "/d.", suffix, NULL);
+ xfree (suffix);
+ if (!name)
+ {
+ *r_info |= 1; /* Out of core etc. */
+ goto leave;
+ }
+
+ /* Stat that directory and check constraints.
+ * The command
+ * gpgconf --remove-socketdir
+ * can be used to remove that directory. */
+ if (stat (name, &sb))
+ {
+ if (errno != ENOENT)
+ *r_info |= 1; /* stat failed. */
+ else if (!skip_checks)
+ {
+ /* Try to create the directory and check again. */
+ if (gnupg_mkdir (name, "-rwx"))
+ *r_info |= 16; /* mkdir failed. */
+ else if (stat (prefix, &sb))
+ {
+ if (errno != ENOENT)
+ *r_info |= 1; /* stat failed. */
+ else
+ *r_info |= 64; /* Subdir does not exist. */
+ }
+ else
+ goto leave; /* Success! */
+ }
+ else
+ *r_info |= 64; /* Subdir does not exist. */
+ if (!skip_checks)
+ {
+ xfree (name);
+ name = NULL;
+ goto leave;
+ }
+ }
+ else if (!S_ISDIR(sb.st_mode)
+ || sb.st_uid != getuid ()
+ || (sb.st_mode & (S_IRWXG|S_IRWXO)))
+ {
+ *r_info |= 8; /* Bad permissions or subdir is not a directory. */
+ if (!skip_checks)
+ {
+ xfree (name);
+ name = NULL;
+ goto leave;
+ }
+ }
+ }
+ else
+ name = xstrdup (prefix);
+
+ leave:
+ /* If nothing works fall back to the homedir. */
+ if (!name)
+ {
+ *r_info |= 128; /* Fallback. */
+ name = xstrdup (gnupg_homedir ());
+ }
+
+#endif /* Unix */
+
+ return name;
+}
+
+
+/*
+ * Return the name of the socket dir. That is the directory used for
+ * the IPC local sockets. This is an absolute directory name.
+ */
+const char *
+gnupg_socketdir (void)
+{
+ static char *name;
+
+ if (!name)
+ {
+ unsigned int dummy;
+ name = _gnupg_socketdir_internal (0, &dummy);
+ }
+
+ return name;
+}
+
+
+/* Return the name of the sysconfdir. This is a static string. This
+ function is required because under Windows we can't simply compile
+ it in. */
+const char *
+gnupg_sysconfdir (void)
+{
+#ifdef HAVE_W32_SYSTEM
+ static char *name;
+
+ if (!name)
+ {
+ const char *s1, *s2;
+ s1 = w32_commondir ();
+ s2 = DIRSEP_S "etc" DIRSEP_S "gnupg";
+ name = xmalloc (strlen (s1) + strlen (s2) + 1);
+ strcpy (stpcpy (name, s1), s2);
+ }
+ return name;
+#else /*!HAVE_W32_SYSTEM*/
+ const char *dir = unix_rootdir (1);
+ if (dir)
+ return dir;
+ else
+ return GNUPG_SYSCONFDIR;
+#endif /*!HAVE_W32_SYSTEM*/
+}
+
+
+const char *
+gnupg_bindir (void)
+{
+ static char *name;
+ const char *rdir;
+
+#if defined(HAVE_W32_SYSTEM)
+ rdir = w32_rootdir ();
+ if (w32_bin_is_bin)
+ {
+ if (!name)
+ name = xstrconcat (rdir, DIRSEP_S "bin", NULL);
+ return name;
+ }
+ else
+ return rdir;
+#else /*!HAVE_W32_SYSTEM*/
+ rdir = unix_rootdir (0);
+ if (rdir)
+ {
+ if (!name)
+ {
+ name = xstrconcat (rdir, DIRSEP_S "bin", NULL);
+ gpgrt_annotate_leaked_object (name);
+ }
+ return name;
+ }
+ else
+ return GNUPG_BINDIR;
+#endif /*!HAVE_W32_SYSTEM*/
+}
+
+
+/* Return the name of the libexec directory. The name is allocated in
+ a static area on the first use. This function won't fail. */
+const char *
+gnupg_libexecdir (void)
+{
+#ifdef HAVE_W32_SYSTEM
+ return gnupg_bindir ();
+#else /*!HAVE_W32_SYSTEM*/
+ static char *name;
+ const char *rdir;
+
+ rdir = unix_rootdir (0);
+ if (rdir)
+ {
+ if (!name)
+ {
+ name = xstrconcat (rdir, DIRSEP_S "libexec", NULL);
+ gpgrt_annotate_leaked_object (name);
+ }
+ return name;
+ }
+ else
+ return GNUPG_LIBEXECDIR;
+#endif /*!HAVE_W32_SYSTEM*/
+}
+
+const char *
+gnupg_libdir (void)
+{
+ static char *name;
+
+#ifdef HAVE_W32_SYSTEM
+ if (!name)
+ name = xstrconcat (w32_rootdir (), DIRSEP_S "lib" DIRSEP_S "gnupg", NULL);
+ return name;
+#else /*!HAVE_W32_SYSTEM*/
+ const char *rdir;
+
+ rdir = unix_rootdir (0);
+ if (rdir)
+ {
+ if (!name)
+ {
+ name = xstrconcat (rdir, DIRSEP_S "lib", DIRSEP_S, "gnupg", NULL);
+ gpgrt_annotate_leaked_object (name);
+ }
+ return name;
+ }
+ else
+ return GNUPG_LIBDIR;
+#endif /*!HAVE_W32_SYSTEM*/
+}
+
+const char *
+gnupg_datadir (void)
+{
+ static char *name;
+
+#ifdef HAVE_W32_SYSTEM
+ if (!name)
+ name = xstrconcat (w32_rootdir (), DIRSEP_S "share" DIRSEP_S "gnupg", NULL);
+ return name;
+#else /*!HAVE_W32_SYSTEM*/
+ const char *rdir;
+
+ rdir = unix_rootdir (0);
+ if (rdir)
+ {
+ if (!name)
+ {
+ name = xstrconcat (rdir, DIRSEP_S "share" DIRSEP_S "gnupg", NULL);
+ gpgrt_annotate_leaked_object (name);
+ }
+ return name;
+ }
+ else
+ return GNUPG_DATADIR;
+#endif /*!HAVE_W32_SYSTEM*/
+}
+
+
+const char *
+gnupg_localedir (void)
+{
+ static char *name;
+
+#ifdef HAVE_W32_SYSTEM
+ if (!name)
+ name = xstrconcat (w32_rootdir (), DIRSEP_S "share" DIRSEP_S "locale",
+ NULL);
+ return name;
+#else /*!HAVE_W32_SYSTEM*/
+ const char *rdir;
+
+ rdir = unix_rootdir (0);
+ if (rdir)
+ {
+ if (!name)
+ {
+ name = xstrconcat (rdir, DIRSEP_S "share" DIRSEP_S "locale", NULL);
+ gpgrt_annotate_leaked_object (name);
+ }
+ return name;
+ }
+ else
+ return LOCALEDIR;
+#endif /*!HAVE_W32_SYSTEM*/
+}
+
+
+/* Return the standard socket name used by gpg-agent. */
+const char *
+gpg_agent_socket_name (void)
+{
+ static char *name;
+
+ if (!name)
+ {
+ name = make_filename (gnupg_socketdir (), GPG_AGENT_SOCK_NAME, NULL);
+ gpgrt_annotate_leaked_object (name);
+ }
+ return name;
+}
+
+
+/* Return the user socket name used by DirMngr. */
+const char *
+dirmngr_socket_name (void)
+{
+ static char *name;
+
+ if (!name)
+ name = make_filename (gnupg_socketdir (), DIRMNGR_SOCK_NAME, NULL);
+ return name;
+}
+
+
+/* Return the default pinentry name. If RESET is true the internal
+ cache is first flushed. */
+static const char *
+get_default_pinentry_name (int reset)
+{
+ static struct {
+ const char *(*rfnc)(void);
+ const char *name;
+ } names[] = {
+ /* The first entry is what we return in case we found no
+ other pinentry. */
+ { gnupg_bindir, DIRSEP_S "pinentry" EXEEXT_S },
+#ifdef HAVE_W32_SYSTEM
+ /* Try Gpg4win directory (with bin and without.) */
+ { w32_rootdir, "\\..\\Gpg4win\\bin\\pinentry.exe" },
+ { w32_rootdir, "\\..\\Gpg4win\\pinentry.exe" },
+ /* Try a pinentry in a dir above us */
+ { w32_rootdir, "\\..\\bin\\pinentry.exe" },
+ /* Try old Gpgwin directory. */
+ { w32_rootdir, "\\..\\GNU\\GnuPG\\pinentry.exe" },
+ /* Try a Pinentry from the common GNU dir. */
+ { w32_rootdir, "\\..\\GNU\\bin\\pinentry.exe" },
+#endif
+ /* Last chance is a pinentry-basic (which comes with the
+ GnuPG 2.1 Windows installer). */
+ { gnupg_bindir, DIRSEP_S "pinentry-basic" EXEEXT_S }
+ };
+ static char *name;
+
+ if (reset)
+ {
+ xfree (name);
+ name = NULL;
+ }
+
+ if (!name)
+ {
+ int i;
+
+ for (i=0; i < DIM(names); i++)
+ {
+ char *name2;
+
+ name2 = xstrconcat (names[i].rfnc (), names[i].name, NULL);
+ if (!gnupg_access (name2, F_OK))
+ {
+ /* Use that pinentry. */
+ xfree (name);
+ name = name2;
+ break;
+ }
+ if (!i) /* Store the first as fallback return. */
+ name = name2;
+ else
+ xfree (name2);
+ }
+ }
+
+ return name;
+}
+
+
+/* If set, 'gnupg_module_name' returns modules from that build
+ * directory. */
+static char *gnupg_build_directory;
+
+/* For sanity checks. */
+static int gnupg_module_name_called;
+
+
+/* Set NEWDIR as the new build directory. This will make
+ * 'gnupg_module_name' return modules from that build directory. Must
+ * be called before any invocation of 'gnupg_module_name', and must
+ * not be called twice. It can be used by test suites to make sure
+ * the components from the build directory are used instead of
+ * potentially outdated installed ones.
+ * Fixme: It might be better to make use of the newer gpgconf.ctl feature
+ * for regression testing.
+ */
+void
+gnupg_set_builddir (const char *newdir)
+{
+ log_assert (! gnupg_module_name_called);
+ log_assert (! gnupg_build_directory);
+ gnupg_build_directory = xtrystrdup (newdir);
+}
+
+
+/* If no build directory has been configured, try to set it from the
+ * environment. We only do this in development builds to avoid
+ * increasing the set of influential environment variables and hence
+ * the attack surface of production builds. */
+static void
+gnupg_set_builddir_from_env (void)
+{
+#if defined(IS_DEVELOPMENT_VERSION) || defined(ENABLE_GNUPG_BUILDDIR_ENVVAR)
+ if (gnupg_build_directory)
+ return;
+
+ gnupg_build_directory = getenv ("GNUPG_BUILDDIR");
+#endif
+}
+
+
+/* Return the file name of a helper tool. WHICH is one of the
+ GNUPG_MODULE_NAME_foo constants. */
+const char *
+gnupg_module_name (int which)
+{
+ gnupg_set_builddir_from_env ();
+ gnupg_module_name_called = 1;
+
+#define X(a,b,c) do { \
+ static char *name; \
+ if (!name) \
+ name = gnupg_build_directory \
+ ? xstrconcat (gnupg_build_directory, \
+ DIRSEP_S b DIRSEP_S c EXEEXT_S, NULL) \
+ : xstrconcat (gnupg_ ## a (), DIRSEP_S c EXEEXT_S, NULL); \
+ return name; \
+ } while (0)
+
+ switch (which)
+ {
+ case GNUPG_MODULE_NAME_AGENT:
+#ifdef GNUPG_DEFAULT_AGENT
+ return GNUPG_DEFAULT_AGENT;
+#else
+ X(bindir, "agent", "gpg-agent");
+#endif
+
+ case GNUPG_MODULE_NAME_PINENTRY:
+#ifdef GNUPG_DEFAULT_PINENTRY
+ return GNUPG_DEFAULT_PINENTRY; /* (Set by a configure option) */
+#else
+ return get_default_pinentry_name (0);
+#endif
+
+ case GNUPG_MODULE_NAME_SCDAEMON:
+#ifdef GNUPG_DEFAULT_SCDAEMON
+ return GNUPG_DEFAULT_SCDAEMON;
+#else
+ X(libexecdir, "scd", "scdaemon");
+#endif
+
+ case GNUPG_MODULE_NAME_DIRMNGR:
+#ifdef GNUPG_DEFAULT_DIRMNGR
+ return GNUPG_DEFAULT_DIRMNGR;
+#else
+ X(bindir, "dirmngr", DIRMNGR_NAME);
+#endif
+
+ case GNUPG_MODULE_NAME_PROTECT_TOOL:
+#ifdef GNUPG_DEFAULT_PROTECT_TOOL
+ return GNUPG_DEFAULT_PROTECT_TOOL;
+#else
+ X(libexecdir, "agent", "gpg-protect-tool");
+#endif
+
+ case GNUPG_MODULE_NAME_DIRMNGR_LDAP:
+#ifdef GNUPG_DEFAULT_DIRMNGR_LDAP
+ return GNUPG_DEFAULT_DIRMNGR_LDAP;
+#else
+ X(libexecdir, "dirmngr", "dirmngr_ldap");
+#endif
+
+ case GNUPG_MODULE_NAME_CHECK_PATTERN:
+ X(libexecdir, "tools", "gpg-check-pattern");
+
+ case GNUPG_MODULE_NAME_GPGSM:
+ X(bindir, "sm", "gpgsm");
+
+ case GNUPG_MODULE_NAME_GPG:
+#if USE_GPG2_HACK
+ if (! gnupg_build_directory)
+ X(bindir, "g10", GPG_NAME "2");
+ else
+#endif
+ X(bindir, "g10", GPG_NAME);
+
+ case GNUPG_MODULE_NAME_GPGV:
+#if USE_GPG2_HACK
+ if (! gnupg_build_directory)
+ X(bindir, "g10", GPG_NAME "v2");
+ else
+#endif
+ X(bindir, "g10", GPG_NAME "v");
+
+ case GNUPG_MODULE_NAME_CONNECT_AGENT:
+ X(bindir, "tools", "gpg-connect-agent");
+
+ case GNUPG_MODULE_NAME_GPGCONF:
+ X(bindir, "tools", "gpgconf");
+
+ default:
+ BUG ();
+ }
+#undef X
+}
+
+
+/* Flush some of the cached module names. This is for example used by
+ gpg-agent to allow configuring a different pinentry. */
+void
+gnupg_module_name_flush_some (void)
+{
+ (void)get_default_pinentry_name (1);
+}
diff --git a/common/host2net.h b/common/host2net.h
new file mode 100644
index 0000000..9eeaf24
--- /dev/null
+++ b/common/host2net.h
@@ -0,0 +1,112 @@
+/* host2net.h - Endian conversion macros
+ * Copyright (C) 1998, 2014, 2015 Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_COMMON_HOST2NET_H
+#define GNUPG_COMMON_HOST2NET_H
+
+#include "types.h"
+
+#define ulongtobuf( p, a ) do { \
+ ((byte*)p)[0] = a >> 24; \
+ ((byte*)p)[1] = a >> 16; \
+ ((byte*)p)[2] = a >> 8; \
+ ((byte*)p)[3] = a ; \
+ } while(0)
+#define ushorttobuf( p, a ) do { \
+ ((byte*)p)[0] = a >> 8; \
+ ((byte*)p)[1] = a ; \
+ } while(0)
+
+
+static inline unsigned long
+buf16_to_ulong (const void *buffer)
+{
+ const unsigned char *p = buffer;
+
+ return (((unsigned long)p[0] << 8) | p[1]);
+}
+
+static inline unsigned int
+buf16_to_uint (const void *buffer)
+{
+ const unsigned char *p = buffer;
+
+ return (((unsigned int)p[0] << 8) | p[1]);
+}
+
+static inline unsigned short
+buf16_to_ushort (const void *buffer)
+{
+ const unsigned char *p = buffer;
+
+ return (((unsigned short)p[0] << 8) | p[1]);
+}
+
+static inline u16
+buf16_to_u16 (const void *buffer)
+{
+ const unsigned char *p = buffer;
+
+ return (((u16)p[0] << 8) | p[1]);
+}
+
+static inline size_t
+buf32_to_size_t (const void *buffer)
+{
+ const unsigned char *p = buffer;
+
+ return (((size_t)p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
+}
+
+static inline unsigned long
+buf32_to_ulong (const void *buffer)
+{
+ const unsigned char *p = buffer;
+
+ return (((unsigned long)p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
+}
+
+static inline unsigned int
+buf32_to_uint (const void *buffer)
+{
+ const unsigned char *p = buffer;
+
+ return (((unsigned int)p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
+}
+
+static inline u32
+buf32_to_u32 (const void *buffer)
+{
+ const unsigned char *p = buffer;
+
+ return (((u32)p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
+}
+
+
+#endif /*GNUPG_COMMON_HOST2NET_H*/
diff --git a/common/i18n.c b/common/i18n.c
new file mode 100644
index 0000000..60362ce
--- /dev/null
+++ b/common/i18n.c
@@ -0,0 +1,237 @@
+/* i18n.c - gettext initialization
+ * Copyright (C) 2007, 2010 Free Software Foundation, Inc.
+ * Copyright (C) 2015 g10 Code GmbH
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#ifdef HAVE_LOCALE_H
+#include <locale.h>
+#endif
+#ifdef HAVE_LANGINFO_CODESET
+#include <langinfo.h>
+#endif
+
+#include "util.h"
+#include "i18n.h"
+
+
+#undef USE_MSGCACHE
+#if defined(HAVE_SETLOCALE) && defined(LC_MESSAGES) \
+ && !defined(USE_SIMPLE_GETTEXT) && defined(ENABLE_NLS)
+# define USE_MSGCACHE 1
+#endif
+
+
+#ifdef USE_MSGCACHE
+/* An object to store pointers to static strings and their static
+ translations. A linked list is not optimal but given that we only
+ have a few dozen messages it should be acceptable. */
+struct msg_cache_s
+{
+ struct msg_cache_s *next;
+ const char *key;
+ const char *value;
+};
+
+/* A object to store an lc_messages string and a link to the cache
+ object. */
+struct msg_cache_heads_s
+{
+ struct msg_cache_heads_s *next;
+ struct msg_cache_s *cache;
+ char lc_messages[1];
+};
+
+/* Out static cache of translated messages. We need this because
+ there is no gettext API to return a translation depending on the
+ locale. Switching the locale for each access to a translatable
+ string seems to be too expensive. Note that this is used only for
+ strings in gpg-agent which are passed to Pinentry. All other
+ strings are using the regular gettext interface. Note that we can
+ never release this memory because consumers take the result as
+ static strings. */
+static struct msg_cache_heads_s *msgcache;
+
+#endif /*USE_MSGCACHE*/
+
+
+void
+i18n_init (void)
+{
+#ifdef USE_SIMPLE_GETTEXT
+ bindtextdomain (PACKAGE_GT, gnupg_localedir ());
+ textdomain (PACKAGE_GT);
+#else
+# ifdef ENABLE_NLS
+ setlocale (LC_ALL, "" );
+ bindtextdomain (PACKAGE_GT, gnupg_localedir ());
+ textdomain (PACKAGE_GT);
+# endif
+#endif
+}
+
+
+/* The Assuan agent protocol requires us to transmit utf-8 strings
+ thus we need a way to temporary switch gettext from native to
+ utf8. */
+char *
+i18n_switchto_utf8 (void)
+{
+#ifdef USE_SIMPLE_GETTEXT
+ /* Return an arbitrary pointer as true value. */
+ return gettext_use_utf8 (1) ? (char*)(-1) : NULL;
+#elif defined(ENABLE_NLS)
+ char *orig_codeset = bind_textdomain_codeset (PACKAGE_GT, NULL);
+# ifdef HAVE_LANGINFO_CODESET
+ if (!orig_codeset)
+ orig_codeset = nl_langinfo (CODESET);
+# endif
+ if (orig_codeset)
+ { /* We only switch when we are able to restore the codeset later.
+ Note that bind_textdomain_codeset does only return on memory
+ errors but not if a codeset is not available. Thus we don't
+ bother printing a diagnostic here. */
+ orig_codeset = xstrdup (orig_codeset);
+ if (!bind_textdomain_codeset (PACKAGE_GT, "utf-8"))
+ {
+ xfree (orig_codeset);
+ orig_codeset = NULL;
+ }
+ }
+ return orig_codeset;
+#else
+ return NULL;
+#endif
+}
+
+/* Switch back to the saved codeset. */
+void
+i18n_switchback (char *saved_codeset)
+{
+#ifdef USE_SIMPLE_GETTEXT
+ gettext_use_utf8 (!!saved_codeset);
+#elif defined(ENABLE_NLS)
+ if (saved_codeset)
+ {
+ bind_textdomain_codeset (PACKAGE_GT, saved_codeset);
+ xfree (saved_codeset);
+ }
+#else
+ (void)saved_codeset;
+#endif
+}
+
+
+/* Gettext variant which temporary switches to utf-8 for string. */
+const char *
+i18n_utf8 (const char *string)
+{
+ char *saved = i18n_switchto_utf8 ();
+ const char *result = _(string);
+ i18n_switchback (saved);
+ return result;
+}
+
+
+/* A variant of gettext which allows the programmer to specify the
+ locale to use for translating the message. The function assumes
+ that utf-8 is used for the encoding. */
+const char *
+i18n_localegettext (const char *lc_messages, const char *string)
+{
+#if USE_MSGCACHE
+ const char *result = NULL;
+ char *saved = NULL;
+ struct msg_cache_heads_s *mh;
+ struct msg_cache_s *mc;
+
+ if (!lc_messages)
+ goto leave;
+
+ /* Lookup in the cache. */
+ for (mh = msgcache; mh; mh = mh->next)
+ if (!strcmp (mh->lc_messages, lc_messages))
+ break;
+ if (mh)
+ {
+ /* A cache entry for this local exists - find the string.
+ Because the system is designed for static strings it is
+ sufficient to compare the pointers. */
+ for (mc = mh->cache; mc; mc = mc->next)
+ if (mc->key == string)
+ {
+ /* Cache hit. */
+ result = mc->value;
+ goto leave;
+ }
+ }
+
+ /* Cached miss. Change the locale, translate, reset locale. */
+ saved = setlocale (LC_MESSAGES, NULL);
+ if (!saved)
+ goto leave;
+ saved = xtrystrdup (saved);
+ if (!saved)
+ goto leave;
+ if (!setlocale (LC_MESSAGES, lc_messages))
+ goto leave;
+
+ bindtextdomain (PACKAGE_GT, gnupg_localedir ());
+ result = gettext (string);
+ setlocale (LC_MESSAGES, saved);
+ bindtextdomain (PACKAGE_GT, gnupg_localedir ());
+
+ /* Cache the result. */
+ if (!mh)
+ {
+ /* First use of this locale - create an entry. */
+ mh = xtrymalloc (sizeof *mh + strlen (lc_messages));
+ if (!mh)
+ goto leave;
+ strcpy (mh->lc_messages, lc_messages);
+ mh->cache = NULL;
+ mh->next = msgcache;
+ msgcache = mh;
+ }
+ mc = xtrymalloc (sizeof *mc);
+ if (!mc)
+ goto leave;
+ mc->key = string;
+ mc->value = result;
+ mc->next = mh->cache;
+ mh->cache = mc;
+
+ leave:
+ xfree (saved);
+ return result? result : _(string);
+
+#else /*!USE_MSGCACHE*/
+
+ (void)lc_messages;
+ return _(string);
+
+#endif /*!USE_MSGCACHE*/
+}
diff --git a/common/i18n.h b/common/i18n.h
new file mode 100644
index 0000000..22e8a90
--- /dev/null
+++ b/common/i18n.h
@@ -0,0 +1,63 @@
+/* i18n.h
+ * Copyright (C) 1998, 2001 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.
+ */
+
+#ifndef GNUPG_COMMON_I18N_H
+#define GNUPG_COMMON_I18N_H
+
+
+#ifdef USE_SIMPLE_GETTEXT
+# include "../common/w32help.h"
+# define _(a) gettext (a)
+# define N_(a) (a)
+#else
+# ifdef HAVE_LOCALE_H
+# include <locale.h>
+# endif
+# ifdef ENABLE_NLS
+# include <libintl.h>
+# define _(a) gettext (a)
+# ifdef gettext_noop
+# define N_(a) gettext_noop (a)
+# else
+# define N_(a) (a)
+# endif
+# else
+# define _(a) (a)
+# define N_(a) (a)
+# define ngettext(a,b,c) ((c)==1? (a):(b))
+# endif
+#endif /*!USE_SIMPLE_GETTEXT*/
+
+#ifndef GNUPG_GCC_ATTR_FORMAT_ARG
+#if __GNUC__ >= 3 /* Actually 2.8 but testing the major is easier. */
+# define GNUPG_GCC_ATTR_FORMAT_ARG(a) __attribute__ ((__format_arg__ (a)))
+#else
+# define GNUPG_GCC_ATTR_FORMAT_ARG(a)
+#endif
+#endif
+
+void i18n_init (void);
+char *i18n_switchto_utf8 (void);
+void i18n_switchback (char *saved_codeset);
+const char *i18n_utf8 (const char *string);
+const char *i18n_localegettext (const char *lc_messages, const char *string)
+ GNUPG_GCC_ATTR_FORMAT_ARG(2);
+
+/* If a module wants a local L_() function we define it here. */
+#ifdef LunderscoreIMPL
+LunderscorePROTO
+LunderscoreIMPL
+#endif
+
+
+#endif /*GNUPG_COMMON_I18N_H*/
diff --git a/common/init.c b/common/init.c
new file mode 100644
index 0000000..4ae7cbc
--- /dev/null
+++ b/common/init.c
@@ -0,0 +1,384 @@
+/* init.c - Various initializations
+ * Copyright (C) 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#ifdef HAVE_W32_SYSTEM
+# ifdef HAVE_WINSOCK2_H
+# include <winsock2.h>
+# endif
+# include <windows.h>
+#endif
+#ifdef HAVE_W32CE_SYSTEM
+# include <assuan.h> /* For _assuan_w32ce_finish_pipe. */
+#endif
+
+#include <gcrypt.h>
+#include "util.h"
+#include "i18n.h"
+#include "w32help.h"
+
+/* This object is used to register memory cleanup functions.
+ Technically they are not needed but they can avoid frequent
+ questions about un-released memory. Note that we use the system
+ malloc and not any wrappers. */
+struct mem_cleanup_item_s;
+typedef struct mem_cleanup_item_s *mem_cleanup_item_t;
+
+struct mem_cleanup_item_s
+{
+ mem_cleanup_item_t next;
+ void (*func) (void);
+};
+
+static mem_cleanup_item_t mem_cleanup_list;
+
+
+/* The default error source of the application. This is different
+ from GPG_ERR_SOURCE_DEFAULT in that it does not depend on the
+ source file and thus is usable in code shared by applications.
+ Note that we need to initialize it because otherwise some linkers
+ (OS X at least) won't find the symbol when linking the t-*.c
+ files. */
+gpg_err_source_t default_errsource = 0;
+
+
+#ifdef HAVE_W32CE_SYSTEM
+static void parse_std_file_handles (int *argcp, char ***argvp);
+static void
+sleep_on_exit (void)
+{
+ /* The sshd on CE swallows some of the command output. Sleeping a
+ while usually helps. */
+ Sleep (400);
+}
+#endif /*HAVE_W32CE_SYSTEM*/
+
+#if HAVE_W32_SYSTEM
+static void prepare_w32_commandline (int *argcp, char ***argvp);
+#endif /*HAVE_W32_SYSTEM*/
+
+
+
+static void
+run_mem_cleanup (void)
+{
+ mem_cleanup_item_t next;
+
+ while (mem_cleanup_list)
+ {
+ next = mem_cleanup_list->next;
+ mem_cleanup_list->func ();
+ free (mem_cleanup_list);
+ mem_cleanup_list = next;
+ }
+}
+
+
+void
+register_mem_cleanup_func (void (*func)(void))
+{
+ mem_cleanup_item_t item;
+
+ for (item = mem_cleanup_list; item; item = item->next)
+ if (item->func == func)
+ return; /* Function has already been registered. */
+
+ item = malloc (sizeof *item);
+ if (item)
+ {
+ item->func = func;
+ item->next = mem_cleanup_list;
+ mem_cleanup_list = item;
+ }
+}
+
+
+/* If STRING is not NULL write string to es_stdout or es_stderr. MODE
+ must be 1 or 2. If STRING is NULL flush the respective stream. */
+static int
+writestring_via_estream (int mode, const char *string)
+{
+ if (mode == 1 || mode == 2)
+ {
+ if (string)
+ return es_fputs (string, mode == 1? es_stdout : es_stderr);
+ else
+ return es_fflush (mode == 1? es_stdout : es_stderr);
+ }
+ else
+ return -1;
+}
+
+
+/* This function should be the first called after main. */
+void
+early_system_init (void)
+{
+}
+
+
+/* This function is to be used early at program startup to make sure
+ that some subsystems are initialized. This is in particular
+ important for W32 to initialize the sockets so that our socket
+ emulation code used directly as well as in libassuan may be used.
+ It should best be called before any I/O is done so that setup
+ required for logging is ready. ARGCP and ARGVP are the addresses
+ of the parameters given to main. This function may modify them.
+
+ This function should be called only via the macro
+ init_common_subsystems.
+
+ CAUTION: This might be called while running suid(root). */
+void
+_init_common_subsystems (gpg_err_source_t errsource, int *argcp, char ***argvp)
+{
+ /* Store the error source in a global variable. */
+ default_errsource = errsource;
+
+ atexit (run_mem_cleanup);
+
+ /* Try to auto set the character set. */
+ set_native_charset (NULL);
+
+#ifdef HAVE_W32_SYSTEM
+ /* For W32 we need to initialize the socket layer. This is because
+ we use recv and send in libassuan as well as at some other
+ places. */
+ {
+ WSADATA wsadat;
+
+ WSAStartup (0x202, &wsadat);
+ }
+#endif
+
+#ifdef HAVE_W32CE_SYSTEM
+ /* Register the sleep exit function before the estream init so that
+ the sleep will be called after the estream registered atexit
+ function which flushes the left open estream streams and in
+ particular es_stdout. */
+ atexit (sleep_on_exit);
+#endif
+
+ if (!gcry_check_version (NEED_LIBGCRYPT_VERSION))
+ {
+ log_fatal (_("%s is too old (need %s, have %s)\n"), "libgcrypt",
+ NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL));
+ }
+
+ /* Initialize the Estream library. */
+ gpgrt_init ();
+ gpgrt_set_alloc_func (gcry_realloc);
+
+#ifdef HAVE_W32CE_SYSTEM
+ /* Special hack for Windows CE: We extract some options from arg
+ to setup the standard handles. */
+ parse_std_file_handles (argcp, argvp);
+#endif
+
+#ifdef HAVE_W32_SYSTEM
+ /* We want gettext to always output UTF-8 and we put the console in
+ * utf-8 mode. */
+ gettext_use_utf8 (1);
+ if (!SetConsoleCP (CP_UTF8) || !SetConsoleOutputCP (CP_UTF8))
+ {
+ /* Don't show the error if the program does not have a console.
+ * This is for example the case for daemons. */
+ int rc = GetLastError ();
+ if (rc != ERROR_INVALID_HANDLE)
+ {
+ log_info ("SetConsoleCP failed: %s\n", w32_strerror (rc));
+ log_info ("Warning: Garbled console data possible\n");
+ }
+ }
+#endif
+
+ /* Access the standard estreams as early as possible. If we don't
+ do this the original stdio streams may have been closed when
+ _es_get_std_stream is first use and in turn it would connect to
+ the bit bucket. */
+ {
+ int i;
+ for (i=0; i < 3; i++)
+ (void)_gpgrt_get_std_stream (i);
+ }
+
+ /* --version et al shall use estream as well. */
+ gnupg_set_usage_outfnc (writestring_via_estream);
+
+ /* Register our string mapper with gpgrt. */
+ gnupg_set_fixed_string_mapper (map_static_macro_string);
+
+ /* Logging shall use the standard socket directory as fallback. */
+ log_set_socket_dir_cb (gnupg_socketdir);
+
+#if HAVE_W32_SYSTEM
+ /* For Standard Windows we use our own parser for the command line
+ * so that we can return an array of utf-8 encoded strings. */
+ prepare_w32_commandline (argcp, argvp);
+#else
+ (void)argcp;
+ (void)argvp;
+#endif
+
+}
+
+
+
+/* WindowsCE uses a very strange way of handling the standard streams.
+ There is a function SetStdioPath to associate a standard stream
+ with a file or a device but what we really want is to use pipes as
+ standard streams. Despite that we implement pipes using a device,
+ we would have some limitations on the number of open pipes due to
+ the 3 character limit of device file name. Thus we don't take this
+ path. Another option would be to install a file system driver with
+ support for pipes; this would allow us to get rid of the device
+ name length limitation. However, with GnuPG we can get away be
+ redefining the standard streams and passing the handles to be used
+ on the command line. This has also the advantage that it makes
+ creating a process much easier and does not require the
+ SetStdioPath set and restore game. The caller needs to pass the
+ rendezvous ids using up to three options:
+
+ -&S0=<rvid> -&S1=<rvid> -&S2=<rvid>
+
+ They are all optional but they must be the first arguments on the
+ command line. Parsing stops as soon as an invalid option is found.
+ These rendezvous ids are then used to finish the pipe creation.*/
+#ifdef HAVE_W32CE_SYSTEM
+static void
+parse_std_file_handles (int *argcp, char ***argvp)
+{
+ int argc = *argcp;
+ char **argv = *argvp;
+ const char *s;
+ assuan_fd_t fd;
+ int i;
+ int fixup = 0;
+
+ if (!argc)
+ return;
+
+ for (argc--, argv++; argc; argc--, argv++)
+ {
+ s = *argv;
+ if (*s == '-' && s[1] == '&' && s[2] == 'S'
+ && (s[3] == '0' || s[3] == '1' || s[3] == '2')
+ && s[4] == '='
+ && (strchr ("-01234567890", s[5]) || !strcmp (s+5, "null")))
+ {
+ if (s[5] == 'n')
+ fd = ASSUAN_INVALID_FD;
+ else
+ fd = _assuan_w32ce_finish_pipe (atoi (s+5), s[3] != '0');
+ _es_set_std_fd (s[3] - '0', (int)fd);
+ fixup++;
+ }
+ else
+ break;
+ }
+
+ if (fixup)
+ {
+ argc = *argcp;
+ argc -= fixup;
+ *argcp = argc;
+
+ argv = *argvp;
+ for (i=1; i < argc; i++)
+ argv[i] = argv[i + fixup];
+ for (; i < argc + fixup; i++)
+ argv[i] = NULL;
+ }
+
+
+}
+#endif /*HAVE_W32CE_SYSTEM*/
+
+
+/* For Windows we need to parse the command line so that we can
+ * provide an UTF-8 encoded argv. If there is any Unicode character
+ * we return a new array but if there is no Unicode character we do
+ * nothing. */
+#ifdef HAVE_W32_SYSTEM
+static void
+prepare_w32_commandline (int *r_argc, char ***r_argv)
+{
+ const wchar_t *wcmdline, *ws;
+ char *cmdline;
+ int argc;
+ char **argv;
+ const char *s;
+ int i, globing, itemsalloced;
+
+ s = strusage (95);
+ globing = (s && *s == '1');
+
+ wcmdline = GetCommandLineW ();
+ if (!wcmdline)
+ {
+ log_error ("GetCommandLineW failed\n");
+ return; /* Ooops. */
+ }
+
+ if (!globing)
+ {
+ /* If globbing is not enabled we use our own parser only if
+ * there are any non-ASCII characters. */
+ for (ws=wcmdline; *ws; ws++)
+ if (!iswascii (*ws))
+ break;
+ if (!*ws)
+ return; /* No Unicode - return directly. */
+ }
+
+ cmdline = wchar_to_utf8 (wcmdline);
+ if (!cmdline)
+ {
+ log_error ("parsing command line failed: %s\n", strerror (errno));
+ return; /* Ooops. */
+ }
+ gpgrt_annotate_leaked_object (cmdline);
+
+ argv = w32_parse_commandline (cmdline, globing, &argc, &itemsalloced);
+ if (!argv)
+ {
+ log_error ("parsing command line failed: %s\n", "internal error");
+ return; /* Ooops. */
+ }
+ gpgrt_annotate_leaked_object (argv);
+ if (itemsalloced)
+ {
+ for (i=0; i < argc; i++)
+ gpgrt_annotate_leaked_object (argv[i]);
+ }
+ *r_argv = argv;
+ *r_argc = argc;
+}
+#endif /*HAVE_W32_SYSTEM*/
diff --git a/common/init.h b/common/init.h
new file mode 100644
index 0000000..3a5beca
--- /dev/null
+++ b/common/init.h
@@ -0,0 +1,47 @@
+/* init.h - Definitions for init functions.
+ * Copyright (C) 2007, 2012 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_COMMON_INIT_H
+#define GNUPG_COMMON_INIT_H
+
+#ifndef GPG_ERR_SOURCE_DEFAULT
+# error GPG_ERR_SOURCE_DEFAULT is not defined
+#elseif GPG_ERR_SOURCE_DEFAULT == GPG_ERR_SOURCE_UNKNOWN
+# error GPG_ERR_SOURCE_DEFAULT has default value
+#endif
+
+void register_mem_cleanup_func (void (*func)(void));
+
+void early_system_init (void);
+void _init_common_subsystems (gpg_err_source_t errsource,
+ int *argcp, char ***argvp);
+#define init_common_subsystems(a,b) \
+ _init_common_subsystems (GPG_ERR_SOURCE_DEFAULT, (a), (b))
+
+#endif /*GNUPG_COMMON_INIT_H*/
diff --git a/common/iobuf.c b/common/iobuf.c
new file mode 100644
index 0000000..6370efb
--- /dev/null
+++ b/common/iobuf.c
@@ -0,0 +1,2698 @@
+/* iobuf.c - File Handling for OpenPGP.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2006, 2007, 2008,
+ * 2009, 2010, 2011 Free Software Foundation, Inc.
+ * Copyright (C) 2015 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#ifdef HAVE_W32_SYSTEM
+# ifdef HAVE_WINSOCK2_H
+# include <winsock2.h>
+# endif
+# include <windows.h>
+#endif
+#ifdef __riscos__
+# include <kernel.h>
+# include <swis.h>
+#endif /* __riscos__ */
+
+#include <assuan.h>
+
+#include "util.h"
+#include "sysutils.h"
+#include "iobuf.h"
+
+/*-- Begin configurable part. --*/
+
+/* The size of the internal buffers.
+ NOTE: If you change this value you MUST also adjust the regression
+ test "armored_key_8192" in armor.test! */
+#define IOBUF_BUFFER_SIZE 8192
+
+/* To avoid a potential DoS with compression packets we better limit
+ the number of filters in a chain. */
+#define MAX_NESTING_FILTER 64
+
+/*-- End configurable part. --*/
+
+
+#ifdef HAVE_W32_SYSTEM
+# ifdef HAVE_W32CE_SYSTEM
+# define FD_FOR_STDIN (es_fileno (es_stdin))
+# define FD_FOR_STDOUT (es_fileno (es_stdout))
+# else
+# define FD_FOR_STDIN (GetStdHandle (STD_INPUT_HANDLE))
+# define FD_FOR_STDOUT (GetStdHandle (STD_OUTPUT_HANDLE))
+# endif
+#else /*!HAVE_W32_SYSTEM*/
+# define FD_FOR_STDIN (0)
+# define FD_FOR_STDOUT (1)
+#endif /*!HAVE_W32_SYSTEM*/
+
+
+/* The context used by the file filter. */
+typedef struct
+{
+ gnupg_fd_t fp; /* Open file pointer or handle. */
+ int keep_open;
+ int no_cache;
+ int eof_seen;
+ int print_only_name; /* Flags indicating that fname is not a real file. */
+ char fname[1]; /* Name of the file. */
+} file_filter_ctx_t;
+
+/* The context used by the estream filter. */
+typedef struct
+{
+ estream_t fp; /* Open estream handle. */
+ int keep_open;
+ int no_cache;
+ int eof_seen;
+ int print_only_name; /* Flags indicating that fname is not a real file. */
+ char fname[1]; /* Name of the file. */
+} file_es_filter_ctx_t;
+
+
+/* Object to control the "close cache". */
+struct close_cache_s
+{
+ struct close_cache_s *next;
+ gnupg_fd_t fp;
+ char fname[1];
+};
+typedef struct close_cache_s *close_cache_t;
+static close_cache_t close_cache;
+
+int iobuf_debug_mode;
+
+
+#ifdef HAVE_W32_SYSTEM
+typedef struct
+{
+ int sock;
+ int keep_open;
+ int no_cache;
+ int eof_seen;
+ int print_only_name; /* Flag indicating that fname is not a real file. */
+ char fname[1]; /* Name of the file */
+
+} sock_filter_ctx_t;
+#endif /*HAVE_W32_SYSTEM*/
+
+/* The first partial length header block must be of size 512 to make
+ * it easier (and more efficient) we use a min. block size of 512 for
+ * all chunks (but the last one) */
+#define OP_MIN_PARTIAL_CHUNK 512
+#define OP_MIN_PARTIAL_CHUNK_2POW 9
+
+/* The context we use for the block filter (used to handle OpenPGP
+ length information header). */
+typedef struct
+{
+ int use;
+ size_t size;
+ size_t count;
+ int partial; /* 1 = partial header, 2 in last partial packet. */
+ char *buffer; /* Used for partial header. */
+ size_t buflen; /* Used size of buffer. */
+ int first_c; /* First character of a partial header (which is > 0). */
+ int eof;
+}
+block_filter_ctx_t;
+
+
+/* Local prototypes. */
+static int underflow (iobuf_t a, int clear_pending_eof);
+static int underflow_target (iobuf_t a, int clear_pending_eof, size_t target);
+static int translate_file_handle (int fd, int for_write);
+
+/* Sends any pending data to the filter's FILTER function. Note: this
+ works on the filter and not on the whole pipeline. That is,
+ iobuf_flush doesn't necessarily cause data to be written to any
+ underlying file; it just causes any data buffered at the filter A
+ to be sent to A's filter function.
+
+ If A is a IOBUF_OUTPUT_TEMP filter, then this also enlarges the
+ buffer by IOBUF_BUFFER_SIZE.
+
+ May only be called on an IOBUF_OUTPUT or IOBUF_OUTPUT_TEMP filters. */
+static int filter_flush (iobuf_t a);
+
+
+
+/* This is a replacement for strcmp. Under W32 it does not
+ distinguish between backslash and slash. */
+static int
+fd_cache_strcmp (const char *a, const char *b)
+{
+#ifdef HAVE_DOSISH_SYSTEM
+ for (; *a && *b; a++, b++)
+ {
+ if (*a != *b && !((*a == '/' && *b == '\\')
+ || (*a == '\\' && *b == '/')) )
+ break;
+ }
+ return *(const unsigned char *)a - *(const unsigned char *)b;
+#else
+ return strcmp (a, b);
+#endif
+}
+
+
+/*
+ * Invalidate (i.e. close) a cached iobuf
+ */
+static int
+fd_cache_invalidate (const char *fname)
+{
+ close_cache_t cc;
+ int rc = 0;
+
+ assert (fname);
+ if (DBG_IOBUF)
+ log_debug ("fd_cache_invalidate (%s)\n", fname);
+
+ for (cc = close_cache; cc; cc = cc->next)
+ {
+ if (cc->fp != GNUPG_INVALID_FD && !fd_cache_strcmp (cc->fname, fname))
+ {
+ if (DBG_IOBUF)
+ log_debug (" did (%s)\n", cc->fname);
+#ifdef HAVE_W32_SYSTEM
+ if (!CloseHandle (cc->fp))
+ rc = -1;
+#else
+ rc = close (cc->fp);
+#endif
+ cc->fp = GNUPG_INVALID_FD;
+ }
+ }
+ return rc;
+}
+
+
+/* Try to sync changes to the disk. This is to avoid data loss during
+ a system crash in write/close/rename cycle on some file
+ systems. */
+static int
+fd_cache_synchronize (const char *fname)
+{
+ int err = 0;
+
+#ifdef HAVE_FSYNC
+ close_cache_t cc;
+
+ if (DBG_IOBUF)
+ log_debug ("fd_cache_synchronize (%s)\n", fname);
+
+ for (cc=close_cache; cc; cc = cc->next )
+ {
+ if (cc->fp != GNUPG_INVALID_FD && !fd_cache_strcmp (cc->fname, fname))
+ {
+ if (DBG_IOBUF)
+ log_debug (" did (%s)\n", cc->fname);
+
+ err = fsync (cc->fp);
+ }
+ }
+#else
+ (void)fname;
+#endif /*HAVE_FSYNC*/
+
+ return err;
+}
+
+
+static gnupg_fd_t
+direct_open (const char *fname, const char *mode, int mode700)
+{
+#ifdef HAVE_W32_SYSTEM
+ unsigned long da, cd, sm;
+ HANDLE hfile;
+
+ (void)mode700;
+ /* Note, that we do not handle all mode combinations */
+
+ /* According to the ReactOS source it seems that open() of the
+ * standard MSW32 crt does open the file in shared mode which is
+ * something new for MS applications ;-)
+ */
+ if (strchr (mode, '+'))
+ {
+ if (fd_cache_invalidate (fname))
+ return GNUPG_INVALID_FD;
+ da = GENERIC_READ | GENERIC_WRITE;
+ cd = OPEN_EXISTING;
+ sm = FILE_SHARE_READ | FILE_SHARE_WRITE;
+ }
+ else if (strchr (mode, 'w'))
+ {
+ if (fd_cache_invalidate (fname))
+ return GNUPG_INVALID_FD;
+ da = GENERIC_WRITE;
+ cd = CREATE_ALWAYS;
+ sm = FILE_SHARE_WRITE;
+ }
+ else
+ {
+ da = GENERIC_READ;
+ cd = OPEN_EXISTING;
+ sm = FILE_SHARE_READ;
+ }
+
+ /* We always use the Unicode version because it supports file names
+ * longer than MAX_PATH. (requires gpgrt 1.45) */
+ if (1)
+ {
+ wchar_t *wfname = gpgrt_fname_to_wchar (fname);
+ if (wfname)
+ {
+ hfile = CreateFileW (wfname, da, sm, NULL, cd,
+ FILE_ATTRIBUTE_NORMAL, NULL);
+ xfree (wfname);
+ }
+ else
+ hfile = INVALID_HANDLE_VALUE;
+ }
+
+ return hfile;
+
+#else /*!HAVE_W32_SYSTEM*/
+
+ int oflag;
+ int cflag = S_IRUSR | S_IWUSR;
+
+ if (!mode700)
+ cflag |= S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
+
+ /* Note, that we do not handle all mode combinations */
+ if (strchr (mode, '+'))
+ {
+ if (fd_cache_invalidate (fname))
+ return GNUPG_INVALID_FD;
+ oflag = O_RDWR;
+ }
+ else if (strchr (mode, 'w'))
+ {
+ if (fd_cache_invalidate (fname))
+ return GNUPG_INVALID_FD;
+ oflag = O_WRONLY | O_CREAT | O_TRUNC;
+ }
+ else
+ {
+ oflag = O_RDONLY;
+ }
+#ifdef O_BINARY
+ if (strchr (mode, 'b'))
+ oflag |= O_BINARY;
+#endif
+
+#ifdef __riscos__
+ {
+ struct stat buf;
+
+ /* Don't allow iobufs on directories */
+ if (!stat (fname, &buf) && S_ISDIR (buf.st_mode) && !S_ISREG (buf.st_mode))
+ return __set_errno (EISDIR);
+ }
+#endif
+ return open (fname, oflag, cflag);
+
+#endif /*!HAVE_W32_SYSTEM*/
+}
+
+
+/*
+ * Instead of closing an FD we keep it open and cache it for later reuse
+ * Note that this caching strategy only works if the process does not chdir.
+ */
+static void
+fd_cache_close (const char *fname, gnupg_fd_t fp)
+{
+ close_cache_t cc;
+
+ assert (fp);
+ if (!fname || !*fname)
+ {
+#ifdef HAVE_W32_SYSTEM
+ CloseHandle (fp);
+#else
+ close (fp);
+#endif
+ if (DBG_IOBUF)
+ log_debug ("fd_cache_close (%d) real\n", (int)fp);
+ return;
+ }
+ /* try to reuse a slot */
+ for (cc = close_cache; cc; cc = cc->next)
+ {
+ if (cc->fp == GNUPG_INVALID_FD && !fd_cache_strcmp (cc->fname, fname))
+ {
+ cc->fp = fp;
+ if (DBG_IOBUF)
+ log_debug ("fd_cache_close (%s) used existing slot\n", fname);
+ return;
+ }
+ }
+ /* add a new one */
+ if (DBG_IOBUF)
+ log_debug ("fd_cache_close (%s) new slot created\n", fname);
+ cc = xcalloc (1, sizeof *cc + strlen (fname));
+ strcpy (cc->fname, fname);
+ cc->fp = fp;
+ cc->next = close_cache;
+ close_cache = cc;
+}
+
+/*
+ * Do a direct_open on FNAME but first try to reuse one from the fd_cache
+ */
+static gnupg_fd_t
+fd_cache_open (const char *fname, const char *mode)
+{
+ close_cache_t cc;
+
+ assert (fname);
+ for (cc = close_cache; cc; cc = cc->next)
+ {
+ if (cc->fp != GNUPG_INVALID_FD && !fd_cache_strcmp (cc->fname, fname))
+ {
+ gnupg_fd_t fp = cc->fp;
+ cc->fp = GNUPG_INVALID_FD;
+ if (DBG_IOBUF)
+ log_debug ("fd_cache_open (%s) using cached fp\n", fname);
+#ifdef HAVE_W32_SYSTEM
+ if (SetFilePointer (fp, 0, NULL, FILE_BEGIN) == 0xffffffff)
+ {
+ log_error ("rewind file failed on handle %p: ec=%d\n",
+ fp, (int) GetLastError ());
+ fp = GNUPG_INVALID_FD;
+ }
+#else
+ if (lseek (fp, 0, SEEK_SET) == (off_t) - 1)
+ {
+ log_error ("can't rewind fd %d: %s\n", fp, strerror (errno));
+ fp = GNUPG_INVALID_FD;
+ }
+#endif
+ return fp;
+ }
+ }
+ if (DBG_IOBUF)
+ log_debug ("fd_cache_open (%s) not cached\n", fname);
+ return direct_open (fname, mode, 0);
+}
+
+
+static int
+file_filter (void *opaque, int control, iobuf_t chain, byte * buf,
+ size_t * ret_len)
+{
+ file_filter_ctx_t *a = opaque;
+ gnupg_fd_t f = a->fp;
+ size_t size = *ret_len;
+ size_t nbytes = 0;
+ int rc = 0;
+
+ (void)chain; /* Not used. */
+
+ if (control == IOBUFCTRL_UNDERFLOW)
+ {
+ assert (size); /* We need a buffer. */
+ if (a->eof_seen)
+ {
+ rc = -1;
+ *ret_len = 0;
+ }
+ else
+ {
+#ifdef HAVE_W32_SYSTEM
+ unsigned long nread;
+
+ nbytes = 0;
+ if (!ReadFile (f, buf, size, &nread, NULL))
+ {
+ int ec = (int) GetLastError ();
+ if (ec != ERROR_BROKEN_PIPE)
+ {
+ rc = gpg_error_from_errno (ec);
+ log_error ("%s: read error: ec=%d\n", a->fname, ec);
+ }
+ }
+ else if (!nread)
+ {
+ a->eof_seen = 1;
+ rc = -1;
+ }
+ else
+ {
+ nbytes = nread;
+ }
+
+#else
+
+ int n;
+
+ nbytes = 0;
+ do
+ {
+ n = read (f, buf, size);
+ }
+ while (n == -1 && errno == EINTR);
+ if (n == -1)
+ { /* error */
+ if (errno != EPIPE)
+ {
+ rc = gpg_error_from_syserror ();
+ log_error ("%s: read error: %s\n",
+ a->fname, strerror (errno));
+ }
+ }
+ else if (!n)
+ { /* eof */
+ a->eof_seen = 1;
+ rc = -1;
+ }
+ else
+ {
+ nbytes = n;
+ }
+#endif
+ *ret_len = nbytes;
+ }
+ }
+ else if (control == IOBUFCTRL_FLUSH)
+ {
+ if (size)
+ {
+#ifdef HAVE_W32_SYSTEM
+ byte *p = buf;
+ unsigned long n;
+
+ nbytes = size;
+ do
+ {
+ if (size && !WriteFile (f, p, nbytes, &n, NULL))
+ {
+ int ec = (int) GetLastError ();
+ rc = gpg_error_from_errno (ec);
+ log_error ("%s: write error: ec=%d\n", a->fname, ec);
+ break;
+ }
+ p += n;
+ nbytes -= n;
+ }
+ while (nbytes);
+ nbytes = p - buf;
+#else
+ byte *p = buf;
+ int n;
+
+ nbytes = size;
+ do
+ {
+ do
+ {
+ n = write (f, p, nbytes);
+ }
+ while (n == -1 && errno == EINTR);
+ if (n > 0)
+ {
+ p += n;
+ nbytes -= n;
+ }
+ }
+ while (n != -1 && nbytes);
+ if (n == -1)
+ {
+ rc = gpg_error_from_syserror ();
+ log_error ("%s: write error: %s\n", a->fname, strerror (errno));
+ }
+ nbytes = p - buf;
+#endif
+ }
+ *ret_len = nbytes;
+ }
+ else if (control == IOBUFCTRL_INIT)
+ {
+ a->eof_seen = 0;
+ a->keep_open = 0;
+ a->no_cache = 0;
+ }
+ else if (control == IOBUFCTRL_DESC)
+ {
+ mem2str (buf, "file_filter(fd)", *ret_len);
+ }
+ else if (control == IOBUFCTRL_FREE)
+ {
+ if (f != FD_FOR_STDIN && f != FD_FOR_STDOUT)
+ {
+ if (DBG_IOBUF)
+ log_debug ("%s: close fd/handle %d\n", a->fname, FD2INT (f));
+ if (!a->keep_open)
+ fd_cache_close (a->no_cache ? NULL : a->fname, f);
+ }
+ xfree (a); /* We can free our context now. */
+ }
+
+ return rc;
+}
+
+
+/* Similar to file_filter but using the estream system. */
+static int
+file_es_filter (void *opaque, int control, iobuf_t chain, byte * buf,
+ size_t * ret_len)
+{
+ file_es_filter_ctx_t *a = opaque;
+ estream_t f = a->fp;
+ size_t size = *ret_len;
+ size_t nbytes = 0;
+ int rc = 0;
+
+ (void)chain; /* Not used. */
+
+ if (control == IOBUFCTRL_UNDERFLOW)
+ {
+ assert (size); /* We need a buffer. */
+ if (a->eof_seen)
+ {
+ rc = -1;
+ *ret_len = 0;
+ }
+ else
+ {
+ nbytes = 0;
+ rc = es_read (f, buf, size, &nbytes);
+ if (rc == -1)
+ { /* error */
+ rc = gpg_error_from_syserror ();
+ log_error ("%s: read error: %s\n", a->fname, strerror (errno));
+ }
+ else if (!nbytes)
+ { /* eof */
+ a->eof_seen = 1;
+ rc = -1;
+ }
+ *ret_len = nbytes;
+ }
+ }
+ else if (control == IOBUFCTRL_FLUSH)
+ {
+ if (size)
+ {
+ byte *p = buf;
+ size_t nwritten;
+
+ nbytes = size;
+ do
+ {
+ nwritten = 0;
+ if (es_write (f, p, nbytes, &nwritten))
+ {
+ rc = gpg_error_from_syserror ();
+ log_error ("%s: write error: %s\n",
+ a->fname, strerror (errno));
+ break;
+ }
+ p += nwritten;
+ nbytes -= nwritten;
+ }
+ while (nbytes);
+ nbytes = p - buf;
+ }
+ *ret_len = nbytes;
+ }
+ else if (control == IOBUFCTRL_INIT)
+ {
+ a->eof_seen = 0;
+ a->no_cache = 0;
+ }
+ else if (control == IOBUFCTRL_DESC)
+ {
+ mem2str (buf, "estream_filter", *ret_len);
+ }
+ else if (control == IOBUFCTRL_FREE)
+ {
+ if (f != es_stdin && f != es_stdout)
+ {
+ if (DBG_IOBUF)
+ log_debug ("%s: es_fclose %p\n", a->fname, f);
+ if (!a->keep_open)
+ es_fclose (f);
+ }
+ f = NULL;
+ xfree (a); /* We can free our context now. */
+ }
+
+ return rc;
+}
+
+
+#ifdef HAVE_W32_SYSTEM
+/* Because network sockets are special objects under Lose32 we have to
+ use a dedicated filter for them. */
+static int
+sock_filter (void *opaque, int control, iobuf_t chain, byte * buf,
+ size_t * ret_len)
+{
+ sock_filter_ctx_t *a = opaque;
+ size_t size = *ret_len;
+ size_t nbytes = 0;
+ int rc = 0;
+
+ (void)chain;
+
+ if (control == IOBUFCTRL_UNDERFLOW)
+ {
+ assert (size); /* need a buffer */
+ if (a->eof_seen)
+ {
+ rc = -1;
+ *ret_len = 0;
+ }
+ else
+ {
+ int nread;
+
+ nread = recv (a->sock, buf, size, 0);
+ if (nread == SOCKET_ERROR)
+ {
+ int ec = (int) WSAGetLastError ();
+ rc = gpg_error_from_errno (ec);
+ log_error ("socket read error: ec=%d\n", ec);
+ }
+ else if (!nread)
+ {
+ a->eof_seen = 1;
+ rc = -1;
+ }
+ else
+ {
+ nbytes = nread;
+ }
+ *ret_len = nbytes;
+ }
+ }
+ else if (control == IOBUFCTRL_FLUSH)
+ {
+ if (size)
+ {
+ byte *p = buf;
+ int n;
+
+ nbytes = size;
+ do
+ {
+ n = send (a->sock, p, nbytes, 0);
+ if (n == SOCKET_ERROR)
+ {
+ int ec = (int) WSAGetLastError ();
+ rc = gpg_error_from_errno (ec);
+ log_error ("socket write error: ec=%d\n", ec);
+ break;
+ }
+ p += n;
+ nbytes -= n;
+ }
+ while (nbytes);
+ nbytes = p - buf;
+ }
+ *ret_len = nbytes;
+ }
+ else if (control == IOBUFCTRL_INIT)
+ {
+ a->eof_seen = 0;
+ a->keep_open = 0;
+ a->no_cache = 0;
+ }
+ else if (control == IOBUFCTRL_DESC)
+ {
+ mem2str (buf, "sock_filter", *ret_len);
+ }
+ else if (control == IOBUFCTRL_FREE)
+ {
+ if (!a->keep_open)
+ closesocket (a->sock);
+ xfree (a); /* we can free our context now */
+ }
+ return rc;
+}
+#endif /*HAVE_W32_SYSTEM*/
+
+/****************
+ * This is used to implement the block write mode.
+ * Block reading is done on a byte by byte basis in readbyte(),
+ * without a filter
+ */
+static int
+block_filter (void *opaque, int control, iobuf_t chain, byte * buffer,
+ size_t * ret_len)
+{
+ block_filter_ctx_t *a = opaque;
+ char *buf = (char *)buffer;
+ size_t size = *ret_len;
+ int c, needed, rc = 0;
+ char *p;
+
+ if (control == IOBUFCTRL_UNDERFLOW)
+ {
+ size_t n = 0;
+
+ p = buf;
+ assert (size); /* need a buffer */
+ if (a->eof) /* don't read any further */
+ rc = -1;
+ while (!rc && size)
+ {
+ if (!a->size)
+ { /* get the length bytes */
+ if (a->partial == 2)
+ {
+ a->eof = 1;
+ if (!n)
+ rc = -1;
+ break;
+ }
+ else if (a->partial)
+ {
+ /* These OpenPGP introduced huffman like encoded length
+ * bytes are really a mess :-( */
+ if (a->first_c)
+ {
+ c = a->first_c;
+ a->first_c = 0;
+ }
+ else if ((c = iobuf_get (chain)) == -1)
+ {
+ log_error ("block_filter: 1st length byte missing\n");
+ rc = GPG_ERR_BAD_DATA;
+ break;
+ }
+ if (c < 192)
+ {
+ a->size = c;
+ a->partial = 2;
+ if (!a->size)
+ {
+ a->eof = 1;
+ if (!n)
+ rc = -1;
+ break;
+ }
+ }
+ else if (c < 224)
+ {
+ a->size = (c - 192) * 256;
+ if ((c = iobuf_get (chain)) == -1)
+ {
+ log_error
+ ("block_filter: 2nd length byte missing\n");
+ rc = GPG_ERR_BAD_DATA;
+ break;
+ }
+ a->size += c + 192;
+ a->partial = 2;
+ if (!a->size)
+ {
+ a->eof = 1;
+ if (!n)
+ rc = -1;
+ break;
+ }
+ }
+ else if (c == 255)
+ {
+ a->size = iobuf_get_noeof (chain) << 24;
+ a->size |= iobuf_get_noeof (chain) << 16;
+ a->size |= iobuf_get_noeof (chain) << 8;
+ if ((c = iobuf_get (chain)) == -1)
+ {
+ log_error ("block_filter: invalid 4 byte length\n");
+ rc = GPG_ERR_BAD_DATA;
+ break;
+ }
+ a->size |= c;
+ a->partial = 2;
+ if (!a->size)
+ {
+ a->eof = 1;
+ if (!n)
+ rc = -1;
+ break;
+ }
+ }
+ else
+ { /* Next partial body length. */
+ a->size = 1 << (c & 0x1f);
+ }
+ /* log_debug("partial: ctx=%p c=%02x size=%u\n", a, c, a->size); */
+ }
+ else
+ BUG ();
+ }
+
+ while (!rc && size && a->size)
+ {
+ needed = size < a->size ? size : a->size;
+ c = iobuf_read (chain, p, needed);
+ if (c < needed)
+ {
+ if (c == -1)
+ c = 0;
+ log_error
+ ("block_filter %p: read error (size=%lu,a->size=%lu)\n",
+ a, (ulong) size + c, (ulong) a->size + c);
+ rc = GPG_ERR_BAD_DATA;
+ }
+ else
+ {
+ size -= c;
+ a->size -= c;
+ p += c;
+ n += c;
+ }
+ }
+ }
+ *ret_len = n;
+ }
+ else if (control == IOBUFCTRL_FLUSH)
+ {
+ if (a->partial)
+ { /* the complicated openpgp scheme */
+ size_t blen, n, nbytes = size + a->buflen;
+
+ assert (a->buflen <= OP_MIN_PARTIAL_CHUNK);
+ if (nbytes < OP_MIN_PARTIAL_CHUNK)
+ {
+ /* not enough to write a partial block out; so we store it */
+ if (!a->buffer)
+ a->buffer = xmalloc (OP_MIN_PARTIAL_CHUNK);
+ memcpy (a->buffer + a->buflen, buf, size);
+ a->buflen += size;
+ }
+ else
+ { /* okay, we can write out something */
+ /* do this in a loop to use the most efficient block lengths */
+ p = buf;
+ do
+ {
+ /* find the best matching block length - this is limited
+ * by the size of the internal buffering */
+ for (blen = OP_MIN_PARTIAL_CHUNK * 2,
+ c = OP_MIN_PARTIAL_CHUNK_2POW + 1; blen <= nbytes;
+ blen *= 2, c++)
+ ;
+ blen /= 2;
+ c--;
+ /* write the partial length header */
+ assert (c <= 0x1f); /*;-) */
+ c |= 0xe0;
+ iobuf_put (chain, c);
+ if ((n = a->buflen))
+ { /* write stuff from the buffer */
+ assert (n == OP_MIN_PARTIAL_CHUNK);
+ if (iobuf_write (chain, a->buffer, n))
+ rc = gpg_error_from_syserror ();
+ a->buflen = 0;
+ nbytes -= n;
+ }
+ if ((n = nbytes) > blen)
+ n = blen;
+ if (n && iobuf_write (chain, p, n))
+ rc = gpg_error_from_syserror ();
+ p += n;
+ nbytes -= n;
+ }
+ while (!rc && nbytes >= OP_MIN_PARTIAL_CHUNK);
+ /* store the rest in the buffer */
+ if (!rc && nbytes)
+ {
+ assert (!a->buflen);
+ assert (nbytes < OP_MIN_PARTIAL_CHUNK);
+ if (!a->buffer)
+ a->buffer = xmalloc (OP_MIN_PARTIAL_CHUNK);
+ memcpy (a->buffer, p, nbytes);
+ a->buflen = nbytes;
+ }
+ }
+ }
+ else
+ BUG ();
+ }
+ else if (control == IOBUFCTRL_INIT)
+ {
+ if (DBG_IOBUF)
+ log_debug ("init block_filter %p\n", a);
+ if (a->partial)
+ a->count = 0;
+ else if (a->use == IOBUF_INPUT)
+ a->count = a->size = 0;
+ else
+ a->count = a->size; /* force first length bytes */
+ a->eof = 0;
+ a->buffer = NULL;
+ a->buflen = 0;
+ }
+ else if (control == IOBUFCTRL_DESC)
+ {
+ mem2str (buf, "block_filter", *ret_len);
+ }
+ else if (control == IOBUFCTRL_FREE)
+ {
+ if (a->use == IOBUF_OUTPUT)
+ { /* write the end markers */
+ if (a->partial)
+ {
+ u32 len;
+ /* write out the remaining bytes without a partial header
+ * the length of this header may be 0 - but if it is
+ * the first block we are not allowed to use a partial header
+ * and frankly we can't do so, because this length must be
+ * a power of 2. This is _really_ complicated because we
+ * have to check the possible length of a packet prior
+ * to it's creation: a chain of filters becomes complicated
+ * and we need a lot of code to handle compressed packets etc.
+ * :-(((((((
+ */
+ /* construct header */
+ len = a->buflen;
+ /*log_debug("partial: remaining length=%u\n", len ); */
+ if (len < 192)
+ rc = iobuf_put (chain, len);
+ else if (len < 8384)
+ {
+ if (!(rc = iobuf_put (chain, ((len - 192) / 256) + 192)))
+ rc = iobuf_put (chain, ((len - 192) % 256));
+ }
+ else
+ { /* use a 4 byte header */
+ if (!(rc = iobuf_put (chain, 0xff)))
+ if (!(rc = iobuf_put (chain, (len >> 24) & 0xff)))
+ if (!(rc = iobuf_put (chain, (len >> 16) & 0xff)))
+ if (!(rc = iobuf_put (chain, (len >> 8) & 0xff)))
+ rc = iobuf_put (chain, len & 0xff);
+ }
+ if (!rc && len)
+ rc = iobuf_write (chain, a->buffer, len);
+ if (rc)
+ {
+ log_error ("block_filter: write error: %s\n",
+ strerror (errno));
+ rc = gpg_error_from_syserror ();
+ }
+ xfree (a->buffer);
+ a->buffer = NULL;
+ a->buflen = 0;
+ }
+ else
+ BUG ();
+ }
+ else if (a->size)
+ {
+ log_error ("block_filter: pending bytes!\n");
+ }
+ if (DBG_IOBUF)
+ log_debug ("free block_filter %p\n", a);
+ xfree (a); /* we can free our context now */
+ }
+
+ return rc;
+}
+
+#define MAX_IOBUF_DESC 32
+/*
+ * Fill the buffer by the description of iobuf A.
+ * The buffer size should be MAX_IOBUF_DESC (or larger).
+ * Returns BUF as (const char *).
+ */
+static const char *
+iobuf_desc (iobuf_t a, byte *buf)
+{
+ size_t len = MAX_IOBUF_DESC;
+
+ if (! a || ! a->filter)
+ memcpy (buf, "?", 2);
+ else
+ a->filter (a->filter_ov, IOBUFCTRL_DESC, NULL, buf, &len);
+
+ return buf;
+}
+
+static void
+print_chain (iobuf_t a)
+{
+ if (!DBG_IOBUF)
+ return;
+ for (; a; a = a->chain)
+ {
+ byte desc[MAX_IOBUF_DESC];
+
+ log_debug ("iobuf chain: %d.%d '%s' filter_eof=%d start=%d len=%d\n",
+ a->no, a->subno, iobuf_desc (a, desc), a->filter_eof,
+ (int) a->d.start, (int) a->d.len);
+ }
+}
+
+int
+iobuf_print_chain (iobuf_t a)
+{
+ print_chain (a);
+ return 0;
+}
+
+iobuf_t
+iobuf_alloc (int use, size_t bufsize)
+{
+ iobuf_t a;
+ static int number = 0;
+
+ assert (use == IOBUF_INPUT || use == IOBUF_INPUT_TEMP
+ || use == IOBUF_OUTPUT || use == IOBUF_OUTPUT_TEMP);
+ if (bufsize == 0)
+ {
+ log_bug ("iobuf_alloc() passed a bufsize of 0!\n");
+ bufsize = IOBUF_BUFFER_SIZE;
+ }
+
+ a = xcalloc (1, sizeof *a);
+ a->use = use;
+ a->d.buf = xmalloc (bufsize);
+ a->d.size = bufsize;
+ a->no = ++number;
+ a->subno = 0;
+ a->real_fname = NULL;
+ return a;
+}
+
+int
+iobuf_close (iobuf_t a)
+{
+ iobuf_t a_chain;
+ size_t dummy_len = 0;
+ int rc = 0;
+
+ for (; a; a = a_chain)
+ {
+ byte desc[MAX_IOBUF_DESC];
+ int rc2 = 0;
+
+ a_chain = a->chain;
+
+ if (a->use == IOBUF_OUTPUT && (rc = filter_flush (a)))
+ log_error ("filter_flush failed on close: %s\n", gpg_strerror (rc));
+
+ if (DBG_IOBUF)
+ log_debug ("iobuf-%d.%d: close '%s'\n",
+ a->no, a->subno, iobuf_desc (a, desc));
+
+ if (a->filter && (rc2 = a->filter (a->filter_ov, IOBUFCTRL_FREE,
+ a->chain, NULL, &dummy_len)))
+ log_error ("IOBUFCTRL_FREE failed on close: %s\n", gpg_strerror (rc));
+ if (! rc && rc2)
+ /* Whoops! An error occurred. Save it in RC if we haven't
+ already recorded an error. */
+ rc = rc2;
+
+ xfree (a->real_fname);
+ if (a->d.buf)
+ {
+ memset (a->d.buf, 0, a->d.size); /* erase the buffer */
+ xfree (a->d.buf);
+ }
+ xfree (a);
+ }
+ return rc;
+}
+
+int
+iobuf_cancel (iobuf_t a)
+{
+ const char *s;
+ iobuf_t a2;
+ int rc;
+#if defined(HAVE_W32_SYSTEM) || defined(__riscos__)
+ char *remove_name = NULL;
+#endif
+
+ if (a && a->use == IOBUF_OUTPUT)
+ {
+ s = iobuf_get_real_fname (a);
+ if (s && *s)
+ {
+#if defined(HAVE_W32_SYSTEM) || defined(__riscos__)
+ remove_name = xstrdup (s);
+#else
+ remove (s);
+#endif
+ }
+ }
+
+ /* send a cancel message to all filters */
+ for (a2 = a; a2; a2 = a2->chain)
+ {
+ size_t dummy;
+ if (a2->filter)
+ a2->filter (a2->filter_ov, IOBUFCTRL_CANCEL, a2->chain, NULL, &dummy);
+ }
+
+ rc = iobuf_close (a);
+#if defined(HAVE_W32_SYSTEM) || defined(__riscos__)
+ if (remove_name)
+ {
+ /* Argg, MSDOS does not allow removing open files. So
+ * we have to do it here */
+ gnupg_remove (remove_name);
+ xfree (remove_name);
+ }
+#endif
+ return rc;
+}
+
+
+iobuf_t
+iobuf_temp (void)
+{
+ return iobuf_alloc (IOBUF_OUTPUT_TEMP, IOBUF_BUFFER_SIZE);
+}
+
+iobuf_t
+iobuf_temp_with_content (const char *buffer, size_t length)
+{
+ iobuf_t a;
+ int i;
+
+ a = iobuf_alloc (IOBUF_INPUT_TEMP, length);
+ assert (length == a->d.size);
+ /* memcpy (a->d.buf, buffer, length); */
+ for (i=0; i < length; i++)
+ a->d.buf[i] = buffer[i];
+ a->d.len = length;
+
+ return a;
+}
+
+
+int
+iobuf_is_pipe_filename (const char *fname)
+{
+ if (!fname || (*fname=='-' && !fname[1]) )
+ return 1;
+ return check_special_filename (fname, 0, 1) != -1;
+}
+
+
+static iobuf_t
+do_open (const char *fname, int special_filenames,
+ int use, const char *opentype, int mode700)
+{
+ iobuf_t a;
+ gnupg_fd_t fp;
+ file_filter_ctx_t *fcx;
+ size_t len = 0;
+ int print_only = 0;
+ int fd;
+ byte desc[MAX_IOBUF_DESC];
+
+ assert (use == IOBUF_INPUT || use == IOBUF_OUTPUT);
+
+ if (special_filenames
+ /* NULL or '-'. */
+ && (!fname || (*fname == '-' && !fname[1])))
+ {
+ if (use == IOBUF_INPUT)
+ {
+ fp = FD_FOR_STDIN;
+ fname = "[stdin]";
+ }
+ else
+ {
+ fp = FD_FOR_STDOUT;
+ fname = "[stdout]";
+ }
+ print_only = 1;
+ }
+ else if (!fname)
+ return NULL;
+ else if (special_filenames
+ && (fd = check_special_filename (fname, 0, 1)) != -1)
+ return iobuf_fdopen (translate_file_handle (fd, use == IOBUF_INPUT ? 0 : 1),
+ opentype);
+ else
+ {
+ if (use == IOBUF_INPUT)
+ fp = fd_cache_open (fname, opentype);
+ else
+ fp = direct_open (fname, opentype, mode700);
+ if (fp == GNUPG_INVALID_FD)
+ return NULL;
+ }
+
+ a = iobuf_alloc (use, IOBUF_BUFFER_SIZE);
+ fcx = xmalloc (sizeof *fcx + strlen (fname));
+ fcx->fp = fp;
+ fcx->print_only_name = print_only;
+ strcpy (fcx->fname, fname);
+ if (!print_only)
+ a->real_fname = xstrdup (fname);
+ a->filter = file_filter;
+ a->filter_ov = fcx;
+ file_filter (fcx, IOBUFCTRL_INIT, NULL, NULL, &len);
+ if (DBG_IOBUF)
+ log_debug ("iobuf-%d.%d: open '%s' desc=%s fd=%d\n",
+ a->no, a->subno, fname, iobuf_desc (a, desc), FD2INT (fcx->fp));
+
+ return a;
+}
+
+iobuf_t
+iobuf_open (const char *fname)
+{
+ return do_open (fname, 1, IOBUF_INPUT, "rb", 0);
+}
+
+iobuf_t
+iobuf_create (const char *fname, int mode700)
+{
+ return do_open (fname, 1, IOBUF_OUTPUT, "wb", mode700);
+}
+
+iobuf_t
+iobuf_openrw (const char *fname)
+{
+ return do_open (fname, 0, IOBUF_OUTPUT, "r+b", 0);
+}
+
+
+static iobuf_t
+do_iobuf_fdopen (int fd, const char *mode, int keep_open)
+{
+ iobuf_t a;
+ gnupg_fd_t fp;
+ file_filter_ctx_t *fcx;
+ size_t len;
+
+ fp = INT2FD (fd);
+
+ a = iobuf_alloc (strchr (mode, 'w') ? IOBUF_OUTPUT : IOBUF_INPUT,
+ IOBUF_BUFFER_SIZE);
+ fcx = xmalloc (sizeof *fcx + 20);
+ fcx->fp = fp;
+ fcx->print_only_name = 1;
+ fcx->keep_open = keep_open;
+ sprintf (fcx->fname, "[fd %d]", fd);
+ a->filter = file_filter;
+ a->filter_ov = fcx;
+ file_filter (fcx, IOBUFCTRL_INIT, NULL, NULL, &len);
+ if (DBG_IOBUF)
+ log_debug ("iobuf-%d.%d: fdopen%s '%s'\n",
+ a->no, a->subno, keep_open? "_nc":"", fcx->fname);
+ iobuf_ioctl (a, IOBUF_IOCTL_NO_CACHE, 1, NULL);
+ return a;
+}
+
+
+iobuf_t
+iobuf_fdopen (int fd, const char *mode)
+{
+ return do_iobuf_fdopen (fd, mode, 0);
+}
+
+iobuf_t
+iobuf_fdopen_nc (int fd, const char *mode)
+{
+ return do_iobuf_fdopen (fd, mode, 1);
+}
+
+
+iobuf_t
+iobuf_esopen (estream_t estream, const char *mode, int keep_open)
+{
+ iobuf_t a;
+ file_es_filter_ctx_t *fcx;
+ size_t len = 0;
+
+ a = iobuf_alloc (strchr (mode, 'w') ? IOBUF_OUTPUT : IOBUF_INPUT,
+ IOBUF_BUFFER_SIZE);
+ fcx = xtrymalloc (sizeof *fcx + 30);
+ fcx->fp = estream;
+ fcx->print_only_name = 1;
+ fcx->keep_open = keep_open;
+ sprintf (fcx->fname, "[fd %p]", estream);
+ a->filter = file_es_filter;
+ a->filter_ov = fcx;
+ file_es_filter (fcx, IOBUFCTRL_INIT, NULL, NULL, &len);
+ if (DBG_IOBUF)
+ log_debug ("iobuf-%d.%d: esopen%s '%s'\n",
+ a->no, a->subno, keep_open? "_nc":"", fcx->fname);
+ return a;
+}
+
+
+iobuf_t
+iobuf_sockopen (int fd, const char *mode)
+{
+ iobuf_t a;
+#ifdef HAVE_W32_SYSTEM
+ sock_filter_ctx_t *scx;
+ size_t len;
+
+ a = iobuf_alloc (strchr (mode, 'w') ? IOBUF_OUTPUT : IOBUF_INPUT,
+ IOBUF_BUFFER_SIZE);
+ scx = xmalloc (sizeof *scx + 25);
+ scx->sock = fd;
+ scx->print_only_name = 1;
+ sprintf (scx->fname, "[sock %d]", fd);
+ a->filter = sock_filter;
+ a->filter_ov = scx;
+ sock_filter (scx, IOBUFCTRL_INIT, NULL, NULL, &len);
+ if (DBG_IOBUF)
+ log_debug ("iobuf-%d.%d: sockopen '%s'\n", a->no, a->subno, scx->fname);
+ iobuf_ioctl (a, IOBUF_IOCTL_NO_CACHE, 1, NULL);
+#else
+ a = iobuf_fdopen (fd, mode);
+#endif
+ return a;
+}
+
+int
+iobuf_ioctl (iobuf_t a, iobuf_ioctl_t cmd, int intval, void *ptrval)
+{
+ byte desc[MAX_IOBUF_DESC];
+
+ if (cmd == IOBUF_IOCTL_KEEP_OPEN)
+ {
+ /* Keep system filepointer/descriptor open. This was used in
+ the past by http.c; this ioctl is not directly used
+ anymore. */
+ if (DBG_IOBUF)
+ log_debug ("iobuf-%d.%d: ioctl '%s' keep_open=%d\n",
+ a ? a->no : -1, a ? a->subno : -1, iobuf_desc (a, desc),
+ intval);
+ for (; a; a = a->chain)
+ if (!a->chain && a->filter == file_filter)
+ {
+ file_filter_ctx_t *b = a->filter_ov;
+ b->keep_open = intval;
+ return 0;
+ }
+#ifdef HAVE_W32_SYSTEM
+ else if (!a->chain && a->filter == sock_filter)
+ {
+ sock_filter_ctx_t *b = a->filter_ov;
+ b->keep_open = intval;
+ return 0;
+ }
+#endif
+ }
+ else if (cmd == IOBUF_IOCTL_INVALIDATE_CACHE)
+ {
+ if (DBG_IOBUF)
+ log_debug ("iobuf-*.*: ioctl '%s' invalidate\n",
+ ptrval ? (char *) ptrval : "?");
+ if (!a && !intval && ptrval)
+ {
+ if (fd_cache_invalidate (ptrval))
+ return -1;
+ return 0;
+ }
+ }
+ else if (cmd == IOBUF_IOCTL_NO_CACHE)
+ {
+ if (DBG_IOBUF)
+ log_debug ("iobuf-%d.%d: ioctl '%s' no_cache=%d\n",
+ a ? a->no : -1, a ? a->subno : -1, iobuf_desc (a, desc),
+ intval);
+ for (; a; a = a->chain)
+ if (!a->chain && a->filter == file_filter)
+ {
+ file_filter_ctx_t *b = a->filter_ov;
+ b->no_cache = intval;
+ return 0;
+ }
+#ifdef HAVE_W32_SYSTEM
+ else if (!a->chain && a->filter == sock_filter)
+ {
+ sock_filter_ctx_t *b = a->filter_ov;
+ b->no_cache = intval;
+ return 0;
+ }
+#endif
+ }
+ else if (cmd == IOBUF_IOCTL_FSYNC)
+ {
+ /* Do a fsync on the open fd and return any errors to the caller
+ of iobuf_ioctl. Note that we work on a file name here. */
+ if (DBG_IOBUF)
+ log_debug ("iobuf-*.*: ioctl '%s' fsync\n",
+ ptrval? (const char*)ptrval:"<null>");
+
+ if (!a && !intval && ptrval)
+ {
+ return fd_cache_synchronize (ptrval);
+ }
+ }
+
+
+ return -1;
+}
+
+
+/****************
+ * Register an i/o filter.
+ */
+int
+iobuf_push_filter (iobuf_t a,
+ int (*f) (void *opaque, int control,
+ iobuf_t chain, byte * buf, size_t * len),
+ void *ov)
+{
+ return iobuf_push_filter2 (a, f, ov, 0);
+}
+
+int
+iobuf_push_filter2 (iobuf_t a,
+ int (*f) (void *opaque, int control,
+ iobuf_t chain, byte * buf, size_t * len),
+ void *ov, int rel_ov)
+{
+ iobuf_t b;
+ size_t dummy_len = 0;
+ int rc = 0;
+
+ if (a->use == IOBUF_OUTPUT && (rc = filter_flush (a)))
+ return rc;
+
+ if (a->subno >= MAX_NESTING_FILTER)
+ {
+ log_error ("i/o filter too deeply nested - corrupted data?\n");
+ return GPG_ERR_BAD_DATA;
+ }
+
+ /* We want to create a new filter and put it in front of A. A
+ simple implementation would do:
+
+ b = iobuf_alloc (...);
+ b->chain = a;
+ return a;
+
+ This is a bit problematic: A is the head of the pipeline and
+ there are potentially many pointers to it. Requiring the caller
+ to update all of these pointers is a burden.
+
+ An alternative implementation would add a level of indirection.
+ For instance, we could use a pipeline object, which contains a
+ pointer to the first filter in the pipeline. This is not what we
+ do either.
+
+ Instead, we allocate a new buffer (B) and copy the first filter's
+ state into that and use the initial buffer (A) for the new
+ filter. One limitation of this approach is that it is not
+ practical to maintain a pointer to a specific filter's state.
+
+ Before:
+
+ A
+ |
+ v 0x100 0x200
+ +----------+ +----------+
+ | filter x |--------->| filter y |---->....
+ +----------+ +----------+
+
+ After: B
+ |
+ v 0x300
+ +----------+
+ A | filter x |
+ | +----------+
+ v 0x100 ^ v 0x200
+ +----------+ +----------+
+ | filter w | | filter y |---->....
+ +----------+ +----------+
+
+ Note: filter x's address changed from 0x100 to 0x300, but A still
+ points to the head of the pipeline.
+ */
+
+ b = xmalloc (sizeof *b);
+ memcpy (b, a, sizeof *b);
+ /* fixme: it is stupid to keep a copy of the name at every level
+ * but we need the name somewhere because the name known by file_filter
+ * may have been released when we need the name of the file */
+ b->real_fname = a->real_fname ? xstrdup (a->real_fname) : NULL;
+ /* remove the filter stuff from the new stream */
+ a->filter = NULL;
+ a->filter_ov = NULL;
+ a->filter_ov_owner = 0;
+ a->filter_eof = 0;
+ if (a->use == IOBUF_OUTPUT_TEMP)
+ /* A TEMP filter buffers any data sent to it; it does not forward
+ any data down the pipeline. If we add a new filter to the
+ pipeline, it shouldn't also buffer data. It should send it
+ downstream to be buffered. Thus, the correct type for a filter
+ added in front of an IOBUF_OUTPUT_TEMP filter is IOBUF_OUPUT, not
+ IOBUF_OUTPUT_TEMP. */
+ {
+ a->use = IOBUF_OUTPUT;
+
+ /* When pipeline is written to, the temp buffer's size is
+ increased accordingly. We don't need to allocate a 10 MB
+ buffer for a non-terminal filter. Just use the default
+ size. */
+ a->d.size = IOBUF_BUFFER_SIZE;
+ }
+ else if (a->use == IOBUF_INPUT_TEMP)
+ /* Same idea as above. */
+ {
+ a->use = IOBUF_INPUT;
+ a->d.size = IOBUF_BUFFER_SIZE;
+ }
+
+ /* The new filter (A) gets a new buffer.
+
+ If the pipeline is an output or temp pipeline, then giving the
+ buffer to the new filter means that data that was written before
+ the filter was pushed gets sent to the filter. That's clearly
+ wrong.
+
+ If the pipeline is an input pipeline, then giving the buffer to
+ the new filter (A) means that data that has read from (B), but
+ not yet read from the pipeline won't be processed by the new
+ filter (A)! That's certainly not what we want. */
+ a->d.buf = xmalloc (a->d.size);
+ a->d.len = 0;
+ a->d.start = 0;
+
+ /* disable nlimit for the new stream */
+ a->ntotal = b->ntotal + b->nbytes;
+ a->nlimit = a->nbytes = 0;
+ a->nofast = 0;
+ /* make a link from the new stream to the original stream */
+ a->chain = b;
+
+ /* setup the function on the new stream */
+ a->filter = f;
+ a->filter_ov = ov;
+ a->filter_ov_owner = rel_ov;
+
+ a->subno = b->subno + 1;
+
+ if (DBG_IOBUF)
+ {
+ byte desc[MAX_IOBUF_DESC];
+ log_debug ("iobuf-%d.%d: push '%s'\n",
+ a->no, a->subno, iobuf_desc (a, desc));
+ print_chain (a);
+ }
+
+ /* now we can initialize the new function if we have one */
+ if (a->filter && (rc = a->filter (a->filter_ov, IOBUFCTRL_INIT, a->chain,
+ NULL, &dummy_len)))
+ log_error ("IOBUFCTRL_INIT failed: %s\n", gpg_strerror (rc));
+ return rc;
+}
+
+/****************
+ * Remove an i/o filter.
+ */
+int
+iobuf_pop_filter (iobuf_t a, int (*f) (void *opaque, int control,
+ iobuf_t chain, byte * buf, size_t * len),
+ void *ov)
+{
+ iobuf_t b;
+ size_t dummy_len = 0;
+ int rc = 0;
+ byte desc[MAX_IOBUF_DESC];
+
+ if (DBG_IOBUF)
+ log_debug ("iobuf-%d.%d: pop '%s'\n",
+ a->no, a->subno, iobuf_desc (a, desc));
+ if (a->use == IOBUF_INPUT_TEMP || a->use == IOBUF_OUTPUT_TEMP)
+ {
+ /* This should be the last filter in the pipeline. */
+ assert (! a->chain);
+ return 0;
+ }
+ if (!a->filter)
+ { /* this is simple */
+ b = a->chain;
+ assert (b);
+ xfree (a->d.buf);
+ xfree (a->real_fname);
+ memcpy (a, b, sizeof *a);
+ xfree (b);
+ return 0;
+ }
+ for (b = a; b; b = b->chain)
+ if (b->filter == f && (!ov || b->filter_ov == ov))
+ break;
+ if (!b)
+ log_bug ("iobuf_pop_filter(): filter function not found\n");
+
+ /* flush this stream if it is an output stream */
+ if (a->use == IOBUF_OUTPUT && (rc = filter_flush (b)))
+ {
+ log_error ("filter_flush failed in iobuf_pop_filter: %s\n",
+ gpg_strerror (rc));
+ return rc;
+ }
+ /* and tell the filter to free it self */
+ if (b->filter && (rc = b->filter (b->filter_ov, IOBUFCTRL_FREE, b->chain,
+ NULL, &dummy_len)))
+ {
+ log_error ("IOBUFCTRL_FREE failed: %s\n", gpg_strerror (rc));
+ return rc;
+ }
+ if (b->filter_ov && b->filter_ov_owner)
+ {
+ xfree (b->filter_ov);
+ b->filter_ov = NULL;
+ }
+
+
+ /* and see how to remove it */
+ if (a == b && !b->chain)
+ log_bug ("can't remove the last filter from the chain\n");
+ else if (a == b)
+ { /* remove the first iobuf from the chain */
+ /* everything from b is copied to a. This is save because
+ * a flush has been done on the to be removed entry
+ */
+ b = a->chain;
+ xfree (a->d.buf);
+ xfree (a->real_fname);
+ memcpy (a, b, sizeof *a);
+ xfree (b);
+ if (DBG_IOBUF)
+ log_debug ("iobuf-%d.%d: popped filter\n", a->no, a->subno);
+ }
+ else if (!b->chain)
+ { /* remove the last iobuf from the chain */
+ log_bug ("Ohh jeee, trying to remove a head filter\n");
+ }
+ else
+ { /* remove an intermediate iobuf from the chain */
+ log_bug ("Ohh jeee, trying to remove an intermediate filter\n");
+ }
+
+ return rc;
+}
+
+
+/****************
+ * read underflow: read at least one byte into the buffer and return
+ * the first byte or -1 on EOF.
+ */
+static int
+underflow (iobuf_t a, int clear_pending_eof)
+{
+ return underflow_target (a, clear_pending_eof, 1);
+}
+
+
+/****************
+ * read underflow: read TARGET bytes into the buffer and return
+ * the first byte or -1 on EOF.
+ */
+static int
+underflow_target (iobuf_t a, int clear_pending_eof, size_t target)
+{
+ size_t len;
+ int rc;
+
+ if (DBG_IOBUF)
+ log_debug ("iobuf-%d.%d: underflow: buffer size: %d; still buffered: %d => space for %d bytes\n",
+ a->no, a->subno,
+ (int) a->d.size, (int) (a->d.len - a->d.start),
+ (int) (a->d.size - (a->d.len - a->d.start)));
+
+ if (a->use == IOBUF_INPUT_TEMP)
+ /* By definition, there isn't more data to read into the
+ buffer. */
+ return -1;
+
+ assert (a->use == IOBUF_INPUT);
+
+ /* If there is still some buffered data, then move it to the start
+ of the buffer and try to fill the end of the buffer. (This is
+ useful if we are called from iobuf_peek().) */
+ assert (a->d.start <= a->d.len);
+ a->d.len -= a->d.start;
+ memmove (a->d.buf, &a->d.buf[a->d.start], a->d.len);
+ a->d.start = 0;
+
+ if (a->d.len < target && a->filter_eof)
+ /* The last time we tried to read from this filter, we got an EOF.
+ We couldn't return the EOF, because there was buffered data.
+ Since there is no longer any buffered data, return the
+ error. */
+ {
+ if (DBG_IOBUF)
+ log_debug ("iobuf-%d.%d: underflow: eof (pending eof)\n",
+ a->no, a->subno);
+ if (! clear_pending_eof)
+ return -1;
+
+ if (a->chain)
+ /* A filter follows this one. Free this filter. */
+ {
+ iobuf_t b = a->chain;
+ if (DBG_IOBUF)
+ log_debug ("iobuf-%d.%d: filter popped (pending EOF returned)\n",
+ a->no, a->subno);
+ xfree (a->d.buf);
+ xfree (a->real_fname);
+ memcpy (a, b, sizeof *a);
+ xfree (b);
+ print_chain (a);
+ }
+ else
+ a->filter_eof = 0; /* for the top level filter */
+ return -1; /* return one(!) EOF */
+ }
+
+ if (a->d.len == 0 && a->error)
+ /* The last time we tried to read from this filter, we got an
+ error. We couldn't return the error, because there was
+ buffered data. Since there is no longer any buffered data,
+ return the error. */
+ {
+ if (DBG_IOBUF)
+ log_debug ("iobuf-%d.%d: pending error (%s) returned\n",
+ a->no, a->subno, gpg_strerror (a->error));
+ return -1;
+ }
+
+ if (a->filter && ! a->filter_eof && ! a->error)
+ /* We have a filter function and the last time we tried to read we
+ didn't get an EOF or an error. Try to fill the buffer. */
+ {
+ /* Be careful to account for any buffered data. */
+ len = a->d.size - a->d.len;
+ if (DBG_IOBUF)
+ log_debug ("iobuf-%d.%d: underflow: A->FILTER (%lu bytes)\n",
+ a->no, a->subno, (ulong) len);
+ if (len == 0)
+ /* There is no space for more data. Don't bother calling
+ A->FILTER. */
+ rc = 0;
+ else
+ rc = a->filter (a->filter_ov, IOBUFCTRL_UNDERFLOW, a->chain,
+ &a->d.buf[a->d.len], &len);
+ a->d.len += len;
+
+ if (DBG_IOBUF)
+ log_debug ("iobuf-%d.%d: A->FILTER() returned rc=%d (%s), read %lu bytes\n",
+ a->no, a->subno,
+ rc, rc == 0 ? "ok" : rc == -1 ? "EOF" : gpg_strerror (rc),
+ (ulong) len);
+/* if( a->no == 1 ) */
+/* log_hexdump (" data:", a->d.buf, len); */
+
+ if (rc == -1)
+ /* EOF. */
+ {
+ size_t dummy_len = 0;
+
+ /* Tell the filter to free itself */
+ if ((rc = a->filter (a->filter_ov, IOBUFCTRL_FREE, a->chain,
+ NULL, &dummy_len)))
+ log_error ("IOBUFCTRL_FREE failed: %s\n", gpg_strerror (rc));
+
+ /* Free everything except for the internal buffer. */
+ if (a->filter_ov && a->filter_ov_owner)
+ xfree (a->filter_ov);
+ a->filter_ov = NULL;
+ a->filter = NULL;
+ a->filter_eof = 1;
+
+ if (clear_pending_eof && a->d.len == 0 && a->chain)
+ /* We don't need to keep this filter around at all:
+
+ - we got an EOF
+ - we have no buffered data
+ - a filter follows this one.
+
+ Unlink this filter. */
+ {
+ iobuf_t b = a->chain;
+ if (DBG_IOBUF)
+ log_debug ("iobuf-%d.%d: pop in underflow (nothing buffered, got EOF)\n",
+ a->no, a->subno);
+ xfree (a->d.buf);
+ xfree (a->real_fname);
+ memcpy (a, b, sizeof *a);
+ xfree (b);
+
+ print_chain (a);
+
+ return -1;
+ }
+ else if (a->d.len == 0)
+ /* We can't unlink this filter (it is the only one in the
+ pipeline), but we can immediately return EOF. */
+ return -1;
+ }
+ else if (rc)
+ /* Record the error. */
+ {
+ a->error = rc;
+
+ if (a->d.len == 0)
+ /* There is no buffered data. Immediately return EOF. */
+ return -1;
+ }
+ }
+
+ assert (a->d.start <= a->d.len);
+ if (a->d.start < a->d.len)
+ return a->d.buf[a->d.start++];
+
+ /* EOF. */
+ return -1;
+}
+
+
+static int
+filter_flush (iobuf_t a)
+{
+ size_t len;
+ int rc;
+
+ if (a->use == IOBUF_OUTPUT_TEMP)
+ { /* increase the temp buffer */
+ size_t newsize = a->d.size + IOBUF_BUFFER_SIZE;
+
+ if (DBG_IOBUF)
+ log_debug ("increasing temp iobuf from %lu to %lu\n",
+ (ulong) a->d.size, (ulong) newsize);
+
+ a->d.buf = xrealloc (a->d.buf, newsize);
+ a->d.size = newsize;
+ return 0;
+ }
+ else if (a->use != IOBUF_OUTPUT)
+ log_bug ("flush on non-output iobuf\n");
+ else if (!a->filter)
+ log_bug ("filter_flush: no filter\n");
+ len = a->d.len;
+ rc = a->filter (a->filter_ov, IOBUFCTRL_FLUSH, a->chain, a->d.buf, &len);
+ if (!rc && len != a->d.len)
+ {
+ log_info ("filter_flush did not write all!\n");
+ rc = GPG_ERR_INTERNAL;
+ }
+ else if (rc)
+ a->error = rc;
+ a->d.len = 0;
+
+ return rc;
+}
+
+
+int
+iobuf_readbyte (iobuf_t a)
+{
+ int c;
+
+ if (a->use == IOBUF_OUTPUT || a->use == IOBUF_OUTPUT_TEMP)
+ {
+ log_bug ("iobuf_readbyte called on a non-INPUT pipeline!\n");
+ return -1;
+ }
+
+ assert (a->d.start <= a->d.len);
+
+ if (a->nlimit && a->nbytes >= a->nlimit)
+ return -1; /* forced EOF */
+
+ if (a->d.start < a->d.len)
+ {
+ c = a->d.buf[a->d.start++];
+ }
+ else if ((c = underflow (a, 1)) == -1)
+ return -1; /* EOF */
+
+ assert (a->d.start <= a->d.len);
+
+ /* Note: if underflow doesn't return EOF, then it returns the first
+ byte that was read and advances a->d.start appropriately. */
+
+ a->nbytes++;
+ return c;
+}
+
+
+int
+iobuf_read (iobuf_t a, void *buffer, unsigned int buflen)
+{
+ unsigned char *buf = (unsigned char *)buffer;
+ int c, n;
+
+ if (a->use == IOBUF_OUTPUT || a->use == IOBUF_OUTPUT_TEMP)
+ {
+ log_bug ("iobuf_read called on a non-INPUT pipeline!\n");
+ return -1;
+ }
+
+ if (a->nlimit)
+ {
+ /* Handle special cases. */
+ for (n = 0; n < buflen; n++)
+ {
+ if ((c = iobuf_readbyte (a)) == -1)
+ {
+ if (!n)
+ return -1; /* eof */
+ break;
+ }
+
+ if (buf)
+ {
+ *buf = c;
+ buf++;
+ }
+ }
+ return n;
+ }
+
+ n = 0;
+ do
+ {
+ if (n < buflen && a->d.start < a->d.len)
+ /* Drain the buffer. */
+ {
+ unsigned size = a->d.len - a->d.start;
+ if (size > buflen - n)
+ size = buflen - n;
+ if (buf)
+ memcpy (buf, a->d.buf + a->d.start, size);
+ n += size;
+ a->d.start += size;
+ if (buf)
+ buf += size;
+ }
+ if (n < buflen)
+ /* Draining the internal buffer didn't fill BUFFER. Call
+ underflow to read more data into the filter's internal
+ buffer. */
+ {
+ if ((c = underflow (a, 1)) == -1)
+ /* EOF. If we managed to read something, don't return EOF
+ now. */
+ {
+ a->nbytes += n;
+ return n ? n : -1 /*EOF*/;
+ }
+ if (buf)
+ *buf++ = c;
+ n++;
+ }
+ }
+ while (n < buflen);
+ a->nbytes += n;
+ return n;
+}
+
+
+
+int
+iobuf_peek (iobuf_t a, byte * buf, unsigned buflen)
+{
+ int n = 0;
+
+ assert (buflen > 0);
+ assert (a->use == IOBUF_INPUT || a->use == IOBUF_INPUT_TEMP);
+
+ if (buflen > a->d.size)
+ /* We can't peek more than we can buffer. */
+ buflen = a->d.size;
+
+ /* Try to fill the internal buffer with enough data to satisfy the
+ request. */
+ while (buflen > a->d.len - a->d.start)
+ {
+ if (underflow_target (a, 0, buflen) == -1)
+ /* EOF. We can't read any more. */
+ break;
+
+ /* Underflow consumes the first character (it's the return
+ value). unget() it by resetting the "file position". */
+ assert (a->d.start == 1);
+ a->d.start = 0;
+ }
+
+ n = a->d.len - a->d.start;
+ if (n > buflen)
+ n = buflen;
+
+ if (n == 0)
+ /* EOF. */
+ return -1;
+
+ memcpy (buf, &a->d.buf[a->d.start], n);
+
+ return n;
+}
+
+
+
+
+int
+iobuf_writebyte (iobuf_t a, unsigned int c)
+{
+ int rc;
+
+ if (a->use == IOBUF_INPUT || a->use == IOBUF_INPUT_TEMP)
+ {
+ log_bug ("iobuf_writebyte called on an input pipeline!\n");
+ return -1;
+ }
+
+ if (a->d.len == a->d.size)
+ if ((rc=filter_flush (a)))
+ return rc;
+
+ assert (a->d.len < a->d.size);
+ a->d.buf[a->d.len++] = c;
+ return 0;
+}
+
+
+int
+iobuf_write (iobuf_t a, const void *buffer, unsigned int buflen)
+{
+ const unsigned char *buf = (const unsigned char *)buffer;
+ int rc;
+
+ if (a->use == IOBUF_INPUT || a->use == IOBUF_INPUT_TEMP)
+ {
+ log_bug ("iobuf_write called on an input pipeline!\n");
+ return -1;
+ }
+
+ do
+ {
+ if (buflen && a->d.len < a->d.size)
+ {
+ unsigned size = a->d.size - a->d.len;
+ if (size > buflen)
+ size = buflen;
+ memcpy (a->d.buf + a->d.len, buf, size);
+ buflen -= size;
+ buf += size;
+ a->d.len += size;
+ }
+ if (buflen)
+ {
+ rc = filter_flush (a);
+ if (rc)
+ return rc;
+ }
+ }
+ while (buflen);
+ return 0;
+}
+
+
+int
+iobuf_writestr (iobuf_t a, const char *buf)
+{
+ if (a->use == IOBUF_INPUT || a->use == IOBUF_INPUT_TEMP)
+ {
+ log_bug ("iobuf_writestr called on an input pipeline!\n");
+ return -1;
+ }
+
+ return iobuf_write (a, buf, strlen (buf));
+}
+
+
+
+int
+iobuf_write_temp (iobuf_t dest, iobuf_t source)
+{
+ assert (source->use == IOBUF_OUTPUT || source->use == IOBUF_OUTPUT_TEMP);
+ assert (dest->use == IOBUF_OUTPUT || dest->use == IOBUF_OUTPUT_TEMP);
+
+ iobuf_flush_temp (source);
+ return iobuf_write (dest, source->d.buf, source->d.len);
+}
+
+size_t
+iobuf_temp_to_buffer (iobuf_t a, byte * buffer, size_t buflen)
+{
+ byte desc[MAX_IOBUF_DESC];
+ size_t n;
+
+ while (1)
+ {
+ int rc = filter_flush (a);
+ if (rc)
+ log_bug ("Flushing iobuf %d.%d (%s) from iobuf_temp_to_buffer failed. Ignoring.\n",
+ a->no, a->subno, iobuf_desc (a, desc));
+ if (! a->chain)
+ break;
+ a = a->chain;
+ }
+
+ n = a->d.len;
+ if (n > buflen)
+ n = buflen;
+ memcpy (buffer, a->d.buf, n);
+ return n;
+}
+
+/* Copies the data from the input iobuf SOURCE to the output iobuf
+ DEST until either an error is encountered or EOF is reached.
+ Returns the number of bytes copies or (size_t)(-1) on error. */
+size_t
+iobuf_copy (iobuf_t dest, iobuf_t source)
+{
+ char *temp;
+ /* Use a 32 KB buffer. */
+ const size_t temp_size = 32 * 1024;
+
+ size_t nread;
+ size_t nwrote = 0;
+ size_t max_read = 0;
+ int err;
+
+ log_assert (source->use == IOBUF_INPUT || source->use == IOBUF_INPUT_TEMP);
+ log_assert (dest->use == IOBUF_OUTPUT || source->use == IOBUF_OUTPUT_TEMP);
+
+ if (iobuf_error (dest))
+ return (size_t)(-1);
+
+ temp = xmalloc (temp_size);
+ while (1)
+ {
+ nread = iobuf_read (source, temp, temp_size);
+ if (nread == -1)
+ /* EOF. */
+ break;
+
+ if (nread > max_read)
+ max_read = nread;
+
+ err = iobuf_write (dest, temp, nread);
+ if (err)
+ break;
+ nwrote += nread;
+ }
+
+ /* Burn the buffer. */
+ if (max_read)
+ wipememory (temp, max_read);
+ xfree (temp);
+
+ return nwrote;
+}
+
+
+void
+iobuf_flush_temp (iobuf_t temp)
+{
+ if (temp->use == IOBUF_INPUT || temp->use == IOBUF_INPUT_TEMP)
+ log_bug ("iobuf_flush_temp called on an input pipeline!\n");
+ while (temp->chain)
+ iobuf_pop_filter (temp, temp->filter, NULL);
+}
+
+
+void
+iobuf_set_limit (iobuf_t a, off_t nlimit)
+{
+ if (nlimit)
+ a->nofast = 1;
+ else
+ a->nofast = 0;
+ a->nlimit = nlimit;
+ a->ntotal += a->nbytes;
+ a->nbytes = 0;
+}
+
+
+
+off_t
+iobuf_get_filelength (iobuf_t a, int *overflow)
+{
+ if (overflow)
+ *overflow = 0;
+
+ /* Hmmm: file_filter may have already been removed */
+ for ( ; a->chain; a = a->chain )
+ ;
+
+ if (a->filter != file_filter)
+ return 0;
+
+ {
+ file_filter_ctx_t *b = a->filter_ov;
+ gnupg_fd_t fp = b->fp;
+
+#if defined(HAVE_W32_SYSTEM)
+ ulong size;
+ static int (* __stdcall get_file_size_ex) (void *handle,
+ LARGE_INTEGER *r_size);
+ static int get_file_size_ex_initialized;
+
+ if (!get_file_size_ex_initialized)
+ {
+ void *handle;
+
+ handle = dlopen ("kernel32.dll", RTLD_LAZY);
+ if (handle)
+ {
+ get_file_size_ex = dlsym (handle, "GetFileSizeEx");
+ if (!get_file_size_ex)
+ dlclose (handle);
+ }
+ get_file_size_ex_initialized = 1;
+ }
+
+ if (get_file_size_ex)
+ {
+ /* This is a newer system with GetFileSizeEx; we use this
+ then because it seem that GetFileSize won't return a
+ proper error in case a file is larger than 4GB. */
+ LARGE_INTEGER exsize;
+
+ if (get_file_size_ex (fp, &exsize))
+ {
+ if (!exsize.u.HighPart)
+ return exsize.u.LowPart;
+ if (overflow)
+ *overflow = 1;
+ return 0;
+ }
+ }
+ else
+ {
+ if ((size=GetFileSize (fp, NULL)) != 0xffffffff)
+ return size;
+ }
+ log_error ("GetFileSize for handle %p failed: %s\n",
+ fp, w32_strerror (-1));
+#else /*!HAVE_W32_SYSTEM*/
+ {
+ struct stat st;
+
+ if ( !fstat (FD2INT (fp), &st) )
+ return st.st_size;
+ log_error("fstat() failed: %s\n", strerror(errno) );
+ }
+#endif /*!HAVE_W32_SYSTEM*/
+ }
+
+ return 0;
+}
+
+
+int
+iobuf_get_fd (iobuf_t a)
+{
+ for (; a->chain; a = a->chain)
+ ;
+
+ if (a->filter != file_filter)
+ return -1;
+
+ {
+ file_filter_ctx_t *b = a->filter_ov;
+ gnupg_fd_t fp = b->fp;
+
+ return FD2INT (fp);
+ }
+}
+
+
+off_t
+iobuf_tell (iobuf_t a)
+{
+ return a->ntotal + a->nbytes;
+}
+
+
+#if !defined(HAVE_FSEEKO) && !defined(fseeko)
+
+#ifdef HAVE_LIMITS_H
+# include <limits.h>
+#endif
+#ifndef LONG_MAX
+# define LONG_MAX ((long) ((unsigned long) -1 >> 1))
+#endif
+#ifndef LONG_MIN
+# define LONG_MIN (-1 - LONG_MAX)
+#endif
+
+/****************
+ * A substitute for fseeko, for hosts that don't have it.
+ */
+static int
+fseeko (FILE * stream, off_t newpos, int whence)
+{
+ while (newpos != (long) newpos)
+ {
+ long pos = newpos < 0 ? LONG_MIN : LONG_MAX;
+ if (fseek (stream, pos, whence) != 0)
+ return -1;
+ newpos -= pos;
+ whence = SEEK_CUR;
+ }
+ return fseek (stream, (long) newpos, whence);
+}
+#endif
+
+int
+iobuf_seek (iobuf_t a, off_t newpos)
+{
+ file_filter_ctx_t *b = NULL;
+
+ if (a->use == IOBUF_OUTPUT || a->use == IOBUF_INPUT)
+ {
+ /* Find the last filter in the pipeline. */
+ for (; a->chain; a = a->chain)
+ ;
+
+ if (a->filter != file_filter)
+ return -1;
+
+ b = a->filter_ov;
+
+#ifdef HAVE_W32_SYSTEM
+ if (SetFilePointer (b->fp, newpos, NULL, FILE_BEGIN) == 0xffffffff)
+ {
+ log_error ("SetFilePointer failed on handle %p: ec=%d\n",
+ b->fp, (int) GetLastError ());
+ return -1;
+ }
+#else
+ if (lseek (b->fp, newpos, SEEK_SET) == (off_t) - 1)
+ {
+ log_error ("can't lseek: %s\n", strerror (errno));
+ return -1;
+ }
+#endif
+ /* Discard the buffer it is not a temp stream. */
+ a->d.len = 0;
+ }
+ a->d.start = 0;
+ a->nbytes = 0;
+ a->nlimit = 0;
+ a->nofast = 0;
+ a->ntotal = newpos;
+ a->error = 0;
+
+ /* It is impossible for A->CHAIN to be non-NULL. If A is an INPUT
+ or OUTPUT buffer, then we find the last filter, which is defined
+ as A->CHAIN being NULL. If A is a TEMP filter, then A must be
+ the only filter in the pipe: when iobuf_push_filter adds a filter
+ to the front of a pipeline, it sets the new filter to be an
+ OUTPUT filter if the pipeline is an OUTPUT or TEMP pipeline and
+ to be an INPUT filter if the pipeline is an INPUT pipeline.
+ Thus, only the last filter in a TEMP pipeline can be a */
+
+ /* remove filters, but the last */
+ if (a->chain)
+ log_debug ("iobuf_pop_filter called in iobuf_seek - please report\n");
+ while (a->chain)
+ iobuf_pop_filter (a, a->filter, NULL);
+
+ return 0;
+}
+
+
+const char *
+iobuf_get_real_fname (iobuf_t a)
+{
+ if (a->real_fname)
+ return a->real_fname;
+
+ /* the old solution */
+ for (; a; a = a->chain)
+ if (!a->chain && a->filter == file_filter)
+ {
+ file_filter_ctx_t *b = a->filter_ov;
+ return b->print_only_name ? NULL : b->fname;
+ }
+
+ return NULL;
+}
+
+const char *
+iobuf_get_fname (iobuf_t a)
+{
+ for (; a; a = a->chain)
+ if (!a->chain && a->filter == file_filter)
+ {
+ file_filter_ctx_t *b = a->filter_ov;
+ return b->fname;
+ }
+ return NULL;
+}
+
+const char *
+iobuf_get_fname_nonnull (iobuf_t a)
+{
+ const char *fname;
+
+ fname = iobuf_get_fname (a);
+ return fname? fname : "[?]";
+}
+
+
+/****************
+ * Enable or disable partial body length mode (RFC 4880 4.2.2.4).
+ *
+ * If LEN is 0, this disables partial block mode by popping the
+ * partial body length filter, which must be the most recently
+ * added filter.
+ *
+ * If LEN is non-zero, it pushes a partial body length filter. If
+ * this is a read filter, LEN must be the length byte from the first
+ * chunk and A should be position just after this first partial body
+ * length header.
+ */
+void
+iobuf_set_partial_body_length_mode (iobuf_t a, size_t len)
+{
+ if (!len)
+ /* Disable partial body length mode. */
+ {
+ if (a->use == IOBUF_INPUT)
+ log_debug ("iobuf_pop_filter called in set_partial_block_mode"
+ " - please report\n");
+
+ log_assert (a->filter == block_filter);
+ iobuf_pop_filter (a, block_filter, NULL);
+ }
+ else
+ /* Enabled partial body length mode. */
+ {
+ block_filter_ctx_t *ctx = xcalloc (1, sizeof *ctx);
+ ctx->use = a->use;
+ ctx->partial = 1;
+ ctx->size = 0;
+ ctx->first_c = len;
+ iobuf_push_filter (a, block_filter, ctx);
+ }
+}
+
+
+
+unsigned int
+iobuf_read_line (iobuf_t a, byte ** addr_of_buffer,
+ unsigned *length_of_buffer, unsigned *max_length)
+{
+ int c;
+ char *buffer = (char *)*addr_of_buffer;
+ unsigned length = *length_of_buffer;
+ unsigned nbytes = 0;
+ unsigned maxlen = *max_length;
+ char *p;
+
+ /* The code assumes that we have space for at least a newline and a
+ NUL character in the buffer. This requires at least 2 bytes. We
+ don't complicate the code by handling the stupid corner case, but
+ simply assert that it can't happen. */
+ assert (!buffer || length >= 2 || maxlen >= 2);
+
+ if (!buffer || length <= 1)
+ /* must allocate a new buffer */
+ {
+ length = 256 <= maxlen ? 256 : maxlen;
+ buffer = xrealloc (buffer, length);
+ *addr_of_buffer = (unsigned char *)buffer;
+ *length_of_buffer = length;
+ }
+
+ p = buffer;
+ while ((c = iobuf_get (a)) != -1)
+ {
+ *p++ = c;
+ nbytes++;
+ if (c == '\n')
+ break;
+
+ if (nbytes == length - 1)
+ /* We don't have enough space to add a \n and a \0. Increase
+ the buffer size. */
+ {
+ if (length == maxlen)
+ /* We reached the buffer's size limit! */
+ {
+ /* Skip the rest of the line. */
+ while (c != '\n' && (c = iobuf_get (a)) != -1)
+ ;
+
+ /* p is pointing at the last byte in the buffer. We
+ always terminate the line with "\n\0" so overwrite
+ the previous byte with a \n. */
+ assert (p > buffer);
+ p[-1] = '\n';
+
+ /* Indicate truncation. */
+ *max_length = 0;
+ break;
+ }
+
+ length += length < 1024 ? 256 : 1024;
+ if (length > maxlen)
+ length = maxlen;
+
+ buffer = xrealloc (buffer, length);
+ *addr_of_buffer = (unsigned char *)buffer;
+ *length_of_buffer = length;
+ p = buffer + nbytes;
+ }
+ }
+ /* Add the terminating NUL. */
+ *p = 0;
+
+ /* Return the number of characters written to the buffer including
+ the newline, but not including the terminating NUL. */
+ return nbytes;
+}
+
+static int
+translate_file_handle (int fd, int for_write)
+{
+#if defined(HAVE_W32CE_SYSTEM)
+ /* This is called only with one of the special filenames. Under
+ W32CE the FD here is not a file descriptor but a rendezvous id,
+ thus we need to finish the pipe first. */
+ fd = _assuan_w32ce_finish_pipe (fd, for_write);
+#elif defined(HAVE_W32_SYSTEM)
+ {
+ int x;
+
+ (void)for_write;
+
+ if (fd == 0)
+ x = (int) GetStdHandle (STD_INPUT_HANDLE);
+ else if (fd == 1)
+ x = (int) GetStdHandle (STD_OUTPUT_HANDLE);
+ else if (fd == 2)
+ x = (int) GetStdHandle (STD_ERROR_HANDLE);
+ else
+ x = fd;
+
+ if (x == -1)
+ log_debug ("GetStdHandle(%d) failed: ec=%d\n",
+ fd, (int) GetLastError ());
+
+ fd = x;
+ }
+#else
+ (void)for_write;
+#endif
+ return fd;
+}
+
+
+void
+iobuf_skip_rest (iobuf_t a, unsigned long n, int partial)
+{
+ if ( partial )
+ {
+ for (;;)
+ {
+ if (a->nofast || a->d.start >= a->d.len)
+ {
+ if (iobuf_readbyte (a) == -1)
+ {
+ break;
+ }
+ }
+ else
+ {
+ unsigned long count = a->d.len - a->d.start;
+ a->nbytes += count;
+ a->d.start = a->d.len;
+ }
+ }
+ }
+ else
+ {
+ unsigned long remaining = n;
+ while (remaining > 0)
+ {
+ if (a->nofast || a->d.start >= a->d.len)
+ {
+ if (iobuf_readbyte (a) == -1)
+ {
+ break;
+ }
+ --remaining;
+ }
+ else
+ {
+ unsigned long count = a->d.len - a->d.start;
+ if (count > remaining)
+ {
+ count = remaining;
+ }
+ a->nbytes += count;
+ a->d.start += count;
+ remaining -= count;
+ }
+ }
+ }
+}
diff --git a/common/iobuf.h b/common/iobuf.h
new file mode 100644
index 0000000..624e154
--- /dev/null
+++ b/common/iobuf.h
@@ -0,0 +1,615 @@
+/* iobuf.h - I/O buffer
+ * Copyright (C) 1998, 1999, 2000, 2001, 2003,
+ * 2010 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_COMMON_IOBUF_H
+#define GNUPG_COMMON_IOBUF_H
+
+/* An iobuf is basically a filter in a pipeline.
+
+ Consider the following command, which consists of three filters
+ that are chained together:
+
+ $ cat file | base64 --decode | gunzip
+
+ The first filter reads the file from the file system and sends that
+ data to the second filter. The second filter decodes
+ base64-encoded data and sends the data to the third and last
+ filter. The last filter decompresses the data and the result is
+ displayed on the terminal. The iobuf system works in the same way
+ where each iobuf is a filter and the individual iobufs can be
+ chained together.
+
+ There are number of predefined filters. iobuf_open(), for
+ instance, creates a filter that reads from a specified file. And,
+ iobuf_temp_with_content() creates a filter that returns some
+ specified contents. There are also filters for writing content.
+ iobuf_openrw opens a file for writing. iobuf_temp creates a filter
+ that writes data to a fixed-sized buffer.
+
+ To chain filters together, you use the iobuf_push_filter()
+ function. The filters are chained together using the chain field
+ in the iobuf_t.
+
+ A pipeline can only be used for reading (IOBUF_INPUT) or for
+ writing (IOBUF_OUTPUT / IOBUF_OUTPUT_TEMP). When reading, data
+ flows from the last filter towards the first. That is, the user
+ calls iobuf_read(), the module reads from the first filter, which
+ gets its input from the second filter, etc. When writing, data
+ flows from the first filter towards the last. In this case, when
+ the user calls iobuf_write(), the data is written to the first
+ filter, which writes the transformed data to the second filter,
+ etc.
+
+ An iobuf_t contains some state about the filter. For instance, it
+ indicates if the filter has already returned EOF (filter_eof) and
+ the next filter in the pipeline, if any (chain). It also contains
+ a function pointer, filter. This is a generic function. It is
+ called when input is needed or output is available. In this case
+ it is passed a pointer to some filter-specific persistent state
+ (filter_ov), the actual operation, the next filter in the chain, if
+ any, and a buffer that either contains the contents to write, if
+ the pipeline is setup to write data, or is the place to store data,
+ if the pipeline is setup to read data.
+
+
+ Unlike a Unix pipeline, an IOBUF pipeline can return EOF multiple
+ times. This is similar to the following:
+
+ { cat file1; cat file2; } | grep foo
+
+ However, instead of grep seeing a single stream, grep would see
+ each byte stream followed by an EOF marker. (When a filter returns
+ EOF, the EOF is returned to the user exactly once and then the
+ filter is removed from the pipeline.) */
+
+/* For estream_t. */
+#include <gpg-error.h>
+
+#include "../common/types.h"
+#include "../common/sysutils.h"
+
+#define DBG_IOBUF iobuf_debug_mode
+
+/* Filter control modes. */
+enum
+ {
+ IOBUFCTRL_INIT = 1,
+ IOBUFCTRL_FREE = 2,
+ IOBUFCTRL_UNDERFLOW = 3,
+ IOBUFCTRL_FLUSH = 4,
+ IOBUFCTRL_DESC = 5,
+ IOBUFCTRL_CANCEL = 6,
+ IOBUFCTRL_USER = 16
+ };
+
+
+/* Command codes for iobuf_ioctl. */
+typedef enum
+ {
+ IOBUF_IOCTL_KEEP_OPEN = 1, /* Uses intval. */
+ IOBUF_IOCTL_INVALIDATE_CACHE = 2, /* Uses ptrval. */
+ IOBUF_IOCTL_NO_CACHE = 3, /* Uses intval. */
+ IOBUF_IOCTL_FSYNC = 4 /* Uses ptrval. */
+ } iobuf_ioctl_t;
+
+enum iobuf_use
+ {
+ /* Pipeline is in input mode. The data flows from the end to the
+ beginning. That is, when reading from the pipeline, the first
+ filter gets its input from the second filter, etc. */
+ IOBUF_INPUT,
+ /* Pipeline is in input mode. The last filter in the pipeline is
+ a temporary buffer from which the data is "read". */
+ IOBUF_INPUT_TEMP,
+ /* Pipeline is in output mode. The data flows from the beginning
+ to the end. That is, when writing to the pipeline, the user
+ writes to the first filter, which transforms the data and sends
+ it to the second filter, etc. */
+ IOBUF_OUTPUT,
+ /* Pipeline is in output mode. The last filter in the pipeline is
+ a temporary buffer that grows as necessary. */
+ IOBUF_OUTPUT_TEMP
+ };
+
+
+typedef struct iobuf_struct *iobuf_t;
+typedef struct iobuf_struct *IOBUF; /* Compatibility with gpg 1.4. */
+
+/* fixme: we should hide most of this stuff */
+struct iobuf_struct
+{
+ /* The type of filter. Either IOBUF_INPUT, IOBUF_OUTPUT or
+ IOBUF_OUTPUT_TEMP. */
+ enum iobuf_use use;
+
+ /* nlimit can be changed using iobuf_set_limit. If non-zero, it is
+ the number of additional bytes that can be read from the filter
+ before EOF is forcefully returned. */
+ off_t nlimit;
+ /* nbytes if the number of bytes that have been read (using
+ iobuf_get / iobuf_readbyte / iobuf_read) since the last call to
+ iobuf_set_limit. */
+ off_t nbytes;
+
+ /* The number of bytes read prior to the last call to
+ iobuf_set_limit. Thus, the total bytes read (i.e., the position
+ of stream) is ntotal + nbytes. */
+ off_t ntotal;
+
+ /* Whether we need to read from the filter one byte at a time or
+ whether we can do bulk reads. We need to read one byte at a time
+ if a limit (set via iobuf_set_limit) is active. */
+ int nofast;
+
+ /* A buffer for unread/unwritten data.
+
+ For an output pipeline (IOBUF_OUTPUT), this is the data that has
+ not yet been written to the filter. Consider a simple pipeline
+ consisting of a single stage, which writes to a file. When you
+ write to the pipeline (iobuf_writebyte or iobuf_write), the data
+ is first stored in this buffer. Only when the buffer is full or
+ you call iobuf_flush() is FILTER actually called and the data
+ written to the file.
+
+ For an input pipeline (IOBUF_INPUT), this is the data that has
+ been read from this filter, but not yet been read from the
+ preceding filter (or the user, if this filter is the head of the
+ pipeline). Again, consider a simple pipeline consisting of a
+ single stage. This stage reads from a file. If you read a
+ single byte (iobuf_get) and the buffer is empty, then FILTER is
+ called to fill the buffer. In this case, a single byte is not
+ requested, but the whole buffer is filled (if possible). */
+ struct
+ {
+ /* Size of the buffer. */
+ size_t size;
+ /* Number of bytes at the beginning of the buffer that have
+ already been consumed. (In other words: the index of the first
+ byte that hasn't been consumed.) This is only non-zero for
+ input filters. */
+ size_t start;
+ /* The number of bytes in the buffer including any bytes that have
+ been consumed. */
+ size_t len;
+ /* The buffer itself. */
+ byte *buf;
+ } d;
+
+ /* When FILTER is called to read some data, it may read some data
+ and then return EOF. We can't return the EOF immediately.
+ Instead, we note that we observed the EOF and when the buffer is
+ finally empty, we return the EOF. */
+ int filter_eof;
+ /* Like filter_eof, when FILTER is called to read some data, it may
+ read some data and then return an error. We can't return the
+ error (in the form of an EOF) immediately. Instead, we note that
+ we observed the error and when the buffer is finally empty, we
+ return the EOF. */
+ int error;
+
+ /* The callback function to read data from the filter, etc. See
+ iobuf_filter_push for details. */
+ int (*filter) (void *opaque, int control,
+ iobuf_t chain, byte * buf, size_t * len);
+ /* An opaque pointer that can be used for local filter state. This
+ is passed as the first parameter to FILTER. */
+ void *filter_ov;
+ /* Whether the iobuf code should free(filter_ov) when destroying the
+ filter. */
+ int filter_ov_owner;
+
+ /* When using iobuf_open, iobuf_create, iobuf_openrw to open a file,
+ the file's name is saved here. This is used to delete the file
+ when an output pipeline (IOBUF_OUPUT) is canceled
+ (iobuf_cancel). */
+ char *real_fname;
+
+ /* The next filter in the pipeline. */
+ iobuf_t chain;
+
+ /* This field is for debugging. Each time a filter is allocated
+ (via iobuf_alloc()), a monotonically increasing counter is
+ incremented and this field is set to the new value. This field
+ should only be accessed via the iobuf_io macro. */
+ int no;
+
+ /* The number of filters in the pipeline following (not including)
+ this one. When you call iobuf_push_filter or iobuf_push_filter2,
+ this value is used to check the length of the pipeline if the
+ pipeline already contains 65 stages then these functions fail.
+ This amount of nesting typically indicates corrupted data or an
+ active denial of service attack. */
+ int subno;
+};
+
+extern int iobuf_debug_mode;
+
+
+/* Returns whether the specified filename corresponds to a pipe. In
+ particular, this function checks if FNAME is "-" and, if special
+ filenames are enabled (see check_special_filename), whether
+ FNAME is a special filename. */
+int iobuf_is_pipe_filename (const char *fname);
+
+/* Allocate a new filter. This filter doesn't have a function
+ assigned to it. Thus you need to manually set IOBUF->FILTER and
+ IOBUF->FILTER_OV, if required. This function is intended to help
+ create a new primary source or primary sink, i.e., the last filter
+ in the pipeline.
+
+ USE is IOBUF_INPUT, IOBUF_INPUT_TEMP, IOBUF_OUTPUT or
+ IOBUF_OUTPUT_TEMP.
+
+ BUFSIZE is the desired internal buffer size (that is, the size of
+ the typical read / write request). */
+iobuf_t iobuf_alloc (int use, size_t bufsize);
+
+/* Create an output filter that simply buffers data written to it.
+ This is useful for collecting data for later processing. The
+ buffer can be written to in the usual way (iobuf_write, etc.). The
+ data can later be extracted using iobuf_write_temp() or
+ iobuf_temp_to_buffer(). */
+iobuf_t iobuf_temp (void);
+
+/* Create an input filter that contains some data for reading. */
+iobuf_t iobuf_temp_with_content (const char *buffer, size_t length);
+
+/* Create an input file filter that reads from a file. If FNAME is
+ '-', reads from stdin. If special filenames are enabled
+ (iobuf_enable_special_filenames), then interprets special
+ filenames. */
+iobuf_t iobuf_open (const char *fname);
+
+/* Create an output file filter that writes to a file. If FNAME is
+ NULL or '-', writes to stdout. If special filenames are enabled
+ (iobuf_enable_special_filenames), then interprets special
+ filenames. If FNAME is not NULL, '-' or a special filename, the
+ file is opened for writing. If the file exists, it is truncated.
+ If MODE700 is TRUE, the file is created with mode 600. Otherwise,
+ mode 666 is used. */
+iobuf_t iobuf_create (const char *fname, int mode700);
+
+/* Create an output file filter that writes to a specified file.
+ Neither '-' nor special file names are recognized. */
+iobuf_t iobuf_openrw (const char *fname);
+
+/* Create a file filter using an existing file descriptor. If MODE
+ contains the letter 'w', creates an output filter. Otherwise,
+ creates an input filter. Note: MODE must reflect the file
+ descriptors actual mode! When the filter is destroyed, the file
+ descriptor is closed. */
+iobuf_t iobuf_fdopen (int fd, const char *mode);
+
+/* Like iobuf_fdopen, but doesn't close the file descriptor when the
+ filter is destroyed. */
+iobuf_t iobuf_fdopen_nc (int fd, const char *mode);
+
+/* Create a filter using an existing estream. If MODE contains the
+ letter 'w', creates an output filter. Otherwise, creates an input
+ filter. If KEEP_OPEN is TRUE, then the stream is not closed when
+ the filter is destroyed. Otherwise, the stream is closed when the
+ filter is destroyed. */
+iobuf_t iobuf_esopen (estream_t estream, const char *mode, int keep_open);
+
+/* Create a filter using an existing socket. On Windows creates a
+ special socket filter. On non-Windows systems simply, this simply
+ calls iobuf_fdopen. */
+iobuf_t iobuf_sockopen (int fd, const char *mode);
+
+/* Set various options / perform different actions on a PIPELINE. See
+ the IOBUF_IOCTL_* macros above. */
+int iobuf_ioctl (iobuf_t a, iobuf_ioctl_t cmd, int intval, void *ptrval);
+
+/* Close a pipeline. The filters in the pipeline are first flushed
+ using iobuf_flush, if they are output filters, and then
+ IOBUFCTRL_FREE is called on each filter.
+
+ If any filter returns a non-zero value in response to the
+ IOBUFCTRL_FREE, that first such non-zero value is returned. Note:
+ processing is not aborted in this case. If all filters are freed
+ successfully, 0 is returned. */
+int iobuf_close (iobuf_t iobuf);
+
+/* Calls IOBUFCTRL_CANCEL on each filter in the pipeline. Then calls
+ io_close() on the pipeline. Finally, if the pipeline is an output
+ pipeline, deletes the file. Returns the result of calling
+ iobuf_close on the pipeline. */
+int iobuf_cancel (iobuf_t iobuf);
+
+/* Add a new filter to the front of a pipeline. A is the head of the
+ pipeline. F is the filter implementation. OV is an opaque pointer
+ that is passed to F and is normally used to hold any internal
+ state, such as a file pointer.
+
+ Note: you may only maintain a reference to an iobuf_t as a
+ reference to the head of the pipeline. That is, don't think about
+ setting a pointer in OV to point to the filter's iobuf_t. This is
+ because when we add a new filter to a pipeline, we memcpy the state
+ in A into new buffer. This has the advantage that there is no need
+ to update any references to the pipeline when a filter is added or
+ removed, but it also means that a filter's state moves around in
+ memory.
+
+ The behavior of the filter function is determined by the value of
+ the control parameter:
+
+ IOBUFCTRL_INIT: Called this value just before the filter is
+ linked into the pipeline. This can be used to initialize
+ internal data structures.
+
+ IOBUFCTRL_FREE: Called with this value just before the filter is
+ removed from the pipeline. Normally used to release internal
+ data structures, close a file handle, etc.
+
+ IOBUFCTRL_UNDERFLOW: Called with this value to fill the passed
+ buffer with more data. *LEN is the size of the buffer. Before
+ returning, it should be set to the number of bytes which were
+ written into the buffer. The function must return 0 to
+ indicate success, -1 on EOF and a GPG_ERR_xxxxx code for any
+ error.
+
+ Note: this function may both return data and indicate an error
+ or EOF. In this case, it simply writes the data to BUF, sets
+ *LEN and returns the appropriate return code. The implication
+ is that if an error occurs and no data has yet been written, it
+ is essential that *LEN be set to 0!
+
+ IOBUFCTRL_FLUSH: Called with this value to write out any
+ collected data. *LEN is the number of bytes in BUF that need
+ to be written out. Returns 0 on success and a GPG_ERR_* code
+ otherwise. *LEN must be set to the number of bytes that were
+ written out.
+
+ IOBUFCTRL_CANCEL: Called with this value when iobuf_cancel() is
+ called on the pipeline.
+
+ IOBUFCTRL_DESC: Called with this value to get a human-readable
+ description of the filter. *LEN is the size of the buffer.
+ The description is filled into BUF, NUL-terminated. Always
+ returns 0.
+ */
+int iobuf_push_filter (iobuf_t a, int (*f) (void *opaque, int control,
+ iobuf_t chain, byte * buf,
+ size_t * len), void *ov);
+/* This variant of iobuf_push_filter allows the called to indicate
+ that OV should be freed when this filter is freed. That is, if
+ REL_OV is TRUE, then when the filter is popped or freed OV will be
+ freed after the filter function is called with control set to
+ IOBUFCTRL_FREE. */
+int iobuf_push_filter2 (iobuf_t a,
+ int (*f) (void *opaque, int control, iobuf_t chain,
+ byte * buf, size_t * len), void *ov,
+ int rel_ov);
+
+/* Pop the top filter. The top filter must have the filter function F
+ and the cookie OV. The cookie check is ignored if OV is NULL. */
+int iobuf_pop_filter (iobuf_t a,
+ int (*f) (void *opaque, int control,
+ iobuf_t chain, byte * buf, size_t * len),
+ void *ov);
+
+/* Used for debugging. Prints out the chain using log_debug if
+ IOBUF_DEBUG_MODE is not 0. */
+int iobuf_print_chain (iobuf_t a);
+
+/* Indicate that some error occurred on the specified filter. */
+#define iobuf_set_error(a) do { (a)->error = 1; } while(0)
+
+/* Return any pending error on filter A. */
+#define iobuf_error(a) ((a)->error)
+
+/* Limit the amount of additional data that may be read from the
+ filter. That is, if you've already read 100 bytes from A and you
+ set the limit to 50, then you can read up to an additional 50 bytes
+ (i.e., a total of 150 bytes) before EOF is forcefully returned.
+ Setting NLIMIT to 0 removes any active limit.
+
+ Note: using iobuf_seek removes any currently enforced limit! */
+void iobuf_set_limit (iobuf_t a, off_t nlimit);
+
+/* Returns the number of bytes that have been read from the pipeline.
+ Note: the result is undefined for IOBUF_OUTPUT and IOBUF_OUTPUT_TEMP
+ pipelines! */
+off_t iobuf_tell (iobuf_t a);
+
+/* There are two cases:
+
+ - If A is an INPUT or OUTPUT pipeline, then the last filter in the
+ pipeline is found. If that is not a file filter, -1 is returned.
+ Otherwise, an fseek(..., SEEK_SET) is performed on the file
+ descriptor.
+
+ - If A is a TEMP pipeline and the *first* (and thus only filter) is
+ a TEMP filter, then the "file position" is effectively unchanged.
+ That is, data is appended to the buffer and the seek does not
+ cause the size of the buffer to grow.
+
+ If no error occurred, then any limit previous set by
+ iobuf_set_limit() is cleared. Further, any error on the filter
+ (the file filter or the temp filter) is cleared.
+
+ Returns 0 on success and -1 if an error occurs. */
+int iobuf_seek (iobuf_t a, off_t newpos);
+
+/* Read a single byte. If a filter has no more data, returns -1 to
+ indicate the EOF. Generally, you don't want to use this function,
+ but instead prefer the iobuf_get macro, which is faster if there is
+ data in the internal buffer. */
+int iobuf_readbyte (iobuf_t a);
+
+/* Get a byte from the iobuf; must check for eof prior to this
+ function. This function returns values in the range 0 .. 255 or -1
+ to indicate EOF. iobuf_get_noeof() does not return -1 to indicate
+ EOF, but masks the returned value to be in the range 0 .. 255. */
+#define iobuf_get(a) \
+ ( ((a)->nofast || (a)->d.start >= (a)->d.len )? \
+ iobuf_readbyte((a)) : ( (a)->nbytes++, (a)->d.buf[(a)->d.start++] ) )
+#define iobuf_get_noeof(a) (iobuf_get((a))&0xff)
+
+/* Fill BUF with up to BUFLEN bytes. If a filter has no more data,
+ returns -1 to indicate the EOF. Otherwise returns the number of
+ bytes read. */
+int iobuf_read (iobuf_t a, void *buf, unsigned buflen);
+
+/* Read a line of input (including the '\n') from the pipeline.
+
+ The semantics are the same as for fgets(), but if the buffer is too
+ short a larger one will be allocated up to *MAX_LENGTH and the end
+ of the line except the trailing '\n' discarded. (Thus,
+ *ADDR_OF_BUFFER must be allocated using malloc().) If the buffer
+ is enlarged, then *LENGTH_OF_BUFFER will be updated to reflect the
+ new size. If the line is truncated, then *MAX_LENGTH will be set
+ to 0. If *ADDR_OF_BUFFER is NULL, a buffer is allocated using
+ malloc().
+
+ A line is considered a byte stream ending in a '\n'. Returns the
+ number of characters written to the buffer (i.e., excluding any
+ discarded characters due to truncation). Thus, use this instead of
+ strlen(buffer) to determine the length of the string as this is
+ unreliable if the input contains NUL characters.
+
+ EOF is indicated by a line of length zero.
+
+ The last LF may be missing due to an EOF. */
+unsigned iobuf_read_line (iobuf_t a, byte ** addr_of_buffer,
+ unsigned *length_of_buffer, unsigned *max_length);
+
+/* Read up to BUFLEN bytes from pipeline A. Note: this function can't
+ return more than the pipeline's internal buffer size. The return
+ value is the number of bytes actually written to BUF. If the
+ filter returns EOF, then this function returns -1.
+
+ This function does not clear any pending EOF. That is, if the
+ pipeline consists of two filters and the first one returns EOF
+ during the peek, then the subsequent iobuf_read* will still return
+ EOF before returning the data from the second filter. */
+int iobuf_peek (iobuf_t a, byte * buf, unsigned buflen);
+
+/* Write a byte to the pipeline. Returns 0 on success and an error
+ code otherwise. */
+int iobuf_writebyte (iobuf_t a, unsigned c);
+
+/* Alias for iobuf_writebyte. */
+#define iobuf_put(a,c) iobuf_writebyte(a,c)
+
+/* Write a sequence of bytes to the pipeline. Returns 0 on success
+ and an error code otherwise. */
+int iobuf_write (iobuf_t a, const void *buf, unsigned buflen);
+
+/* Write a string (not including the NUL terminator) to the pipeline.
+ Returns 0 on success and an error code otherwise. */
+int iobuf_writestr (iobuf_t a, const char *buf);
+
+/* Flushes the pipeline removing all filters but the sink (the last
+ filter) in the process. */
+void iobuf_flush_temp (iobuf_t temp);
+
+/* Flushes the pipeline SOURCE removing all filters but the sink (the
+ last filter) in the process (i.e., it calls
+ iobuf_flush_temp(source)) and then writes the data to the pipeline
+ DEST. Note: this doesn't free (iobuf_close()) SOURCE. Both SOURCE
+ and DEST must be output pipelines. */
+int iobuf_write_temp (iobuf_t dest, iobuf_t source);
+
+/* Flushes each filter in the pipeline (i.e., sends any buffered data
+ to the filter by calling IOBUFCTRL_FLUSH). Then, copies up to the
+ first BUFLEN bytes from the last filter's internal buffer (which
+ will only be non-empty if it is a temp filter) to the buffer
+ BUFFER. Returns the number of bytes actually copied. */
+size_t iobuf_temp_to_buffer (iobuf_t a, byte * buffer, size_t buflen);
+
+/* Copies the data from the input iobuf SOURCE to the output iobuf
+ DEST until either an error is encountered or EOF is reached.
+ Returns the number of bytes successfully written. If an error
+ occurred, then any buffered bytes are not returned to SOURCE and are
+ effectively lost. To check if an error occurred, use
+ iobuf_error. */
+size_t iobuf_copy (iobuf_t dest, iobuf_t source);
+
+/* Return the size of any underlying file. This only works with
+ file_filter based pipelines.
+
+ On Win32, it is sometimes not possible to determine the size of
+ files larger than 4GB. In this case, *OVERFLOW (if not NULL) is
+ set to 1. Otherwise, *OVERFLOW is set to 0. */
+off_t iobuf_get_filelength (iobuf_t a, int *overflow);
+#define IOBUF_FILELENGTH_LIMIT 0xffffffff
+
+/* Return the file descriptor designating the underlying file. This
+ only works with file_filter based pipelines. */
+int iobuf_get_fd (iobuf_t a);
+
+/* Return the real filename, if available. This only supports
+ pipelines that end in file filters. Returns NULL if not
+ available. */
+const char *iobuf_get_real_fname (iobuf_t a);
+
+/* Return the filename or a description thereof. For instance, for
+ iobuf_open("-"), this will return "[stdin]". This only supports
+ pipelines that end in file filters. Returns NULL if not
+ available. */
+const char *iobuf_get_fname (iobuf_t a);
+
+/* Like iobuf_getfname, but instead of returning NULL if no
+ description is available, return "[?]". */
+const char *iobuf_get_fname_nonnull (iobuf_t a);
+
+/* Pushes a filter on the pipeline that interprets the datastream as
+ an OpenPGP data block whose length is encoded using partial body
+ length headers (see Section 4.2.2.4 of RFC 4880). Concretely, it
+ just returns / writes the data and finishes the packet with an
+ EOF. */
+void iobuf_set_partial_body_length_mode (iobuf_t a, size_t len);
+
+/* If PARTIAL is set, then read from the pipeline until the first EOF
+ is returned.
+
+ If PARTIAL is 0, then read up to N bytes or until the first EOF is
+ returned.
+
+ Recall: a filter can return EOF. In this case, it and all
+ preceding filters are popped from the pipeline and the next read is
+ from the following filter (which may or may not return EOF). */
+void iobuf_skip_rest (iobuf_t a, unsigned long n, int partial);
+
+#define iobuf_where(a) "[don't know]"
+
+/* Each time a filter is allocated (via iobuf_alloc()), a
+ monotonically increasing counter is incremented and this field is
+ set to the new value. This macro returns that number. */
+#define iobuf_id(a) ((a)->no)
+
+#define iobuf_get_temp_buffer(a) ( (a)->d.buf )
+#define iobuf_get_temp_length(a) ( (a)->d.len )
+
+/* Whether the filter uses an in-memory buffer. */
+#define iobuf_is_temp(a) ( (a)->use == IOBUF_OUTPUT_TEMP )
+
+#endif /*GNUPG_COMMON_IOBUF_H*/
diff --git a/common/ksba-io-support.c b/common/ksba-io-support.c
new file mode 100644
index 0000000..2832a4f
--- /dev/null
+++ b/common/ksba-io-support.c
@@ -0,0 +1,762 @@
+/* kska-io-support.c - Supporting functions for ksba reader and writer
+ * Copyright (C) 2001-2005, 2007, 2010-2011, 2017 Werner Koch
+ * Copyright (C) 2006 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <time.h>
+#include <assert.h>
+#include <ksba.h>
+
+#include "util.h"
+#include "i18n.h"
+#include "ksba-io-support.h"
+
+
+#ifdef HAVE_DOSISH_SYSTEM
+ #define LF "\r\n"
+#else
+ #define LF "\n"
+#endif
+
+
+/* Data used by the reader callbacks. */
+struct reader_cb_parm_s
+{
+ estream_t fp;
+
+ unsigned char line[1024];
+ int linelen;
+ int readpos;
+ int have_lf;
+ unsigned long line_counter;
+
+ int allow_multi_pem; /* Allow processing of multiple PEM objects. */
+ int autodetect; /* Try to detect the input encoding. */
+ int assume_pem; /* Assume input encoding is PEM. */
+ int assume_base64; /* Assume input is base64 encoded. */
+
+ int identified;
+ int is_pem;
+ int is_base64;
+ int stop_seen;
+ int might_be_smime;
+
+ int eof_seen;
+
+ struct {
+ int idx;
+ unsigned char val;
+ int stop_seen;
+ } base64;
+};
+
+
+/* Data used by the writer callbacks. */
+struct writer_cb_parm_s
+{
+ estream_t stream; /* Output stream. */
+
+ char *pem_name; /* Malloced. */
+
+ int wrote_begin;
+ int did_finish;
+
+ struct {
+ int idx;
+ int quad_count;
+ unsigned char radbuf[4];
+ } base64;
+
+};
+
+
+/* Context for this module's functions. */
+struct gnupg_ksba_io_s {
+ union {
+ struct reader_cb_parm_s rparm;
+ struct writer_cb_parm_s wparm;
+ } u;
+
+ union {
+ ksba_reader_t reader;
+ ksba_writer_t writer;
+ } u2;
+};
+
+
+/* The base-64 character list */
+static char bintoasc[64] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789+/";
+/* The reverse base-64 list */
+static unsigned char asctobin[256] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
+ 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+ 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
+ 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24,
+ 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
+ 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff
+};
+
+
+static int
+has_only_base64 (const unsigned char *line, int linelen)
+{
+ if (linelen < 20)
+ return 0;
+ for (; linelen; line++, linelen--)
+ {
+ if (*line == '\n' || (linelen > 1 && *line == '\r' && line[1] == '\n'))
+ break;
+ if ( !strchr (bintoasc, *line) )
+ return 0;
+ }
+ return 1; /* yes */
+}
+
+static int
+is_empty_line (const unsigned char *line, int linelen)
+{
+ if (linelen >= 2 && *line == '\r' && line[1] == '\n')
+ return 1;
+ if (linelen >= 1 && *line == '\n')
+ return 1;
+ return 0;
+}
+
+
+static int
+base64_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread)
+{
+ struct reader_cb_parm_s *parm = cb_value;
+ size_t n;
+ int c, c2;
+
+ *nread = 0;
+ if (!buffer)
+ return -1; /* not supported */
+
+ next:
+ if (!parm->linelen)
+ {
+ /* read an entire line or up to the size of the buffer */
+ parm->line_counter++;
+ parm->have_lf = 0;
+ for (n=0; n < DIM(parm->line);)
+ {
+ c = es_getc (parm->fp);
+ if (c == EOF)
+ {
+ parm->eof_seen = 1;
+ if (es_ferror (parm->fp))
+ return -1;
+ break;
+ }
+ parm->line[n++] = c;
+ if (c == '\n')
+ {
+ parm->have_lf = 1;
+ /* Fixme: we need to skip overlong lines while detecting
+ the dashed lines */
+ break;
+ }
+ }
+ parm->linelen = n;
+ if (!n)
+ return -1; /* eof */
+ parm->readpos = 0;
+ }
+
+ if (!parm->identified)
+ {
+ if (!parm->autodetect)
+ {
+ if (parm->assume_pem)
+ {
+ /* wait for the header line */
+ parm->linelen = parm->readpos = 0;
+ if (!parm->have_lf
+ || strncmp ((char*)parm->line, "-----BEGIN ", 11)
+ || !strncmp ((char*)parm->line+11, "PGP ", 4))
+ goto next;
+ parm->is_pem = 1;
+ }
+ else if (parm->assume_base64)
+ parm->is_base64 = 1;
+ }
+ else if (parm->line_counter == 1 && !parm->have_lf)
+ {
+ /* first line too long - assume DER encoding */
+ parm->is_pem = 0;
+ }
+ else if (parm->line_counter == 1 && parm->linelen && *parm->line == 0x30)
+ {
+ /* the very first byte does pretty much look like a SEQUENCE tag*/
+ parm->is_pem = 0;
+ }
+ else if ( parm->have_lf
+ && !strncmp ((char*)parm->line, "-----BEGIN ", 11)
+ && strncmp ((char *)parm->line+11, "PGP ", 4) )
+ {
+ /* Fixme: we must only compare if the line really starts at
+ the beginning */
+ parm->is_pem = 1;
+ parm->linelen = parm->readpos = 0;
+ }
+ else if ( parm->have_lf && parm->line_counter == 1
+ && parm->linelen >= 13
+ && !ascii_memcasecmp (parm->line, "Content-Type:", 13))
+ { /* might be a S/MIME body */
+ parm->might_be_smime = 1;
+ parm->linelen = parm->readpos = 0;
+ goto next;
+ }
+ else if (parm->might_be_smime == 1
+ && is_empty_line (parm->line, parm->linelen))
+ {
+ parm->might_be_smime = 2;
+ parm->linelen = parm->readpos = 0;
+ goto next;
+ }
+ else if (parm->might_be_smime == 2)
+ {
+ parm->might_be_smime = 0;
+ if ( !has_only_base64 (parm->line, parm->linelen))
+ {
+ parm->linelen = parm->readpos = 0;
+ goto next;
+ }
+ parm->is_pem = 1;
+ }
+ else
+ {
+ parm->linelen = parm->readpos = 0;
+ goto next;
+ }
+ parm->identified = 1;
+ parm->base64.stop_seen = 0;
+ parm->base64.idx = 0;
+ }
+
+
+ n = 0;
+ if (parm->is_pem || parm->is_base64)
+ {
+ if (parm->is_pem && parm->have_lf
+ && !strncmp ((char*)parm->line, "-----END ", 9))
+ {
+ parm->identified = 0;
+ parm->linelen = parm->readpos = 0;
+
+ /* If the caller want to read multiple PEM objects from one
+ file, we have to reset our internal state and return a
+ EOF immediately. The caller is the expected to use
+ ksba_reader_clear to clear the EOF condition and continue
+ to read. If we don't want to do that we just return 0
+ bytes which will force the ksba_reader to skip until
+ EOF. */
+ if (parm->allow_multi_pem)
+ {
+ parm->identified = 0;
+ parm->autodetect = 0;
+ parm->assume_pem = 1;
+ parm->stop_seen = 0;
+ return -1; /* Send EOF now. */
+ }
+ }
+ else if (parm->stop_seen)
+ { /* skip the rest of the line */
+ parm->linelen = parm->readpos = 0;
+ }
+ else
+ {
+ int idx = parm->base64.idx;
+ unsigned char val = parm->base64.val;
+
+ while (n < count && parm->readpos < parm->linelen )
+ {
+ c = parm->line[parm->readpos++];
+ if (c == '\n' || c == ' ' || c == '\r' || c == '\t')
+ continue;
+ if ((c = asctobin[(c2=c)]) == 255)
+ {
+ if (c2 == '=')
+ { /* pad character: stop */
+ if (idx == 1)
+ buffer[n++] = val;
+ parm->stop_seen = 1;
+ break;
+ }
+ else if (c2 == '-'
+ && parm->readpos == 1
+ && parm->readpos-1+9 < parm->linelen
+ && !strncmp ((char*)parm->line + parm->readpos-1,
+ "-----END ", 9))
+ { /* END line seen (padding was not needed). */
+ parm->stop_seen = 1;
+ break;
+ }
+ log_error (_("invalid radix64 character %02x skipped\n"),
+ c2);
+ continue;
+ }
+ switch (idx)
+ {
+ case 0:
+ val = c << 2;
+ break;
+ case 1:
+ val |= (c>>4)&3;
+ buffer[n++] = val;
+ val = (c<<4)&0xf0;
+ break;
+ case 2:
+ val |= (c>>2)&15;
+ buffer[n++] = val;
+ val = (c<<6)&0xc0;
+ break;
+ case 3:
+ val |= c&0x3f;
+ buffer[n++] = val;
+ break;
+ }
+ idx = (idx+1) % 4;
+ }
+ if (parm->readpos == parm->linelen)
+ parm->linelen = parm->readpos = 0;
+
+ parm->base64.idx = idx;
+ parm->base64.val = val;
+ }
+ }
+ else
+ { /* DER encoded */
+ while (n < count && parm->readpos < parm->linelen)
+ buffer[n++] = parm->line[parm->readpos++];
+ if (parm->readpos == parm->linelen)
+ parm->linelen = parm->readpos = 0;
+ }
+
+ *nread = n;
+ return 0;
+}
+
+
+
+static int
+simple_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread)
+{
+ struct reader_cb_parm_s *parm = cb_value;
+ size_t n;
+ int c = 0;
+
+ *nread = 0;
+ if (!buffer)
+ return -1; /* not supported */
+
+ for (n=0; n < count; n++)
+ {
+ c = es_getc (parm->fp);
+ if (c == EOF)
+ {
+ parm->eof_seen = 1;
+ if (es_ferror (parm->fp))
+ return -1;
+ if (n)
+ break; /* Return what we have before an EOF. */
+ return -1;
+ }
+ *(byte *)buffer++ = c;
+ }
+
+ *nread = n;
+ return 0;
+}
+
+
+
+
+static int
+base64_writer_cb (void *cb_value, const void *buffer, size_t count)
+{
+ struct writer_cb_parm_s *parm = cb_value;
+ unsigned char radbuf[4];
+ int i, c, idx, quad_count;
+ const unsigned char *p;
+ estream_t stream = parm->stream;
+
+ if (!count)
+ return 0;
+
+ if (!parm->wrote_begin)
+ {
+ if (parm->pem_name)
+ {
+ es_fputs ("-----BEGIN ", stream);
+ es_fputs (parm->pem_name, stream);
+ es_fputs ("-----\n", stream);
+ }
+ parm->wrote_begin = 1;
+ parm->base64.idx = 0;
+ parm->base64.quad_count = 0;
+ }
+
+ idx = parm->base64.idx;
+ quad_count = parm->base64.quad_count;
+ for (i=0; i < idx; i++)
+ radbuf[i] = parm->base64.radbuf[i];
+
+ for (p=buffer; count; p++, count--)
+ {
+ radbuf[idx++] = *p;
+ if (idx > 2)
+ {
+ idx = 0;
+ c = bintoasc[(*radbuf >> 2) & 077];
+ es_putc (c, stream);
+ c = bintoasc[(((*radbuf<<4)&060)|((radbuf[1] >> 4)&017))&077];
+ es_putc (c, stream);
+ c = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077];
+ es_putc (c, stream);
+ c = bintoasc[radbuf[2]&077];
+ es_putc (c, stream);
+ if (++quad_count >= (64/4))
+ {
+ es_fputs (LF, stream);
+ quad_count = 0;
+ }
+ }
+ }
+ for (i=0; i < idx; i++)
+ parm->base64.radbuf[i] = radbuf[i];
+ parm->base64.idx = idx;
+ parm->base64.quad_count = quad_count;
+
+ return es_ferror (stream)? gpg_error_from_syserror () : 0;
+}
+
+
+/* This callback is only used in stream mode. However, we don't
+ restrict it to this. */
+static int
+plain_writer_cb (void *cb_value, const void *buffer, size_t count)
+{
+ struct writer_cb_parm_s *parm = cb_value;
+ estream_t stream = parm->stream;
+
+ if (!count)
+ return 0;
+
+ es_write (stream, buffer, count, NULL);
+
+ return es_ferror (stream)? gpg_error_from_syserror () : 0;
+}
+
+
+static int
+base64_finish_write (struct writer_cb_parm_s *parm)
+{
+ unsigned char *radbuf;
+ int c, idx, quad_count;
+ estream_t stream = parm->stream;
+
+ if (!parm->wrote_begin)
+ return 0; /* Nothing written or we are not called in base-64 mode. */
+
+ /* flush the base64 encoding */
+ idx = parm->base64.idx;
+ quad_count = parm->base64.quad_count;
+ if (idx)
+ {
+ radbuf = parm->base64.radbuf;
+
+ c = bintoasc[(*radbuf>>2)&077];
+ es_putc (c, stream);
+ if (idx == 1)
+ {
+ c = bintoasc[((*radbuf << 4) & 060) & 077];
+ es_putc (c, stream);
+ es_putc ('=', stream);
+ es_putc ('=', stream);
+ }
+ else
+ {
+ c = bintoasc[(((*radbuf<<4)&060)|((radbuf[1]>>4)&017))&077];
+ es_putc (c, stream);
+ c = bintoasc[((radbuf[1] << 2) & 074) & 077];
+ es_putc (c, stream);
+ es_putc ('=', stream);
+
+ }
+ if (++quad_count >= (64/4))
+ {
+ es_fputs (LF, stream);
+ quad_count = 0;
+ }
+ }
+
+ if (quad_count)
+ es_fputs (LF, stream);
+
+ if (parm->pem_name)
+ {
+ es_fputs ("-----END ", stream);
+ es_fputs (parm->pem_name, stream);
+ es_fputs ("-----\n", stream);
+ }
+
+ return es_ferror (stream)? gpg_error_from_syserror () : 0;
+}
+
+
+
+
+/* Create a reader for the stream FP. FLAGS can be used to specify
+ * the expected input encoding.
+ *
+ * The function returns a gnupg_ksba_io_t object which must be passed to
+ * the gpgme_destroy_reader function. The created ksba_reader_t
+ * object is stored at R_READER - the caller must not call the
+ * ksba_reader_release function on.
+ *
+ * The supported flags are:
+ *
+ * GNUPG_KSBA_IO_PEM - Assume the input is PEM encoded
+ * GNUPG_KSBA_IO_BASE64 - Assume the input is Base64 encoded.
+ * GNUPG_KSBA_IO_AUTODETECT - The reader tries to detect the encoding.
+ * GNUPG_KSBA_IO_MULTIPEM - The reader expects that the caller uses
+ * ksba_reader_clear after EOF until no more
+ * objects were found.
+ *
+ * Note that the PEM flag has a higher priority than the BASE64 flag
+ * which in turn has a gight priority than the AUTODETECT flag.
+ */
+gpg_error_t
+gnupg_ksba_create_reader (gnupg_ksba_io_t *ctx,
+ unsigned int flags, estream_t fp,
+ ksba_reader_t *r_reader)
+{
+ int rc;
+ ksba_reader_t r;
+
+ *r_reader = NULL;
+ *ctx = xtrycalloc (1, sizeof **ctx);
+ if (!*ctx)
+ return out_of_core ();
+ (*ctx)->u.rparm.allow_multi_pem = !!(flags & GNUPG_KSBA_IO_MULTIPEM);
+
+ rc = ksba_reader_new (&r);
+ if (rc)
+ {
+ xfree (*ctx); *ctx = NULL;
+ return rc;
+ }
+
+ (*ctx)->u.rparm.fp = fp;
+ if ((flags & GNUPG_KSBA_IO_PEM))
+ {
+ (*ctx)->u.rparm.assume_pem = 1;
+ (*ctx)->u.rparm.assume_base64 = 1;
+ rc = ksba_reader_set_cb (r, base64_reader_cb, &(*ctx)->u.rparm);
+ }
+ else if ((flags & GNUPG_KSBA_IO_BASE64))
+ {
+ (*ctx)->u.rparm.assume_base64 = 1;
+ rc = ksba_reader_set_cb (r, base64_reader_cb, &(*ctx)->u.rparm);
+ }
+ else if ((flags & GNUPG_KSBA_IO_AUTODETECT))
+ {
+ (*ctx)->u.rparm.autodetect = 1;
+ rc = ksba_reader_set_cb (r, base64_reader_cb, &(*ctx)->u.rparm);
+ }
+ else
+ rc = ksba_reader_set_cb (r, simple_reader_cb, &(*ctx)->u.rparm);
+
+ if (rc)
+ {
+ ksba_reader_release (r);
+ xfree (*ctx); *ctx = NULL;
+ return rc;
+ }
+
+ (*ctx)->u2.reader = r;
+ *r_reader = r;
+ return 0;
+}
+
+
+/* Return True if an EOF as been seen. */
+int
+gnupg_ksba_reader_eof_seen (gnupg_ksba_io_t ctx)
+{
+ return ctx && ctx->u.rparm.eof_seen;
+}
+
+
+/* Destroy a reader object. */
+void
+gnupg_ksba_destroy_reader (gnupg_ksba_io_t ctx)
+{
+ if (!ctx)
+ return;
+
+ ksba_reader_release (ctx->u2.reader);
+ xfree (ctx);
+}
+
+
+
+/* Create a writer for the given STREAM. Depending on FLAGS an output
+ * encoding is chosen. In PEM mode PEM_NAME is used for the header
+ * and footer lines; if PEM_NAME is NULL the string "CMS OBJECT" is
+ * used.
+ *
+ * The function returns a gnupg_ksba_io_t object which must be passed to
+ * the gpgme_destroy_writer function. The created ksba_writer_t
+ * object is stored at R_WRITER - the caller must not call the
+ * ksba_reader_release function on it.
+ *
+ * The supported flags are:
+ *
+ * GNUPG_KSBA_IO_PEM - Write output as PEM
+ * GNUPG_KSBA_IO_BASE64 - Write output as plain Base64; note that the PEM
+ * flag overrides this flag.
+ *
+ */
+gpg_error_t
+gnupg_ksba_create_writer (gnupg_ksba_io_t *ctx, unsigned int flags,
+ const char *pem_name, estream_t stream,
+ ksba_writer_t *r_writer)
+{
+ int rc;
+ ksba_writer_t w;
+
+ *r_writer = NULL;
+ *ctx = xtrycalloc (1, sizeof **ctx);
+ if (!*ctx)
+ return gpg_error_from_syserror ();
+
+ rc = ksba_writer_new (&w);
+ if (rc)
+ {
+ xfree (*ctx); *ctx = NULL;
+ return rc;
+ }
+
+ if ((flags & GNUPG_KSBA_IO_PEM) || (flags & GNUPG_KSBA_IO_BASE64))
+ {
+ (*ctx)->u.wparm.stream = stream;
+ if ((flags & GNUPG_KSBA_IO_PEM))
+ {
+ (*ctx)->u.wparm.pem_name = xtrystrdup (pem_name
+ ? pem_name
+ : "CMS OBJECT");
+ if (!(*ctx)->u.wparm.pem_name)
+ {
+ rc = gpg_error_from_syserror ();
+ ksba_writer_release (w);
+ xfree (*ctx); *ctx = NULL;
+ return rc;
+ }
+ }
+ rc = ksba_writer_set_cb (w, base64_writer_cb, &(*ctx)->u.wparm);
+ }
+ else if (stream)
+ {
+ (*ctx)->u.wparm.stream = stream;
+ rc = ksba_writer_set_cb (w, plain_writer_cb, &(*ctx)->u.wparm);
+ }
+ else
+ rc = gpg_error (GPG_ERR_INV_ARG);
+
+ if (rc)
+ {
+ ksba_writer_release (w);
+ xfree (*ctx); *ctx = NULL;
+ return rc;
+ }
+
+ (*ctx)->u2.writer = w;
+ *r_writer = w;
+ return 0;
+}
+
+
+/* Flush a writer. This is for example required to write the padding
+ * or the PEM footer. */
+gpg_error_t
+gnupg_ksba_finish_writer (gnupg_ksba_io_t ctx)
+{
+ struct writer_cb_parm_s *parm;
+
+ if (!ctx)
+ return gpg_error (GPG_ERR_INV_VALUE);
+ parm = &ctx->u.wparm;
+ if (parm->did_finish)
+ return 0; /* Already done. */
+ parm->did_finish = 1;
+ if (!parm->stream)
+ return 0; /* Callback was not used. */
+ return base64_finish_write (parm);
+}
+
+
+/* Destroy a writer object. */
+void
+gnupg_ksba_destroy_writer (gnupg_ksba_io_t ctx)
+{
+ if (!ctx)
+ return;
+
+ ksba_writer_release (ctx->u2.writer);
+ xfree (ctx->u.wparm.pem_name);
+ xfree (ctx);
+}
diff --git a/common/ksba-io-support.h b/common/ksba-io-support.h
new file mode 100644
index 0000000..e33e0ed
--- /dev/null
+++ b/common/ksba-io-support.h
@@ -0,0 +1,66 @@
+/* ksba-io-support.h - Supporting functions for ksba reader and writer
+ * Copyright (C) 2017 Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_KSBA_IO_SUPPORT_H
+#define GNUPG_KSBA_IO_SUPPORT_H
+
+/* Flags used with gnupg_ksba_create_reader and
+ * gnupg_ksba_create_writer. */
+#define GNUPG_KSBA_IO_PEM 1 /* X.509 PEM format. */
+#define GNUPG_KSBA_IO_BASE64 2 /* Plain Base64 format. */
+#define GNUPG_KSBA_IO_AUTODETECT 4 /* Try to autodetect the format. */
+#define GNUPG_KSBA_IO_MULTIPEM 8 /* Allow more than one PEM chunk. */
+
+
+/* Context object. */
+typedef struct gnupg_ksba_io_s *gnupg_ksba_io_t;
+
+
+
+gpg_error_t gnupg_ksba_create_reader (gnupg_ksba_io_t *ctx,
+ unsigned int flags,
+ estream_t fp,
+ ksba_reader_t *r_reader);
+
+int gnupg_ksba_reader_eof_seen (gnupg_ksba_io_t ctx);
+void gnupg_ksba_destroy_reader (gnupg_ksba_io_t ctx);
+
+gpg_error_t gnupg_ksba_create_writer (gnupg_ksba_io_t *ctx,
+ unsigned int flags,
+ const char *pem_name,
+ estream_t stream,
+ ksba_writer_t *r_writer);
+
+gpg_error_t gnupg_ksba_finish_writer (gnupg_ksba_io_t ctx);
+void gnupg_ksba_destroy_writer (gnupg_ksba_io_t ctx);
+
+
+
+
+#endif /*GNUPG_KSBA_IO_SUPPORT_H*/
diff --git a/common/localename.c b/common/localename.c
new file mode 100644
index 0000000..b620a74
--- /dev/null
+++ b/common/localename.c
@@ -0,0 +1,127 @@
+/* localename.c - Determine the current selected locale.
+ * Copyright (C) 1995-1999, 2000-2003, 2007,
+ * 2008 Free Software Foundation, Inc.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+/* Written by Ulrich Drepper <drepper@gnu.org>, 1995. */
+/* Win32 code written by Tor Lillqvist <tml@iki.fi>. */
+/* Modified for GpgOL use by Werner Koch <wk@gnupg.org>, 2005. */
+/* Modified for GnuPG use by Werner Koch <wk@gnupg.org>, 2007 */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_LOCALE_H
+#include <locale.h>
+#endif
+#include <gpg-error.h> /* We need gettext_localename for W32. */
+
+#include "../common/w32help.h"
+
+/* XPG3 defines the result of 'setlocale (category, NULL)' as:
+ "Directs 'setlocale()' to query 'category' and return the current
+ setting of 'local'."
+ However it does not specify the exact format. Neither do SUSV2 and
+ ISO C 99. So we can use this feature only on selected systems (e.g.
+ those using GNU C Library). */
+#if defined _LIBC || (defined __GNU_LIBRARY__ && __GNU_LIBRARY__ >= 2)
+# define HAVE_LOCALE_NULL
+#endif
+
+/* Use a dummy value for LC_MESSAGES in case it is not defined. This
+ works because we always test for HAVE_LC_MESSAGES and the core
+ function takes the category as a string as well. */
+#ifndef HAVE_LC_MESSAGES
+#define LC_MESSAGES 0
+#endif
+
+
+/* Determine the current locale's name, and canonicalize it into XPG syntax
+ language[_territory[.codeset]][@modifier]
+ The codeset part in the result is not reliable; the locale_charset()
+ should be used for codeset information instead.
+ The result must not be freed; it is statically allocated. */
+
+#ifndef HAVE_W32_SYSTEM
+static const char *
+do_nl_locale_name (int category, const char *categoryname)
+{
+ const char *retval;
+
+ /* Use the POSIX methods of looking to 'LC_ALL', 'LC_xxx', and 'LANG'.
+ On some systems this can be done by the 'setlocale' function itself. */
+# if defined HAVE_SETLOCALE && defined HAVE_LC_MESSAGES && defined HAVE_LOCALE_NULL
+ (void)categoryname;
+ retval = setlocale (category, NULL);
+# else
+ (void)category;
+ /* Setting of LC_ALL overwrites all other. */
+ retval = getenv ("LC_ALL");
+ if (retval == NULL || retval[0] == '\0')
+ {
+ /* Next comes the name of the desired category. */
+ retval = getenv (categoryname);
+ if (retval == NULL || retval[0] == '\0')
+ {
+ /* Last possibility is the LANG environment variable. */
+ retval = getenv ("LANG");
+ if (retval == NULL || retval[0] == '\0')
+ /* We use C as the default domain. POSIX says this is
+ implementation defined. */
+ retval = "C";
+ }
+ }
+# endif
+
+ return retval;
+}
+#endif /* HAVE_W32_SYSTEM */
+
+
+
+/* Return the locale used for translatable messages. The standard C
+ and POSIX are locale names are mapped to an empty string. If a
+ locale can't be found an empty string will be returned. */
+const char *
+gnupg_messages_locale_name (void)
+{
+ const char *s;
+
+#ifdef HAVE_W32_SYSTEM
+ /* We use the localename function libgpg-error. */
+ s = gettext_localename ();
+#else
+ s = do_nl_locale_name (LC_MESSAGES, "LC_MESSAGES");
+#endif
+ if (!s)
+ s = "";
+ else if (!strcmp (s, "C") || !strcmp (s, "POSIX"))
+ s = "";
+
+ return s;
+}
diff --git a/common/logging.c b/common/logging.c
new file mode 100644
index 0000000..7fe8b74
--- /dev/null
+++ b/common/logging.c
@@ -0,0 +1,1110 @@
+/* logging.c - Useful logging functions
+ * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006,
+ * 2009, 2010 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute and/or modify this
+ * part of GnuPG under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * 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 copies of the GNU General Public License
+ * and the GNU Lesser General Public License along with this program;
+ * if not, see <https://www.gnu.org/licenses/>.
+ */
+
+
+#include <config.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef HAVE_W32_SYSTEM
+# ifdef HAVE_WINSOCK2_H
+# include <winsock2.h>
+# endif
+# include <windows.h>
+#else /*!HAVE_W32_SYSTEM*/
+# include <sys/socket.h>
+# include <sys/un.h>
+# include <netinet/in.h>
+# include <arpa/inet.h>
+#endif /*!HAVE_W32_SYSTEM*/
+#include <unistd.h>
+#include <fcntl.h>
+#include <assert.h>
+/* #include <execinfo.h> */
+
+#define GNUPG_COMMON_NEED_AFLOCAL 1
+#include "util.h"
+#include "i18n.h"
+#include "common-defs.h"
+#include "logging.h"
+#include "sysutils.h"
+
+#ifdef HAVE_W32_SYSTEM
+# ifndef S_IRWXG
+# define S_IRGRP S_IRUSR
+# define S_IWGRP S_IWUSR
+# endif
+# ifndef S_IRWXO
+# define S_IROTH S_IRUSR
+# define S_IWOTH S_IWUSR
+# endif
+#endif
+
+
+#ifdef HAVE_W32CE_SYSTEM
+# define isatty(a) (0)
+#endif
+
+#undef WITH_IPV6
+#if defined (AF_INET6) && defined(PF_INET) \
+ && defined (INET6_ADDRSTRLEN) && defined(HAVE_INET_PTON)
+# define WITH_IPV6 1
+#endif
+
+#ifndef EAFNOSUPPORT
+# define EAFNOSUPPORT EINVAL
+#endif
+#ifndef INADDR_NONE /* Slowaris is missing that. */
+#define INADDR_NONE ((unsigned long)(-1))
+#endif /*INADDR_NONE*/
+
+#ifdef HAVE_W32_SYSTEM
+#define sock_close(a) closesocket(a)
+#else
+#define sock_close(a) close(a)
+#endif
+
+
+static estream_t logstream;
+static int log_socket = -1;
+static char prefix_buffer[80];
+static int with_time;
+static int with_prefix;
+static int with_pid;
+#ifdef HAVE_W32_SYSTEM
+static int no_registry;
+#endif
+static int (*get_pid_suffix_cb)(unsigned long *r_value);
+static const char * (*socket_dir_cb)(void);
+static int running_detached;
+static int force_prefixes;
+
+static int missing_lf;
+static int errorcount;
+
+
+int
+log_get_errorcount (int clear)
+{
+ int n = errorcount;
+ if( clear )
+ errorcount = 0;
+ return n;
+}
+
+void
+log_inc_errorcount (void)
+{
+ /* Protect against counter overflow. */
+ if (errorcount < 30000)
+ errorcount++;
+}
+
+
+/* The following 3 functions are used by es_fopencookie to write logs
+ to a socket. */
+struct fun_cookie_s
+{
+ int fd;
+ int quiet;
+ int want_socket;
+ int is_socket;
+#ifdef HAVE_W32CE_SYSTEM
+ int use_writefile;
+#endif
+ char name[1];
+};
+
+
+/* Write NBYTES of BUFFER to file descriptor FD. */
+static int
+writen (int fd, const void *buffer, size_t nbytes, int is_socket)
+{
+ const char *buf = buffer;
+ size_t nleft = nbytes;
+ int nwritten;
+#ifndef HAVE_W32_SYSTEM
+ (void)is_socket; /* Not required. */
+#endif
+
+ while (nleft > 0)
+ {
+#ifdef HAVE_W32_SYSTEM
+ if (is_socket)
+ nwritten = send (fd, buf, nleft, 0);
+ else
+#endif
+ nwritten = write (fd, buf, nleft);
+
+ if (nwritten < 0 && errno == EINTR)
+ continue;
+ if (nwritten < 0)
+ return -1;
+ nleft -= nwritten;
+ buf = buf + nwritten;
+ }
+
+ return 0;
+}
+
+
+/* Returns true if STR represents a valid port number in decimal
+ notation and no garbage is following. */
+static int
+parse_portno (const char *str, unsigned short *r_port)
+{
+ unsigned int value;
+
+ for (value=0; *str && (*str >= '0' && *str <= '9'); str++)
+ {
+ value = value * 10 + (*str - '0');
+ if (value > 65535)
+ return 0;
+ }
+ if (*str || !value)
+ return 0;
+
+ *r_port = value;
+ return 1;
+}
+
+
+static gpgrt_ssize_t
+fun_writer (void *cookie_arg, const void *buffer, size_t size)
+{
+ struct fun_cookie_s *cookie = cookie_arg;
+
+ /* FIXME: Use only estream with a callback for socket writing. This
+ avoids the ugly mix of fd and estream code. */
+
+ /* Note that we always try to reconnect to the socket but print
+ error messages only the first time an error occurred. If
+ RUNNING_DETACHED is set we don't fall back to stderr and even do
+ not print any error messages. This is needed because detached
+ processes often close stderr and by writing to file descriptor 2
+ we might send the log message to a file not intended for logging
+ (e.g. a pipe or network connection). */
+ if (cookie->want_socket && cookie->fd == -1)
+ {
+#ifdef WITH_IPV6
+ struct sockaddr_in6 srvr_addr_in6;
+#endif
+ struct sockaddr_in srvr_addr_in;
+#ifndef HAVE_W32_SYSTEM
+ struct sockaddr_un srvr_addr_un;
+#endif
+ const char *name_for_err = "";
+ size_t addrlen;
+ struct sockaddr *srvr_addr = NULL;
+ unsigned short port = 0;
+ int af = AF_LOCAL;
+ int pf = PF_LOCAL;
+ const char *name = cookie->name;
+
+ /* Not yet open or meanwhile closed due to an error. */
+ cookie->is_socket = 0;
+
+ /* Check whether this is a TCP socket or a local socket. */
+ if (!strncmp (name, "tcp://", 6) && name[6])
+ {
+ name += 6;
+ af = AF_INET;
+ pf = PF_INET;
+ }
+#ifndef HAVE_W32_SYSTEM
+ else if (!strncmp (name, "socket://", 9))
+ name += 9;
+#endif
+
+ if (af == AF_LOCAL)
+ {
+ addrlen = 0;
+#ifndef HAVE_W32_SYSTEM
+ memset (&srvr_addr, 0, sizeof srvr_addr);
+ srvr_addr_un.sun_family = af;
+ if (!*name && (name = socket_dir_cb ()) && *name)
+ {
+ if (strlen (name) + 7 < sizeof (srvr_addr_un.sun_path)-1)
+ {
+ strncpy (srvr_addr_un.sun_path,
+ name, sizeof (srvr_addr_un.sun_path)-1);
+ strcat (srvr_addr_un.sun_path, "/S.log");
+ srvr_addr_un.sun_path[sizeof (srvr_addr_un.sun_path)-1] = 0;
+ srvr_addr = (struct sockaddr *)&srvr_addr_un;
+ addrlen = SUN_LEN (&srvr_addr_un);
+ name_for_err = srvr_addr_un.sun_path;
+ }
+ }
+ else
+ {
+ if (*name && strlen (name) < sizeof (srvr_addr_un.sun_path)-1)
+ {
+ strncpy (srvr_addr_un.sun_path,
+ name, sizeof (srvr_addr_un.sun_path)-1);
+ srvr_addr_un.sun_path[sizeof (srvr_addr_un.sun_path)-1] = 0;
+ srvr_addr = (struct sockaddr *)&srvr_addr_un;
+ addrlen = SUN_LEN (&srvr_addr_un);
+ }
+ }
+#endif /*!HAVE_W32SYSTEM*/
+ }
+ else
+ {
+ char *addrstr, *p;
+#ifdef HAVE_INET_PTON
+ void *addrbuf = NULL;
+#endif /*HAVE_INET_PTON*/
+
+ addrstr = xtrymalloc (strlen (name) + 1);
+ if (!addrstr)
+ addrlen = 0; /* This indicates an error. */
+ else if (*name == '[')
+ {
+ /* Check for IPv6 literal address. */
+ strcpy (addrstr, name+1);
+ p = strchr (addrstr, ']');
+ if (!p || p[1] != ':' || !parse_portno (p+2, &port))
+ {
+ gpg_err_set_errno (EINVAL);
+ addrlen = 0;
+ }
+ else
+ {
+ *p = 0;
+#ifdef WITH_IPV6
+ af = AF_INET6;
+ pf = PF_INET6;
+ memset (&srvr_addr_in6, 0, sizeof srvr_addr_in6);
+ srvr_addr_in6.sin6_family = af;
+ srvr_addr_in6.sin6_port = htons (port);
+#ifdef HAVE_INET_PTON
+ addrbuf = &srvr_addr_in6.sin6_addr;
+#endif /*HAVE_INET_PTON*/
+ srvr_addr = (struct sockaddr *)&srvr_addr_in6;
+ addrlen = sizeof srvr_addr_in6;
+#else
+ gpg_err_set_errno (EAFNOSUPPORT);
+ addrlen = 0;
+#endif
+ }
+ }
+ else
+ {
+ /* Check for IPv4 literal address. */
+ strcpy (addrstr, name);
+ p = strchr (addrstr, ':');
+ if (!p || !parse_portno (p+1, &port))
+ {
+ gpg_err_set_errno (EINVAL);
+ addrlen = 0;
+ }
+ else
+ {
+ *p = 0;
+ memset (&srvr_addr_in, 0, sizeof srvr_addr_in);
+ srvr_addr_in.sin_family = af;
+ srvr_addr_in.sin_port = htons (port);
+#ifdef HAVE_INET_PTON
+ addrbuf = &srvr_addr_in.sin_addr;
+#endif /*HAVE_INET_PTON*/
+ srvr_addr = (struct sockaddr *)&srvr_addr_in;
+ addrlen = sizeof srvr_addr_in;
+ }
+ }
+
+ if (addrlen)
+ {
+#ifdef HAVE_INET_PTON
+ if (inet_pton (af, addrstr, addrbuf) != 1)
+ addrlen = 0;
+#else /*!HAVE_INET_PTON*/
+ /* We need to use the old function. If we are here v6
+ support isn't enabled anyway and thus we can do fine
+ without. Note that Windows has a compatible inet_pton
+ function named inetPton, but only since Vista. */
+ srvr_addr_in.sin_addr.s_addr = inet_addr (addrstr);
+ if (srvr_addr_in.sin_addr.s_addr == INADDR_NONE)
+ addrlen = 0;
+#endif /*!HAVE_INET_PTON*/
+ }
+
+ xfree (addrstr);
+ }
+
+ cookie->fd = addrlen? socket (pf, SOCK_STREAM, 0) : -1;
+ if (cookie->fd == -1)
+ {
+ if (!cookie->quiet && !running_detached
+ && isatty (es_fileno (es_stderr)))
+ es_fprintf (es_stderr, "failed to create socket for logging: %s\n",
+ strerror(errno));
+ }
+ else
+ {
+ if (connect (cookie->fd, srvr_addr, addrlen) == -1)
+ {
+ if (!cookie->quiet && !running_detached
+ && isatty (es_fileno (es_stderr)))
+ es_fprintf (es_stderr, "can't connect to '%s%s': %s\n",
+ cookie->name, name_for_err, strerror(errno));
+ sock_close (cookie->fd);
+ cookie->fd = -1;
+ }
+ }
+
+ if (cookie->fd == -1)
+ {
+ if (!running_detached)
+ {
+ /* Due to all the problems with apps not running
+ detached but being called with stderr closed or used
+ for a different purposes, it does not make sense to
+ switch to stderr. We therefore disable it. */
+ if (!cookie->quiet)
+ {
+ /* fputs ("switching logging to stderr\n", stderr);*/
+ cookie->quiet = 1;
+ }
+ cookie->fd = -1; /*fileno (stderr);*/
+ }
+ }
+ else /* Connection has been established. */
+ {
+ cookie->quiet = 0;
+ cookie->is_socket = 1;
+ }
+ }
+
+ log_socket = cookie->fd;
+ if (cookie->fd != -1)
+ {
+#ifdef HAVE_W32CE_SYSTEM
+ if (cookie->use_writefile)
+ {
+ DWORD nwritten;
+
+ WriteFile ((HANDLE)cookie->fd, buffer, size, &nwritten, NULL);
+ return (gpgrt_ssize_t)size; /* Okay. */
+ }
+#endif
+ if (!writen (cookie->fd, buffer, size, cookie->is_socket))
+ return (gpgrt_ssize_t)size; /* Okay. */
+ }
+
+ if (!running_detached && cookie->fd != -1
+ && isatty (es_fileno (es_stderr)))
+ {
+ if (*cookie->name)
+ es_fprintf (es_stderr, "error writing to '%s': %s\n",
+ cookie->name, strerror(errno));
+ else
+ es_fprintf (es_stderr, "error writing to file descriptor %d: %s\n",
+ cookie->fd, strerror(errno));
+ }
+ if (cookie->is_socket && cookie->fd != -1)
+ {
+ sock_close (cookie->fd);
+ cookie->fd = -1;
+ log_socket = -1;
+ }
+
+ return (gpgrt_ssize_t)size;
+}
+
+
+static int
+fun_closer (void *cookie_arg)
+{
+ struct fun_cookie_s *cookie = cookie_arg;
+
+ if (cookie->fd != -1 && cookie->fd != 2)
+ sock_close (cookie->fd);
+ xfree (cookie);
+ log_socket = -1;
+ return 0;
+}
+
+
+/* Common function to either set the logging to a file or a file
+ descriptor. */
+static void
+set_file_fd (const char *name, int fd)
+{
+ estream_t fp;
+ int want_socket;
+#ifdef HAVE_W32CE_SYSTEM
+ int use_writefile = 0;
+#endif
+ struct fun_cookie_s *cookie;
+
+ /* Close an open log stream. */
+ if (logstream)
+ {
+ if (logstream != es_stderr)
+ es_fclose (logstream);
+ logstream = NULL;
+ }
+
+ /* Figure out what kind of logging we want. */
+ if (name && !strcmp (name, "-"))
+ {
+ name = NULL;
+ fd = es_fileno (es_stderr);
+ }
+
+ want_socket = 0;
+ if (name && !strncmp (name, "tcp://", 6) && name[6])
+ want_socket = 1;
+#ifndef HAVE_W32_SYSTEM
+ else if (name && !strncmp (name, "socket://", 9))
+ want_socket = 2;
+#endif /*HAVE_W32_SYSTEM*/
+#ifdef HAVE_W32CE_SYSTEM
+ else if (name && !strcmp (name, "GPG2:"))
+ {
+ HANDLE hd;
+
+ ActivateDevice (L"Drivers\\"GNUPG_NAME"_Log", 0);
+ /* Ignore a filename and write the debug output to the GPG2:
+ device. */
+ hd = CreateFile (L"GPG2:", GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ fd = (hd == INVALID_HANDLE_VALUE)? -1 : (int)hd;
+ name = NULL;
+ force_prefixes = 1;
+ use_writefile = 1;
+ }
+#endif /*HAVE_W32CE_SYSTEM*/
+
+ /* Setup a new stream. */
+
+ /* The xmalloc below is justified because we can expect that this
+ function is called only during initialization and there is no
+ easy way out of this error condition. */
+ cookie = xmalloc (sizeof *cookie + (name? strlen (name):0));
+ strcpy (cookie->name, name? name:"");
+ cookie->quiet = 0;
+ cookie->is_socket = 0;
+ cookie->want_socket = want_socket;
+#ifdef HAVE_W32CE_SYSTEM
+ cookie->use_writefile = use_writefile;
+#endif
+ if (!name)
+ cookie->fd = fd;
+ else if (want_socket)
+ cookie->fd = -1;
+ else
+ {
+ do
+ cookie->fd = open (name, O_WRONLY|O_APPEND|O_CREAT,
+ (S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR|S_IWGRP|S_IWOTH));
+ while (cookie->fd == -1 && errno == EINTR);
+ }
+ log_socket = cookie->fd;
+
+ {
+ es_cookie_io_functions_t io = { NULL };
+ io.func_write = fun_writer;
+ io.func_close = fun_closer;
+
+ fp = es_fopencookie (cookie, "w", io);
+ }
+
+ /* On error default to a stderr based estream. */
+ if (!fp)
+ fp = es_stderr;
+
+ es_setvbuf (fp, NULL, _IOLBF, 0);
+
+ logstream = fp;
+
+ /* We always need to print the prefix and the pid for socket mode,
+ so that the server reading the socket can do something
+ meaningful. */
+ force_prefixes = want_socket;
+
+ missing_lf = 0;
+}
+
+
+/* Set the file to write log to. The special names NULL and "-" may
+ be used to select stderr and names formatted like
+ "socket:///home/foo/mylogs" may be used to write the logging to the
+ socket "/home/foo/mylogs". If the connection to the socket fails
+ or a write error is detected, the function writes to stderr and
+ tries the next time again to connect the socket.
+ */
+void
+log_set_file (const char *name)
+{
+ set_file_fd (name? name: "-", -1);
+}
+
+void
+log_set_fd (int fd)
+{
+ if (! gnupg_fd_valid (fd))
+ log_fatal ("logger-fd is invalid: %s\n", strerror (errno));
+
+ set_file_fd (NULL, fd);
+}
+
+
+/* Set a function to retrieve the directory name of a socket if
+ * only "socket://" has been given to log_set_file. */
+void
+log_set_socket_dir_cb (const char *(*fnc)(void))
+{
+ socket_dir_cb = fnc;
+}
+
+
+void
+log_set_pid_suffix_cb (int (*cb)(unsigned long *r_value))
+{
+ get_pid_suffix_cb = cb;
+}
+
+
+void
+log_set_prefix (const char *text, unsigned int flags)
+{
+ if (text)
+ {
+ strncpy (prefix_buffer, text, sizeof (prefix_buffer)-1);
+ prefix_buffer[sizeof (prefix_buffer)-1] = 0;
+ }
+
+ with_prefix = (flags & GPGRT_LOG_WITH_PREFIX);
+ with_time = (flags & GPGRT_LOG_WITH_TIME);
+ with_pid = (flags & GPGRT_LOG_WITH_PID);
+ running_detached = (flags & GPGRT_LOG_RUN_DETACHED);
+#ifdef HAVE_W32_SYSTEM
+ no_registry = (flags & GPGRT_LOG_NO_REGISTRY);
+#endif
+}
+
+
+const char *
+log_get_prefix (unsigned int *flags)
+{
+ if (flags)
+ {
+ *flags = 0;
+ if (with_prefix)
+ *flags |= GPGRT_LOG_WITH_PREFIX;
+ if (with_time)
+ *flags |= GPGRT_LOG_WITH_TIME;
+ if (with_pid)
+ *flags |= GPGRT_LOG_WITH_PID;
+ if (running_detached)
+ *flags |= GPGRT_LOG_RUN_DETACHED;
+#ifdef HAVE_W32_SYSTEM
+ if (no_registry)
+ *flags |= GPGRT_LOG_NO_REGISTRY;
+#endif
+ }
+ return prefix_buffer;
+}
+
+/* This function returns true if the file descriptor FD is in use for
+ logging. This is preferable over a test using log_get_fd in that
+ it allows the logging code to use more then one file descriptor. */
+int
+log_test_fd (int fd)
+{
+ if (logstream)
+ {
+ int tmp = es_fileno (logstream);
+ if ( tmp != -1 && tmp == fd)
+ return 1;
+ }
+ if (log_socket != -1 && log_socket == fd)
+ return 1;
+ return 0;
+}
+
+int
+log_get_fd ()
+{
+ return logstream? es_fileno(logstream) : -1;
+}
+
+estream_t
+log_get_stream ()
+{
+ if (!logstream)
+ {
+ log_set_file (NULL); /* Make sure a log stream has been set. */
+ assert (logstream);
+ }
+ return logstream;
+}
+
+
+static void
+print_prefix (int level, int leading_backspace)
+{
+ if (level != GPGRT_LOG_CONT)
+ { /* Note this does not work for multiple line logging as we would
+ * need to print to a buffer first */
+ if (with_time && !force_prefixes)
+ {
+ struct tm *tp;
+ time_t atime = time (NULL);
+
+ tp = localtime (&atime);
+ es_fprintf_unlocked (logstream, "%04d-%02d-%02d %02d:%02d:%02d ",
+ 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday,
+ tp->tm_hour, tp->tm_min, tp->tm_sec );
+ }
+ if (with_prefix || force_prefixes)
+ es_fputs_unlocked (prefix_buffer, logstream);
+ if (with_pid || force_prefixes)
+ {
+ unsigned long pidsuf;
+ int pidfmt;
+
+ if (get_pid_suffix_cb && (pidfmt=get_pid_suffix_cb (&pidsuf)))
+ es_fprintf_unlocked (logstream, pidfmt == 1? "[%u.%lu]":"[%u.%lx]",
+ (unsigned int)getpid (), pidsuf);
+ else
+ es_fprintf_unlocked (logstream, "[%u]", (unsigned int)getpid ());
+ }
+ if ((!with_time && (with_prefix || with_pid)) || force_prefixes)
+ es_putc_unlocked (':', logstream);
+ /* A leading backspace suppresses the extra space so that we can
+ correctly output, programname, filename and linenumber. */
+ if (!leading_backspace
+ && (with_time || with_prefix || with_pid || force_prefixes))
+ es_putc_unlocked (' ', logstream);
+ }
+
+ switch (level)
+ {
+ case GPGRT_LOG_BEGIN: break;
+ case GPGRT_LOG_CONT: break;
+ case GPGRT_LOG_INFO: break;
+ case GPGRT_LOG_WARN: break;
+ case GPGRT_LOG_ERROR: break;
+ case GPGRT_LOG_FATAL: es_fputs_unlocked ("Fatal: ",logstream ); break;
+ case GPGRT_LOG_BUG: es_fputs_unlocked ("Ohhhh jeeee: ", logstream); break;
+ case GPGRT_LOG_DEBUG: es_fputs_unlocked ("DBG: ", logstream ); break;
+ default:
+ es_fprintf_unlocked (logstream,"[Unknown log level %d]: ", level);
+ break;
+ }
+}
+
+
+static void
+do_logv (int level, int ignore_arg_ptr, const char *extrastring,
+ const char *prefmt, const char *fmt, va_list arg_ptr)
+{
+ int leading_backspace = (fmt && *fmt == '\b');
+
+ if (!logstream)
+ {
+#ifdef HAVE_W32_SYSTEM
+ char *tmp;
+
+ tmp = (no_registry
+ ? NULL
+ : read_w32_registry_string (NULL, GNUPG_REGISTRY_DIR,
+ "DefaultLogFile"));
+ log_set_file (tmp && *tmp? tmp : NULL);
+ xfree (tmp);
+#else
+ log_set_file (NULL); /* Make sure a log stream has been set. */
+#endif
+ assert (logstream);
+ }
+
+ es_flockfile (logstream);
+ if (missing_lf && level != GPGRT_LOG_CONT)
+ es_putc_unlocked ('\n', logstream );
+ missing_lf = 0;
+
+ print_prefix (level, leading_backspace);
+ if (leading_backspace)
+ fmt++;
+
+ if (fmt)
+ {
+ if (prefmt)
+ es_fputs_unlocked (prefmt, logstream);
+
+ if (ignore_arg_ptr)
+ { /* This is used by log_string and comes with the extra
+ * feature that after a LF the next line is indent at the
+ * length of the prefix. Note that we do not yet include
+ * the length of the timestamp and pid in the indent
+ * computation. */
+ const char *p, *pend;
+
+ for (p = fmt; (pend = strchr (p, '\n')); p = pend+1)
+ es_fprintf_unlocked (logstream, "%*s%.*s",
+ (int)((p != fmt
+ && (with_prefix || force_prefixes))
+ ?strlen (prefix_buffer)+2:0), "",
+ (int)(pend - p)+1, p);
+ es_fputs_unlocked (p, logstream);
+ }
+ else
+ es_vfprintf_unlocked (logstream, fmt, arg_ptr);
+ if (*fmt && fmt[strlen(fmt)-1] != '\n')
+ missing_lf = 1;
+ }
+
+ /* If we have an EXTRASTRING print it now while we still hold the
+ * lock on the logstream. */
+ if (extrastring)
+ {
+ int c;
+
+ if (missing_lf)
+ {
+ es_putc_unlocked ('\n', logstream);
+ missing_lf = 0;
+ }
+ print_prefix (level, leading_backspace);
+ es_fputs_unlocked (">> ", logstream);
+ missing_lf = 1;
+ while ((c = *extrastring++))
+ {
+ missing_lf = 1;
+ if (c == '\\')
+ es_fputs_unlocked ("\\\\", logstream);
+ else if (c == '\r')
+ es_fputs_unlocked ("\\r", logstream);
+ else if (c == '\n')
+ {
+ es_fputs_unlocked ("\\n\n", logstream);
+ if (*extrastring)
+ {
+ print_prefix (level, leading_backspace);
+ es_fputs_unlocked (">> ", logstream);
+ }
+ else
+ missing_lf = 0;
+ }
+ else
+ es_putc_unlocked (c, logstream);
+ }
+ if (missing_lf)
+ {
+ es_putc_unlocked ('\n', logstream);
+ missing_lf = 0;
+ }
+ }
+
+ if (level == GPGRT_LOG_FATAL)
+ {
+ if (missing_lf)
+ es_putc_unlocked ('\n', logstream);
+ es_funlockfile (logstream);
+ exit (2);
+ }
+ else if (level == GPGRT_LOG_BUG)
+ {
+ if (missing_lf)
+ es_putc_unlocked ('\n', logstream );
+ es_funlockfile (logstream);
+ /* Using backtrace requires a configure test and to pass
+ * -rdynamic to gcc. Thus we do not enable it now. */
+ /* { */
+ /* void *btbuf[20]; */
+ /* int btidx, btlen; */
+ /* char **btstr; */
+
+ /* btlen = backtrace (btbuf, DIM (btbuf)); */
+ /* btstr = backtrace_symbols (btbuf, btlen); */
+ /* if (btstr) */
+ /* for (btidx=0; btidx < btlen; btidx++) */
+ /* log_debug ("[%d] %s\n", btidx, btstr[btidx]); */
+ /* } */
+ abort ();
+ }
+ else
+ es_funlockfile (logstream);
+}
+
+
+void
+log_log (int level, const char *fmt, ...)
+{
+ va_list arg_ptr ;
+
+ va_start (arg_ptr, fmt) ;
+ do_logv (level, 0, NULL, NULL, fmt, arg_ptr);
+ va_end (arg_ptr);
+}
+
+
+void
+log_logv (int level, const char *fmt, va_list arg_ptr)
+{
+ do_logv (level, 0, NULL, NULL, fmt, arg_ptr);
+}
+
+
+/* Same as log_logv but PREFIX is printed immediately before FMT.
+ * Note that PREFIX is an additional string and independent of the
+ * prefix set by log_set_prefix. */
+void
+log_logv_with_prefix (int level, const char *prefix,
+ const char *fmt, va_list arg_ptr)
+{
+ do_logv (level, 0, NULL, prefix, fmt, arg_ptr);
+}
+
+
+static void
+do_log_ignore_arg (int level, const char *str, ...)
+{
+ va_list arg_ptr;
+ va_start (arg_ptr, str);
+ do_logv (level, 1, NULL, NULL, str, arg_ptr);
+ va_end (arg_ptr);
+}
+
+
+/* Log STRING at LEVEL but indent from the second line on by the
+ * length of the prefix. */
+void
+log_string (int level, const char *string)
+{
+ /* We need a dummy arg_ptr, but there is no portable way to create
+ * one. So we call the do_logv function through a variadic wrapper. */
+ do_log_ignore_arg (level, string);
+}
+
+
+void
+log_info (const char *fmt, ...)
+{
+ va_list arg_ptr ;
+
+ va_start (arg_ptr, fmt);
+ do_logv (GPGRT_LOG_INFO, 0, NULL, NULL, fmt, arg_ptr);
+ va_end (arg_ptr);
+}
+
+
+void
+log_error (const char *fmt, ...)
+{
+ va_list arg_ptr ;
+
+ va_start (arg_ptr, fmt);
+ do_logv (GPGRT_LOG_ERROR, 0, NULL, NULL, fmt, arg_ptr);
+ va_end (arg_ptr);
+ log_inc_errorcount ();
+}
+
+
+void
+log_fatal (const char *fmt, ...)
+{
+ va_list arg_ptr ;
+
+ va_start (arg_ptr, fmt);
+ do_logv (GPGRT_LOG_FATAL, 0, NULL, NULL, fmt, arg_ptr);
+ va_end (arg_ptr);
+ abort (); /* Never called; just to make the compiler happy. */
+}
+
+
+void
+log_bug (const char *fmt, ...)
+{
+ va_list arg_ptr ;
+
+ va_start (arg_ptr, fmt);
+ do_logv (GPGRT_LOG_BUG, 0, NULL, NULL, fmt, arg_ptr);
+ va_end (arg_ptr);
+ abort (); /* Never called; just to make the compiler happy. */
+}
+
+
+void
+log_debug (const char *fmt, ...)
+{
+ va_list arg_ptr ;
+
+ va_start (arg_ptr, fmt);
+ do_logv (GPGRT_LOG_DEBUG, 0, NULL, NULL, fmt, arg_ptr);
+ va_end (arg_ptr);
+}
+
+
+/* The same as log_debug but at the end of the output STRING is
+ * printed with LFs expanded to include the prefix and a final --end--
+ * marker. */
+void
+log_debug_with_string (const char *string, const char *fmt, ...)
+{
+ va_list arg_ptr ;
+
+ va_start (arg_ptr, fmt);
+ do_logv (GPGRT_LOG_DEBUG, 0, string, NULL, fmt, arg_ptr);
+ va_end (arg_ptr);
+}
+
+
+void
+log_printf (const char *fmt, ...)
+{
+ va_list arg_ptr;
+
+ va_start (arg_ptr, fmt);
+ do_logv (fmt ? GPGRT_LOG_CONT : GPGRT_LOG_BEGIN, 0, NULL, NULL, fmt, arg_ptr);
+ va_end (arg_ptr);
+}
+
+
+/* Flush the log - this is useful to make sure that the trailing
+ linefeed has been printed. */
+void
+log_flush (void)
+{
+ do_log_ignore_arg (GPGRT_LOG_CONT, NULL);
+}
+
+
+/* Print a hexdump of BUFFER. With TEXT of NULL print just the raw
+ dump, with TEXT just an empty string, print a trailing linefeed,
+ otherwise print an entire debug line. */
+void
+log_printhex (const void *buffer, size_t length, const char *fmt, ...)
+{
+ if (fmt && *fmt)
+ {
+ va_list arg_ptr ;
+
+ va_start (arg_ptr, fmt);
+ do_logv (GPGRT_LOG_DEBUG, 0, NULL, NULL, fmt, arg_ptr);
+ va_end (arg_ptr);
+ log_printf (" ");
+ }
+ if (length)
+ {
+ const unsigned char *p = buffer;
+ log_printf ("%02X", *p);
+ for (length--, p++; length--; p++)
+ log_printf (" %02X", *p);
+ }
+ if (fmt)
+ log_printf ("\n");
+}
+
+
+/*
+void
+log_printcanon () {}
+is found in sexputils.c
+*/
+
+/*
+void
+log_printsexp () {}
+is found in sexputils.c
+*/
+
+
+void
+log_clock (const char *string)
+{
+#if 0
+ static unsigned long long initial;
+ struct timespec tv;
+ unsigned long long now;
+
+ if (clock_gettime (CLOCK_REALTIME, &tv))
+ {
+ log_debug ("error getting the realtime clock value\n");
+ return;
+ }
+ now = tv.tv_sec * 1000000000ull;
+ now += tv.tv_nsec;
+
+ if (!initial)
+ initial = now;
+
+ log_debug ("[%6llu] %s", (now - initial)/1000, string);
+#else
+ /* You need to link with -ltr to enable the above code. */
+ log_debug ("[not enabled in the source] %s", string);
+#endif
+}
+
+
+#ifdef GPGRT_HAVE_MACRO_FUNCTION
+void
+bug_at( const char *file, int line, const char *func )
+{
+ log_log (GPGRT_LOG_BUG, "... this is a bug (%s:%d:%s)\n", file, line, func);
+ abort (); /* Never called; just to make the compiler happy. */
+}
+#else /*!GPGRT_HAVE_MACRO_FUNCTION*/
+void
+bug_at( const char *file, int line )
+{
+ log_log (GPGRT_LOG_BUG, "you found a bug ... (%s:%d)\n", file, line);
+ abort (); /* Never called; just to make the compiler happy. */
+}
+#endif /*!GPGRT_HAVE_MACRO_FUNCTION*/
+
+
+#ifdef GPGRT_HAVE_MACRO_FUNCTION
+void
+_log_assert (const char *expr, const char *file, int line, const char *func)
+{
+ log_log (GPGRT_LOG_BUG, "Assertion \"%s\" in %s failed (%s:%d)\n",
+ expr, func, file, line);
+ abort (); /* Never called; just to make the compiler happy. */
+}
+#else /*!GPGRT_HAVE_MACRO_FUNCTION*/
+void
+_log_assert (const char *expr, const char *file, int line)
+{
+ log_log (GPGRT_LOG_BUG, "Assertion \"%s\" failed (%s:%d)\n",
+ expr, file, line);
+ abort (); /* Never called; just to make the compiler happy. */
+}
+#endif /*!GPGRT_HAVE_MACRO_FUNCTION*/
diff --git a/common/logging.h b/common/logging.h
new file mode 100644
index 0000000..cb1ec11
--- /dev/null
+++ b/common/logging.h
@@ -0,0 +1,142 @@
+/* logging.h
+ * Copyright (C) 1999, 2000, 2001, 2004, 2006,
+ * 2010 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute and/or modify this
+ * part of GnuPG under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * 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 copies of the GNU General Public License
+ * and the GNU Lesser General Public License along with this program;
+ * if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_COMMON_LOGGING_H
+#define GNUPG_COMMON_LOGGING_H
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <gpg-error.h>
+#include "mischelp.h"
+#include "w32help.h"
+
+int log_get_errorcount (int clear);
+void log_inc_errorcount (void);
+void log_set_file( const char *name );
+void log_set_fd (int fd);
+void log_set_socket_dir_cb (const char *(*fnc)(void));
+void log_set_pid_suffix_cb (int (*cb)(unsigned long *r_value));
+void log_set_prefix (const char *text, unsigned int flags);
+const char *log_get_prefix (unsigned int *flags);
+int log_test_fd (int fd);
+int log_get_fd(void);
+estream_t log_get_stream (void);
+
+#ifdef GPGRT_HAVE_MACRO_FUNCTION
+ void bug_at (const char *file, int line, const char *func)
+ GPGRT_ATTR_NORETURN;
+ void _log_assert (const char *expr, const char *file, int line,
+ const char *func) GPGRT_ATTR_NORETURN;
+# define BUG() bug_at( __FILE__ , __LINE__, __FUNCTION__)
+# define log_assert(expr) \
+ ((expr) \
+ ? (void) 0 \
+ : _log_assert (#expr, __FILE__, __LINE__, __FUNCTION__))
+#else /*!GPGRT_HAVE_MACRO_FUNCTION*/
+ void bug_at (const char *file, int line);
+ void _log_assert (const char *expr, const char *file, int line);
+# define BUG() bug_at( __FILE__ , __LINE__ )
+# define log_assert(expr) \
+ ((expr) \
+ ? (void) 0 \
+ : _log_assert (#expr, __FILE__, __LINE__))
+#endif /*!GPGRT_HAVE_MACRO_FUNCTION*/
+
+/* Flag values for log_set_prefix. */
+#define GPGRT_LOG_WITH_PREFIX 1
+#define GPGRT_LOG_WITH_TIME 2
+#define GPGRT_LOG_WITH_PID 4
+#define GPGRT_LOG_RUN_DETACHED 256
+#define GPGRT_LOG_NO_REGISTRY 512
+
+/* Log levels as used by log_log. */
+enum jnlib_log_levels {
+ GPGRT_LOG_BEGIN,
+ GPGRT_LOG_CONT,
+ GPGRT_LOG_INFO,
+ GPGRT_LOG_WARN,
+ GPGRT_LOG_ERROR,
+ GPGRT_LOG_FATAL,
+ GPGRT_LOG_BUG,
+ GPGRT_LOG_DEBUG
+};
+void log_log (int level, const char *fmt, ...) GPGRT_ATTR_PRINTF(2,3);
+void log_logv (int level, const char *fmt, va_list arg_ptr);
+void log_logv_with_prefix (int level, const char *prefix,
+ const char *fmt, va_list arg_ptr);
+void log_string (int level, const char *string);
+void log_bug (const char *fmt, ...) GPGRT_ATTR_NR_PRINTF(1,2);
+void log_fatal (const char *fmt, ...) GPGRT_ATTR_NR_PRINTF(1,2);
+void log_error (const char *fmt, ...) GPGRT_ATTR_PRINTF(1,2);
+void log_info (const char *fmt, ...) GPGRT_ATTR_PRINTF(1,2);
+void log_debug (const char *fmt, ...) GPGRT_ATTR_PRINTF(1,2);
+void log_debug_with_string (const char *string, const char *fmt,
+ ...) GPGRT_ATTR_PRINTF(2,3);
+void log_printf (const char *fmt, ...) GPGRT_ATTR_PRINTF(1,2);
+void log_flush (void);
+
+/* Print a hexdump of BUFFER. With FMT passed as NULL print just the
+ * raw dump, with FMT being an empty string, print a trailing
+ * linefeed, otherwise print an entire debug line with expanded FMT
+ * followed by the hexdump and a final LF. */
+void log_printhex (const void *buffer, size_t length,
+ const char *fmt, ...) GPGRT_ATTR_PRINTF(3,4);
+
+void log_clock (const char *string);
+
+
+/* Some handy assertion macros which don't abort. */
+
+#define return_if_fail(expr) do { \
+ if (!(expr)) { \
+ log_debug ("%s:%d: assertion '%s' failed\n", \
+ __FILE__, __LINE__, #expr ); \
+ return; \
+ } } while (0)
+#define return_null_if_fail(expr) do { \
+ if (!(expr)) { \
+ log_debug ("%s:%d: assertion '%s' failed\n", \
+ __FILE__, __LINE__, #expr ); \
+ return NULL; \
+ } } while (0)
+#define return_val_if_fail(expr,val) do { \
+ if (!(expr)) { \
+ log_debug ("%s:%d: assertion '%s' failed\n", \
+ __FILE__, __LINE__, #expr ); \
+ return (val); \
+ } } while (0)
+#define never_reached() do { \
+ log_debug ("%s:%d: oops - should never get here\n", \
+ __FILE__, __LINE__ ); \
+ } while (0)
+
+
+#endif /*GNUPG_COMMON_LOGGING_H*/
diff --git a/common/mapstrings.c b/common/mapstrings.c
new file mode 100644
index 0000000..16da48e
--- /dev/null
+++ b/common/mapstrings.c
@@ -0,0 +1,216 @@
+/* mapstrings.c - Static string mapping
+ * Copyright (C) 2014 Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "util.h"
+#include "stringhelp.h"
+#include "membuf.h"
+
+
+static struct {
+ const char *name;
+ const char *value;
+} macros[] = {
+#ifdef PACKAGE_BUGREPORT
+ { "EMAIL", PACKAGE_BUGREPORT },
+#else
+ { "EMAIL", "bug@example.org" },
+#endif
+ { "GNUPG", GNUPG_NAME },
+ { "GPG", GPG_NAME },
+ { "GPGSM", GPGSM_NAME },
+ { "GPG_AGENT", GPG_AGENT_NAME },
+ { "SCDAEMON", SCDAEMON_NAME },
+ { "DIRMNGR", DIRMNGR_NAME },
+ { "G13", G13_NAME },
+ { "GPGCONF", GPGCONF_NAME },
+ { "GPGTAR", GPGTAR_NAME }
+};
+
+
+
+/* A list to remember already done mappings. */
+struct mapping_s
+{
+ struct mapping_s *next;
+ const char *key;
+ const char *value;
+};
+static struct mapping_s *mappings;
+
+
+/* Similar to above but using two integers and a domain as key. */
+struct intmapping_s
+{
+ struct intmapping_s *next;
+ int key1;
+ int key2;
+ const char *string;
+ char domain[1];
+};
+static struct intmapping_s *intmappings;
+
+
+/* If STRING has already been mapped, return the mapped string. If
+ not return NULL. */
+static const char *
+already_mapped (const char *string)
+{
+ struct mapping_s *m;
+
+ for (m=mappings; m; m = m->next)
+ if (m->key == string && !strcmp (m->key, string))
+ return m->value;
+ return NULL;
+}
+
+
+/* Store NEWSTRING under key STRING and return NEWSTRING. */
+static const char *
+store_mapping (const char *string, char *newstring)
+{
+ struct mapping_s *m;
+
+ m = xmalloc (sizeof *m);
+ m->key = string;
+ m->value = newstring;
+ m->next = mappings;
+ mappings = m;
+ return newstring;
+}
+
+
+/* Find the first macro in STRING. Return a pointer to the
+ replacement value, set BEGPTR to the leading '@', and set ENDPTR to
+ the terminating '@'. If no macro is found return NULL. */
+const char *
+find_macro (const char *string, const char **begptr,
+ const char **endptr)
+{
+ const char *s, *s2, *s3;
+ int idx;
+
+ s = string;
+ if (!s)
+ return NULL;
+
+ for (; (s2 = strchr (s, '@')); s = s2)
+ {
+ s2++;
+ if (*s2 >= 'A' && *s2 <= 'Z' && (s3 = (strchr (s2, '@'))))
+ {
+ for (idx=0; idx < DIM (macros); idx++)
+ if (strlen (macros[idx].name) == (s3 - s2)
+ && !memcmp (macros[idx].name, s2, (s3 - s2)))
+ {
+ *begptr = s2 - 1;
+ *endptr = s3;
+ return macros[idx].value;
+ }
+ }
+ }
+ return NULL;
+}
+
+
+/* If STRING includes known @FOO@ macros, replace these macros and
+ return a new static string. Warning: STRING must have been
+ allocated statically. Note that this function allocates memory
+ which will not be released (similar to gettext). */
+const char *
+map_static_macro_string (const char *string)
+{
+ const char *s, *s2, *s3, *value;
+ membuf_t mb;
+ char *p;
+
+ if ((s = already_mapped (string)))
+ return s;
+ s = string;
+ value = find_macro (s, &s2, &s3);
+ if (!value)
+ return string; /* No macros at all. */
+
+ init_membuf (&mb, strlen (string) + 100);
+ do
+ {
+ put_membuf (&mb, s, s2 - s);
+ put_membuf_str (&mb, value);
+ s = s3 + 1;
+ }
+ while ((value = find_macro (s, &s2, &s3)));
+ put_membuf_str (&mb, s);
+ put_membuf (&mb, "", 1);
+
+ p = get_membuf_shrink (&mb, NULL);
+ if (!p)
+ log_fatal ("map_static_macro_string failed: %s\n", strerror (errno));
+
+ return store_mapping (string, p);
+}
+
+
+/* If a list of strings has already been mapped to a the tuple
+ * (DOMAIN,KEY1,KEY2) return that string. If not, create a mapping
+ * made up of the concatenation of the given strings. */
+const char *
+map_static_strings (const char *domain, int key1, int key2,
+ const char *string1, ...)
+{
+ va_list arg_ptr;
+ struct intmapping_s *m;
+
+ if (!string1 || !domain)
+ return "";
+
+ for (m = intmappings; m; m = m->next)
+ if (m->key1 == key1 && m->key2 == key2 && !strcmp (domain, m->domain))
+ return m->string;
+
+ m = xmalloc (sizeof *m + strlen (domain));
+ strcpy (m->domain, domain);
+ m->key1 = key1;
+ m->key2 = key2;
+
+ va_start (arg_ptr, string1);
+ m->string = vstrconcat (string1, arg_ptr);
+ va_end (arg_ptr);
+ if (!m->string)
+ log_fatal ("map_static_strings failed: %s\n", strerror (errno));
+
+ gpgrt_annotate_leaked_object (m->string);
+ gpgrt_annotate_leaked_object (m);
+
+ m->next = intmappings;
+ intmappings = m;
+ return m->string;
+}
diff --git a/common/mbox-util.c b/common/mbox-util.c
new file mode 100644
index 0000000..76255ba
--- /dev/null
+++ b/common/mbox-util.c
@@ -0,0 +1,282 @@
+/* mbox-util.c - Mail address helper functions
+ * Copyright (C) 1998-2010 Free Software Foundation, Inc.
+ * Copyright (C) 1998-2015 Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This file 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 Lesser General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+/* NB: GPGME uses the same code to reflect our idea on how to extract
+ * a mail address from a user id.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "util.h"
+#include "mbox-util.h"
+
+
+static int
+string_count_chr (const char *string, int c)
+{
+ int count;
+
+ for (count=0; *string; string++ )
+ if ( *string == c )
+ count++;
+ return count;
+}
+
+static int
+mem_count_chr (const void *buffer, int c, size_t length)
+{
+ const char *s = buffer;
+ int count;
+
+ for (count=0; length; length--, s++)
+ if (*s == c)
+ count++;
+ return count;
+}
+
+
+/* This is a case-sensitive version of our memistr. I wonder why no
+ standard function memstr exists but I better do not use the name
+ memstr to avoid future conflicts. */
+static const char *
+my_memstr (const void *buffer, size_t buflen, const char *sub)
+{
+ const unsigned char *buf = buffer;
+ const unsigned char *t = (const unsigned char *)buf;
+ const unsigned char *s = (const unsigned char *)sub;
+ size_t n = buflen;
+
+ for ( ; n ; t++, n-- )
+ {
+ if (*t == *s)
+ {
+ for (buf = t++, buflen = n--, s++; n && *t ==*s; t++, s++, n--)
+ ;
+ if (!*s)
+ return (const char*)buf;
+ t = (const unsigned char *)buf;
+ s = (const unsigned char *)sub ;
+ n = buflen;
+ }
+ }
+ return NULL;
+}
+
+
+
+static int
+string_has_ctrl_or_space (const char *string)
+{
+ for (; *string; string++ )
+ if (!(*string & 0x80) && *string <= 0x20)
+ return 1;
+ return 0;
+}
+
+
+/* Return true if STRING has two consecutive '.' after an '@'
+ sign. */
+static int
+has_dotdot_after_at (const char *string)
+{
+ string = strchr (string, '@');
+ if (!string)
+ return 0; /* No at-sign. */
+ string++;
+ return !!strstr (string, "..");
+}
+
+
+/* Check whether BUFFER has characters not valid in an RFC-822
+ address. LENGTH gives the length of BUFFER.
+
+ To cope with OpenPGP we ignore non-ascii characters so that for
+ example umlauts are legal in an email address. An OpenPGP user ID
+ must be utf-8 encoded but there is no strict requirement for
+ RFC-822. Thus to avoid IDNA encoding we put the address verbatim
+ as utf-8 into the user ID under the assumption that mail programs
+ handle IDNA at a lower level and take OpenPGP user IDs as utf-8.
+ Note that we can't do an utf-8 encoding checking here because in
+ keygen.c this function is called with the native encoding and
+ native to utf-8 encoding is only done later. */
+int
+has_invalid_email_chars (const void *buffer, size_t length)
+{
+ const unsigned char *s = buffer;
+ int at_seen=0;
+ const char *valid_chars=
+ "01234567890_-.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+ for ( ; length && *s; length--, s++ )
+ {
+ if ((*s & 0x80))
+ continue; /* We only care about ASCII. */
+ if (*s == '@')
+ at_seen=1;
+ else if (!at_seen && !(strchr (valid_chars, *s)
+ || strchr ("!#$%&'*+/=?^`{|}~", *s)))
+ return 1;
+ else if (at_seen && !strchr (valid_chars, *s))
+ return 1;
+ }
+ return 0;
+}
+
+
+/* Same as is_valid_mailbox (see below) but operates on non-nul
+ terminated buffer. */
+int
+is_valid_mailbox_mem (const void *name_arg, size_t namelen)
+{
+ const char *name = name_arg;
+
+ return !( !name
+ || !namelen
+ || has_invalid_email_chars (name, namelen)
+ || mem_count_chr (name, '@', namelen) != 1
+ || *name == '@'
+ || name[namelen-1] == '@'
+ || name[namelen-1] == '.'
+ || my_memstr (name, namelen, ".."));
+}
+
+
+/* Check whether NAME represents a valid mailbox according to
+ RFC822. Returns true if so. */
+int
+is_valid_mailbox (const char *name)
+{
+ return name? is_valid_mailbox_mem (name, strlen (name)) : 0;
+}
+
+
+/* Return the mailbox (local-part@domain) form a standard user id.
+ All plain ASCII characters in the result are converted to
+ lowercase. Caller must free the result. Returns NULL if no valid
+ mailbox was found (or we are out of memory). */
+char *
+mailbox_from_userid (const char *userid)
+{
+ const char *s, *s_end;
+ size_t len;
+ char *result = NULL;
+
+ s = strchr (userid, '<');
+ if (s)
+ {
+ /* Seems to be a standard user id. */
+ s++;
+ s_end = strchr (s, '>');
+ if (s_end && s_end > s)
+ {
+ len = s_end - s;
+ result = xtrymalloc (len + 1);
+ if (!result)
+ return NULL; /* Ooops - out of core. */
+ strncpy (result, s, len);
+ result[len] = 0;
+ /* Apply some basic checks on the address. We do not use
+ is_valid_mailbox because those checks are too strict. */
+ if (string_count_chr (result, '@') != 1 /* Need exactly one '@. */
+ || *result == '@' /* local-part missing. */
+ || result[len-1] == '@' /* domain missing. */
+ || result[len-1] == '.' /* ends with a dot. */
+ || string_has_ctrl_or_space (result)
+ || has_dotdot_after_at (result))
+ {
+ xfree (result);
+ result = NULL;
+ errno = EINVAL;
+ }
+ }
+ else
+ errno = EINVAL;
+ }
+ else if (is_valid_mailbox (userid))
+ {
+ /* The entire user id is a mailbox. Return that one. Note that
+ this fallback method has some restrictions on the valid
+ syntax of the mailbox. However, those who want weird
+ addresses should know about it and use the regular <...>
+ syntax. */
+ result = xtrystrdup (userid);
+ }
+ else
+ errno = EINVAL;
+
+ return result? ascii_strlwr (result): NULL;
+}
+
+
+/* Check whether UID is a valid standard user id of the form
+ "Heinrich Heine <heinrichh@duesseldorf.de>"
+ and return true if this is the case. */
+int
+is_valid_user_id (const char *uid)
+{
+ if (!uid || !*uid)
+ return 0;
+
+ return 1;
+}
+
+
+/* Returns true if STRING is a valid domain name according to the LDH
+ * rule. */
+int
+is_valid_domain_name (const char *string)
+{
+ static char const ldh_chars[] =
+ "01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-";
+ const char *s;
+
+ /* Note that we do not check the length limit of a label or the
+ * entire name */
+
+ for (s=string; *s; s++)
+ if (*s == '.')
+ {
+ if (string == s)
+ return 0; /* Dot at the start of the string. */
+ /* (may also be at the end like in ".") */
+ if (s[1] == '.')
+ return 0; /* No - double dot. */
+ }
+ else if (!strchr (ldh_chars, *s))
+ return 0;
+ else if (*s == '-')
+ {
+ if (string == s)
+ return 0; /* Leading hyphen. */
+ if (s[-1] == '.')
+ return 0; /* Hyphen at begin of a label. */
+ if (s[1] == '.')
+ return 0; /* Hyphen at start of a label. */
+ if (!s[1])
+ return 0; /* Trailing hyphen. */
+ }
+
+ return !!*string;
+}
diff --git a/common/mbox-util.h b/common/mbox-util.h
new file mode 100644
index 0000000..7355cee
--- /dev/null
+++ b/common/mbox-util.h
@@ -0,0 +1,30 @@
+/* mbox-util.h - Defs for mail address helper functions
+ * Copyright (C) 2015 Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This file 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 Lesser General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+#ifndef GNUPG_COMMON_MBOX_UTIL_H
+#define GNUPG_COMMON_MBOX_UTIL_H
+
+int has_invalid_email_chars (const void *buffer, size_t length);
+int is_valid_mailbox (const char *name);
+int is_valid_mailbox_mem (const void *buffer, size_t length);
+char *mailbox_from_userid (const char *userid);
+int is_valid_user_id (const char *uid);
+int is_valid_domain_name (const char *string);
+
+
+#endif /*GNUPG_COMMON_MBOX_UTIL_H*/
diff --git a/common/membuf.c b/common/membuf.c
new file mode 100644
index 0000000..009fbc3
--- /dev/null
+++ b/common/membuf.c
@@ -0,0 +1,233 @@
+/* membuf.c - A simple implementation of a dynamic buffer.
+ * Copyright (C) 2001, 2003, 2009, 2011 Free Software Foundation, Inc.
+ * Copyright (C) 2013 Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stdarg.h>
+
+#include "util.h"
+#include "membuf.h"
+
+
+/* A simple implementation of a dynamic buffer. Use init_membuf() to
+ create a buffer, put_membuf to append bytes and get_membuf to
+ release and return the buffer. Allocation errors are detected but
+ only returned at the final get_membuf(), this helps not to clutter
+ the code with out of core checks. */
+
+void
+init_membuf (membuf_t *mb, int initiallen)
+{
+ mb->len = 0;
+ mb->size = initiallen;
+ mb->out_of_core = 0;
+ mb->buf = xtrymalloc (initiallen);
+ if (!mb->buf)
+ mb->out_of_core = errno;
+}
+
+/* Same as init_membuf but allocates the buffer in secure memory. */
+void
+init_membuf_secure (membuf_t *mb, int initiallen)
+{
+ mb->len = 0;
+ mb->size = initiallen;
+ mb->out_of_core = 0;
+ mb->buf = xtrymalloc_secure (initiallen);
+ if (!mb->buf)
+ mb->out_of_core = errno;
+}
+
+
+/* Shift the content of the membuf MB by AMOUNT bytes. The next
+ operation will then behave as if AMOUNT bytes had not been put into
+ the buffer. If AMOUNT is greater than the actual accumulated
+ bytes, the membuf is basically reset to its initial state. */
+void
+clear_membuf (membuf_t *mb, size_t amount)
+{
+ /* No need to clear if we are already out of core. */
+ if (mb->out_of_core)
+ return;
+ if (amount >= mb->len)
+ mb->len = 0;
+ else
+ {
+ mb->len -= amount;
+ memmove (mb->buf, mb->buf+amount, mb->len);
+ }
+}
+
+
+void
+put_membuf (membuf_t *mb, const void *buf, size_t len)
+{
+ if (mb->out_of_core || !len)
+ return;
+
+ if (mb->len + len >= mb->size)
+ {
+ char *p;
+
+ mb->size += len + 1024;
+ p = xtryrealloc (mb->buf, mb->size);
+ if (!p)
+ {
+ mb->out_of_core = errno ? errno : ENOMEM;
+ /* Wipe out what we already accumulated. This is required
+ in case we are storing sensitive data here. The membuf
+ API does not provide another way to cleanup after an
+ error. */
+ wipememory (mb->buf, mb->len);
+ return;
+ }
+ mb->buf = p;
+ }
+ if (buf)
+ memcpy (mb->buf + mb->len, buf, len);
+ else
+ memset (mb->buf + mb->len, 0, len);
+ mb->len += len;
+}
+
+
+/* A variant of put_membuf accepting a void * and returning a
+ gpg_error_t (which will always return 0) to be used as a generic
+ callback handler. This function also allows buffer to be NULL. */
+gpg_error_t
+put_membuf_cb (void *opaque, const void *buf, size_t len)
+{
+ membuf_t *data = opaque;
+
+ if (buf)
+ put_membuf (data, buf, len);
+ return 0;
+}
+
+
+void
+put_membuf_str (membuf_t *mb, const char *string)
+{
+ put_membuf (mb, string, strlen (string));
+}
+
+
+void
+put_membuf_printf (membuf_t *mb, const char *format, ...)
+{
+ int rc;
+ va_list arg_ptr;
+ char *buf;
+
+ va_start (arg_ptr, format);
+ rc = gpgrt_vasprintf (&buf, format, arg_ptr);
+ if (rc < 0)
+ mb->out_of_core = errno ? errno : ENOMEM;
+ va_end (arg_ptr);
+ if (rc >= 0)
+ {
+ put_membuf (mb, buf, strlen (buf));
+ xfree (buf);
+ }
+}
+
+
+void *
+get_membuf (membuf_t *mb, size_t *len)
+{
+ char *p;
+
+ if (mb->out_of_core)
+ {
+ if (mb->buf)
+ {
+ wipememory (mb->buf, mb->len);
+ xfree (mb->buf);
+ mb->buf = NULL;
+ }
+ gpg_err_set_errno (mb->out_of_core);
+ return NULL;
+ }
+
+ p = mb->buf;
+ if (len)
+ *len = mb->len;
+ mb->buf = NULL;
+ mb->out_of_core = ENOMEM; /* hack to make sure it won't get reused. */
+ return p;
+}
+
+
+/* Same as get_membuf but shrinks the reallocated space to the
+ required size. */
+void *
+get_membuf_shrink (membuf_t *mb, size_t *len)
+{
+ void *p, *pp;
+ size_t dummylen;
+
+ if (!len)
+ len = &dummylen;
+
+ p = get_membuf (mb, len);
+ if (!p)
+ return NULL;
+ if (*len)
+ {
+ pp = xtryrealloc (p, *len);
+ if (pp)
+ p = pp;
+ }
+
+ return p;
+}
+
+
+/* Peek at the membuf MB. On success a pointer to the buffer is
+ returned which is valid until the next operation on MB. If LEN is
+ not NULL the current LEN of the buffer is stored there. On error
+ NULL is returned and ERRNO is set. */
+const void *
+peek_membuf (membuf_t *mb, size_t *len)
+{
+ const char *p;
+
+ if (mb->out_of_core)
+ {
+ gpg_err_set_errno (mb->out_of_core);
+ return NULL;
+ }
+
+ p = mb->buf;
+ if (len)
+ *len = mb->len;
+ return p;
+}
diff --git a/common/membuf.h b/common/membuf.h
new file mode 100644
index 0000000..1497bcd
--- /dev/null
+++ b/common/membuf.h
@@ -0,0 +1,64 @@
+/* membuf.h - A simple implementation of a dynamic buffer
+ * Copyright (C) 2001, 2003 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_COMMON_MEMBUF_H
+#define GNUPG_COMMON_MEMBUF_H
+
+#include "mischelp.h"
+
+/* The definition of the structure is private, we only need it here,
+ so it can be allocated on the stack. */
+struct private_membuf_s
+{
+ size_t len;
+ size_t size;
+ char *buf;
+ int out_of_core;
+};
+
+typedef struct private_membuf_s membuf_t;
+
+/* Return the current length of the membuf. */
+#define get_membuf_len(a) ((a)->len)
+#define is_membuf_ready(a) ((a)->buf || (a)->out_of_core)
+#define MEMBUF_ZERO { 0, 0, NULL, 0}
+
+void init_membuf (membuf_t *mb, int initiallen);
+void init_membuf_secure (membuf_t *mb, int initiallen);
+void clear_membuf (membuf_t *mb, size_t amount);
+void put_membuf (membuf_t *mb, const void *buf, size_t len);
+gpg_error_t put_membuf_cb (void *opaque, const void *buf, size_t len);
+void put_membuf_str (membuf_t *mb, const char *string);
+void put_membuf_printf (membuf_t *mb, const char *format,
+ ...) GPGRT_ATTR_PRINTF(2,3);
+void *get_membuf (membuf_t *mb, size_t *len);
+void *get_membuf_shrink (membuf_t *mb, size_t *len);
+const void *peek_membuf (membuf_t *mb, size_t *len);
+
+#endif /*GNUPG_COMMON_MEMBUF_H*/
diff --git a/common/miscellaneous.c b/common/miscellaneous.c
new file mode 100644
index 0000000..c377554
--- /dev/null
+++ b/common/miscellaneous.c
@@ -0,0 +1,842 @@
+/* miscellaneous.c - Stuff not fitting elsewhere
+ * Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <errno.h>
+
+#include "util.h"
+#include "iobuf.h"
+#include "i18n.h"
+
+/* Used by libgcrypt for logging. */
+static void
+my_gcry_logger (void *dummy, int level, const char *fmt, va_list arg_ptr)
+{
+ (void)dummy;
+
+ /* Map the log levels. */
+ switch (level)
+ {
+ case GCRY_LOG_CONT: level = GPGRT_LOG_CONT; break;
+ case GCRY_LOG_INFO: level = GPGRT_LOG_INFO; break;
+ case GCRY_LOG_WARN: level = GPGRT_LOG_WARN; break;
+ case GCRY_LOG_ERROR:level = GPGRT_LOG_ERROR; break;
+ case GCRY_LOG_FATAL:level = GPGRT_LOG_FATAL; break;
+ case GCRY_LOG_BUG: level = GPGRT_LOG_BUG; break;
+ case GCRY_LOG_DEBUG:level = GPGRT_LOG_DEBUG; break;
+ default: level = GPGRT_LOG_ERROR; break;
+ }
+ log_logv (level, fmt, arg_ptr);
+}
+
+
+/* This function is called by libgcrypt on a fatal error. */
+static void
+my_gcry_fatalerror_handler (void *opaque, int rc, const char *text)
+{
+ (void)opaque;
+
+ log_fatal ("libgcrypt problem: %s\n", text ? text : gpg_strerror (rc));
+ abort ();
+}
+
+
+/* This function is called by libgcrypt if it ran out of core and
+ there is no way to return that error to the caller. We do our own
+ function here to make use of our logging functions. */
+static int
+my_gcry_outofcore_handler (void *opaque, size_t req_n, unsigned int flags)
+{
+ static int been_here; /* Used to protect against recursive calls. */
+
+ (void)opaque;
+
+ if (!been_here)
+ {
+ been_here = 1;
+ if ( (flags & 1) )
+ log_fatal (_("out of core in secure memory "
+ "while allocating %lu bytes"), (unsigned long)req_n);
+ else
+ log_fatal (_("out of core while allocating %lu bytes"),
+ (unsigned long)req_n);
+ }
+ return 0; /* Let libgcrypt call its own fatal error handler.
+ Actually this will turn out to be
+ my_gcry_fatalerror_handler. */
+}
+
+
+/* Setup libgcrypt to use our own logging functions. Should be used
+ early at startup. */
+void
+setup_libgcrypt_logging (void)
+{
+ gcry_set_log_handler (my_gcry_logger, NULL);
+ gcry_set_fatalerror_handler (my_gcry_fatalerror_handler, NULL);
+ gcry_set_outofcore_handler (my_gcry_outofcore_handler, NULL);
+}
+
+
+/* Print an out of core message and let the process die. The printed
+ * error is taken from ERRNO. */
+void
+xoutofcore (void)
+{
+ gpg_error_t err = gpg_error_from_syserror ();
+ log_fatal (_("error allocating enough memory: %s\n"), gpg_strerror (err));
+ abort (); /* Never called; just to make the compiler happy. */
+}
+
+
+/* This is safe version of realloc useful for reallocing a calloced
+ * array. There are two ways to call it: The first example
+ * reallocates the array A to N elements each of SIZE but does not
+ * clear the newly allocated elements:
+ *
+ * p = gpgrt_reallocarray (a, n, n, nsize);
+ *
+ * Note that when NOLD is larger than N no cleaning is needed anyway.
+ * The second example reallocates an array of size NOLD to N elements
+ * each of SIZE but clear the newly allocated elements:
+ *
+ * p = gpgrt_reallocarray (a, nold, n, nsize);
+ *
+ * Note that gnupg_reallocarray (NULL, 0, n, nsize) is equivalent to
+ * gcry_calloc (n, nsize).
+ */
+void *
+gnupg_reallocarray (void *a, size_t oldnmemb, size_t nmemb, size_t size)
+{
+ size_t oldbytes, bytes;
+ char *p;
+
+ bytes = nmemb * size; /* size_t is unsigned so the behavior on overflow
+ * is defined. */
+ if (size && bytes / size != nmemb)
+ {
+ gpg_err_set_errno (ENOMEM);
+ return NULL;
+ }
+
+ p = gcry_realloc (a, bytes);
+ if (p && oldnmemb < nmemb)
+ {
+ /* OLDNMEMBS is lower than NMEMB thus the user asked for a
+ calloc. Clear all newly allocated members. */
+ oldbytes = oldnmemb * size;
+ if (size && oldbytes / size != oldnmemb)
+ {
+ xfree (p);
+ gpg_err_set_errno (ENOMEM);
+ return NULL;
+ }
+ memset (p + oldbytes, 0, bytes - oldbytes);
+ }
+ return p;
+}
+
+
+/* Die-on-error version of gnupg_reallocarray. */
+void *
+xreallocarray (void *a, size_t oldnmemb, size_t nmemb, size_t size)
+{
+ void *p = gnupg_reallocarray (a, oldnmemb, nmemb, size);
+ if (!p)
+ xoutofcore ();
+ return p;
+}
+
+
+/* A wrapper around gcry_cipher_algo_name to return the string
+ "AES-128" instead of "AES". Given that we have an alias in
+ libgcrypt for it, it does not harm to too much to return this other
+ string. Some users complained that we print "AES" but "AES192"
+ and "AES256". We can't fix that in libgcrypt but it is pretty
+ safe to do it in an application. */
+const char *
+gnupg_cipher_algo_name (int algo)
+{
+ const char *s;
+
+ s = gcry_cipher_algo_name (algo);
+ if (!strcmp (s, "AES"))
+ s = "AES128";
+ return s;
+}
+
+
+void
+obsolete_option (const char *configname, unsigned int configlineno,
+ const char *name)
+{
+ if (configname)
+ log_info (_("%s:%u: obsolete option \"%s\" - it has no effect\n"),
+ configname, configlineno, name);
+ else
+ log_info (_("WARNING: \"%s%s\" is an obsolete option - it has no effect\n"),
+ "--", name);
+}
+
+
+/* Decide whether the filename is stdout or a real filename and return
+ * an appropriate string. */
+const char *
+print_fname_stdout (const char *s)
+{
+ if( !s || (*s == '-' && !s[1]) )
+ return "[stdout]";
+ return s;
+}
+
+
+/* Decide whether the filename is stdin or a real filename and return
+ * an appropriate string. */
+const char *
+print_fname_stdin (const char *s)
+{
+ if( !s || (*s == '-' && !s[1]) )
+ return "[stdin]";
+ return s;
+}
+
+
+static int
+do_print_utf8_buffer (estream_t stream,
+ const void *buffer, size_t length,
+ const char *delimiters, size_t *bytes_written)
+{
+ const char *p = buffer;
+ size_t i;
+
+ /* We can handle plain ascii simpler, so check for it first. */
+ for (i=0; i < length; i++ )
+ {
+ if ( (p[i] & 0x80) )
+ break;
+ }
+ if (i < length)
+ {
+ int delim = delimiters? *delimiters : 0;
+ char *buf;
+ int ret;
+
+ /*(utf8 conversion already does the control character quoting). */
+ buf = utf8_to_native (p, length, delim);
+ if (bytes_written)
+ *bytes_written = strlen (buf);
+ ret = es_fputs (buf, stream);
+ xfree (buf);
+ return ret == EOF? ret : (int)i;
+ }
+ else
+ return es_write_sanitized (stream, p, length, delimiters, bytes_written);
+}
+
+
+void
+print_utf8_buffer3 (estream_t stream, const void *p, size_t n,
+ const char *delim)
+{
+ do_print_utf8_buffer (stream, p, n, delim, NULL);
+}
+
+
+void
+print_utf8_buffer2 (estream_t stream, const void *p, size_t n, int delim)
+{
+ char tmp[2];
+
+ tmp[0] = delim;
+ tmp[1] = 0;
+ do_print_utf8_buffer (stream, p, n, tmp, NULL);
+}
+
+
+void
+print_utf8_buffer (estream_t stream, const void *p, size_t n)
+{
+ do_print_utf8_buffer (stream, p, n, NULL, NULL);
+}
+
+
+void
+print_utf8_string (estream_t stream, const char *p)
+{
+ if (!p)
+ p = "";
+ do_print_utf8_buffer (stream, p, strlen (p), NULL, NULL);
+}
+
+
+/* Write LENGTH bytes of BUFFER to FP as a hex encoded string.
+ RESERVED must be 0. */
+void
+print_hexstring (FILE *fp, const void *buffer, size_t length, int reserved)
+{
+#define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A'))
+ const unsigned char *s;
+
+ (void)reserved;
+
+ for (s = buffer; length; s++, length--)
+ {
+ putc ( tohex ((*s>>4)&15), fp);
+ putc ( tohex (*s&15), fp);
+ }
+#undef tohex
+}
+
+
+/* Create a string from the buffer P_ARG of length N which is suitable
+ * for printing. Caller must release the created string using xfree.
+ * On error ERRNO is set and NULL returned. Errors are only possible
+ * due to malloc failure. */
+char *
+try_make_printable_string (const void *p_arg, size_t n, int delim)
+{
+ const unsigned char *p = p_arg;
+ size_t save_n, buflen;
+ const unsigned char *save_p;
+ char *buffer, *d;
+
+ /* First count length. */
+ for (save_n = n, save_p = p, buflen=1 ; n; n--, p++ )
+ {
+ if ( *p < 0x20 || *p == 0x7f || *p == delim || (delim && *p=='\\'))
+ {
+ if ( *p=='\n' || *p=='\r' || *p=='\f'
+ || *p=='\v' || *p=='\b' || !*p )
+ buflen += 2;
+ else
+ buflen += 5;
+ }
+ else
+ buflen++;
+ }
+ p = save_p;
+ n = save_n;
+ /* And now make the string */
+ d = buffer = xtrymalloc (buflen);
+ for ( ; n; n--, p++ )
+ {
+ if (*p < 0x20 || *p == 0x7f || *p == delim || (delim && *p=='\\')) {
+ *d++ = '\\';
+ if( *p == '\n' )
+ *d++ = 'n';
+ else if( *p == '\r' )
+ *d++ = 'r';
+ else if( *p == '\f' )
+ *d++ = 'f';
+ else if( *p == '\v' )
+ *d++ = 'v';
+ else if( *p == '\b' )
+ *d++ = 'b';
+ else if( !*p )
+ *d++ = '0';
+ else {
+ sprintf(d, "x%02x", *p );
+ d += 3;
+ }
+ }
+ else
+ *d++ = *p;
+ }
+ *d = 0;
+ return buffer;
+}
+
+
+/* Same as try_make_printable_string but terminates the process on
+ * memory shortage. */
+char *
+make_printable_string (const void *p, size_t n, int delim )
+{
+ char *string = try_make_printable_string (p, n, delim);
+ if (!string)
+ xoutofcore ();
+ return string;
+}
+
+
+/* Decode the C formatted string SRC and return the result in a newly
+ * allocated buffer. In error returns NULL and sets ERRNO. */
+char *
+decode_c_string (const char *src)
+{
+ char *buffer, *dst;
+ int val;
+
+ /* The converted string will never be larger than the original
+ string. */
+ buffer = dst = xtrymalloc (strlen (src) + 1);
+ if (!buffer)
+ return NULL;
+
+ while (*src)
+ {
+ if (*src != '\\')
+ {
+ *dst++ = *src++;
+ continue;
+ }
+
+#define DECODE_ONE(_m,_r) case _m: src += 2; *dst++ = _r; break;
+
+ switch (src[1])
+ {
+ DECODE_ONE ('n', '\n');
+ DECODE_ONE ('r', '\r');
+ DECODE_ONE ('f', '\f');
+ DECODE_ONE ('v', '\v');
+ DECODE_ONE ('b', '\b');
+ DECODE_ONE ('t', '\t');
+ DECODE_ONE ('\\', '\\');
+ DECODE_ONE ('\'', '\'');
+ DECODE_ONE ('\"', '\"');
+
+ case 'x':
+ val = hextobyte (src+2);
+ if (val == -1) /* Bad coding, keep as is. */
+ {
+ *dst++ = *src++;
+ *dst++ = *src++;
+ if (*src)
+ *dst++ = *src++;
+ if (*src)
+ *dst++ = *src++;
+ }
+ else if (!val)
+ {
+ /* A binary zero is not representable in a C string thus
+ * we keep the C-escaping. Note that this will also
+ * never be larger than the source string. */
+ *dst++ = '\\';
+ *dst++ = '0';
+ src += 4;
+ }
+ else
+ {
+ *(unsigned char *)dst++ = val;
+ src += 4;
+ }
+ break;
+
+ default: /* Bad coding; keep as is.. */
+ *dst++ = *src++;
+ *dst++ = *src++;
+ break;
+ }
+#undef DECODE_ONE
+ }
+ *dst++ = 0;
+
+ return buffer;
+}
+
+
+/* Check whether (BUF,LEN) is valid header for an OpenPGP compressed
+ * packet. LEN should be at least 6. */
+static int
+is_openpgp_compressed_packet (unsigned char *buf, size_t len)
+{
+ int c, ctb, pkttype;
+ int lenbytes;
+
+ ctb = *buf++; len--;
+ if (!(ctb & 0x80))
+ return 0; /* Invalid packet. */
+
+ if ((ctb & 0x40)) /* New style (OpenPGP) CTB. */
+ {
+ pkttype = (ctb & 0x3f);
+ if (!len)
+ return 0; /* Expected first length octet missing. */
+ c = *buf++; len--;
+ if (c < 192)
+ ;
+ else if (c < 224)
+ {
+ if (!len)
+ return 0; /* Expected second length octet missing. */
+ }
+ else if (c == 255)
+ {
+ if (len < 4)
+ return 0; /* Expected length octets missing */
+ }
+ }
+ else /* Old style CTB. */
+ {
+ pkttype = (ctb>>2)&0xf;
+ lenbytes = ((ctb&3)==3)? 0 : (1<<(ctb & 3));
+ if (len < lenbytes)
+ return 0; /* Not enough length bytes. */
+ }
+
+ return (pkttype == 8);
+}
+
+
+
+/*
+ * Check if the file is compressed.
+ */
+int
+is_file_compressed (const char *s, int *ret_rc)
+{
+ iobuf_t a;
+ byte buf[6];
+ int i;
+ int rc = 0;
+ int overflow;
+
+ struct magic_compress_s {
+ size_t len;
+ byte magic[4];
+ } magic[] = {
+ { 3, { 0x42, 0x5a, 0x68, 0x00 } }, /* bzip2 */
+ { 3, { 0x1f, 0x8b, 0x08, 0x00 } }, /* gzip */
+ { 4, { 0x50, 0x4b, 0x03, 0x04 } }, /* (pk)zip */
+ };
+
+ if ( iobuf_is_pipe_filename (s) || !ret_rc )
+ return 0; /* We can't check stdin or no file was given */
+
+ a = iobuf_open( s );
+ if ( a == NULL ) {
+ *ret_rc = gpg_error_from_syserror ();
+ return 0;
+ }
+ iobuf_ioctl (a, IOBUF_IOCTL_NO_CACHE, 1, NULL);
+
+ if ( iobuf_get_filelength( a, &overflow ) < 6 && !overflow) {
+ *ret_rc = 0;
+ goto leave;
+ }
+
+ if ( iobuf_read( a, buf, 6 ) == -1 ) {
+ *ret_rc = a->error;
+ goto leave;
+ }
+
+ for ( i = 0; i < DIM( magic ); i++ ) {
+ if ( !memcmp( buf, magic[i].magic, magic[i].len ) ) {
+ *ret_rc = 0;
+ rc = 1;
+ goto leave;
+ }
+ }
+
+ if (is_openpgp_compressed_packet (buf, 6))
+ {
+ *ret_rc = 0;
+ rc = 1;
+ }
+
+ leave:
+ iobuf_close( a );
+ return rc;
+}
+
+
+/* Try match against each substring of multistr, delimited by | */
+int
+match_multistr (const char *multistr,const char *match)
+{
+ do
+ {
+ size_t seglen = strcspn (multistr,"|");
+ if (!seglen)
+ break;
+ /* Using the localized strncasecmp! */
+ if (strncasecmp(multistr,match,seglen)==0)
+ return 1;
+ multistr += seglen;
+ if (*multistr == '|')
+ multistr++;
+ }
+ while (*multistr);
+
+ return 0;
+}
+
+
+
+/* Parse the first portion of the version number S and store it at
+ NUMBER. On success, the function returns a pointer into S starting
+ with the first character, which is not part of the initial number
+ portion; on failure, NULL is returned. */
+static const char*
+parse_version_number (const char *s, int *number)
+{
+ int val = 0;
+
+ if (*s == '0' && digitp (s+1))
+ return NULL; /* Leading zeros are not allowed. */
+ for (; digitp (s); s++ )
+ {
+ val *= 10;
+ val += *s - '0';
+ }
+ *number = val;
+ return val < 0? NULL : s;
+}
+
+/* Break up the complete string representation of the version number S,
+ which is expected to have this format:
+
+ <major number>.<minor number>.<micro number><patch level>.
+
+ The major, minor and micro number components will be stored at
+ MAJOR, MINOR and MICRO. On success, a pointer to the last
+ component, the patch level, will be returned; on failure, NULL will
+ be returned. */
+static const char *
+parse_version_string (const char *s, int *major, int *minor, int *micro)
+{
+ s = parse_version_number (s, major);
+ if (!s || *s != '.')
+ return NULL;
+ s++;
+ s = parse_version_number (s, minor);
+ if (!s || *s != '.')
+ return NULL;
+ s++;
+ s = parse_version_number (s, micro);
+ if (!s)
+ return NULL;
+ return s; /* Patchlevel. */
+}
+
+/* Return true if version string is at least version B. */
+int
+gnupg_compare_version (const char *a, const char *b)
+{
+ int a_major, a_minor, a_micro;
+ int b_major, b_minor, b_micro;
+ const char *a_plvl, *b_plvl;
+
+ if (!a || !b)
+ return 0;
+
+ /* Parse version A. */
+ a_plvl = parse_version_string (a, &a_major, &a_minor, &a_micro);
+ if (!a_plvl )
+ return 0; /* Invalid version number. */
+
+ /* Parse version B. */
+ b_plvl = parse_version_string (b, &b_major, &b_minor, &b_micro);
+ if (!b_plvl )
+ return 0; /* Invalid version number. */
+
+ /* Compare version numbers. */
+ return (a_major > b_major
+ || (a_major == b_major && a_minor > b_minor)
+ || (a_major == b_major && a_minor == b_minor
+ && a_micro > b_micro)
+ || (a_major == b_major && a_minor == b_minor
+ && a_micro == b_micro
+ && strcmp (a_plvl, b_plvl) >= 0));
+}
+
+
+
+/* Parse an --debug style argument. We allow the use of number values
+ * in the usual C notation or a string with comma separated keywords.
+ *
+ * Returns: 0 on success or -1 and ERRNO set on error. On success the
+ * supplied variable is updated by the parsed flags.
+ *
+ * If STRING is NULL the enabled debug flags are printed.
+ *
+ * See doc/DETAILS for a summary of used debug options.
+ */
+int
+parse_debug_flag (const char *string, unsigned int *debugvar,
+ const struct debug_flags_s *flags)
+
+{
+ unsigned long result = 0;
+ int i, j;
+
+ if (!string)
+ {
+ if (debugvar)
+ {
+ log_info ("enabled debug flags:");
+ for (i=0; flags[i].name; i++)
+ if ((*debugvar & flags[i].flag))
+ log_printf (" %s", flags[i].name);
+ log_printf ("\n");
+ }
+ return 0;
+ }
+
+ while (spacep (string))
+ string++;
+ if (*string == '-')
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!strcmp (string, "?") || !strcmp (string, "help"))
+ {
+ log_info ("available debug flags:\n");
+ for (i=0; flags[i].name; i++)
+ log_info (" %5u %s\n", flags[i].flag, flags[i].name);
+ if (flags[i].flag != 77)
+ exit (0);
+ }
+ else if (digitp (string))
+ {
+ errno = 0;
+ result = strtoul (string, NULL, 0);
+ if (result == ULONG_MAX && errno == ERANGE)
+ return -1;
+ }
+ else
+ {
+ char **words;
+ words = strtokenize (string, ",");
+ if (!words)
+ return -1;
+ for (i=0; words[i]; i++)
+ {
+ if (*words[i])
+ {
+ for (j=0; flags[j].name; j++)
+ if (!strcmp (words[i], flags[j].name))
+ {
+ result |= flags[j].flag;
+ break;
+ }
+ if (!flags[j].name)
+ {
+ if (!strcmp (words[i], "none"))
+ {
+ *debugvar = 0;
+ result = 0;
+ }
+ else if (!strcmp (words[i], "all"))
+ result = ~0;
+ else
+ log_info (_("unknown debug flag '%s' ignored\n"), words[i]);
+ }
+ }
+ }
+ xfree (words);
+ }
+
+ *debugvar |= result;
+ return 0;
+}
+
+
+
+/* Parse an --comaptibility_flags style argument consisting of comma
+ * separated strings.
+ *
+ * Returns: 0 on success or -1 and ERRNO set on error. On success the
+ * supplied variable is updated by the parsed flags.
+ *
+ * If STRING is NULL the enabled flags are printed.
+ */
+int
+parse_compatibility_flags (const char *string, unsigned int *flagvar,
+ const struct compatibility_flags_s *flags)
+
+{
+ unsigned long result = 0;
+ int i, j;
+
+ if (!string)
+ {
+ if (flagvar)
+ {
+ log_info ("enabled compatibility flags:");
+ for (i=0; flags[i].name; i++)
+ if ((*flagvar & flags[i].flag))
+ log_printf (" %s", flags[i].name);
+ log_printf ("\n");
+ }
+ return 0;
+ }
+
+ while (spacep (string))
+ string++;
+
+ if (!strcmp (string, "?") || !strcmp (string, "help"))
+ {
+ log_info ("available compatibility flags:\n");
+ for (i=0; flags[i].name; i++)
+ log_info (" %s\n", flags[i].name);
+ if (flags[i].flag != 77)
+ exit (0);
+ }
+ else
+ {
+ char **words;
+ words = strtokenize (string, ",");
+ if (!words)
+ return -1;
+ for (i=0; words[i]; i++)
+ {
+ if (*words[i])
+ {
+ for (j=0; flags[j].name; j++)
+ if (!strcmp (words[i], flags[j].name))
+ {
+ result |= flags[j].flag;
+ break;
+ }
+ if (!flags[j].name)
+ {
+ if (!strcmp (words[i], "none"))
+ {
+ *flagvar = 0;
+ result = 0;
+ }
+ else if (!strcmp (words[i], "all"))
+ result = ~0;
+ else
+ log_info ("unknown compatibility flag '%s' ignored\n",
+ words[i]);
+ }
+ }
+ }
+ xfree (words);
+ }
+
+ *flagvar |= result;
+ return 0;
+}
diff --git a/common/mischelp.c b/common/mischelp.c
new file mode 100644
index 0000000..ee85002
--- /dev/null
+++ b/common/mischelp.c
@@ -0,0 +1,205 @@
+/* mischelp.c - Miscellaneous helper functions
+ * Copyright (C) 1998, 2000, 2001, 2006, 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute and/or modify this
+ * part of GnuPG under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * 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 copies of the GNU General Public License
+ * and the GNU Lesser General Public License along with this program;
+ * if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#ifdef HAVE_W32_SYSTEM
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+#else /*!HAVE_W32_SYSTEM*/
+# include <sys/types.h>
+# include <sys/stat.h>
+# include <unistd.h>
+#endif /*!HAVE_W32_SYSTEM*/
+#include <errno.h>
+
+#include "util.h"
+#include "common-defs.h"
+#include "stringhelp.h"
+#include "utf8conv.h"
+#include "mischelp.h"
+
+
+void
+wipememory (void *ptr, size_t len)
+{
+#if defined(HAVE_W32_SYSTEM) && defined(SecureZeroMemory)
+ SecureZeroMemory (ptr, len);
+#elif defined(HAVE_EXPLICIT_BZERO)
+ explicit_bzero (ptr, len);
+#else
+ /* Prevent compiler from optimizing away the call to memset by accessing
+ memset through volatile pointer. */
+ static void *(*volatile memset_ptr)(void *, int, size_t) = (void *)memset;
+ memset_ptr (ptr, 0, len);
+#endif
+}
+
+
+/* Check whether the files NAME1 and NAME2 are identical. This is for
+ example achieved by comparing the inode numbers of the files. */
+int
+same_file_p (const char *name1, const char *name2)
+{
+ int yes;
+
+ /* First try a shortcut. */
+ if (!compare_filenames (name1, name2))
+ yes = 1;
+ else
+ {
+#ifdef HAVE_W32_SYSTEM
+ HANDLE file1, file2;
+ BY_HANDLE_FILE_INFORMATION info1, info2;
+ wchar_t *wname;
+
+ wname = gpgrt_fname_to_wchar (name1);
+ if (wname)
+ {
+ file1 = CreateFileW (wname, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
+ xfree (wname);
+ }
+ else
+ file1 = INVALID_HANDLE_VALUE;
+
+ if (file1 == INVALID_HANDLE_VALUE)
+ yes = 0; /* If we can't open the file, it is not the same. */
+ else
+ {
+ wname = gpgrt_fname_to_wchar (name2);
+ if (wname)
+ {
+ file2 = CreateFileW (wname, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
+ xfree (wname);
+ }
+ else
+ file2 = INVALID_HANDLE_VALUE;
+
+ if (file2 == INVALID_HANDLE_VALUE)
+ yes = 0; /* If we can't open the file, it is not the same. */
+ else
+ {
+ yes = (GetFileInformationByHandle (file1, &info1)
+ && GetFileInformationByHandle (file2, &info2)
+ && info1.dwVolumeSerialNumber==info2.dwVolumeSerialNumber
+ && info1.nFileIndexHigh == info2.nFileIndexHigh
+ && info1.nFileIndexLow == info2.nFileIndexLow);
+ CloseHandle (file2);
+ }
+ CloseHandle (file1);
+ }
+#else /*!HAVE_W32_SYSTEM*/
+ struct stat info1, info2;
+
+ yes = (!stat (name1, &info1) && !stat (name2, &info2)
+ && info1.st_dev == info2.st_dev && info1.st_ino == info2.st_ino);
+#endif /*!HAVE_W32_SYSTEM*/
+ }
+ return yes;
+}
+
+
+/*
+ timegm() is a GNU function that might not be available everywhere.
+ It's basically the inverse of gmtime() - you give it a struct tm,
+ and get back a time_t. It differs from mktime() in that it handles
+ the case where the struct tm is UTC and the local environment isn't.
+
+ Note, that this replacement implementation might not be thread-safe!
+
+ Some BSDs don't handle the putenv("foo") case properly, so we use
+ unsetenv if the platform has it to remove environment variables.
+*/
+#ifndef HAVE_TIMEGM
+time_t
+timegm (struct tm *tm)
+{
+#ifdef HAVE_W32_SYSTEM
+ /* This one is thread safe. */
+ SYSTEMTIME st;
+ FILETIME ft;
+ unsigned long long cnsecs;
+
+ st.wYear = tm->tm_year + 1900;
+ st.wMonth = tm->tm_mon + 1;
+ st.wDay = tm->tm_mday;
+ st.wHour = tm->tm_hour;
+ st.wMinute = tm->tm_min;
+ st.wSecond = tm->tm_sec;
+ st.wMilliseconds = 0; /* Not available. */
+ st.wDayOfWeek = 0; /* Ignored. */
+
+ /* System time is UTC thus the conversion is pretty easy. */
+ if (!SystemTimeToFileTime (&st, &ft))
+ {
+ gpg_err_set_errno (EINVAL);
+ return (time_t)(-1);
+ }
+
+ cnsecs = (((unsigned long long)ft.dwHighDateTime << 32)
+ | ft.dwLowDateTime);
+ cnsecs -= 116444736000000000ULL; /* The filetime epoch is 1601-01-01. */
+ return (time_t)(cnsecs / 10000000ULL);
+
+#else /* (Non thread safe implementation!) */
+
+ time_t answer;
+ char *zone;
+
+ zone=getenv("TZ");
+ putenv("TZ=UTC");
+ tzset();
+ answer=mktime(tm);
+ if(zone)
+ {
+ static char *old_zone;
+
+ if (!old_zone)
+ {
+ old_zone = malloc(3+strlen(zone)+1);
+ if (old_zone)
+ {
+ strcpy(old_zone,"TZ=");
+ strcat(old_zone,zone);
+ }
+ }
+ if (old_zone)
+ putenv (old_zone);
+ }
+ else
+ gnupg_unsetenv("TZ");
+
+ tzset();
+ return answer;
+#endif
+}
+#endif /*!HAVE_TIMEGM*/
diff --git a/common/mischelp.h b/common/mischelp.h
new file mode 100644
index 0000000..bdee5a4
--- /dev/null
+++ b/common/mischelp.h
@@ -0,0 +1,92 @@
+/* mischelp.h - Miscellaneous helper macros and functions
+ * Copyright (C) 1999, 2000, 2001, 2002, 2003,
+ * 2006, 2007, 2009 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute and/or modify this
+ * part of GnuPG under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * 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 copies of the GNU General Public License
+ * and the GNU Lesser General Public License along with this program;
+ * if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_COMMON_MISCHELP_H
+#define GNUPG_COMMON_MISCHELP_H
+
+
+/* Check whether the files NAME1 and NAME2 are identical. This is for
+ example achieved by comparing the inode numbers of the files. */
+int same_file_p (const char *name1, const char *name2);
+
+
+#ifndef HAVE_TIMEGM
+#include <time.h>
+time_t timegm (struct tm *tm);
+#endif /*!HAVE_TIMEGM*/
+
+
+#define DIM(v) (sizeof(v)/sizeof((v)[0]))
+#define DIMof(type,member) DIM(((type *)0)->member)
+
+/* To avoid that a compiler optimizes certain memset calls away,
+ wipememory function may be used instead. */
+void wipememory(void *ptr, size_t len);
+
+/* Include hacks which are mainly required for Slowaris. */
+#ifdef GNUPG_COMMON_NEED_AFLOCAL
+#ifndef HAVE_W32_SYSTEM
+# include <sys/socket.h>
+# include <sys/un.h>
+#else
+# ifdef HAVE_WINSOCK2_H
+# include <winsock2.h>
+# endif
+# include <windows.h>
+#endif
+
+#ifndef PF_LOCAL
+# ifdef PF_UNIX
+# define PF_LOCAL PF_UNIX
+# else
+# define PF_LOCAL AF_UNIX
+# endif
+#endif /*PF_LOCAL*/
+#ifndef AF_LOCAL
+# define AF_LOCAL AF_UNIX
+#endif /*AF_UNIX*/
+
+/* We used to avoid this macro in GnuPG and inlined the AF_LOCAL name
+ length computation directly with the little twist of adding 1 extra
+ byte. It seems that this was needed once on an old HP/UX box and
+ there are also rumours that 4.3 Reno and DEC systems need it. This
+ one-off buglet did not harm any current system until it came to Mac
+ OS X where the kernel (as of May 2009) exhibited a strange bug: The
+ systems basically froze in the connect call if the passed name
+ contained an invalid directory part. Ignore the old Unices. */
+#ifndef SUN_LEN
+# define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) \
+ + strlen ((ptr)->sun_path))
+#endif /*SUN_LEN*/
+#endif /*GNUPG_COMMON_NEED_AFLOCAL*/
+
+
+#endif /*GNUPG_COMMON_MISCHELP_H*/
diff --git a/common/mkdir_p.c b/common/mkdir_p.c
new file mode 100644
index 0000000..6fb98c3
--- /dev/null
+++ b/common/mkdir_p.c
@@ -0,0 +1,187 @@
+/* mkdir_p.c - Create a directory and any missing parents.
+ * Copyright (C) 2015 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <assert.h>
+#include <stdarg.h>
+
+#include "util.h"
+#include "stringhelp.h"
+#include "logging.h"
+#include "sysutils.h"
+#include "mkdir_p.h"
+
+
+gpg_error_t
+gnupg_amkdir_p (const char **directory_components)
+{
+ gpg_error_t err = 0;
+ int count;
+ char **dirs;
+ int i;
+
+ for (count = 0; directory_components[count]; count ++)
+ ;
+
+ /* log_debug ("%s: %d directory components.\n", __func__, count); */
+
+ dirs = xtrycalloc (count, sizeof *dirs);
+ if (!dirs)
+ return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
+
+ for (i = 0; directory_components[i]; i ++)
+ {
+ if (i == 0)
+ dirs[i] = make_filename_try (directory_components[i], NULL);
+ else
+ dirs[i] = make_filename_try (dirs[i-1], directory_components[i], NULL);
+ if (!dirs[i])
+ {
+ err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
+ goto out;
+ }
+
+ /* log_debug ("%s: Directory %d: `%s'.\n", __func__, i, dirs[i]); */
+ }
+
+ for (i = count - 1; i >= 0; i --)
+ {
+ struct stat s;
+
+ /* log_debug ("%s: stat(%s)\n", __func__, dirs[i]); */
+
+ if (!gnupg_stat (dirs[i], &s))
+ {
+ if ( ! S_ISDIR (s.st_mode))
+ {
+ /* log_debug ("%s: %s exists, but is not a directory!\n", */
+ /* __func__, dirs[i]); */
+ err = gpg_err_make (default_errsource, GPG_ERR_ENOTDIR);
+ goto out;
+ }
+ else
+ {
+ /* Got a directory. */
+ /* log_debug ("%s: %s exists and is a directory!\n", */
+ /* __func__, dirs[i]); */
+ err = 0;
+ break;
+ }
+ }
+ else if (errno == ENOENT)
+ /* This directory does not exist yet. Continue walking up the
+ hierarchy. */
+ {
+ /* log_debug ("%s: %s does not exist!\n", */
+ /* __func__, dirs[i]); */
+ continue;
+ }
+ else
+ /* Some other error code. Die. Note: this could be ENOTDIR
+ (we return this above), which means that a component of the
+ path prefix is not a directory. */
+ {
+ /* log_debug ("%s: stat(%s) => %s!\n", */
+ /* __func__, dirs[i], strerror (errno)); */
+ err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
+ goto out;
+ }
+ }
+
+ assert (i >= -1);
+ /* DIRS[I] exists. Start with the following entry. */
+ i ++;
+
+ for (; i < count; i ++)
+ {
+ /* log_debug ("Creating directory: %s\n", dirs[i]); */
+
+ if (gnupg_mkdir (dirs[i], "-rwx"))
+ {
+ err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
+ goto out;
+ }
+ }
+
+ out:
+ for (i = 0; i < count; i ++)
+ xfree (dirs[i]);
+ xfree (dirs);
+
+ /* log_debug ("%s: Returning %s\n", __func__, gpg_strerror (rc)); */
+
+ return err;
+}
+
+
+gpg_error_t
+gnupg_mkdir_p (const char *directory_component, ...)
+{
+ va_list ap;
+ gpg_error_t err = 0;
+ int i;
+ int space = 1;
+ const char **dirs;
+
+ dirs = xtrymalloc (space * sizeof (char *));
+ if (!dirs)
+ return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
+
+ dirs[0] = directory_component;
+
+ va_start (ap, directory_component);
+ for (i = 1; dirs[i - 1]; i ++)
+ {
+ if (i == space)
+ {
+ const char **tmp_dirs;
+
+ space = 2 * space;
+ tmp_dirs = xtryrealloc (dirs, space * sizeof (char *));
+ if (!tmp_dirs)
+ {
+ err = gpg_err_make (default_errsource,
+ gpg_err_code_from_syserror ());
+ break;
+ }
+ dirs = tmp_dirs;
+ }
+ dirs[i] = va_arg (ap, char *);
+ }
+ va_end (ap);
+
+ if (!err)
+ err = gnupg_amkdir_p (dirs);
+
+ xfree (dirs);
+
+ return err;
+}
diff --git a/common/mkdir_p.h b/common/mkdir_p.h
new file mode 100644
index 0000000..1e939b3
--- /dev/null
+++ b/common/mkdir_p.h
@@ -0,0 +1,52 @@
+/* mkdir_p.h - Create a directory and any missing parents.
+ * Copyright (C) 2015 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef MKDIR_P_H
+#define MKDIR_P_H
+
+#include "types.h"
+
+/* Create a directory as well as any missing parents.
+
+ The arguments must be NULL termianted. If DIRECTORY_COMPONENTS...
+ consists of two elements, "foo/bar" and "xyzzy", this function will
+ first try to create the directory "foo/bar" and then the directory
+ "foo/bar/xyzzy". On success returns 0, otherwise an error code is
+ returned. */
+gpg_error_t gnupg_mkdir_p (const char *directory_component, ...) GPGRT_ATTR_SENTINEL(0);
+
+/* Like mkdir_p, but DIRECTORY_COMPONENTS is a NULL terminated
+ array, e.g.:
+
+ char **dirs = { "foo", "bar", NULL };
+ amkdir_p (dirs);
+ */
+gpg_error_t gnupg_amkdir_p (const char **directory_components);
+
+#endif
diff --git a/common/mkstrtable.awk b/common/mkstrtable.awk
new file mode 100644
index 0000000..60efce8
--- /dev/null
+++ b/common/mkstrtable.awk
@@ -0,0 +1,185 @@
+# mkstrtable.awk
+# Copyright (C) 2003, 2004 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, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception, g10 Code GmbH gives unlimited permission to
+# copy, distribute and modify the C source files that are the output
+# of mkstrtable.awk. You need not follow the terms of the GNU General
+# Public License when using or distributing such scripts, even though
+# portions of the text of mkstrtable.awk appear in them. The GNU
+# General Public License (GPL) does govern all other use of the material
+# that constitutes the mkstrtable.awk program.
+#
+# Certain portions of the mkstrtable.awk source text are designed to be
+# copied (in certain cases, depending on the input) into the output of
+# mkstrtable.awk. We call these the "data" portions. The rest of the
+# mkstrtable.awk source text consists of comments plus executable code
+# that decides which of the data portions to output in any given case.
+# We call these comments and executable code the "non-data" portions.
+# mkstrtable.h never copies any of the non-data portions into its output.
+#
+# This special exception to the GPL applies to versions of mkstrtable.awk
+# released by g10 Code GmbH. When you make and distribute a modified version
+# of mkstrtable.awk, you may extend this special exception to the GPL to
+# apply to your modified version as well, *unless* your modified version
+# has the potential to copy into its output some of the text that was the
+# non-data portion of the version that you started with. (In other words,
+# unless your change moves or copies text from the non-data portions to the
+# data portions.) If your modification has such potential, you must delete
+# any notice of this special exception to the GPL from your modified version.
+
+# This script outputs a source file that does define the following
+# symbols:
+#
+# static const char msgstr[];
+# A string containing all messages in the list.
+#
+# static const int msgidx[];
+# A list of index numbers, one for each message, that points to the
+# beginning of the string in msgstr.
+#
+# msgidxof (code);
+# A macro that maps code numbers to idx numbers. If a DEFAULT MESSAGE
+# is provided (see below), its index will be returned for unknown codes.
+# Otherwise -1 is returned for codes that do not appear in the list.
+# You can lookup the message with code CODE with:
+# msgstr + msgidx[msgidxof (code)].
+#
+# The input file has the following format:
+# CODE1 ... MESSAGE1 (code nr, <tab>, something, <tab>, msg)
+# CODE2 ... MESSAGE2 (code nr, <tab>, something, <tab>, msg)
+# ...
+# CODEn ... MESSAGEn (code nr, <tab>, something, <tab>, msg)
+# ... DEFAULT-MESSAGE (<tab>, something, <tab>, fall-back msg)
+#
+# Comments (starting with # and ending at the end of the line) are removed,
+# as is trailing whitespace. The last line is optional; if no DEFAULT
+# MESSAGE is given, msgidxof will return the number -1 for unknown
+# index numbers.
+#
+# The field to be used is specified with the variable "textidx" on
+# the command line. It defaults to 2.
+#
+# The variable nogettext can be set to 1 to suppress gettext markers.
+#
+# The variable prefix can be used to prepend a string to each message.
+#
+# The variable pkg_namespace can be used to prepend a string to each
+# variable and macro name.
+
+BEGIN {
+ FS = "[\t]+";
+# cpos holds the current position in the message string.
+ cpos = 0;
+# msg holds the number of messages.
+ msg = 0;
+ print "/* Output of mkstrtable.awk. DO NOT EDIT. */";
+ print "";
+ header = 1;
+ if (textidx == 0)
+ textidx = 2;
+# nogettext can be set to 1 to suppress gettext noop markers.
+}
+
+/^#/ { next; }
+
+header {
+ if ($1 ~ /^[0123456789]+$/)
+ {
+ print "/* The purpose of this complex string table is to produce";
+ print " optimal code with a minimum of relocations. */";
+ print "";
+ print "static const char " pkg_namespace "msgstr[] = ";
+ header = 0;
+ }
+ else
+ print;
+}
+
+!header {
+ sub (/#.+/, "");
+ sub (/[ ]+$/, ""); # Strip trailing space and tab characters.
+
+ if (/^$/)
+ next;
+
+# Print the string msgstr line by line. We delay output by one line to be able
+# to treat the last line differently (see END).
+ if (last_msgstr)
+ {
+ if (nogettext)
+ print " \"" last_msgstr "\" \"\\0\"";
+ else
+ print " gettext_noop (\"" last_msgstr "\") \"\\0\"";
+ }
+ last_msgstr = prefix $textidx;
+
+# Remember the error code and msgidx of each error message.
+ code[msg] = $1;
+ pos[msg] = cpos;
+ cpos += length (last_msgstr) + 1;
+ msg++;
+
+ if ($1 == "")
+ {
+ has_default = 1;
+ exit;
+ }
+}
+END {
+ if (has_default)
+ coded_msgs = msg - 1;
+ else
+ coded_msgs = msg;
+
+ if (nogettext)
+ print " \"" prefix last_msgstr "\";";
+ else
+ print " gettext_noop (\"" prefix last_msgstr "\");";
+ print "";
+ print "static const int " pkg_namespace "msgidx[] =";
+ print " {";
+ for (i = 0; i < coded_msgs; i++)
+ print " " pos[i] ",";
+ print " " pos[coded_msgs];
+ print " };";
+ print "";
+ print "#define " pkg_namespace "msgidxof(code) (0 ? -1 \\";
+
+# Gather the ranges.
+ skip = code[0];
+ start = code[0];
+ stop = code[0];
+ for (i = 1; i < coded_msgs; i++)
+ {
+ if (code[i] == stop + 1)
+ stop++;
+ else
+ {
+ print " : ((code >= " start ") && (code <= " stop ")) ? (code - " \
+ skip ") \\";
+ skip += code[i] - stop - 1;
+ start = code[i];
+ stop = code[i];
+ }
+ }
+ print " : ((code >= " start ") && (code <= " stop ")) ? (code - " \
+ skip ") \\";
+ if (has_default)
+ print " : " stop + 1 " - " skip ")";
+ else
+ print " : -1)";
+
+ }
diff --git a/common/name-value.c b/common/name-value.c
new file mode 100644
index 0000000..b9b13d1
--- /dev/null
+++ b/common/name-value.c
@@ -0,0 +1,908 @@
+/* name-value.c - Parser and writer for a name-value format.
+ * Copyright (C) 2016 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+/*
+ * This module aso provides features for the extended private key
+ * format of gpg-agent.
+ */
+
+#include <config.h>
+#include <assert.h>
+#include <gcrypt.h>
+#include <gpg-error.h>
+#include <string.h>
+
+#include "mischelp.h"
+#include "strlist.h"
+#include "util.h"
+#include "name-value.h"
+
+struct name_value_container
+{
+ struct name_value_entry *first;
+ struct name_value_entry *last;
+ unsigned int private_key_mode:1;
+};
+
+
+struct name_value_entry
+{
+ struct name_value_entry *prev;
+ struct name_value_entry *next;
+
+ /* The name. Comments and blank lines have NAME set to NULL. */
+ char *name;
+
+ /* The value as stored in the file. We store it when we parse
+ a file so that we can reproduce it. */
+ strlist_t raw_value;
+
+ /* The decoded value. */
+ char *value;
+};
+
+
+/* Helper */
+static inline gpg_error_t
+my_error_from_syserror (void)
+{
+ return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
+}
+
+
+static inline gpg_error_t
+my_error (gpg_err_code_t ec)
+{
+ return gpg_err_make (default_errsource, ec);
+}
+
+
+
+
+/* Allocation and deallocation. */
+
+/* Allocate a private key container structure. */
+nvc_t
+nvc_new (void)
+{
+ return xtrycalloc (1, sizeof (struct name_value_container));
+}
+
+
+/* Allocate a private key container structure for use with private keys. */
+nvc_t
+nvc_new_private_key (void)
+{
+ nvc_t nvc = nvc_new ();
+ if (nvc)
+ nvc->private_key_mode = 1;
+ return nvc;
+}
+
+
+static void
+nve_release (nve_t entry, int private_key_mode)
+{
+ if (entry == NULL)
+ return;
+
+ xfree (entry->name);
+ if (entry->value && private_key_mode)
+ wipememory (entry->value, strlen (entry->value));
+ xfree (entry->value);
+ if (private_key_mode)
+ free_strlist_wipe (entry->raw_value);
+ else
+ free_strlist (entry->raw_value);
+ xfree (entry);
+}
+
+
+/* Release a private key container structure. */
+void
+nvc_release (nvc_t pk)
+{
+ nve_t e, next;
+
+ if (pk == NULL)
+ return;
+
+ for (e = pk->first; e; e = next)
+ {
+ next = e->next;
+ nve_release (e, pk->private_key_mode);
+ }
+
+ xfree (pk);
+}
+
+
+
+/* Dealing with names and values. */
+
+/* Check whether the given name is valid. Valid names start with a
+ letter, end with a colon, and contain only alphanumeric characters
+ and the hyphen. */
+static int
+valid_name (const char *name)
+{
+ size_t i, len = strlen (name);
+
+ if (! alphap (name) || len == 0 || name[len - 1] != ':')
+ return 0;
+
+ for (i = 1; i < len - 1; i++)
+ if (! alnump (&name[i]) && name[i] != '-')
+ return 0;
+
+ return 1;
+}
+
+
+/* Makes sure that ENTRY has a RAW_VALUE. */
+static gpg_error_t
+assert_raw_value (nve_t entry)
+{
+ gpg_error_t err = 0;
+ size_t len, offset;
+#define LINELEN 70
+ char buf[LINELEN+3];
+
+ if (entry->raw_value)
+ return 0;
+
+ len = strlen (entry->value);
+ offset = 0;
+ while (len)
+ {
+ size_t amount, linelen = LINELEN;
+
+ /* On the first line we need to subtract space for the name. */
+ if (entry->raw_value == NULL && strlen (entry->name) < linelen)
+ linelen -= strlen (entry->name);
+
+ /* See if the rest of the value fits in this line. */
+ if (len <= linelen)
+ amount = len;
+ else
+ {
+ size_t i;
+
+ /* Find a suitable space to break on. */
+ for (i = linelen - 1; linelen - i < 30; i--)
+ if (ascii_isspace (entry->value[offset+i]))
+ break;
+
+ if (ascii_isspace (entry->value[offset+i]))
+ {
+ /* Found one. */
+ amount = i;
+ }
+ else
+ {
+ /* Just induce a hard break. */
+ amount = linelen;
+ }
+ }
+
+ snprintf (buf, sizeof buf, " %.*s\n", (int) amount,
+ &entry->value[offset]);
+ if (append_to_strlist_try (&entry->raw_value, buf) == NULL)
+ {
+ err = my_error_from_syserror ();
+ goto leave;
+ }
+
+ offset += amount;
+ len -= amount;
+ }
+
+ leave:
+ if (err)
+ {
+ free_strlist_wipe (entry->raw_value);
+ entry->raw_value = NULL;
+ }
+
+ return err;
+#undef LINELEN
+}
+
+
+/* Computes the length of the value encoded as continuation. If
+ *SWALLOW_WS is set, all whitespace at the beginning of S is
+ swallowed. If START is given, a pointer to the beginning of the
+ value is stored there. */
+static size_t
+continuation_length (const char *s, int *swallow_ws, const char **start)
+{
+ size_t len;
+
+ if (*swallow_ws)
+ {
+ /* The previous line was a blank line and we inserted a newline.
+ Swallow all whitespace at the beginning of this line. */
+ while (ascii_isspace (*s))
+ s++;
+ }
+ else
+ {
+ /* Iff a continuation starts with more than one space, it
+ encodes a space. */
+ if (ascii_isspace (*s))
+ s++;
+ }
+
+ /* Strip whitespace at the end. */
+ len = strlen (s);
+ while (len > 0 && ascii_isspace (s[len-1]))
+ len--;
+
+ if (len == 0)
+ {
+ /* Blank lines encode newlines. */
+ len = 1;
+ s = "\n";
+ *swallow_ws = 1;
+ }
+ else
+ *swallow_ws = 0;
+
+ if (start)
+ *start = s;
+
+ return len;
+}
+
+
+/* Makes sure that ENTRY has a VALUE. */
+static gpg_error_t
+assert_value (nve_t entry)
+{
+ size_t len;
+ int swallow_ws;
+ strlist_t s;
+ char *p;
+
+ if (entry->value)
+ return 0;
+
+ len = 0;
+ swallow_ws = 0;
+ for (s = entry->raw_value; s; s = s->next)
+ len += continuation_length (s->d, &swallow_ws, NULL);
+
+ /* Add one for the terminating zero. */
+ len += 1;
+
+ entry->value = p = xtrymalloc (len);
+ if (entry->value == NULL)
+ return my_error_from_syserror ();
+
+ swallow_ws = 0;
+ for (s = entry->raw_value; s; s = s->next)
+ {
+ const char *start;
+ size_t l = continuation_length (s->d, &swallow_ws, &start);
+
+ memcpy (p, start, l);
+ p += l;
+ }
+
+ *p++ = 0;
+ assert (p - entry->value == len);
+
+ return 0;
+}
+
+
+/* Get the name. */
+char *
+nve_name (nve_t pke)
+{
+ return pke->name;
+}
+
+
+/* Get the value. */
+char *
+nve_value (nve_t pke)
+{
+ if (assert_value (pke))
+ return NULL;
+ return pke->value;
+}
+
+
+
+/* Adding and modifying values. */
+
+/* Add (NAME, VALUE, RAW_VALUE) to PK. NAME may be NULL for comments
+ and blank lines. At least one of VALUE and RAW_VALUE must be
+ given. If PRESERVE_ORDER is not given, entries with the same name
+ are grouped. NAME, VALUE and RAW_VALUE is consumed. */
+static gpg_error_t
+_nvc_add (nvc_t pk, char *name, char *value, strlist_t raw_value,
+ int preserve_order)
+{
+ gpg_error_t err = 0;
+ nve_t e;
+
+ assert (value || raw_value);
+
+ if (name && ! valid_name (name))
+ {
+ err = my_error (GPG_ERR_INV_NAME);
+ goto leave;
+ }
+
+ if (name
+ && pk->private_key_mode
+ && !ascii_strcasecmp (name, "Key:")
+ && nvc_lookup (pk, "Key:"))
+ {
+ err = my_error (GPG_ERR_INV_NAME);
+ goto leave;
+ }
+
+ e = xtrycalloc (1, sizeof *e);
+ if (e == NULL)
+ {
+ err = my_error_from_syserror ();
+ goto leave;
+ }
+
+ e->name = name;
+ e->value = value;
+ e->raw_value = raw_value;
+
+ if (pk->first)
+ {
+ nve_t last;
+
+ if (preserve_order || name == NULL)
+ last = pk->last;
+ else
+ {
+ /* See if there is already an entry with NAME. */
+ last = nvc_lookup (pk, name);
+
+ /* If so, find the last in that block. */
+ if (last)
+ {
+ while (last->next)
+ {
+ nve_t next = last->next;
+
+ if (next->name && ascii_strcasecmp (next->name, name) == 0)
+ last = next;
+ else
+ break;
+ }
+ }
+ else /* Otherwise, just find the last entry. */
+ last = pk->last;
+ }
+
+ if (last->next)
+ {
+ e->prev = last;
+ e->next = last->next;
+ last->next = e;
+ e->next->prev = e;
+ }
+ else
+ {
+ e->prev = last;
+ last->next = e;
+ pk->last = e;
+ }
+ }
+ else
+ pk->first = pk->last = e;
+
+ leave:
+ if (err)
+ {
+ xfree (name);
+ if (value)
+ wipememory (value, strlen (value));
+ xfree (value);
+ free_strlist_wipe (raw_value);
+ }
+
+ return err;
+}
+
+
+/* Add (NAME, VALUE) to PK. If an entry with NAME already exists, it
+ is not updated but the new entry is appended. */
+gpg_error_t
+nvc_add (nvc_t pk, const char *name, const char *value)
+{
+ char *k, *v;
+
+ k = xtrystrdup (name);
+ if (k == NULL)
+ return my_error_from_syserror ();
+
+ v = xtrystrdup (value);
+ if (v == NULL)
+ {
+ xfree (k);
+ return my_error_from_syserror ();
+ }
+
+ return _nvc_add (pk, k, v, NULL, 0);
+}
+
+
+/* Add (NAME, VALUE) to PK. If an entry with NAME already exists, it
+ is updated with VALUE. If multiple entries with NAME exist, the
+ first entry is updated. */
+gpg_error_t
+nvc_set (nvc_t pk, const char *name, const char *value)
+{
+ nve_t e;
+
+ if (! valid_name (name))
+ return GPG_ERR_INV_NAME;
+
+ e = nvc_lookup (pk, name);
+ if (e)
+ return nve_set (e, value);
+ else
+ return nvc_add (pk, name, value);
+}
+
+
+/* Update entry E to VALUE. */
+gpg_error_t
+nve_set (nve_t e, const char *value)
+{
+ char *v;
+
+ if (!e)
+ return GPG_ERR_INV_ARG;
+
+ v = xtrystrdup (value? value:"");
+ if (!v)
+ return my_error_from_syserror ();
+
+ free_strlist_wipe (e->raw_value);
+ e->raw_value = NULL;
+ if (e->value)
+ wipememory (e->value, strlen (e->value));
+ xfree (e->value);
+ e->value = v;
+
+ return 0;
+}
+
+
+/* Delete the given entry from PK. */
+void
+nvc_delete (nvc_t pk, nve_t entry)
+{
+ if (entry->prev)
+ entry->prev->next = entry->next;
+ else
+ pk->first = entry->next;
+
+ if (entry->next)
+ entry->next->prev = entry->prev;
+ else
+ pk->last = entry->prev;
+
+ nve_release (entry, pk->private_key_mode);
+}
+
+/* Delete the entries with NAME from PK. */
+void
+nvc_delete_named (nvc_t pk, const char *name)
+{
+ nve_t e;
+
+ if (!valid_name (name))
+ return;
+
+ while ((e = nvc_lookup (pk, name)))
+ nvc_delete (pk, e);
+}
+
+
+
+
+/* Lookup and iteration. */
+
+/* Get the first non-comment entry. */
+nve_t
+nvc_first (nvc_t pk)
+{
+ nve_t entry;
+
+ if (!pk)
+ return NULL;
+
+ for (entry = pk->first; entry; entry = entry->next)
+ if (entry->name)
+ return entry;
+
+ return NULL;
+}
+
+
+/* Get the first entry with the given name. Return NULL if it does
+ * not exist. */
+nve_t
+nvc_lookup (nvc_t pk, const char *name)
+{
+ nve_t entry;
+
+ if (!pk)
+ return NULL;
+
+ for (entry = pk->first; entry; entry = entry->next)
+ if (entry->name && ascii_strcasecmp (entry->name, name) == 0)
+ return entry;
+
+ return NULL;
+}
+
+
+/* Get the next non-comment entry. */
+nve_t
+nve_next (nve_t entry)
+{
+ for (entry = entry->next; entry; entry = entry->next)
+ if (entry->name)
+ return entry;
+ return NULL;
+}
+
+
+/* Get the next entry with the given name. */
+nve_t
+nve_next_value (nve_t entry, const char *name)
+{
+ for (entry = entry->next; entry; entry = entry->next)
+ if (entry->name && ascii_strcasecmp (entry->name, name) == 0)
+ return entry;
+ return NULL;
+}
+
+
+/* Return the string for the first entry in NVC with NAME. If an
+ * entry with NAME is missing in NVC or its value is the empty string
+ * NULL is returned. Note that the returned string is a pointer
+ * into NVC. */
+const char *
+nvc_get_string (nvc_t nvc, const char *name)
+{
+ nve_t item;
+
+ if (!nvc)
+ return NULL;
+ item = nvc_lookup (nvc, name);
+ if (!item)
+ return NULL;
+ return nve_value (item);
+}
+
+
+/* Return true if NAME exists and its value is true; that is either
+ * "yes", "true", or a decimal value unequal to 0. */
+int
+nvc_get_boolean (nvc_t nvc, const char *name)
+{
+ nve_t item;
+ const char *s;
+
+ if (!nvc)
+ return 0;
+ item = nvc_lookup (nvc, name);
+ if (!item)
+ return 0;
+ s = nve_value (item);
+ if (s && (atoi (s)
+ || !ascii_strcasecmp (s, "yes")
+ || !ascii_strcasecmp (s, "true")))
+ return 1;
+ return 0;
+}
+
+
+
+/* Private key handling. */
+
+/* Get the private key. */
+gpg_error_t
+nvc_get_private_key (nvc_t pk, gcry_sexp_t *retsexp)
+{
+ gpg_error_t err;
+ nve_t e;
+
+ e = pk->private_key_mode? nvc_lookup (pk, "Key:") : NULL;
+ if (e == NULL)
+ return my_error (GPG_ERR_MISSING_KEY);
+
+ err = assert_value (e);
+ if (err)
+ return err;
+
+ return gcry_sexp_sscan (retsexp, NULL, e->value, strlen (e->value));
+}
+
+
+/* Set the private key. */
+gpg_error_t
+nvc_set_private_key (nvc_t pk, gcry_sexp_t sexp)
+{
+ gpg_error_t err;
+ char *raw, *clean, *p;
+ size_t len, i;
+
+ if (!pk->private_key_mode)
+ return my_error (GPG_ERR_MISSING_KEY);
+
+ len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_ADVANCED, NULL, 0);
+
+ raw = xtrymalloc (len);
+ if (raw == NULL)
+ return my_error_from_syserror ();
+
+ clean = xtrymalloc (len);
+ if (clean == NULL)
+ {
+ xfree (raw);
+ return my_error_from_syserror ();
+ }
+
+ gcry_sexp_sprint (sexp, GCRYSEXP_FMT_ADVANCED, raw, len);
+
+ /* Strip any whitespace at the end. */
+ i = strlen (raw) - 1;
+ while (i && ascii_isspace (raw[i]))
+ {
+ raw[i] = 0;
+ i--;
+ }
+
+ /* Replace any newlines with spaces, remove superfluous whitespace. */
+ len = strlen (raw);
+ for (p = clean, i = 0; i < len; i++)
+ {
+ char c = raw[i];
+
+ /* Collapse contiguous and superfluous spaces. */
+ if (ascii_isspace (c) && i > 0
+ && (ascii_isspace (raw[i-1]) || raw[i-1] == '(' || raw[i-1] == ')'))
+ continue;
+
+ if (c == '\n')
+ c = ' ';
+
+ *p++ = c;
+ }
+ *p = 0;
+
+ err = nvc_set (pk, "Key:", clean);
+ xfree (raw);
+ xfree (clean);
+ return err;
+}
+
+
+
+/* Parsing and serialization. */
+
+static gpg_error_t
+do_nvc_parse (nvc_t *result, int *errlinep, estream_t stream,
+ int for_private_key)
+{
+ gpg_error_t err = 0;
+ gpgrt_ssize_t len;
+ char *buf = NULL;
+ size_t buf_len = 0;
+ char *name = NULL;
+ strlist_t raw_value = NULL;
+
+ *result = for_private_key? nvc_new_private_key () : nvc_new ();
+ if (*result == NULL)
+ return my_error_from_syserror ();
+
+ if (errlinep)
+ *errlinep = 0;
+ while ((len = es_read_line (stream, &buf, &buf_len, NULL)) > 0)
+ {
+ char *p;
+ if (errlinep)
+ *errlinep += 1;
+
+ /* Skip any whitespace. */
+ for (p = buf; *p && ascii_isspace (*p); p++)
+ /* Do nothing. */;
+
+ if (name && (spacep (buf) || *p == 0))
+ {
+ /* A continuation. */
+ if (append_to_strlist_try (&raw_value, buf) == NULL)
+ {
+ err = my_error_from_syserror ();
+ goto leave;
+ }
+ continue;
+ }
+
+ /* No continuation. Add the current entry if any. */
+ if (raw_value)
+ {
+ err = _nvc_add (*result, name, NULL, raw_value, 1);
+ name = NULL;
+ if (err)
+ goto leave;
+ }
+
+ /* And prepare for the next one. */
+ name = NULL;
+ raw_value = NULL;
+
+ if (*p != 0 && *p != '#')
+ {
+ char *colon, *value, tmp;
+
+ colon = strchr (buf, ':');
+ if (colon == NULL)
+ {
+ err = my_error (GPG_ERR_INV_VALUE);
+ goto leave;
+ }
+
+ value = colon + 1;
+ tmp = *value;
+ *value = 0;
+ name = xtrystrdup (p);
+ *value = tmp;
+
+ if (name == NULL)
+ {
+ err = my_error_from_syserror ();
+ goto leave;
+ }
+
+ if (append_to_strlist_try (&raw_value, value) == NULL)
+ {
+ err = my_error_from_syserror ();
+ goto leave;
+ }
+ continue;
+ }
+
+ if (append_to_strlist_try (&raw_value, buf) == NULL)
+ {
+ err = my_error_from_syserror ();
+ goto leave;
+ }
+ }
+ if (len < 0)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+
+ /* Add the final entry. */
+ if (raw_value)
+ err = _nvc_add (*result, name, NULL, raw_value, 1);
+
+ leave:
+ gpgrt_free (buf);
+ if (err)
+ {
+ nvc_release (*result);
+ *result = NULL;
+ }
+
+ return err;
+}
+
+
+/* Parse STREAM and return a newly allocated name value container
+ structure in RESULT. If ERRLINEP is given, the line number the
+ parser was last considering is stored there. */
+gpg_error_t
+nvc_parse (nvc_t *result, int *errlinep, estream_t stream)
+{
+ return do_nvc_parse (result, errlinep, stream, 0);
+}
+
+
+/* Parse STREAM and return a newly allocated name value container
+ structure in RESULT - assuming the extended private key format. If
+ ERRLINEP is given, the line number the parser was last considering
+ is stored there. */
+gpg_error_t
+nvc_parse_private_key (nvc_t *result, int *errlinep, estream_t stream)
+{
+ return do_nvc_parse (result, errlinep, stream, 1);
+}
+
+
+/* Helper fpr nvc_write. */
+static gpg_error_t
+write_one_entry (nve_t entry, estream_t stream)
+{
+ gpg_error_t err;
+ strlist_t sl;
+
+ if (entry->name)
+ es_fputs (entry->name, stream);
+
+ err = assert_raw_value (entry);
+ if (err)
+ return err;
+
+ for (sl = entry->raw_value; sl; sl = sl->next)
+ es_fputs (sl->d, stream);
+
+ if (es_ferror (stream))
+ return my_error_from_syserror ();
+
+ return 0;
+}
+
+
+/* Write a representation of PK to STREAM. */
+gpg_error_t
+nvc_write (nvc_t pk, estream_t stream)
+{
+ gpg_error_t err = 0;
+ nve_t entry;
+ nve_t keyentry = NULL;
+
+ for (entry = pk->first; entry; entry = entry->next)
+ {
+ if (pk->private_key_mode
+ && entry->name && !ascii_strcasecmp (entry->name, "Key:"))
+ {
+ if (!keyentry)
+ keyentry = entry;
+ continue;
+ }
+
+ err = write_one_entry (entry, stream);
+ if (err)
+ return err;
+ }
+
+ /* In private key mode we write the Key always last. */
+ if (keyentry)
+ err = write_one_entry (keyentry, stream);
+
+ return err;
+}
diff --git a/common/name-value.h b/common/name-value.h
new file mode 100644
index 0000000..fd0a98c
--- /dev/null
+++ b/common/name-value.h
@@ -0,0 +1,132 @@
+/* name-value.h - Parser and writer for a name-value format.
+ * Copyright (C) 2016 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_COMMON_NAME_VALUE_H
+#define GNUPG_COMMON_NAME_VALUE_H
+
+struct name_value_container;
+typedef struct name_value_container *nvc_t;
+
+struct name_value_entry;
+typedef struct name_value_entry *nve_t;
+
+
+
+/* Memory management, and dealing with entries. */
+
+/* Allocate a name value container structure. */
+nvc_t nvc_new (void);
+
+/* Allocate a name value container structure for use with the extended
+ * private key format. */
+nvc_t nvc_new_private_key (void);
+
+/* Release a name value container structure. */
+void nvc_release (nvc_t pk);
+
+/* Get the name. */
+char *nve_name (nve_t pke);
+
+/* Get the value. */
+char *nve_value (nve_t pke);
+
+
+
+/* Lookup and iteration. */
+
+/* Get the first non-comment entry. */
+nve_t nvc_first (nvc_t pk);
+
+/* Get the first entry with the given name. */
+nve_t nvc_lookup (nvc_t pk, const char *name);
+
+/* Get the next non-comment entry. */
+nve_t nve_next (nve_t entry);
+
+/* Get the next entry with the given name. */
+nve_t nve_next_value (nve_t entry, const char *name);
+
+/* Return the string for the first entry in NVC with NAME or NULL. */
+const char *nvc_get_string (nvc_t nvc, const char *name);
+
+/* Return a boolean value for the first entry in NVC with NAME. */
+int nvc_get_boolean (nvc_t nvc, const char *name);
+
+
+
+/* Adding and modifying values. */
+
+/* Add (NAME, VALUE) to PK. If an entry with NAME already exists, it
+ is not updated but the new entry is appended. */
+gpg_error_t nvc_add (nvc_t pk, const char *name, const char *value);
+
+/* Add (NAME, VALUE) to PK. If an entry with NAME already exists, it
+ is updated with VALUE. If multiple entries with NAME exist, the
+ first entry is updated. */
+gpg_error_t nvc_set (nvc_t pk, const char *name, const char *value);
+
+/* Update entry E to VALUE. */
+gpg_error_t nve_set (nve_t e, const char *value);
+
+/* Delete the given entry from PK. */
+void nvc_delete (nvc_t pk, nve_t pke);
+
+/* Delete the entries with NAME from PK. */
+void nvc_delete_named (nvc_t pk, const char *name);
+
+
+
+/* Private key handling. */
+
+/* Get the private key. */
+gpg_error_t nvc_get_private_key (nvc_t pk, gcry_sexp_t *retsexp);
+
+/* Set the private key. */
+gpg_error_t nvc_set_private_key (nvc_t pk, gcry_sexp_t sexp);
+
+
+
+/* Parsing and serialization. */
+
+/* Parse STREAM and return a newly allocated private key container
+ structure in RESULT. If ERRLINEP is given, the line number the
+ parser was last considering is stored there. */
+gpg_error_t nvc_parse (nvc_t *result, int *errlinep, estream_t stream);
+
+/* Parse STREAM and return a newly allocated name value container
+ structure in RESULT - assuming the extended private key format. If
+ ERRLINEP is given, the line number the parser was last considering
+ is stored there. */
+gpg_error_t nvc_parse_private_key (nvc_t *result, int *errlinep,
+ estream_t stream);
+
+/* Write a representation of PK to STREAM. */
+gpg_error_t nvc_write (nvc_t pk, estream_t stream);
+
+#endif /* GNUPG_COMMON_NAME_VALUE_H */
diff --git a/common/openpgp-fpr.c b/common/openpgp-fpr.c
new file mode 100644
index 0000000..7b11008
--- /dev/null
+++ b/common/openpgp-fpr.c
@@ -0,0 +1,283 @@
+/* openpgp-fpr.c - OpenPGP Fingerprint computation
+ * Copyright (C) 2021 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: (LGPL-3.0-or-later OR GPL-2.0-or-later)
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "util.h"
+#include "openpgpdefs.h"
+
+/* Count the number of bits, assuming the A represents an unsigned big
+ * integer of length LEN bytes. */
+static unsigned int
+count_bits (const unsigned char *a, size_t len)
+{
+ unsigned int n = len * 8;
+ int i;
+
+ for (; len && !*a; len--, a++, n -=8)
+ ;
+ if (len)
+ {
+ for (i=7; i && !(*a & (1<<i)); i--)
+ n--;
+ }
+ return n;
+}
+
+/* Variant of count_bits for simple octet strings. */
+static unsigned int
+count_sos_bits (const unsigned char *a, size_t len)
+{
+ unsigned int n = len * 8;
+ int i;
+
+ if (len == 0 || *a == 0)
+ return n;
+
+ for (i=7; i && !(*a & (1<<i)); i--)
+ n--;
+
+ return n;
+}
+
+
+gpg_error_t
+compute_openpgp_fpr (int keyversion, int pgpalgo, unsigned long timestamp,
+ gcry_buffer_t *iov, int iovcnt,
+ unsigned char *result, unsigned int *r_resultlen)
+{
+ gpg_error_t err;
+ int hashalgo;
+ unsigned char prefix[15];
+ size_t n;
+ int i;
+
+ if (r_resultlen)
+ *r_resultlen = 0;
+
+ if (iovcnt < 2)
+ return gpg_error (GPG_ERR_INV_ARG);
+
+ /* Note that iov[0] is reserved. */
+ for (n=0, i=1; i < iovcnt; i++)
+ n += iov[i].len;
+
+ i = 0;
+ if (keyversion == 5)
+ {
+ hashalgo = GCRY_MD_SHA256;
+ n += 10; /* Add the prefix length. */
+ prefix[i++] = 0x9a;
+ prefix[i++] = (n >> 24);
+ prefix[i++] = (n >> 16);
+ }
+ else if (keyversion == 4)
+ {
+ hashalgo = GCRY_MD_SHA1;
+ n += 6; /* Add the prefix length. */
+ prefix[i++] = 0x99;
+ }
+ else
+ return gpg_error (GPG_ERR_UNKNOWN_VERSION);
+
+ prefix[i++] = (n >> 8);
+ prefix[i++] = n;
+ prefix[i++] = keyversion;
+ prefix[i++] = (timestamp >> 24);
+ prefix[i++] = (timestamp >> 16);
+ prefix[i++] = (timestamp >> 8);
+ prefix[i++] = (timestamp);
+ prefix[i++] = pgpalgo;
+ if (keyversion == 5)
+ {
+ prefix[i++] = ((n-10) >> 24);
+ prefix[i++] = ((n-10) >> 16);
+ prefix[i++] = ((n-10) >> 8);
+ prefix[i++] = (n-10);
+ }
+ log_assert (i <= sizeof prefix);
+ /* The first element is reserved for our use; set it. */
+ iov[0].size = 0;
+ iov[0].off = 0;
+ iov[0].len = i;
+ iov[0].data = prefix;
+
+ /* for (i=0; i < iovcnt; i++) */
+ /* log_printhex (iov[i].data, iov[i].len, "cmpfpr i=%d: ", i); */
+
+ err = gcry_md_hash_buffers (hashalgo, 0, result, iov, iovcnt);
+ /* log_printhex (result, 20, "fingerpint: "); */
+
+ /* Better clear the first element because it was set by us. */
+ iov[0].size = 0;
+ iov[0].off = 0;
+ iov[0].len = 0;
+ iov[0].data = NULL;
+
+ if (!err && r_resultlen)
+ *r_resultlen = (hashalgo == GCRY_MD_SHA1)? 20 : 32;
+
+ return err;
+}
+
+
+gpg_error_t
+compute_openpgp_fpr_rsa (int keyversion, unsigned long timestamp,
+ const unsigned char *m, unsigned int mlen,
+ const unsigned char *e, unsigned int elen,
+ unsigned char *result, unsigned int *r_resultlen)
+{
+ gcry_buffer_t iov[5] = { {0} };
+ unsigned char nbits_m[2], nbits_e[2];
+ unsigned int n;
+
+ /* Strip leading zeroes. */
+ for (; mlen && !*m; mlen--, m++)
+ ;
+ for (; elen && !*e; elen--, e++)
+ ;
+
+ /* Count bits. */
+ n = count_bits (m, mlen);
+ nbits_m[0] = n >> 8;
+ nbits_m[1] = n;
+
+ n = count_bits (e, elen);
+ nbits_e[0] = n >> 8;
+ nbits_e[1] = n;
+
+ /* Put parms into the array. Note that iov[0] is reserved. */
+ iov[1].len = 2;
+ iov[1].data = nbits_m;
+ iov[2].len = mlen;
+ iov[2].data = (void*)m;
+ iov[3].len = 2;
+ iov[3].data = nbits_e;
+ iov[4].len = elen;
+ iov[4].data = (void*)e;
+
+ return compute_openpgp_fpr (keyversion, PUBKEY_ALGO_RSA, timestamp,
+ iov, 5, result, r_resultlen);
+}
+
+
+/* Determine KDF hash algorithm and KEK encryption algorithm by CURVE.
+ * The returned buffer has a length of 4.
+ * Note: This needs to be kept in sync with the table in g10/ecdh.c */
+static const unsigned char*
+default_ecdh_params (unsigned int nbits)
+{
+ /* See RFC-6637 for those constants.
+ 0x03: Number of bytes
+ 0x01: Version for this parameter format
+ KEK digest algorithm
+ KEK cipher algorithm
+ */
+ if (nbits <= 256)
+ return (const unsigned char*)"\x03\x01\x08\x07";
+ else if (nbits <= 384)
+ return (const unsigned char*)"\x03\x01\x09\x09";
+ else
+ return (const unsigned char*)"\x03\x01\x0a\x09";
+}
+
+
+gpg_error_t
+compute_openpgp_fpr_ecc (int keyversion, unsigned long timestamp,
+ const char *curvename, int for_encryption,
+ const unsigned char *q, unsigned int qlen,
+ const unsigned char *kdf, unsigned int kdflen,
+ unsigned char *result, unsigned int *r_resultlen)
+{
+ gpg_error_t err;
+ const char *curveoidstr;
+ gcry_mpi_t curveoid = NULL;
+ unsigned int curvebits;
+ int pgpalgo;
+ const unsigned char *oidraw;
+ size_t oidrawlen;
+ gcry_buffer_t iov[5] = { {0} };
+ unsigned int iovlen;
+ unsigned char nbits_q[2];
+ unsigned int n;
+
+ curveoidstr = openpgp_curve_to_oid (curvename, &curvebits, &pgpalgo);
+ err = openpgp_oid_from_str (curveoidstr, &curveoid);
+ if (err)
+ goto leave;
+ oidraw = gcry_mpi_get_opaque (curveoid, &n);
+ if (!oidraw)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+ oidrawlen = (n+7)/8;
+
+ /* If the curve does not enforce a certain algorithm, we use the
+ * for_encryption flag to decide which algo to use. */
+ if (!pgpalgo)
+ pgpalgo = for_encryption? PUBKEY_ALGO_ECDH : PUBKEY_ALGO_ECDSA;
+
+ /* Count bits. */
+ n = count_sos_bits (q, qlen);
+ nbits_q[0] = n >> 8;
+ nbits_q[1] = n;
+
+ /* Put parms into the array. Note that iov[0] is reserved. */
+ iov[1].len = oidrawlen;
+ iov[1].data = (void*)oidraw;
+ iov[2].len = 2;
+ iov[2].data = nbits_q;
+ iov[3].len = qlen;
+ iov[3].data = (void*)q;
+ iovlen = 4;
+ if (pgpalgo == PUBKEY_ALGO_ECDH)
+ {
+ if (!kdf || !kdflen || !kdf[0])
+ {
+ /* No KDF given - use the default. */
+ kdflen = 4;
+ kdf = default_ecdh_params (curvebits);
+ }
+ iov[4].len = kdflen;
+ iov[4].data = (void*)kdf;
+ iovlen++;
+ }
+
+ err = compute_openpgp_fpr (keyversion, pgpalgo, timestamp,
+ iov, iovlen, result, r_resultlen);
+
+ leave:
+ gcry_mpi_release (curveoid);
+ return err;
+}
diff --git a/common/openpgp-oid.c b/common/openpgp-oid.c
new file mode 100644
index 0000000..943fe3e
--- /dev/null
+++ b/common/openpgp-oid.c
@@ -0,0 +1,472 @@
+/* openpgp-oids.c - OID helper for OpenPGP
+ * Copyright (C) 2011 Free Software Foundation, Inc.
+ * Copyright (C) 2013 Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "util.h"
+#include "openpgpdefs.h"
+
+/* A table with all our supported OpenPGP curves. */
+static struct {
+ const char *name; /* Standard name. */
+ const char *oidstr; /* IETF formatted OID. */
+ unsigned int nbits; /* Nominal bit length of the curve. */
+ const char *alias; /* NULL or alternative name of the curve. */
+ int pubkey_algo; /* Required OpenPGP algo or 0 for ECDSA/ECDH. */
+} oidtable[] = {
+
+ { "Curve25519", "1.3.6.1.4.1.3029.1.5.1", 255, "cv25519", PUBKEY_ALGO_ECDH },
+ { "Ed25519", "1.3.6.1.4.1.11591.15.1", 255, "ed25519", PUBKEY_ALGO_EDDSA },
+
+ { "NIST P-256", "1.2.840.10045.3.1.7", 256, "nistp256" },
+ { "NIST P-384", "1.3.132.0.34", 384, "nistp384" },
+ { "NIST P-521", "1.3.132.0.35", 521, "nistp521" },
+
+ { "brainpoolP256r1", "1.3.36.3.3.2.8.1.1.7", 256 },
+ { "brainpoolP384r1", "1.3.36.3.3.2.8.1.1.11", 384 },
+ { "brainpoolP512r1", "1.3.36.3.3.2.8.1.1.13", 512 },
+
+ { "secp256k1", "1.3.132.0.10", 256 },
+
+ { NULL, NULL, 0}
+};
+
+
+/* The OID for Curve Ed25519 in OpenPGP format. */
+static const char oid_ed25519[] =
+ { 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xda, 0x47, 0x0f, 0x01 };
+
+/* The OID for Curve25519 in OpenPGP format. */
+static const char oid_cv25519[] =
+ { 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01 };
+
+
+/* Helper for openpgp_oid_from_str. */
+static size_t
+make_flagged_int (unsigned long value, char *buf, size_t buflen)
+{
+ int more = 0;
+ int shift;
+
+ /* fixme: figure out the number of bits in an ulong and start with
+ that value as shift (after making it a multiple of 7) a more
+ straigtforward implementation is to do it in reverse order using
+ a temporary buffer - saves a lot of compares */
+ for (more=0, shift=28; shift > 0; shift -= 7)
+ {
+ if (more || value >= (1<<shift))
+ {
+ buf[buflen++] = 0x80 | (value >> shift);
+ value -= (value >> shift) << shift;
+ more = 1;
+ }
+ }
+ buf[buflen++] = value;
+ return buflen;
+}
+
+
+/* Convert the OID given in dotted decimal form in STRING to an DER
+ * encoding and store it as an opaque value at R_MPI. The format of
+ * the DER encoded is not a regular ASN.1 object but the modified
+ * format as used by OpenPGP for the ECC curve description. On error
+ * the function returns and error code an NULL is stored at R_BUG.
+ * Note that scanning STRING stops at the first white space
+ * character. */
+gpg_error_t
+openpgp_oid_from_str (const char *string, gcry_mpi_t *r_mpi)
+{
+ unsigned char *buf;
+ size_t buflen;
+ unsigned long val1, val;
+ const char *endp;
+ int arcno;
+
+ *r_mpi = NULL;
+
+ if (!string || !*string)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ /* We can safely assume that the encoded OID is shorter than the string. */
+ buf = xtrymalloc (1 + strlen (string) + 2);
+ if (!buf)
+ return gpg_error_from_syserror ();
+ /* Save the first byte for the length. */
+ buflen = 1;
+
+ val1 = 0; /* Avoid compiler warning. */
+ arcno = 0;
+ do {
+ arcno++;
+ val = strtoul (string, (char**)&endp, 10);
+ if (!digitp (string) || !(*endp == '.' || !*endp))
+ {
+ xfree (buf);
+ return gpg_error (GPG_ERR_INV_OID_STRING);
+ }
+ if (*endp == '.')
+ string = endp+1;
+
+ if (arcno == 1)
+ {
+ if (val > 2)
+ break; /* Not allowed, error caught below. */
+ val1 = val;
+ }
+ else if (arcno == 2)
+ { /* Need to combine the first two arcs in one octet. */
+ if (val1 < 2)
+ {
+ if (val > 39)
+ {
+ xfree (buf);
+ return gpg_error (GPG_ERR_INV_OID_STRING);
+ }
+ buf[buflen++] = val1*40 + val;
+ }
+ else
+ {
+ val += 80;
+ buflen = make_flagged_int (val, buf, buflen);
+ }
+ }
+ else
+ {
+ buflen = make_flagged_int (val, buf, buflen);
+ }
+ } while (*endp == '.');
+
+ if (arcno == 1 || buflen < 2 || buflen > 254 )
+ { /* It is not possible to encode only the first arc. */
+ xfree (buf);
+ return gpg_error (GPG_ERR_INV_OID_STRING);
+ }
+
+ *buf = buflen - 1;
+ *r_mpi = gcry_mpi_set_opaque (NULL, buf, buflen * 8);
+ if (!*r_mpi)
+ {
+ xfree (buf);
+ return gpg_error_from_syserror ();
+ }
+ return 0;
+}
+
+
+/* Return a malloced string representation of the OID in the buffer
+ * (BUF,LEN). In case of an error NULL is returned and ERRNO is set.
+ * As per OpenPGP spec the first byte of the buffer is the length of
+ * the rest; the function performs a consistency check. */
+char *
+openpgp_oidbuf_to_str (const unsigned char *buf, size_t len)
+{
+ char *string, *p;
+ int n = 0;
+ unsigned long val, valmask;
+
+ valmask = (unsigned long)0xfe << (8 * (sizeof (valmask) - 1));
+ /* The first bytes gives the length; check consistency. */
+
+ if (!len || buf[0] != len -1)
+ {
+ gpg_err_set_errno (EINVAL);
+ return NULL;
+ }
+ /* Skip length byte. */
+ len--;
+ buf++;
+
+ /* To calculate the length of the string we can safely assume an
+ upper limit of 3 decimal characters per byte. Two extra bytes
+ account for the special first octect */
+ string = p = xtrymalloc (len*(1+3)+2+1);
+ if (!string)
+ return NULL;
+ if (!len)
+ {
+ *p = 0;
+ return string;
+ }
+
+ if (buf[0] < 40)
+ p += sprintf (p, "0.%d", buf[n]);
+ else if (buf[0] < 80)
+ p += sprintf (p, "1.%d", buf[n]-40);
+ else {
+ val = buf[n] & 0x7f;
+ while ( (buf[n]&0x80) && ++n < len )
+ {
+ if ( (val & valmask) )
+ goto badoid; /* Overflow. */
+ val <<= 7;
+ val |= buf[n] & 0x7f;
+ }
+ if (val < 80)
+ goto badoid;
+ val -= 80;
+ sprintf (p, "2.%lu", val);
+ p += strlen (p);
+ }
+ for (n++; n < len; n++)
+ {
+ val = buf[n] & 0x7f;
+ while ( (buf[n]&0x80) && ++n < len )
+ {
+ if ( (val & valmask) )
+ goto badoid; /* Overflow. */
+ val <<= 7;
+ val |= buf[n] & 0x7f;
+ }
+ sprintf (p, ".%lu", val);
+ p += strlen (p);
+ }
+
+ *p = 0;
+ return string;
+
+ badoid:
+ /* Return a special OID (gnu.gnupg.badoid) to indicate the error
+ case. The OID is broken and thus we return one which can't do
+ any harm. Formally this does not need to be a bad OID but an OID
+ with an arc that can't be represented in a 32 bit word is more
+ than likely corrupt. */
+ xfree (string);
+ return xtrystrdup ("1.3.6.1.4.1.11591.2.12242973");
+}
+
+
+/* Return a malloced string representation of the OID in the opaque
+ * MPI A. In case of an error NULL is returned and ERRNO is set. */
+char *
+openpgp_oid_to_str (gcry_mpi_t a)
+{
+ const unsigned char *buf;
+ unsigned int lengthi;
+
+ if (!a
+ || !gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE)
+ || !(buf = gcry_mpi_get_opaque (a, &lengthi)))
+ {
+ gpg_err_set_errno (EINVAL);
+ return NULL;
+ }
+
+ buf = gcry_mpi_get_opaque (a, &lengthi);
+ return openpgp_oidbuf_to_str (buf, (lengthi+7)/8);
+}
+
+
+/* Return true if (BUF,LEN) represents the OID for Ed25519. */
+int
+openpgp_oidbuf_is_ed25519 (const void *buf, size_t len)
+{
+ return (buf && len == DIM (oid_ed25519)
+ && !memcmp (buf, oid_ed25519, DIM (oid_ed25519)));
+}
+
+
+/* Return true if A represents the OID for Ed25519. */
+int
+openpgp_oid_is_ed25519 (gcry_mpi_t a)
+{
+ const unsigned char *buf;
+ unsigned int nbits;
+
+ if (!a || !gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE))
+ return 0;
+
+ buf = gcry_mpi_get_opaque (a, &nbits);
+ return openpgp_oidbuf_is_ed25519 (buf, (nbits+7)/8);
+}
+
+
+/* Return true if (BUF,LEN) represents the OID for Curve25519. */
+int
+openpgp_oidbuf_is_cv25519 (const void *buf, size_t len)
+{
+ return (buf && len == DIM (oid_cv25519)
+ && !memcmp (buf, oid_cv25519, DIM (oid_cv25519)));
+}
+
+
+/* Return true if the MPI A represents the OID for Curve25519. */
+int
+openpgp_oid_is_cv25519 (gcry_mpi_t a)
+{
+ const unsigned char *buf;
+ unsigned int nbits;
+
+ if (!a || !gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE))
+ return 0;
+
+ buf = gcry_mpi_get_opaque (a, &nbits);
+ return openpgp_oidbuf_is_cv25519 (buf, (nbits+7)/8);
+}
+
+
+/* Map the Libgcrypt ECC curve NAME to an OID. If R_NBITS is not NULL
+ store the bit size of the curve there. Returns NULL for unknown
+ curve names. If R_ALGO is not NULL and a specific ECC algorithm is
+ required for this curve its OpenPGP algorithm number is stored
+ there; otherwise 0 is stored which indicates that ECDSA or ECDH can
+ be used. */
+const char *
+openpgp_curve_to_oid (const char *name, unsigned int *r_nbits, int *r_algo)
+{
+ int i;
+ unsigned int nbits = 0;
+ const char *oidstr = NULL;
+ int algo = 0;
+
+ if (name)
+ {
+ for (i=0; oidtable[i].name; i++)
+ if (!strcmp (oidtable[i].name, name)
+ || (oidtable[i].alias && !strcmp (oidtable[i].alias, name)))
+ {
+ oidstr = oidtable[i].oidstr;
+ nbits = oidtable[i].nbits;
+ algo = oidtable[i].pubkey_algo;
+ break;
+ }
+ if (!oidtable[i].name)
+ {
+ /* If not found assume the input is already an OID and check
+ whether we support it. */
+ for (i=0; oidtable[i].name; i++)
+ if (!strcmp (name, oidtable[i].oidstr))
+ {
+ oidstr = oidtable[i].oidstr;
+ nbits = oidtable[i].nbits;
+ algo = oidtable[i].pubkey_algo;
+ break;
+ }
+ }
+ }
+
+ if (r_nbits)
+ *r_nbits = nbits;
+ if (r_algo)
+ *r_algo = algo;
+ return oidstr;
+}
+
+
+/* Map an OpenPGP OID to the Libgcrypt curve NAME. Returns NULL for
+ unknown curve names. Unless CANON is set we prefer an alias name
+ here which is more suitable for printing. */
+const char *
+openpgp_oid_to_curve (const char *oidstr, int canon)
+{
+ int i;
+
+ if (!oidstr)
+ return NULL;
+
+ for (i=0; oidtable[i].name; i++)
+ if (!strcmp (oidtable[i].oidstr, oidstr))
+ return !canon && oidtable[i].alias? oidtable[i].alias : oidtable[i].name;
+
+ return NULL;
+}
+
+
+/* Return true if the curve with NAME is supported. */
+static int
+curve_supported_p (const char *name)
+{
+ int result = 0;
+ gcry_sexp_t keyparms;
+
+ if (!gcry_sexp_build (&keyparms, NULL, "(public-key(ecc(curve %s)))", name))
+ {
+ result = !!gcry_pk_get_curve (keyparms, 0, NULL);
+ gcry_sexp_release (keyparms);
+ }
+ return result;
+}
+
+
+/* Enumerate available and supported OpenPGP curves. The caller needs
+ to set the integer variable at ITERP to zero and keep on calling
+ this function until NULL is returned. */
+const char *
+openpgp_enum_curves (int *iterp)
+{
+ int idx = *iterp;
+
+ while (idx >= 0 && idx < DIM (oidtable) && oidtable[idx].name)
+ {
+ if (curve_supported_p (oidtable[idx].name))
+ {
+ *iterp = idx + 1;
+ return oidtable[idx].alias? oidtable[idx].alias : oidtable[idx].name;
+ }
+ idx++;
+ }
+ *iterp = idx;
+ return NULL;
+}
+
+
+/* Return the Libgcrypt name for the gpg curve NAME if supported. If
+ * R_ALGO is not NULL the required OpenPGP public key algo or 0 is
+ * stored at that address. If R_NBITS is not NULL the nominal bitsize
+ * of the curves is stored there. NULL is returned if the curve is
+ * not supported. */
+const char *
+openpgp_is_curve_supported (const char *name, int *r_algo,
+ unsigned int *r_nbits)
+{
+ int idx;
+
+ if (r_algo)
+ *r_algo = 0;
+ if (r_nbits)
+ *r_nbits = 0;
+ for (idx = 0; idx < DIM (oidtable) && oidtable[idx].name; idx++)
+ {
+ if ((!strcmp (name, oidtable[idx].name)
+ || (oidtable[idx].alias && !strcmp (name, (oidtable[idx].alias))))
+ && curve_supported_p (oidtable[idx].name))
+ {
+ if (r_algo)
+ *r_algo = oidtable[idx].pubkey_algo;
+ if (r_nbits)
+ *r_nbits = oidtable[idx].nbits;
+ return oidtable[idx].name;
+ }
+ }
+ return NULL;
+}
diff --git a/common/openpgpdefs.h b/common/openpgpdefs.h
new file mode 100644
index 0000000..05f3621
--- /dev/null
+++ b/common/openpgpdefs.h
@@ -0,0 +1,230 @@
+/* openpgpdefs.h - Constants from the OpenPGP standard (rfc2440)
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
+ * 2006 Free Software Foundation, Inc.
+ * Copyright (C) 2014 Werner Koch
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_COMMON_OPENPGPDEFS_H
+#define GNUPG_COMMON_OPENPGPDEFS_H
+
+typedef enum
+ {
+ PKT_NONE = 0,
+ PKT_PUBKEY_ENC = 1, /* Public key encrypted packet. */
+ PKT_SIGNATURE = 2, /* Secret key encrypted packet. */
+ PKT_SYMKEY_ENC = 3, /* Session key packet. */
+ PKT_ONEPASS_SIG = 4, /* One pass sig packet. */
+ PKT_SECRET_KEY = 5, /* Secret key. */
+ PKT_PUBLIC_KEY = 6, /* Public key. */
+ PKT_SECRET_SUBKEY = 7, /* Secret subkey. */
+ PKT_COMPRESSED = 8, /* Compressed data packet. */
+ PKT_ENCRYPTED = 9, /* Conventional encrypted data. */
+ PKT_MARKER = 10, /* Marker packet. */
+ PKT_PLAINTEXT = 11, /* Literal data packet. */
+ PKT_RING_TRUST = 12, /* Keyring trust packet. */
+ PKT_USER_ID = 13, /* User id packet. */
+ PKT_PUBLIC_SUBKEY = 14, /* Public subkey. */
+ PKT_OLD_COMMENT = 16, /* Comment packet from an OpenPGP draft. */
+ PKT_ATTRIBUTE = 17, /* PGP's attribute packet. */
+ PKT_ENCRYPTED_MDC = 18, /* Integrity protected encrypted data. */
+ PKT_MDC = 19, /* Manipulation detection code packet. */
+ PKT_ENCRYPTED_AEAD= 20, /* AEAD encrypted data packet. */
+ PKT_COMMENT = 61, /* new comment packet (GnuPG specific). */
+ PKT_GPG_CONTROL = 63 /* internal control packet (GnuPG specific). */
+ }
+pkttype_t;
+
+static inline const char *
+pkttype_str (pkttype_t type)
+{
+ switch (type)
+ {
+ case PKT_PUBKEY_ENC: return "PUBKEY_ENC";
+ case PKT_SIGNATURE: return "SIGNATURE";
+ case PKT_SYMKEY_ENC: return "SYMKEY_ENC";
+ case PKT_ONEPASS_SIG: return "ONEPASS_SIG";
+ case PKT_SECRET_KEY: return "SECRET_KEY";
+ case PKT_PUBLIC_KEY: return "PUBLIC_KEY";
+ case PKT_SECRET_SUBKEY: return "SECRET_SUBKEY";
+ case PKT_COMPRESSED: return "COMPRESSED";
+ case PKT_ENCRYPTED: return "ENCRYPTED";
+ case PKT_MARKER: return "MARKER";
+ case PKT_PLAINTEXT: return "PLAINTEXT";
+ case PKT_RING_TRUST: return "RING_TRUST";
+ case PKT_USER_ID: return "USER_ID";
+ case PKT_PUBLIC_SUBKEY: return "PUBLIC_SUBKEY";
+ case PKT_OLD_COMMENT: return "OLD_COMMENT";
+ case PKT_ATTRIBUTE: return "ATTRIBUTE";
+ case PKT_ENCRYPTED_MDC: return "ENCRYPTED_MDC";
+ case PKT_MDC: return "MDC";
+ case PKT_COMMENT: return "COMMENT";
+ case PKT_GPG_CONTROL: return "GPG_CONTROL";
+ default: return "unknown packet type";
+ }
+}
+
+typedef enum
+ {
+ SIGSUBPKT_TEST_CRITICAL = -3,
+ SIGSUBPKT_LIST_UNHASHED = -2,
+ SIGSUBPKT_LIST_HASHED = -1,
+ SIGSUBPKT_NONE = 0,
+ SIGSUBPKT_SIG_CREATED = 2, /* Signature creation time. */
+ SIGSUBPKT_SIG_EXPIRE = 3, /* Signature expiration time. */
+ SIGSUBPKT_EXPORTABLE = 4, /* Exportable. */
+ SIGSUBPKT_TRUST = 5, /* Trust signature. */
+ SIGSUBPKT_REGEXP = 6, /* Regular expression. */
+ SIGSUBPKT_REVOCABLE = 7, /* Revocable. */
+ SIGSUBPKT_KEY_EXPIRE = 9, /* Key expiration time. */
+ SIGSUBPKT_ARR = 10, /* Additional recipient request. */
+ SIGSUBPKT_PREF_SYM = 11, /* Preferred symmetric algorithms. */
+ SIGSUBPKT_REV_KEY = 12, /* Revocation key. */
+ SIGSUBPKT_ISSUER = 16, /* Issuer key ID. */
+ SIGSUBPKT_NOTATION = 20, /* Notation data. */
+ SIGSUBPKT_PREF_HASH = 21, /* Preferred hash algorithms. */
+ SIGSUBPKT_PREF_COMPR = 22, /* Preferred compression algorithms. */
+ SIGSUBPKT_KS_FLAGS = 23, /* Key server preferences. */
+ SIGSUBPKT_PREF_KS = 24, /* Preferred keyserver. */
+ SIGSUBPKT_PRIMARY_UID = 25, /* Primary user id. */
+ SIGSUBPKT_POLICY = 26, /* Policy URL. */
+ SIGSUBPKT_KEY_FLAGS = 27, /* Key flags. */
+ SIGSUBPKT_SIGNERS_UID = 28, /* Signer's user id. */
+ SIGSUBPKT_REVOC_REASON = 29, /* Reason for revocation. */
+ SIGSUBPKT_FEATURES = 30, /* Feature flags. */
+
+ SIGSUBPKT_SIGNATURE = 32, /* Embedded signature. */
+ SIGSUBPKT_ISSUER_FPR = 33, /* Issuer fingerprint. */
+ SIGSUBPKT_PREF_AEAD = 34, /* Preferred AEAD algorithms. */
+
+ SIGSUBPKT_KEY_BLOCK = 38, /* Entire key used. */
+
+ SIGSUBPKT_FLAG_CRITICAL = 128
+ }
+sigsubpkttype_t;
+
+
+/* Note that we encode the AEAD algo in a 3 bit field at some places. */
+typedef enum
+ {
+ AEAD_ALGO_NONE = 0,
+ AEAD_ALGO_EAX = 1,
+ AEAD_ALGO_OCB = 2
+ }
+aead_algo_t;
+
+
+typedef enum
+ {
+ CIPHER_ALGO_NONE = 0,
+ CIPHER_ALGO_IDEA = 1,
+ CIPHER_ALGO_3DES = 2,
+ CIPHER_ALGO_CAST5 = 3,
+ CIPHER_ALGO_BLOWFISH = 4, /* 128 bit */
+ /* 5 & 6 are reserved */
+ CIPHER_ALGO_AES = 7,
+ CIPHER_ALGO_AES192 = 8,
+ CIPHER_ALGO_AES256 = 9,
+ CIPHER_ALGO_TWOFISH = 10, /* 256 bit */
+ CIPHER_ALGO_CAMELLIA128 = 11,
+ CIPHER_ALGO_CAMELLIA192 = 12,
+ CIPHER_ALGO_CAMELLIA256 = 13,
+ CIPHER_ALGO_PRIVATE10 = 110
+ }
+cipher_algo_t;
+
+
+typedef enum
+ {
+ PUBKEY_ALGO_RSA = 1,
+ PUBKEY_ALGO_RSA_E = 2, /* RSA encrypt only (legacy). */
+ PUBKEY_ALGO_RSA_S = 3, /* RSA sign only (legacy). */
+ PUBKEY_ALGO_ELGAMAL_E = 16, /* Elgamal encrypt only. */
+ PUBKEY_ALGO_DSA = 17,
+ PUBKEY_ALGO_ECDH = 18, /* RFC-6637 */
+ PUBKEY_ALGO_ECDSA = 19, /* RFC-6637 */
+ PUBKEY_ALGO_ELGAMAL = 20, /* Elgamal encrypt+sign (legacy). */
+ /* 21 reserved by OpenPGP. */
+ PUBKEY_ALGO_EDDSA = 22, /* EdDSA (not yet assigned). */
+ PUBKEY_ALGO_PRIVATE10 = 110
+ }
+pubkey_algo_t;
+
+
+typedef enum
+ {
+ DIGEST_ALGO_MD5 = 1,
+ DIGEST_ALGO_SHA1 = 2,
+ DIGEST_ALGO_RMD160 = 3,
+ /* 4, 5, 6, and 7 are reserved. */
+ DIGEST_ALGO_SHA256 = 8,
+ DIGEST_ALGO_SHA384 = 9,
+ DIGEST_ALGO_SHA512 = 10,
+ DIGEST_ALGO_SHA224 = 11,
+ DIGEST_ALGO_PRIVATE10 = 110
+ }
+digest_algo_t;
+
+
+typedef enum
+ {
+ COMPRESS_ALGO_NONE = 0,
+ COMPRESS_ALGO_ZIP = 1,
+ COMPRESS_ALGO_ZLIB = 2,
+ COMPRESS_ALGO_BZIP2 = 3,
+ COMPRESS_ALGO_PRIVATE10 = 110
+ }
+compress_algo_t;
+
+/* Limits to be used for static arrays. */
+#define OPENPGP_MAX_NPKEY 5 /* Maximum number of public key parameters. */
+#define OPENPGP_MAX_NSKEY 7 /* Maximum number of secret key parameters. */
+#define OPENPGP_MAX_NSIG 2 /* Maximum number of signature parameters. */
+#define OPENPGP_MAX_NENC 2 /* Maximum number of encryption parameters. */
+
+
+/*-- openpgp-fpr.c --*/
+gpg_error_t compute_openpgp_fpr (int keyversion, int pgpalgo,
+ unsigned long timestamp,
+ gcry_buffer_t *iov, int iovcnt,
+ unsigned char *result,
+ unsigned int *r_resultlen);
+gpg_error_t compute_openpgp_fpr_rsa (int keyversion,
+ unsigned long timestamp,
+ const unsigned char *m, unsigned int mlen,
+ const unsigned char *e, unsigned int elen,
+ unsigned char *result,
+ unsigned int *r_resultlen);
+gpg_error_t compute_openpgp_fpr_ecc (int keyversion,
+ unsigned long timestamp,
+ const char *curvename, int for_encryption,
+ const unsigned char *q, unsigned int qlen,
+ const unsigned char *kdf,
+ unsigned int kdflen,
+ unsigned char *result,
+ unsigned int *r_resultlen);
+
+
+#endif /*GNUPG_COMMON_OPENPGPDEFS_H*/
diff --git a/common/percent.c b/common/percent.c
new file mode 100644
index 0000000..224de78
--- /dev/null
+++ b/common/percent.c
@@ -0,0 +1,321 @@
+/* percent.c - Percent escaping
+ * Copyright (C) 2008, 2009 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "util.h"
+
+
+/* Create a newly alloced string from STRING with all spaces and
+ control characters converted to plus signs or %xx sequences. The
+ function returns the new string or NULL in case of a malloc
+ failure.
+
+ Note that we also escape the quote character to work around a bug
+ in the mingw32 runtime which does not correcty handle command line
+ quoting. We correctly double the quote mark when calling a program
+ (i.e. gpg-protect-tool), but the pre-main code does not notice the
+ double quote as an escaped quote. We do this also on POSIX systems
+ for consistency. */
+char *
+percent_plus_escape (const char *string)
+{
+ char *buffer, *p;
+ const char *s;
+ size_t length;
+
+ for (length=1, s=string; *s; s++)
+ {
+ if (*s == '+' || *s == '\"' || *s == '%'
+ || *(const unsigned char *)s < 0x20)
+ length += 3;
+ else
+ length++;
+ }
+
+ buffer = p = xtrymalloc (length);
+ if (!buffer)
+ return NULL;
+
+ for (s=string; *s; s++)
+ {
+ if (*s == '+' || *s == '\"' || *s == '%'
+ || *(const unsigned char *)s < 0x20)
+ {
+ snprintf (p, 4, "%%%02X", *(unsigned char *)s);
+ p += 3;
+ }
+ else if (*s == ' ')
+ *p++ = '+';
+ else
+ *p++ = *s;
+ }
+ *p = 0;
+
+ return buffer;
+
+}
+
+
+/* Create a newly malloced string from (DATA,DATALEN) with embedded
+ * nuls quoted as %00. The standard percent unescaping can be used to
+ * reverse this encoding. With PLUS_ESCAPE set plus-escaping (spaces
+ * are replaced by a '+') and escaping of characters with values less
+ * than 0x20 is used. If PREFIX is not NULL it will be prepended to
+ * the output in standard escape format; that is PLUS_ESCAPING is
+ * ignored for PREFIX. */
+char *
+percent_data_escape (int plus_escape, const char *prefix,
+ const void *data, size_t datalen)
+{
+ char *buffer, *p;
+ const unsigned char *s;
+ size_t n;
+ size_t length = 1;
+
+ if (prefix)
+ {
+ for (s = prefix; *s; s++)
+ {
+ if (*s == '%' || *s < 0x20)
+ length += 3;
+ else
+ length++;
+ }
+ }
+
+ for (s=data, n=datalen; n; s++, n--)
+ {
+ if (!*s || *s == '%' || (plus_escape && (*s < ' ' || *s == '+')))
+ length += 3;
+ else
+ length++;
+ }
+
+ buffer = p = xtrymalloc (length);
+ if (!buffer)
+ return NULL;
+
+ if (prefix)
+ {
+ for (s = prefix; *s; s++)
+ {
+ if (*s == '%' || *s < 0x20)
+ {
+ snprintf (p, 4, "%%%02X", *s);
+ p += 3;
+ }
+ else
+ *p++ = *s;
+ }
+ }
+
+ for (s=data, n=datalen; n; s++, n--)
+ {
+ if (!*s)
+ {
+ memcpy (p, "%00", 3);
+ p += 3;
+ }
+ else if (*s == '%')
+ {
+ memcpy (p, "%25", 3);
+ p += 3;
+ }
+ else if (plus_escape && *s == ' ')
+ {
+ *p++ = '+';
+ }
+ else if (plus_escape && (*s < ' ' || *s == '+'))
+ {
+ snprintf (p, 4, "%%%02X", *s);
+ p += 3;
+ }
+ else
+ *p++ = *s;
+ }
+ *p = 0;
+
+ return buffer;
+}
+
+
+/* Do the percent and plus/space unescaping from STRING to BUFFER and
+ return the length of the valid buffer. Plus unescaping is only
+ done if WITHPLUS is true. An escaped Nul character will be
+ replaced by NULREPL. */
+static size_t
+do_unescape (unsigned char *buffer, const unsigned char *string,
+ int withplus, int nulrepl)
+{
+ unsigned char *p = buffer;
+
+ while (*string)
+ {
+ if (*string == '%' && string[1] && string[2])
+ {
+ string++;
+ *p = xtoi_2 (string);
+ if (!*p)
+ *p = nulrepl;
+ string++;
+ }
+ else if (*string == '+' && withplus)
+ *p = ' ';
+ else
+ *p = *string;
+ p++;
+ string++;
+ }
+
+ return (p - buffer);
+}
+
+
+/* Count space required after unescaping STRING. Note that this will
+ never be larger than strlen (STRING). */
+static size_t
+count_unescape (const unsigned char *string)
+{
+ size_t n = 0;
+
+ while (*string)
+ {
+ if (*string == '%' && string[1] && string[2])
+ {
+ string++;
+ string++;
+ }
+ string++;
+ n++;
+ }
+
+ return n;
+}
+
+
+/* Helper. */
+static char *
+do_plus_or_plain_unescape (const char *string, int withplus, int nulrepl)
+{
+ size_t nbytes, n;
+ char *newstring;
+
+ nbytes = count_unescape (string);
+ newstring = xtrymalloc (nbytes+1);
+ if (newstring)
+ {
+ n = do_unescape (newstring, string, withplus, nulrepl);
+ assert (n == nbytes);
+ newstring[n] = 0;
+ }
+ return newstring;
+}
+
+
+/* Create a new allocated string from STRING with all "%xx" sequences
+ decoded and all plus signs replaced by a space. Embedded Nul
+ characters are replaced by the value of NULREPL. The function
+ returns the new string or NULL in case of a malloc failure. */
+char *
+percent_plus_unescape (const char *string, int nulrepl)
+{
+ return do_plus_or_plain_unescape (string, 1, nulrepl);
+}
+
+
+/* Create a new allocated string from STRING with all "%xx" sequences
+ decoded. Embedded Nul characters are replaced by the value of
+ NULREPL. The function returns the new string or NULL in case of a
+ malloc failure. */
+char *
+percent_unescape (const char *string, int nulrepl)
+{
+ return do_plus_or_plain_unescape (string, 0, nulrepl);
+}
+
+
+static size_t
+do_unescape_inplace (char *string, int withplus, int nulrepl)
+{
+ unsigned char *p, *p0;
+
+ p = p0 = string;
+ while (*string)
+ {
+ if (*string == '%' && string[1] && string[2])
+ {
+ string++;
+ *p = xtoi_2 (string);
+ if (!*p)
+ *p = nulrepl;
+ string++;
+ }
+ else if (*string == '+' && withplus)
+ *p = ' ';
+ else
+ *p = *string;
+ p++;
+ string++;
+ }
+
+ return (p - p0);
+}
+
+
+/* Perform percent and plus unescaping in STRING and return the new
+ valid length of the string. Embedded Nul characters are replaced
+ by the value of NULREPL. A terminating Nul character is not
+ inserted; the caller might want to call this function this way:
+
+ foo[percent_plus_unescape_inplace (foo, 0)] = 0;
+ */
+size_t
+percent_plus_unescape_inplace (char *string, int nulrepl)
+{
+ return do_unescape_inplace (string, 1, nulrepl);
+}
+
+
+/* Perform percent unescaping in STRING and return the new valid
+ length of the string. Embedded Nul characters are replaced by the
+ value of NULREPL. A terminating Nul character is not inserted; the
+ caller might want to call this function this way:
+
+ foo[percent_unescape_inplace (foo, 0)] = 0;
+ */
+size_t
+percent_unescape_inplace (char *string, int nulrepl)
+{
+ return do_unescape_inplace (string, 0, nulrepl);
+}
diff --git a/common/recsel.c b/common/recsel.c
new file mode 100644
index 0000000..df77b57
--- /dev/null
+++ b/common/recsel.c
@@ -0,0 +1,632 @@
+/* recsel.c - Record selection
+ * Copyright (C) 2014, 2016 Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "util.h"
+#include "recsel.h"
+
+/* Select operators. */
+typedef enum
+ {
+ SELECT_SAME,
+ SELECT_SUB,
+ SELECT_NONEMPTY,
+ SELECT_ISTRUE,
+ SELECT_EQ, /* Numerically equal. */
+ SELECT_LE,
+ SELECT_GE,
+ SELECT_LT,
+ SELECT_GT,
+ SELECT_STRLE, /* String is less or equal. */
+ SELECT_STRGE,
+ SELECT_STRLT,
+ SELECT_STRGT
+ } select_op_t;
+
+
+/* Definition for a select expression. */
+struct recsel_expr_s
+{
+ recsel_expr_t next;
+ select_op_t op; /* Operation code. */
+ unsigned int not:1; /* Negate operators. */
+ unsigned int disjun:1;/* Start of a disjunction. */
+ unsigned int xcase:1; /* String match is case sensitive. */
+ const char *value; /* (Points into NAME.) */
+ long numvalue; /* strtol of VALUE. */
+ char name[1]; /* Name of the property. */
+};
+
+
+/* Helper */
+static inline gpg_error_t
+my_error_from_syserror (void)
+{
+ return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
+}
+
+/* Helper */
+static inline gpg_error_t
+my_error (gpg_err_code_t ec)
+{
+ return gpg_err_make (default_errsource, ec);
+}
+
+
+/* This is a case-sensitive version of our memistr. I wonder why no
+ * standard function memstr exists but I better do not use the name
+ * memstr to avoid future conflicts.
+ *
+ * FIXME: Move this to a stringhelp.c
+ */
+static const char *
+my_memstr (const void *buffer, size_t buflen, const char *sub)
+{
+ const unsigned char *buf = buffer;
+ const unsigned char *t = (const unsigned char *)buf;
+ const unsigned char *s = (const unsigned char *)sub;
+ size_t n = buflen;
+
+ for ( ; n ; t++, n-- )
+ {
+ if (*t == *s)
+ {
+ for (buf = t++, buflen = n--, s++; n && *t ==*s; t++, s++, n--)
+ ;
+ if (!*s)
+ return (const char*)buf;
+ t = (const unsigned char *)buf;
+ s = (const unsigned char *)sub ;
+ n = buflen;
+ }
+ }
+ return NULL;
+}
+
+
+/* Return a pointer to the next logical connection operator or NULL if
+ * none. */
+static char *
+find_next_lc (char *string)
+{
+ char *p1, *p2;
+
+ p1 = strchr (string, '&');
+ if (p1 && p1[1] != '&')
+ p1 = NULL;
+ p2 = strchr (string, '|');
+ if (p2 && p2[1] != '|')
+ p2 = NULL;
+ if (p1 && !p2)
+ return p1;
+ if (!p1)
+ return p2;
+ return p1 < p2 ? p1 : p2;
+}
+
+
+/* Parse an expression. The expression syntax is:
+ *
+ * [<lc>] {{<flag>} PROPNAME <op> VALUE [<lc>]}
+ *
+ * A [] indicates an optional part, a {} a repetition. PROPNAME and
+ * VALUE may not be the empty string. White space between the
+ * elements is ignored. Numerical values are computed as long int;
+ * standard C notation applies. <lc> is the logical connection
+ * operator; either "&&" for a conjunction or "||" for a disjunction.
+ * A conjunction is assumed at the begin of an expression and
+ * conjunctions have higher precedence than disjunctions. If VALUE
+ * starts with one of the characters used in any <op> a space after
+ * the <op> is required. A VALUE is terminated by an <lc> unless the
+ * "--" <flag> is used in which case the VALUE spans to the end of the
+ * expression. <op> may be any of
+ *
+ * =~ Substring must match
+ * !~ Substring must not match
+ * = The full string must match
+ * <> The full string must not match
+ * == The numerical value must match
+ * != The numerical value must not match
+ * <= The numerical value of the field must be LE than the value.
+ * < The numerical value of the field must be LT than the value.
+ * >= The numerical value of the field must be GT than the value.
+ * >= The numerical value of the field must be GE than the value.
+ * -n True if value is not empty (no VALUE parameter allowed).
+ * -z True if value is empty (no VALUE parameter allowed).
+ * -t Alias for "PROPNAME != 0" (no VALUE parameter allowed).
+ * -f Alias for "PROPNAME == 0" (no VALUE parameter allowed).
+ *
+ * Values for <flag> must be space separated and any of:
+ *
+ * -- VALUE spans to the end of the expression.
+ * -c The string match in this part is done case-sensitive.
+ * -t Do not trim leading and trailing spaces from VALUE.
+ * Note that a space after <op> is here required.
+ *
+ * For example four calls to recsel_parse_expr() with these values for
+ * EXPR
+ *
+ * "uid =~ Alfa"
+ * "&& uid !~ Test"
+ * "|| uid =~ Alpha"
+ * "uid !~ Test"
+ *
+ * or the equivalent expression
+ *
+ * "uid =~ Alfa" && uid !~ Test" || uid =~ Alpha" && "uid !~ Test"
+ *
+ * are making a selector for records where the "uid" property contains
+ * the strings "Alfa" or "Alpha" but not the String "test".
+ *
+ * The caller must pass the address of a selector variable to this
+ * function and initialize the value of the function to NULL before
+ * the first call. recset_release needs to be called to free the
+ * selector.
+ */
+gpg_error_t
+recsel_parse_expr (recsel_expr_t *selector, const char *expression)
+{
+ recsel_expr_t se_head = NULL;
+ recsel_expr_t se, se2;
+ char *expr_buffer;
+ char *expr;
+ char *s0, *s;
+ int toend = 0;
+ int xcase = 0;
+ int notrim = 0;
+ int disjun = 0;
+ char *next_lc = NULL;
+
+ while (*expression == ' ' || *expression == '\t')
+ expression++;
+
+ expr_buffer = xtrystrdup (expression);
+ if (!expr_buffer)
+ return my_error_from_syserror ();
+ expr = expr_buffer;
+
+ if (*expr == '|' && expr[1] == '|')
+ {
+ disjun = 1;
+ expr += 2;
+ }
+ else if (*expr == '&' && expr[1] == '&')
+ expr += 2;
+
+ next_term:
+ while (*expr == ' ' || *expr == '\t')
+ expr++;
+
+ while (*expr == '-')
+ {
+ switch (*++expr)
+ {
+ case '-': toend = 1; break;
+ case 'c': xcase = 1; break;
+ case 't': notrim = 1; break;
+ default:
+ log_error ("invalid flag '-%c' in expression\n", *expr);
+ recsel_release (se_head);
+ xfree (expr_buffer);
+ return my_error (GPG_ERR_INV_FLAG);
+ }
+ expr++;
+ while (*expr == ' ' || *expr == '\t')
+ expr++;
+ }
+
+ next_lc = toend? NULL : find_next_lc (expr);
+ if (next_lc)
+ *next_lc = 0; /* Terminate this term. */
+
+ se = xtrymalloc (sizeof *se + strlen (expr));
+ if (!se)
+ return my_error_from_syserror ();
+ strcpy (se->name, expr);
+ se->next = NULL;
+ se->not = 0;
+ se->disjun = disjun;
+ se->xcase = xcase;
+
+ if (!se_head)
+ se_head = se;
+ else
+ {
+ for (se2 = se_head; se2->next; se2 = se2->next)
+ ;
+ se2->next = se;
+ }
+
+
+ s = strpbrk (expr, "=<>!~-");
+ if (!s || s == expr )
+ {
+ log_error ("no field name given in expression\n");
+ recsel_release (se_head);
+ xfree (expr_buffer);
+ return my_error (GPG_ERR_NO_NAME);
+ }
+ s0 = s;
+
+ if (!strncmp (s, "=~", 2))
+ {
+ se->op = SELECT_SUB;
+ s += 2;
+ }
+ else if (!strncmp (s, "!~", 2))
+ {
+ se->op = SELECT_SUB;
+ se->not = 1;
+ s += 2;
+ }
+ else if (!strncmp (s, "<>", 2))
+ {
+ se->op = SELECT_SAME;
+ se->not = 1;
+ s += 2;
+ }
+ else if (!strncmp (s, "==", 2))
+ {
+ se->op = SELECT_EQ;
+ s += 2;
+ }
+ else if (!strncmp (s, "!=", 2))
+ {
+ se->op = SELECT_EQ;
+ se->not = 1;
+ s += 2;
+ }
+ else if (!strncmp (s, "<=", 2))
+ {
+ se->op = SELECT_LE;
+ s += 2;
+ }
+ else if (!strncmp (s, ">=", 2))
+ {
+ se->op = SELECT_GE;
+ s += 2;
+ }
+ else if (!strncmp (s, "<", 1))
+ {
+ se->op = SELECT_LT;
+ s += 1;
+ }
+ else if (!strncmp (s, ">", 1))
+ {
+ se->op = SELECT_GT;
+ s += 1;
+ }
+ else if (!strncmp (s, "=", 1))
+ {
+ se->op = SELECT_SAME;
+ s += 1;
+ }
+ else if (!strncmp (s, "-z", 2))
+ {
+ se->op = SELECT_NONEMPTY;
+ se->not = 1;
+ s += 2;
+ }
+ else if (!strncmp (s, "-n", 2))
+ {
+ se->op = SELECT_NONEMPTY;
+ s += 2;
+ }
+ else if (!strncmp (s, "-f", 2))
+ {
+ se->op = SELECT_ISTRUE;
+ se->not = 1;
+ s += 2;
+ }
+ else if (!strncmp (s, "-t", 2))
+ {
+ se->op = SELECT_ISTRUE;
+ s += 2;
+ }
+ else if (!strncmp (s, "-le", 3))
+ {
+ se->op = SELECT_STRLE;
+ s += 3;
+ }
+ else if (!strncmp (s, "-ge", 3))
+ {
+ se->op = SELECT_STRGE;
+ s += 3;
+ }
+ else if (!strncmp (s, "-lt", 3))
+ {
+ se->op = SELECT_STRLT;
+ s += 3;
+ }
+ else if (!strncmp (s, "-gt", 3))
+ {
+ se->op = SELECT_STRGT;
+ s += 3;
+ }
+ else
+ {
+ log_error ("invalid operator in expression\n");
+ recsel_release (se_head);
+ xfree (expr_buffer);
+ return my_error (GPG_ERR_INV_OP);
+ }
+
+ /* We require that a space is used if the value starts with any of
+ the operator characters. */
+ if (se->op == SELECT_NONEMPTY || se->op == SELECT_ISTRUE)
+ ;
+ else if (strchr ("=<>!~", *s))
+ {
+ log_error ("invalid operator in expression\n");
+ recsel_release (se_head);
+ xfree (expr_buffer);
+ return my_error (GPG_ERR_INV_OP);
+ }
+
+ if (*s == ' ' || *s == '\t')
+ s++;
+ if (!notrim)
+ while (*s == ' ' || *s == '\t')
+ s++;
+
+ if (se->op == SELECT_NONEMPTY || se->op == SELECT_ISTRUE)
+ {
+ if (*s)
+ {
+ log_error ("value given for -n or -z\n");
+ recsel_release (se_head);
+ xfree (expr_buffer);
+ return my_error (GPG_ERR_SYNTAX);
+ }
+ }
+ else
+ {
+ if (!*s)
+ {
+ log_error ("no value given in expression\n");
+ recsel_release (se_head);
+ xfree (expr_buffer);
+ return my_error (GPG_ERR_MISSING_VALUE);
+ }
+ }
+
+ se->name[s0 - expr] = 0;
+ trim_spaces (se->name);
+ if (!se->name[0])
+ {
+ log_error ("no field name given in expression\n");
+ recsel_release (se_head);
+ xfree (expr_buffer);
+ return my_error (GPG_ERR_NO_NAME);
+ }
+
+ if (!notrim)
+ trim_spaces (se->name + (s - expr));
+ se->value = se->name + (s - expr);
+ if (!se->value[0] && !(se->op == SELECT_NONEMPTY || se->op == SELECT_ISTRUE))
+ {
+ log_error ("no value given in expression\n");
+ recsel_release (se_head);
+ xfree (expr_buffer);
+ return my_error (GPG_ERR_MISSING_VALUE);
+ }
+
+ se->numvalue = strtol (se->value, NULL, 0);
+
+ if (next_lc)
+ {
+ disjun = next_lc[1] == '|';
+ expr = next_lc + 2;
+ goto next_term;
+ }
+
+ /* Read:y Append to passes last selector. */
+ if (!*selector)
+ *selector = se_head;
+ else
+ {
+ for (se2 = *selector; se2->next; se2 = se2->next)
+ ;
+ se2->next = se_head;
+ }
+
+ xfree (expr_buffer);
+ return 0;
+}
+
+
+void
+recsel_release (recsel_expr_t a)
+{
+ while (a)
+ {
+ recsel_expr_t tmp = a->next;
+ xfree (a);
+ a = tmp;
+ }
+}
+
+
+void
+recsel_dump (recsel_expr_t selector)
+{
+ recsel_expr_t se;
+
+ log_debug ("--- Begin selectors ---\n");
+ for (se = selector; se; se = se->next)
+ {
+ log_debug ("%s %s %s %s '%s'\n",
+ se==selector? " ": (se->disjun? "||":"&&"),
+ se->xcase? "-c":" ",
+ se->name,
+ se->op == SELECT_SAME? (se->not? "<>":"= "):
+ se->op == SELECT_SUB? (se->not? "!~":"=~"):
+ se->op == SELECT_NONEMPTY?(se->not? "-z":"-n"):
+ se->op == SELECT_ISTRUE? (se->not? "-f":"-t"):
+ se->op == SELECT_EQ? (se->not? "!=":"=="):
+ se->op == SELECT_LT? "< ":
+ se->op == SELECT_LE? "<=":
+ se->op == SELECT_GT? "> ":
+ se->op == SELECT_GE? ">=":
+ se->op == SELECT_STRLT? "-lt":
+ se->op == SELECT_STRLE? "-le":
+ se->op == SELECT_STRGT? "-gt":
+ se->op == SELECT_STRGE? "-ge":
+ /**/ "[oops]",
+ se->value);
+ }
+ log_debug ("--- End selectors ---\n");
+}
+
+
+/* Return true if the record RECORD has been selected. The GETVAL
+ * function is called with COOKIE and the NAME of a property used in
+ * the expression. */
+int
+recsel_select (recsel_expr_t selector,
+ const char *(*getval)(void *cookie, const char *propname),
+ void *cookie)
+{
+ recsel_expr_t se;
+ const char *value;
+ size_t selen, valuelen;
+ long numvalue;
+ int result = 1;
+
+ se = selector;
+ while (se)
+ {
+ value = getval? getval (cookie, se->name) : NULL;
+ if (!value)
+ value = "";
+
+ if (!*value)
+ {
+ /* Field is empty. */
+ result = 0;
+ }
+ else /* Field has a value. */
+ {
+ valuelen = strlen (value);
+ numvalue = strtol (value, NULL, 0);
+ selen = strlen (se->value);
+
+ switch (se->op)
+ {
+ case SELECT_SAME:
+ if (se->xcase)
+ result = (valuelen==selen && !memcmp (value,se->value,selen));
+ else
+ result = (valuelen==selen && !memicmp (value,se->value,selen));
+ break;
+ case SELECT_SUB:
+ if (se->xcase)
+ result = !!my_memstr (value, valuelen, se->value);
+ else
+ result = !!memistr (value, valuelen, se->value);
+ break;
+ case SELECT_NONEMPTY:
+ result = !!valuelen;
+ break;
+ case SELECT_ISTRUE:
+ result = !!numvalue;
+ break;
+ case SELECT_EQ:
+ result = (numvalue == se->numvalue);
+ break;
+ case SELECT_GT:
+ result = (numvalue > se->numvalue);
+ break;
+ case SELECT_GE:
+ result = (numvalue >= se->numvalue);
+ break;
+ case SELECT_LT:
+ result = (numvalue < se->numvalue);
+ break;
+ case SELECT_LE:
+ result = (numvalue <= se->numvalue);
+ break;
+ case SELECT_STRGT:
+ if (se->xcase)
+ result = strcmp (value, se->value) > 0;
+ else
+ result = strcasecmp (value, se->value) > 0;
+ break;
+ case SELECT_STRGE:
+ if (se->xcase)
+ result = strcmp (value, se->value) >= 0;
+ else
+ result = strcasecmp (value, se->value) >= 0;
+ break;
+ case SELECT_STRLT:
+ if (se->xcase)
+ result = strcmp (value, se->value) < 0;
+ else
+ result = strcasecmp (value, se->value) < 0;
+ break;
+ case SELECT_STRLE:
+ if (se->xcase)
+ result = strcmp (value, se->value) <= 0;
+ else
+ result = strcasecmp (value, se->value) <= 0;
+ break;
+ }
+ }
+
+ if (se->not)
+ result = !result;
+
+ if (result)
+ {
+ /* This expression evaluated to true. See whether there are
+ remaining expressions in this conjunction. */
+ if (!se->next || se->next->disjun)
+ break; /* All expressions are true. Return True. */
+ se = se->next; /* Test the next. */
+ }
+ else
+ {
+ /* This expression evaluated to false and thus the
+ * conjunction evaluates to false. We skip over the
+ * remaining expressions of this conjunction and continue
+ * with the next disjunction if any. */
+ do
+ se = se->next;
+ while (se && !se->disjun);
+ }
+ }
+
+ return result;
+}
diff --git a/common/recsel.h b/common/recsel.h
new file mode 100644
index 0000000..0e0a792
--- /dev/null
+++ b/common/recsel.h
@@ -0,0 +1,43 @@
+/* recsel.c - Record selection
+ * Copyright (C) 2016 Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+#ifndef GNUPG_COMMON_RECSEL_H
+#define GNUPG_COMMON_RECSEL_H
+
+struct recsel_expr_s;
+typedef struct recsel_expr_s *recsel_expr_t;
+
+gpg_error_t recsel_parse_expr (recsel_expr_t *selector, const char *expr);
+void recsel_release (recsel_expr_t a);
+void recsel_dump (recsel_expr_t selector);
+int recsel_select (recsel_expr_t selector,
+ const char *(*getval)(void *cookie, const char *propname),
+ void *cookie);
+
+
+#endif /*GNUPG_COMMON_RECSEL_H*/
diff --git a/common/server-help.c b/common/server-help.c
new file mode 100644
index 0000000..e5a69e0
--- /dev/null
+++ b/common/server-help.c
@@ -0,0 +1,185 @@
+/* server-help.h - Helper functions for writing Assuan servers.
+ * Copyright (C) 2003, 2009, 2010 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <string.h>
+
+#include "util.h"
+#include "server-help.h"
+
+
+static GPGRT_INLINE gpg_error_t
+my_error (int e)
+{
+ return gpg_err_make (default_errsource, (e));
+}
+
+static GPGRT_INLINE gpg_error_t
+my_error_from_syserror (void)
+{
+ return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
+}
+
+
+/* Skip over options in LINE.
+
+ Blanks after the options are also removed. Options are indicated
+ by two leading dashes followed by a string consisting of non-space
+ characters. The special option "--" indicates an explicit end of
+ options; all what follows will not be considered an option. The
+ first no-option string also indicates the end of option parsing. */
+char *
+skip_options (const char *line)
+{
+ while (spacep (line))
+ line++;
+ while (*line == '-' && line[1] == '-')
+ {
+ while (*line && !spacep (line))
+ line++;
+ while (spacep (line))
+ line++;
+ }
+ return (char*) line;
+}
+
+
+/* Check whether the option NAME appears in LINE. */
+int
+has_option (const char *line, const char *name)
+{
+ const char *s;
+ int n = strlen (name);
+
+ s = strstr (line, name);
+ if (s && s >= skip_options (line))
+ return 0;
+ return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n)));
+}
+
+
+/* Same as has_option but only considers options at the begin of the
+ line. This is useful for commands which allow arbitrary strings on
+ the line. */
+int
+has_leading_option (const char *line, const char *name)
+{
+ const char *s;
+ int n;
+
+ if (name[0] != '-' || name[1] != '-' || !name[2] || spacep (name+2))
+ return 0;
+ n = strlen (name);
+ while ( *line == '-' && line[1] == '-' )
+ {
+ s = line;
+ while (*line && !spacep (line))
+ line++;
+ if (n == (line - s) && !strncmp (s, name, n))
+ return 1;
+ while (spacep (line))
+ line++;
+ }
+ return 0;
+}
+
+
+/* Same as has_option but does only test for the name of the option
+ and ignores an argument, i.e. with NAME being "--hash" it would
+ return a pointer for "--hash" as well as for "--hash=foo". If
+ there is no such option NULL is returned. The pointer returned
+ points right behind the option name, this may be an equal sign, Nul
+ or a space. */
+const char *
+has_option_name (const char *line, const char *name)
+{
+ const char *s;
+ int n = strlen (name);
+
+ s = strstr (line, name);
+ return (s && (s == line || spacep (s-1))
+ && (!s[n] || spacep (s+n) || s[n] == '=')) ? (s+n) : NULL;
+}
+
+
+/* Parse an option with the format "--NAME=VALUE" which must occur in
+ * LINE before a double-dash. LINE is written to but not modified by
+ * this function. If the option is found and has a value the value is
+ * stored as a malloced string at R_VALUE. If the option was not
+ * found or an error occurred NULL is stored there. Note that
+ * currently the value must be a string without any space; we may
+ * eventually update this function to allow for a quoted value. */
+gpg_error_t
+get_option_value (char *line, const char *name, char **r_value)
+{
+ char *p, *pend;
+ int c;
+
+ *r_value = NULL;
+
+ p = (char*)has_option_name (line, name);
+ if (!p || p >= skip_options (line))
+ return 0;
+
+ if (*p != '=' || !p[1] || spacep (p+1))
+ return my_error (GPG_ERR_INV_ARG);
+ p++;
+ for (pend = p; *pend && !spacep (pend); pend++)
+ ;
+ c = *pend;
+ *pend = 0;
+ *r_value = xtrystrdup (p);
+ *pend = c;
+ if (!p)
+ return my_error_from_syserror ();
+ return 0;
+}
+
+
+/* Return a pointer to the argument of the option with NAME. If such
+ an option is not given, NULL is returned. */
+char *
+option_value (const char *line, const char *name)
+{
+ char *s;
+ int n = strlen (name);
+
+ s = strstr (line, name);
+ if (s && s >= skip_options (line))
+ return NULL;
+ if (s && (s == line || spacep (s-1))
+ && s[n] && (spacep (s+n) || s[n] == '='))
+ {
+ s += n + 1;
+ s += strspn (s, " ");
+ if (*s && !spacep(s))
+ return s;
+ }
+ return NULL;
+}
diff --git a/common/server-help.h b/common/server-help.h
new file mode 100644
index 0000000..9d2f4cf
--- /dev/null
+++ b/common/server-help.h
@@ -0,0 +1,70 @@
+/* server-help.h - Helper functions for writing Assuan servers.
+ * Copyright (C) 2003, 2009, 2010 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_COMMON_SERVER_HELP_H
+#define GNUPG_COMMON_SERVER_HELP_H
+
+/* Skip over options in LINE.
+
+ Blanks after the options are also removed. Options are indicated
+ by two leading dashes followed by a string consisting of non-space
+ characters. The special option "--" indicates an explicit end of
+ options; all what follows will not be considered an option. The
+ first no-option string also indicates the end of option parsing. */
+char *skip_options (const char *line);
+
+/* Check whether the option NAME appears in LINE. */
+int has_option (const char *line, const char *name);
+
+/* Same as has_option but only considers options at the begin of the
+ line. This is useful for commands which allow arbitrary strings on
+ the line. */
+int has_leading_option (const char *line, const char *name);
+
+/* Same as has_option but does only test for the name of the option
+ and ignores an argument, i.e. with NAME being "--hash" it would
+ return a pointer for "--hash" as well as for "--hash=foo". If
+ there is no such option NULL is returned. The pointer returned
+ points right behind the option name, this may be an equal sign, Nul
+ or a space. */
+const char *has_option_name (const char *line, const char *name);
+
+/* Same as has_option_name but ignores all options after a "--" and
+ * does not return a const char ptr. */
+char *has_leading_option_name (char *line, const char *name);
+
+/* Parse an option with the format "--NAME=VALUE" and return the value
+ * as a malloced string. */
+gpg_error_t get_option_value (char *line, const char *name, char **r_value);
+
+/* Return a pointer to the argument of the option with NAME. If such
+ an option is not given, NULL is returned. */
+char *option_value (const char *line, const char *name);
+
+#endif /* GNUPG_COMMON_SERVER_HELP_H */
diff --git a/common/session-env.c b/common/session-env.c
new file mode 100644
index 0000000..c46529a
--- /dev/null
+++ b/common/session-env.c
@@ -0,0 +1,406 @@
+/* session-env.c - Session environment helper functions.
+ * Copyright (C) 2009 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <ctype.h>
+#include <assert.h>
+#include <unistd.h>
+
+#include "util.h"
+#include "session-env.h"
+
+
+struct variable_s
+{
+ char *value; /* Pointer into NAME to the Nul terminated value. */
+ int is_default; /* The value is a default one. */
+ char name[1]; /* Nul terminated Name and space for the value. */
+};
+
+
+
+/* The session environment object. */
+struct session_environment_s
+{
+ size_t arraysize; /* Allocated size or ARRAY. */
+ size_t arrayused; /* Used size of ARRAY. */
+ struct variable_s **array; /* Array of variables. NULL slots are unused. */
+};
+
+
+/* A list of environment variables we pass from the actual user
+ (e.g. gpgme) down to the pinentry. We do not handle the locale
+ settings because they do not only depend on envvars. */
+static struct
+{
+ const char *name;
+ const char *assname; /* Name used by Assuan or NULL. */
+} stdenvnames[] = {
+ { "GPG_TTY", "ttyname" }, /* GnuPG specific envvar. */
+ { "TERM", "ttytype" }, /* Used to set ttytype. */
+ { "DISPLAY", "display" }, /* The X-Display. */
+ { "XAUTHORITY","xauthority"}, /* Xlib Authentication. */
+ { "XMODIFIERS" }, /* Used by Xlib to select X input
+ modules (eg "@im=SCIM"). */
+ { "WAYLAND_DISPLAY" }, /* For the Wayland display engine. */
+ { "XDG_SESSION_TYPE" }, /* Used by Qt and other non-GTK toolkits
+ to check for x11 or wayland. */
+ { "QT_QPA_PLATFORM" }, /* Used by Qt to explicitly request
+ x11 or wayland; in particular, needed
+ to make Qt use Wayland on Gnome. */
+ { "GTK_IM_MODULE" }, /* Used by gtk to select gtk input
+ modules (eg "scim-bridge"). */
+ { "DBUS_SESSION_BUS_ADDRESS" },/* Used by GNOME3 to talk to gcr over
+ dbus */
+ { "QT_IM_MODULE" }, /* Used by Qt to select qt input
+ modules (eg "xim"). */
+ { "INSIDE_EMACS" }, /* Set by Emacs before running a
+ process. */
+ { "PINENTRY_USER_DATA", "pinentry-user-data"}
+ /* Used for communication with
+ non-standard Pinentries. */
+};
+
+
+/* Track last allocated arraysize of all objects ever created. If
+ nothing has ever been allocated we use INITIAL_ARRAYSIZE and we
+ will never use more than MAXDEFAULT_ARRAYSIZE for initial
+ allocation. Note that this is not reentrant if used with a
+ preemptive thread model. */
+static size_t lastallocatedarraysize;
+#define INITIAL_ARRAYSIZE 8 /* Let's use the number of stdenvnames. */
+#define CHUNK_ARRAYSIZE 10
+#define MAXDEFAULT_ARRAYSIZE (INITIAL_ARRAYSIZE + CHUNK_ARRAYSIZE * 5)
+
+
+/* Return the names of standard environment variables one after the
+ other. The caller needs to set the value at the address of
+ ITERATOR initially to 0 and then call this function until it returns
+ NULL. */
+const char *
+session_env_list_stdenvnames (int *iterator, const char **r_assname)
+{
+ int idx = *iterator;
+
+ if (idx < 0 || idx >= DIM (stdenvnames))
+ return NULL;
+ *iterator = idx + 1;
+ if (r_assname)
+ *r_assname = stdenvnames[idx].assname;
+ return stdenvnames[idx].name;
+}
+
+
+/* Create a new session environment object. Return NULL and sets
+ ERRNO on failure. */
+session_env_t
+session_env_new (void)
+{
+ session_env_t se;
+
+ se = xtrycalloc (1, sizeof *se);
+ if (se)
+ {
+ se->arraysize = (lastallocatedarraysize?
+ lastallocatedarraysize : INITIAL_ARRAYSIZE);
+ se->array = xtrycalloc (se->arraysize, sizeof *se->array);
+ if (!se->array)
+ {
+ xfree (se);
+ se = NULL;
+ }
+ }
+
+ return se;
+}
+
+
+/* Release a session environment object. */
+void
+session_env_release (session_env_t se)
+{
+ int idx;
+
+ if (!se)
+ return;
+
+ if (se->arraysize > INITIAL_ARRAYSIZE
+ && se->arraysize <= MAXDEFAULT_ARRAYSIZE
+ && se->arraysize > lastallocatedarraysize)
+ lastallocatedarraysize = se->arraysize;
+
+ for (idx=0; idx < se->arrayused; idx++)
+ if (se->array[idx])
+ xfree (se->array[idx]);
+ xfree (se->array);
+ xfree (se);
+}
+
+
+static gpg_error_t
+delete_var (session_env_t se, const char *name)
+{
+ int idx;
+
+ for (idx=0; idx < se->arrayused; idx++)
+ if (se->array[idx] && !strcmp (se->array[idx]->name, name))
+ {
+ xfree (se->array[idx]);
+ se->array[idx] = NULL;
+ }
+ return 0;
+}
+
+
+static gpg_error_t
+update_var (session_env_t se, const char *string, size_t namelen,
+ const char *explicit_value, int set_default)
+{
+ int idx;
+ int freeidx = -1;
+ const char *value;
+ size_t valuelen;
+ struct variable_s *var;
+
+ if (explicit_value)
+ value = explicit_value;
+ else
+ value = string + namelen + 1;
+ valuelen = strlen (value);
+
+ for (idx=0; idx < se->arrayused; idx++)
+ {
+ if (!se->array[idx])
+ freeidx = idx;
+ else if (!strncmp (se->array[idx]->name, string, namelen)
+ && strlen (se->array[idx]->name) == namelen)
+ {
+ if (strlen (se->array[idx]->value) == valuelen)
+ {
+ /* The new value has the same length. We can update it
+ in-place. */
+ memcpy (se->array[idx]->value, value, valuelen);
+ se->array[idx]->is_default = !!set_default;
+ return 0;
+ }
+ /* Prepare for update. */
+ freeidx = idx;
+ }
+ }
+
+ if (freeidx == -1)
+ {
+ if (se->arrayused == se->arraysize)
+ {
+ /* Reallocate the array. */
+ size_t newsize;
+ struct variable_s **newarray;
+
+ newsize = se->arraysize + CHUNK_ARRAYSIZE;
+ newarray = xtrycalloc (newsize, sizeof *newarray);
+ if (!newarray)
+ return gpg_error_from_syserror ();
+ for (idx=0; idx < se->arrayused; idx++)
+ newarray[idx] = se->array[idx];
+ se->arraysize = newsize;
+ xfree (se->array);
+ se->array = newarray;
+ }
+ freeidx = se->arrayused++;
+ }
+
+ /* Allocate new memory and return an error if that didn't worked.
+ Allocating it first allows us to keep the old value; it doesn't
+ matter that arrayused has already been incremented in case of a
+ new entry - it will then pint to a NULL slot. */
+ var = xtrymalloc (sizeof *var + namelen + 1 + valuelen);
+ if (!var)
+ return gpg_error_from_syserror ();
+ var->is_default = !!set_default;
+ memcpy (var->name, string, namelen);
+ var->name[namelen] = '\0';
+ var->value = var->name + namelen + 1;
+ strcpy (var->value, value);
+
+ xfree (se->array[freeidx]);
+ se->array[freeidx] = var;
+ return 0;
+}
+
+
+/* Set or update an environment variable of the session environment.
+ String is similar to the putval(3) function but it is reentrant and
+ takes a copy. In particular it exhibits this behaviour:
+
+ <NAME> Delete envvar NAME
+ <KEY>= Set envvar NAME to the empty string
+ <KEY>=<VALUE> Set envvar NAME to VALUE
+
+ On success 0 is returned; on error an gpg-error code. */
+gpg_error_t
+session_env_putenv (session_env_t se, const char *string)
+{
+ const char *s;
+
+ if (!string || !*string)
+ return gpg_error (GPG_ERR_INV_VALUE);
+ s = strchr (string, '=');
+ if (s == string)
+ return gpg_error (GPG_ERR_INV_VALUE);
+ if (!s)
+ return delete_var (se, string);
+ else
+ return update_var (se, string, s - string, NULL, 0);
+}
+
+
+/* Same as session_env_putenv but with name and value given as distict
+ values. */
+gpg_error_t
+session_env_setenv (session_env_t se, const char *name, const char *value)
+{
+ if (!name || !*name)
+ return gpg_error (GPG_ERR_INV_VALUE);
+ if (!value)
+ return delete_var (se, name);
+ else
+ return update_var (se, name, strlen (name), value, 0);
+}
+
+
+
+
+/* Return the value of the environment variable NAME from the SE
+ object. If the variable does not exist, NULL is returned. The
+ returned value is valid as long as SE is valid and as long it has
+ not been removed or updated by a call to session_env_putenv. The
+ caller MUST not change the returned value. */
+char *
+session_env_getenv (session_env_t se, const char *name)
+{
+ int idx;
+
+ if (!se || !name || !*name)
+ return NULL;
+
+ for (idx=0; idx < se->arrayused; idx++)
+ if (se->array[idx] && !strcmp (se->array[idx]->name, name))
+ return se->array[idx]->is_default? NULL : se->array[idx]->value;
+ return NULL;
+}
+
+
+/* Return the value of the environment variable NAME from the SE
+ object. The returned value is valid as long as SE is valid and as
+ long it has not been removed or updated by a call to
+ session_env_putenv. If the variable does not exist, the function
+ tries to return the value trough a call to getenv; if that returns
+ a value, this value is recorded and used. If no value could be
+ found, returns NULL. The caller must not change the returned
+ value. */
+char *
+session_env_getenv_or_default (session_env_t se, const char *name,
+ int *r_default)
+{
+ int idx;
+ char *defvalue;
+
+ if (r_default)
+ *r_default = 0;
+ if (!se || !name || !*name)
+ return NULL;
+
+ for (idx=0; idx < se->arrayused; idx++)
+ if (se->array[idx] && !strcmp (se->array[idx]->name, name))
+ {
+ if (r_default && se->array[idx]->is_default)
+ *r_default = 1;
+ return se->array[idx]->value;
+ }
+
+ /* Get the default value with an additional fallback for GPG_TTY. */
+ defvalue = getenv (name);
+ if ((!defvalue || !*defvalue) && !strcmp (name, "GPG_TTY")
+ && gnupg_ttyname (0))
+ {
+ defvalue = gnupg_ttyname (0);
+ }
+ if (defvalue)
+ {
+ /* Record the default value for later use so that we are safe
+ from later modifications of the environment. We need to take
+ a copy to better cope with the rules of putenv(3). We ignore
+ the error of the update function because we can't return an
+ explicit error anyway and the following scan would then fail
+ anyway. */
+ update_var (se, name, strlen (name), defvalue, 1);
+
+ for (idx=0; idx < se->arrayused; idx++)
+ if (se->array[idx] && !strcmp (se->array[idx]->name, name))
+ {
+ if (r_default && se->array[idx]->is_default)
+ *r_default = 1;
+ return se->array[idx]->value;
+ }
+ }
+
+ return NULL;
+}
+
+
+/* List the entire environment stored in SE. The caller initially
+ needs to set the value of ITERATOR to 0 and then call this function
+ until it returns NULL. The value is returned at R_VALUE. If
+ R_DEFAULT is not NULL, the default flag is stored on return. The
+ default flag indicates that the value has been taken from the
+ process' environment. The caller must not change the returned
+ name or value. */
+char *
+session_env_listenv (session_env_t se, int *iterator,
+ const char **r_value, int *r_default)
+{
+ int idx = *iterator;
+
+ if (!se || idx < 0)
+ return NULL;
+
+ for (; idx < se->arrayused; idx++)
+ if (se->array[idx])
+ {
+ *iterator = idx+1;
+ if (r_default)
+ *r_default = se->array[idx]->is_default;
+ if (r_value)
+ *r_value = se->array[idx]->value;
+ return se->array[idx]->name;
+ }
+ return NULL;
+}
diff --git a/common/session-env.h b/common/session-env.h
new file mode 100644
index 0000000..8709e22
--- /dev/null
+++ b/common/session-env.h
@@ -0,0 +1,53 @@
+/* session-env.h - Definitions for session environment functions
+ * Copyright (C) 2009 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_COMMON_SESSION_ENV_H
+#define GNUPG_COMMON_SESSION_ENV_H
+
+struct session_environment_s;
+typedef struct session_environment_s *session_env_t;
+
+const char *session_env_list_stdenvnames (int *iterator,
+ const char **r_assname);
+
+session_env_t session_env_new (void);
+void session_env_release (session_env_t se);
+
+gpg_error_t session_env_putenv (session_env_t se, const char *string);
+gpg_error_t session_env_setenv (session_env_t se,
+ const char *name, const char *value);
+
+char *session_env_getenv (session_env_t se, const char *name);
+char *session_env_getenv_or_default (session_env_t se, const char *name,
+ int *r_default);
+char *session_env_listenv (session_env_t se, int *iterator,
+ const char **r_value, int *r_default);
+
+
+#endif /*GNUPG_COMMON_SESSION_ENV_H*/
diff --git a/common/sexp-parse.h b/common/sexp-parse.h
new file mode 100644
index 0000000..4f77f14
--- /dev/null
+++ b/common/sexp-parse.h
@@ -0,0 +1,137 @@
+/* sexp-parse.h - S-expression helper functions
+ * Copyright (C) 2002, 2003, 2007 Free Software Foundation, Inc.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef SEXP_PARSE_H
+#define SEXP_PARSE_H
+
+#include <gpg-error.h>
+
+
+/* Return the length of the next S-Exp part and update the pointer to
+ the first data byte. 0 is returned on error */
+static inline size_t
+snext (unsigned char const **buf)
+{
+ const unsigned char *s;
+ int n;
+
+ s = *buf;
+ for (n=0; *s && *s != ':' && (*s >= '0' && *s <= '9'); s++)
+ n = n*10 + (*s - '0');
+ if (!n || *s != ':')
+ return 0; /* we don't allow empty lengths */
+ *buf = s+1;
+ return n;
+}
+
+/* Skip over the S-Expression BUF points to and update BUF to point to
+ the character right behind. DEPTH gives the initial number of open
+ lists and may be passed as a positive number to skip over the
+ remainder of an S-Expression if the current position is somewhere
+ in an S-Expression. The function may return an error code if it
+ encounters an impossible condition. */
+static inline gpg_error_t
+sskip (unsigned char const **buf, int *depth)
+{
+ const unsigned char *s = *buf;
+ size_t n;
+ int d = *depth;
+
+ while (d > 0)
+ {
+ if (*s == '(')
+ {
+ d++;
+ s++;
+ }
+ else if (*s == ')')
+ {
+ d--;
+ s++;
+ }
+ else
+ {
+ if (!d)
+ return gpg_error (GPG_ERR_INV_SEXP);
+ n = snext (&s);
+ if (!n)
+ return gpg_error (GPG_ERR_INV_SEXP);
+ s += n;
+ }
+ }
+ *buf = s;
+ *depth = d;
+ return 0;
+}
+
+
+/* Check whether the string at the address BUF points to matches
+ the token. Return true on match and update BUF to point behind the
+ token. Return false and do not update the buffer if it does not
+ match. */
+static inline int
+smatch (unsigned char const **buf, size_t buflen, const char *token)
+{
+ size_t toklen = strlen (token);
+
+ if (buflen != toklen || memcmp (*buf, token, toklen))
+ return 0;
+ *buf += toklen;
+ return 1;
+}
+
+/* Format VALUE for use as the length indicatior of an S-expression.
+ The caller needs to provide a buffer HELP_BUFFER wth a length of
+ HELP_BUFLEN. The return value is a pointer into HELP_BUFFER with
+ the formatted length string. The colon and a trailing nul are
+ appended. HELP_BUFLEN must be at least 3 - a more useful value is
+ 15. If LENGTH is not NULL, the LENGTH of the resulting string
+ (excluding the terminating nul) is stored at that address. */
+static inline char *
+smklen (char *help_buffer, size_t help_buflen, size_t value, size_t *length)
+{
+ char *p = help_buffer + help_buflen;
+
+ if (help_buflen >= 3)
+ {
+ *--p = 0;
+ *--p = ':';
+ do
+ {
+ *--p = '0' + (value % 10);
+ value /= 10;
+ }
+ while (value && p > help_buffer);
+ }
+
+ if (length)
+ *length = (help_buffer + help_buflen) - p;
+ return p;
+}
+
+
+#endif /*SEXP_PARSE_H*/
diff --git a/common/sexputil.c b/common/sexputil.c
new file mode 100644
index 0000000..68388e1
--- /dev/null
+++ b/common/sexputil.c
@@ -0,0 +1,1188 @@
+/* sexputil.c - Utility functions for S-expressions.
+ * Copyright (C) 2005, 2007, 2009 Free Software Foundation, Inc.
+ * Copyright (C) 2013 Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+/* This file implements a few utility functions useful when working
+ with canonical encrypted S-expressions (i.e. not the S-exprssion
+ objects from libgcrypt). */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#ifdef HAVE_LOCALE_H
+#include <locale.h>
+#endif
+
+#include "util.h"
+#include "tlv.h"
+#include "sexp-parse.h"
+#include "openpgpdefs.h" /* for pubkey_algo_t */
+
+
+/* Return a malloced string with the S-expression CANON in advanced
+ format. Returns NULL on error. */
+static char *
+sexp_to_string (gcry_sexp_t sexp)
+{
+ size_t n;
+ char *result;
+
+ if (!sexp)
+ return NULL;
+ n = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_ADVANCED, NULL, 0);
+ if (!n)
+ return NULL;
+ result = xtrymalloc (n);
+ if (!result)
+ return NULL;
+ n = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_ADVANCED, result, n);
+ if (!n)
+ BUG ();
+
+ return result;
+}
+
+
+/* Return a malloced string with the S-expression CANON in advanced
+ format. Returns NULL on error. */
+char *
+canon_sexp_to_string (const unsigned char *canon, size_t canonlen)
+{
+ size_t n;
+ gcry_sexp_t sexp;
+ char *result;
+
+ n = gcry_sexp_canon_len (canon, canonlen, NULL, NULL);
+ if (!n)
+ return NULL;
+ if (gcry_sexp_sscan (&sexp, NULL, canon, n))
+ return NULL;
+ result = sexp_to_string (sexp);
+ gcry_sexp_release (sexp);
+ return result;
+}
+
+
+/* Print the canonical encoded S-expression in SEXP in advanced
+ format. SEXPLEN may be passed as 0 is SEXP is known to be valid.
+ With TEXT of NULL print just the raw S-expression, with TEXT just
+ an empty string, print a trailing linefeed, otherwise print an
+ entire debug line. */
+void
+log_printcanon (const char *text, const unsigned char *sexp, size_t sexplen)
+{
+ if (text && *text)
+ log_debug ("%s ", text);
+ if (sexp)
+ {
+ char *buf = canon_sexp_to_string (sexp, sexplen);
+ log_printf ("%s", buf? buf : "[invalid S-expression]");
+ xfree (buf);
+ }
+ if (text)
+ log_printf ("\n");
+}
+
+
+/* Print the gcryp S-expression in SEXP in advanced format. With TEXT
+ of NULL print just the raw S-expression, with TEXT just an empty
+ string, print a trailing linefeed, otherwise print an entire debug
+ line. */
+void
+log_printsexp (const char *text, gcry_sexp_t sexp)
+{
+ if (text && *text)
+ log_debug ("%s ", text);
+ if (sexp)
+ {
+ char *buf = sexp_to_string (sexp);
+ log_printf ("%s", buf? buf : "[invalid S-expression]");
+ xfree (buf);
+ }
+ if (text)
+ log_printf ("\n");
+}
+
+
+/* Helper function to create a canonical encoded S-expression from a
+ Libgcrypt S-expression object. The function returns 0 on success
+ and the malloced canonical S-expression is stored at R_BUFFER and
+ the allocated length at R_BUFLEN. On error an error code is
+ returned and (NULL, 0) stored at R_BUFFER and R_BUFLEN. If the
+ allocated buffer length is not required, NULL by be used for
+ R_BUFLEN. */
+gpg_error_t
+make_canon_sexp (gcry_sexp_t sexp, unsigned char **r_buffer, size_t *r_buflen)
+{
+ size_t len;
+ unsigned char *buf;
+
+ *r_buffer = NULL;
+ if (r_buflen)
+ *r_buflen = 0;;
+
+ len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, NULL, 0);
+ if (!len)
+ return gpg_error (GPG_ERR_BUG);
+ buf = xtrymalloc (len);
+ if (!buf)
+ return gpg_error_from_syserror ();
+ len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, buf, len);
+ if (!len)
+ return gpg_error (GPG_ERR_BUG);
+
+ *r_buffer = buf;
+ if (r_buflen)
+ *r_buflen = len;
+
+ return 0;
+}
+
+
+/* Same as make_canon_sexp but pad the buffer to multiple of 64
+ bits. If SECURE is set, secure memory will be allocated. */
+gpg_error_t
+make_canon_sexp_pad (gcry_sexp_t sexp, int secure,
+ unsigned char **r_buffer, size_t *r_buflen)
+{
+ size_t len;
+ unsigned char *buf;
+
+ *r_buffer = NULL;
+ if (r_buflen)
+ *r_buflen = 0;;
+
+ len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, NULL, 0);
+ if (!len)
+ return gpg_error (GPG_ERR_BUG);
+ len += (8 - len % 8) % 8;
+ buf = secure? xtrycalloc_secure (1, len) : xtrycalloc (1, len);
+ if (!buf)
+ return gpg_error_from_syserror ();
+ if (!gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, buf, len))
+ return gpg_error (GPG_ERR_BUG);
+
+ *r_buffer = buf;
+ if (r_buflen)
+ *r_buflen = len;
+
+ return 0;
+}
+
+/* Return the so called "keygrip" which is the SHA-1 hash of the
+ public key parameters expressed in a way depended on the algorithm.
+
+ KEY is expected to be an canonical encoded S-expression with a
+ public or private key. KEYLEN is the length of that buffer.
+
+ GRIP must be at least 20 bytes long. On success 0 is returned, on
+ error an error code. */
+gpg_error_t
+keygrip_from_canon_sexp (const unsigned char *key, size_t keylen,
+ unsigned char *grip)
+{
+ gpg_error_t err;
+ gcry_sexp_t sexp;
+
+ if (!grip)
+ return gpg_error (GPG_ERR_INV_VALUE);
+ err = gcry_sexp_sscan (&sexp, NULL, (const char *)key, keylen);
+ if (err)
+ return err;
+ if (!gcry_pk_get_keygrip (sexp, grip))
+ err = gpg_error (GPG_ERR_INTERNAL);
+ gcry_sexp_release (sexp);
+ return err;
+}
+
+
+/* Compare two simple S-expressions like "(3:foo)". Returns 0 if they
+ are identical or !0 if they are not. Note that this function can't
+ be used for sorting. */
+int
+cmp_simple_canon_sexp (const unsigned char *a_orig,
+ const unsigned char *b_orig)
+{
+ const char *a = (const char *)a_orig;
+ const char *b = (const char *)b_orig;
+ unsigned long n1, n2;
+ char *endp;
+
+ if (!a && !b)
+ return 0; /* Both are NULL, they are identical. */
+ if (!a || !b)
+ return 1; /* One is NULL, they are not identical. */
+ if (*a != '(' || *b != '(')
+ log_bug ("invalid S-exp in cmp_simple_canon_sexp\n");
+
+ a++;
+ n1 = strtoul (a, &endp, 10);
+ a = endp;
+ b++;
+ n2 = strtoul (b, &endp, 10);
+ b = endp;
+
+ if (*a != ':' || *b != ':' )
+ log_bug ("invalid S-exp in cmp_simple_canon_sexp\n");
+ if (n1 != n2)
+ return 1; /* Not the same. */
+
+ for (a++, b++; n1; n1--, a++, b++)
+ if (*a != *b)
+ return 1; /* Not the same. */
+ return 0;
+}
+
+
+
+/* Helper for cmp_canon_sexp. */
+static int
+cmp_canon_sexp_def_tcmp (void *ctx, int depth,
+ const unsigned char *aval, size_t alen,
+ const unsigned char *bval, size_t blen)
+{
+ (void)ctx;
+ (void)depth;
+
+ if (alen > blen)
+ return 1;
+ else if (alen < blen)
+ return -1;
+ else
+ return memcmp (aval, bval, alen);
+}
+
+
+/* Compare the two canonical encoded s-expressions A with maximum
+ * length ALEN and B with maximum length BLEN.
+ *
+ * Returns 0 if they match.
+ *
+ * If TCMP is NULL, this is not different really different from a
+ * memcmp but does not consider any garbage after the last closing
+ * parentheses.
+ *
+ * If TCMP is not NULL, it is expected to be a function to compare the
+ * values of each token. TCMP is called for each token while parsing
+ * the s-expressions until TCMP return a non-zero value. Here the CTX
+ * receives the provided value TCMPCTX, DEPTH is the number of
+ * currently open parentheses and (AVAL,ALEN) and (BVAL,BLEN) the
+ * values of the current token. TCMP needs to return zero to indicate
+ * that the tokens match. */
+int
+cmp_canon_sexp (const unsigned char *a, size_t alen,
+ const unsigned char *b, size_t blen,
+ int (*tcmp)(void *ctx, int depth,
+ const unsigned char *aval, size_t avallen,
+ const unsigned char *bval, size_t bvallen),
+ void *tcmpctx)
+{
+ const unsigned char *a_buf, *a_tok;
+ const unsigned char *b_buf, *b_tok;
+ size_t a_buflen, a_toklen;
+ size_t b_buflen, b_toklen;
+ int a_depth, b_depth, ret;
+
+ if ((!a && !b) || (!alen && !blen))
+ return 0; /* Both are NULL, they are identical. */
+ if (!a || !b)
+ return !!a - !!b; /* One is NULL, they are not identical. */
+ if (*a != '(' || *b != '(')
+ log_bug ("invalid S-exp in %s\n", __func__);
+
+ if (!tcmp)
+ tcmp = cmp_canon_sexp_def_tcmp;
+
+ a_depth = 0;
+ a_buf = a;
+ a_buflen = alen;
+ b_depth = 0;
+ b_buf = b;
+ b_buflen = blen;
+
+ for (;;)
+ {
+ if (parse_sexp (&a_buf, &a_buflen, &a_depth, &a_tok, &a_toklen))
+ return -1; /* A is invalid. */
+ if (parse_sexp (&b_buf, &b_buflen, &b_depth, &b_tok, &b_toklen))
+ return -1; /* B is invalid. */
+ if (!a_depth && !b_depth)
+ return 0; /* End of both expressions - they match. */
+ if (a_depth != b_depth)
+ return a_depth - b_depth; /* Not the same structure */
+ if (!a_tok && !b_tok)
+ ; /* parens */
+ else if (a_tok && b_tok)
+ {
+ ret = tcmp (tcmpctx, a_depth, a_tok, a_toklen, b_tok, b_toklen);
+ if (ret)
+ return ret; /* Mismatch */
+ }
+ else /* One has a paren other has not. */
+ return !!a_tok - !!b_tok;
+ }
+}
+
+
+/* Create a simple S-expression from the hex string at LINE. Returns
+ a newly allocated buffer with that canonical encoded S-expression
+ or NULL in case of an error. On return the number of characters
+ scanned in LINE will be stored at NSCANNED. This functions stops
+ converting at the first character not representing a hexdigit. Odd
+ numbers of hex digits are allowed; a leading zero is then
+ assumed. If no characters have been found, NULL is returned.*/
+unsigned char *
+make_simple_sexp_from_hexstr (const char *line, size_t *nscanned)
+{
+ size_t n, len;
+ const char *s;
+ unsigned char *buf;
+ unsigned char *p;
+ char numbuf[50], *numbufp;
+ size_t numbuflen;
+
+ for (n=0, s=line; hexdigitp (s); s++, n++)
+ ;
+ if (nscanned)
+ *nscanned = n;
+ if (!n)
+ return NULL;
+ len = ((n+1) & ~0x01)/2;
+ numbufp = smklen (numbuf, sizeof numbuf, len, &numbuflen);
+ buf = xtrymalloc (1 + numbuflen + len + 1 + 1);
+ if (!buf)
+ return NULL;
+ buf[0] = '(';
+ p = (unsigned char *)stpcpy ((char *)buf+1, numbufp);
+ s = line;
+ if ((n&1))
+ {
+ *p++ = xtoi_1 (s);
+ s++;
+ n--;
+ }
+ for (; n > 1; n -=2, s += 2)
+ *p++ = xtoi_2 (s);
+ *p++ = ')';
+ *p = 0; /* (Not really neaded.) */
+
+ return buf;
+}
+
+
+/* Return the hash algorithm from a KSBA sig-val. SIGVAL is a
+ canonical encoded S-expression. Return 0 if the hash algorithm is
+ not encoded in SIG-VAL or it is not supported by libgcrypt. */
+int
+hash_algo_from_sigval (const unsigned char *sigval)
+{
+ const unsigned char *s = sigval;
+ size_t n;
+ int depth;
+ char buffer[50];
+
+ if (!s || *s != '(')
+ return 0; /* Invalid S-expression. */
+ s++;
+ n = snext (&s);
+ if (!n)
+ return 0; /* Invalid S-expression. */
+ if (!smatch (&s, n, "sig-val"))
+ return 0; /* Not a sig-val. */
+ if (*s != '(')
+ return 0; /* Invalid S-expression. */
+ s++;
+ /* Skip over the algo+parameter list. */
+ depth = 1;
+ if (sskip (&s, &depth) || depth)
+ return 0; /* Invalid S-expression. */
+ if (*s != '(')
+ return 0; /* No further list. */
+ /* Check whether this is (hash ALGO). */
+ s++;
+ n = snext (&s);
+ if (!n)
+ return 0; /* Invalid S-expression. */
+ if (!smatch (&s, n, "hash"))
+ return 0; /* Not a "hash" keyword. */
+ n = snext (&s);
+ if (!n || n+1 >= sizeof (buffer))
+ return 0; /* Algorithm string is missing or too long. */
+ memcpy (buffer, s, n);
+ buffer[n] = 0;
+
+ return gcry_md_map_name (buffer);
+}
+
+
+/* Create a public key S-expression for an RSA public key from the
+ modulus M with length MLEN and the public exponent E with length
+ ELEN. Returns a newly allocated buffer of NULL in case of a memory
+ allocation problem. If R_LEN is not NULL, the length of the
+ canonical S-expression is stored there. */
+unsigned char *
+make_canon_sexp_from_rsa_pk (const void *m_arg, size_t mlen,
+ const void *e_arg, size_t elen,
+ size_t *r_len)
+{
+ const unsigned char *m = m_arg;
+ const unsigned char *e = e_arg;
+ int m_extra = 0;
+ int e_extra = 0;
+ char mlen_str[35];
+ char elen_str[35];
+ unsigned char *keybuf, *p;
+ const char part1[] = "(10:public-key(3:rsa(1:n";
+ const char part2[] = ")(1:e";
+ const char part3[] = ")))";
+
+ /* Remove leading zeroes. */
+ for (; mlen && !*m; mlen--, m++)
+ ;
+ for (; elen && !*e; elen--, e++)
+ ;
+
+ /* Insert a leading zero if the number would be zero or interpreted
+ as negative. */
+ if (!mlen || (m[0] & 0x80))
+ m_extra = 1;
+ if (!elen || (e[0] & 0x80))
+ e_extra = 1;
+
+ /* Build the S-expression. */
+ snprintf (mlen_str, sizeof mlen_str, "%u:", (unsigned int)mlen+m_extra);
+ snprintf (elen_str, sizeof elen_str, "%u:", (unsigned int)elen+e_extra);
+
+ keybuf = xtrymalloc (strlen (part1) + strlen (mlen_str) + mlen + m_extra
+ + strlen (part2) + strlen (elen_str) + elen + e_extra
+ + strlen (part3) + 1);
+ if (!keybuf)
+ return NULL;
+
+ p = stpcpy (keybuf, part1);
+ p = stpcpy (p, mlen_str);
+ if (m_extra)
+ *p++ = 0;
+ memcpy (p, m, mlen);
+ p += mlen;
+ p = stpcpy (p, part2);
+ p = stpcpy (p, elen_str);
+ if (e_extra)
+ *p++ = 0;
+ memcpy (p, e, elen);
+ p += elen;
+ p = stpcpy (p, part3);
+
+ if (r_len)
+ *r_len = p - keybuf;
+
+ return keybuf;
+}
+
+
+/* Return the parameters of a public RSA key expressed as an
+ canonical encoded S-expression. */
+gpg_error_t
+get_rsa_pk_from_canon_sexp (const unsigned char *keydata, size_t keydatalen,
+ unsigned char const **r_n, size_t *r_nlen,
+ unsigned char const **r_e, size_t *r_elen)
+{
+ gpg_error_t err;
+ const unsigned char *buf, *tok;
+ size_t buflen, toklen;
+ int depth, last_depth1, last_depth2;
+ const unsigned char *rsa_n = NULL;
+ const unsigned char *rsa_e = NULL;
+ size_t rsa_n_len, rsa_e_len;
+
+ *r_n = NULL;
+ *r_nlen = 0;
+ *r_e = NULL;
+ *r_elen = 0;
+
+ buf = keydata;
+ buflen = keydatalen;
+ depth = 0;
+ if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
+ return err;
+ if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
+ return err;
+ if (!tok || toklen != 10 || memcmp ("public-key", tok, toklen))
+ return gpg_error (GPG_ERR_BAD_PUBKEY);
+ if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
+ return err;
+ if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
+ return err;
+ if (!tok || toklen != 3 || memcmp ("rsa", tok, toklen))
+ return gpg_error (GPG_ERR_WRONG_PUBKEY_ALGO);
+
+ last_depth1 = depth;
+ while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))
+ && depth && depth >= last_depth1)
+ {
+ if (tok)
+ return gpg_error (GPG_ERR_UNKNOWN_SEXP);
+ if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
+ return err;
+ if (tok && toklen == 1)
+ {
+ const unsigned char **mpi;
+ size_t *mpi_len;
+
+ switch (*tok)
+ {
+ case 'n': mpi = &rsa_n; mpi_len = &rsa_n_len; break;
+ case 'e': mpi = &rsa_e; mpi_len = &rsa_e_len; break;
+ default: mpi = NULL; mpi_len = NULL; break;
+ }
+ if (mpi && *mpi)
+ return gpg_error (GPG_ERR_DUP_VALUE);
+
+ if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
+ return err;
+ if (tok && mpi)
+ {
+ /* Strip off leading zero bytes and save. */
+ for (;toklen && !*tok; toklen--, tok++)
+ ;
+ *mpi = tok;
+ *mpi_len = toklen;
+ }
+ }
+
+ /* Skip to the end of the list. */
+ last_depth2 = depth;
+ while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))
+ && depth && depth >= last_depth2)
+ ;
+ if (err)
+ return err;
+ }
+
+ if (err)
+ return err;
+
+ if (!rsa_n || !rsa_n_len || !rsa_e || !rsa_e_len)
+ return gpg_error (GPG_ERR_BAD_PUBKEY);
+
+ *r_n = rsa_n;
+ *r_nlen = rsa_n_len;
+ *r_e = rsa_e;
+ *r_elen = rsa_e_len;
+ return 0;
+}
+
+
+/* Return the public key parameter Q of a public RSA or ECC key
+ * expressed as an canonical encoded S-expression. */
+gpg_error_t
+get_ecc_q_from_canon_sexp (const unsigned char *keydata, size_t keydatalen,
+ unsigned char const **r_q, size_t *r_qlen)
+{
+ gpg_error_t err;
+ const unsigned char *buf, *tok;
+ size_t buflen, toklen;
+ int depth, last_depth1, last_depth2;
+ const unsigned char *ecc_q = NULL;
+ size_t ecc_q_len;
+
+ *r_q = NULL;
+ *r_qlen = 0;
+
+ buf = keydata;
+ buflen = keydatalen;
+ depth = 0;
+ if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
+ return err;
+ if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
+ return err;
+ if (!tok || toklen != 10 || memcmp ("public-key", tok, toklen))
+ return gpg_error (GPG_ERR_BAD_PUBKEY);
+ if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
+ return err;
+ if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
+ return err;
+ if (tok && toklen == 3 && !memcmp ("ecc", tok, toklen))
+ ;
+ else if (tok && toklen == 5 && (!memcmp ("ecdsa", tok, toklen)
+ || !memcmp ("eddsa", tok, toklen)))
+ ;
+ else
+ return gpg_error (GPG_ERR_WRONG_PUBKEY_ALGO);
+
+ last_depth1 = depth;
+ while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))
+ && depth && depth >= last_depth1)
+ {
+ if (tok)
+ return gpg_error (GPG_ERR_UNKNOWN_SEXP);
+ if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
+ return err;
+ if (tok && toklen == 1)
+ {
+ const unsigned char **mpi;
+ size_t *mpi_len;
+
+ switch (*tok)
+ {
+ case 'q': mpi = &ecc_q; mpi_len = &ecc_q_len; break;
+ default: mpi = NULL; mpi_len = NULL; break;
+ }
+ if (mpi && *mpi)
+ return gpg_error (GPG_ERR_DUP_VALUE);
+
+ if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
+ return err;
+ if (tok && mpi)
+ {
+ *mpi = tok;
+ *mpi_len = toklen;
+ }
+ }
+
+ /* Skip to the end of the list. */
+ last_depth2 = depth;
+ while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))
+ && depth && depth >= last_depth2)
+ ;
+ if (err)
+ return err;
+ }
+
+ if (err)
+ return err;
+
+ if (!ecc_q || !ecc_q_len)
+ return gpg_error (GPG_ERR_BAD_PUBKEY);
+
+ *r_q = ecc_q;
+ *r_qlen = ecc_q_len;
+ return 0;
+}
+
+
+/* Return an uncompressed point (X,Y) in P at R_BUF as a malloced
+ * buffer with its byte length stored at R_BUFLEN. May not be used
+ * for sensitive data. */
+static gpg_error_t
+ec2os (gcry_mpi_t x, gcry_mpi_t y, gcry_mpi_t p,
+ unsigned char **r_buf, unsigned int *r_buflen)
+{
+ gpg_error_t err;
+ int pbytes = (mpi_get_nbits (p)+7)/8;
+ size_t n;
+ unsigned char *buf, *ptr;
+
+ *r_buf = NULL;
+ *r_buflen = 0;
+
+ buf = xtrymalloc (1 + 2*pbytes);
+ if (!buf)
+ return gpg_error_from_syserror ();
+ *buf = 04; /* Uncompressed point. */
+ ptr = buf+1;
+ err = gcry_mpi_print (GCRYMPI_FMT_USG, ptr, pbytes, &n, x);
+ if (err)
+ {
+ xfree (buf);
+ return err;
+ }
+ if (n < pbytes)
+ {
+ memmove (ptr+(pbytes-n), ptr, n);
+ memset (ptr, 0, (pbytes-n));
+ }
+ ptr += pbytes;
+ err = gcry_mpi_print (GCRYMPI_FMT_USG, ptr, pbytes, &n, y);
+ if (err)
+ {
+ xfree (buf);
+ return err;
+ }
+ if (n < pbytes)
+ {
+ memmove (ptr+(pbytes-n), ptr, n);
+ memset (ptr, 0, (pbytes-n));
+ }
+
+ *r_buf = buf;
+ *r_buflen = 1 + 2*pbytes;
+ return 0;
+}
+
+
+/* Convert the ECC parameter Q in the canonical s-expression
+ * (KEYDATA,KEYDATALEN) to uncompressed form. On success and if a
+ * conversion was done, the new canonical encoded s-expression is
+ * returned at (R_NEWKEYDAT,R_NEWKEYDATALEN); if a conversion was not
+ * required (NULL,0) is stored there. On error an error code is
+ * returned. The function may take any kind of key but will only do
+ * the conversion for ECC curves where compression is supported. */
+gpg_error_t
+uncompress_ecc_q_in_canon_sexp (const unsigned char *keydata,
+ size_t keydatalen,
+ unsigned char **r_newkeydata,
+ size_t *r_newkeydatalen)
+{
+ gpg_error_t err;
+ const unsigned char *buf, *tok;
+ size_t buflen, toklen, n;
+ int depth, last_depth1, last_depth2;
+ const unsigned char *q_ptr; /* Points to the value of "q". */
+ size_t q_ptrlen; /* Remaining length in KEYDATA. */
+ size_t q_toklen; /* Q's length including prefix. */
+ const unsigned char *curve_ptr; /* Points to the value of "curve". */
+ size_t curve_ptrlen; /* Remaining length in KEYDATA. */
+ gcry_mpi_t x, y; /* Point Q */
+ gcry_mpi_t p, a, b; /* Curve parameters. */
+ gcry_mpi_t x3, t, p1_4; /* Helper */
+ int y_bit;
+ unsigned char *qvalue; /* Q in uncompressed form. */
+ unsigned int qvaluelen;
+ unsigned char *dst; /* Helper */
+ char lenstr[35]; /* Helper for a length prefix. */
+
+ *r_newkeydata = NULL;
+ *r_newkeydatalen = 0;
+
+ buf = keydata;
+ buflen = keydatalen;
+ depth = 0;
+ if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
+ return err;
+ if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
+ return err;
+ if (!tok)
+ return gpg_error (GPG_ERR_BAD_PUBKEY);
+ else if (toklen == 10 || !memcmp ("public-key", tok, toklen))
+ ;
+ else if (toklen == 11 || !memcmp ("private-key", tok, toklen))
+ ;
+ else if (toklen == 20 || !memcmp ("shadowed-private-key", tok, toklen))
+ ;
+ else
+ return gpg_error (GPG_ERR_BAD_PUBKEY);
+
+ if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
+ return err;
+ if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
+ return err;
+
+ if (tok && toklen == 3 && !memcmp ("ecc", tok, toklen))
+ ;
+ else if (tok && toklen == 5 && !memcmp ("ecdsa", tok, toklen))
+ ;
+ else
+ return 0; /* Other algo - no need for conversion. */
+
+ last_depth1 = depth;
+ q_ptr = curve_ptr = NULL;
+ q_ptrlen = 0; /*(silence cc warning)*/
+ while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))
+ && depth && depth >= last_depth1)
+ {
+ if (tok)
+ return gpg_error (GPG_ERR_UNKNOWN_SEXP);
+ if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
+ return err;
+ if (tok && toklen == 1 && *tok == 'q' && !q_ptr)
+ {
+ q_ptr = buf;
+ q_ptrlen = buflen;
+ }
+ else if (tok && toklen == 5 && !memcmp (tok, "curve", 5) && !curve_ptr)
+ {
+ curve_ptr = buf;
+ curve_ptrlen = buflen;
+ }
+
+ if (q_ptr && curve_ptr)
+ break; /* We got all what we need. */
+
+ /* Skip to the end of the list. */
+ last_depth2 = depth;
+ while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))
+ && depth && depth >= last_depth2)
+ ;
+ if (err)
+ return err;
+ }
+ if (err)
+ return err;
+
+ if (!q_ptr)
+ return 0; /* No Q - nothing to do. */
+
+ /* Get Q's value and check whether uncompressing is at all required. */
+ buf = q_ptr;
+ buflen = q_ptrlen;
+ if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
+ return err;
+ if (toklen < 2 || !(*tok == 0x02 || *tok == 0x03))
+ return 0; /* Invalid length or not compressed. */
+ q_toklen = buf - q_ptr; /* We want the length with the prefix. */
+
+ /* Put the x-coordinate of q into X and remember the y bit */
+ y_bit = (*tok == 0x03);
+ err = gcry_mpi_scan (&x, GCRYMPI_FMT_USG, tok+1, toklen-1, NULL);
+ if (err)
+ return err;
+
+ /* For uncompressing we need to know the curve. */
+ if (!curve_ptr)
+ {
+ gcry_mpi_release (x);
+ return gpg_error (GPG_ERR_INV_CURVE);
+ }
+ buf = curve_ptr;
+ buflen = curve_ptrlen;
+ if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
+ {
+ gcry_mpi_release (x);
+ return err;
+ }
+
+ {
+ char name[50];
+ gcry_sexp_t curveparam;
+
+ if (toklen + 1 > sizeof name)
+ {
+ gcry_mpi_release (x);
+ return gpg_error (GPG_ERR_TOO_LARGE);
+ }
+ mem2str (name, tok, toklen+1);
+ curveparam = gcry_pk_get_param (GCRY_PK_ECC, name);
+ if (!curveparam)
+ {
+ gcry_mpi_release (x);
+ return gpg_error (GPG_ERR_UNKNOWN_CURVE);
+ }
+
+ err = gcry_sexp_extract_param (curveparam, NULL, "pab", &p, &a, &b, NULL);
+ gcry_sexp_release (curveparam);
+ if (err)
+ {
+ gcry_mpi_release (x);
+ return gpg_error (GPG_ERR_INTERNAL);
+ }
+ }
+
+ if (!mpi_test_bit (p, 1))
+ {
+ /* No support for point compression for this curve. */
+ gcry_mpi_release (x);
+ gcry_mpi_release (p);
+ gcry_mpi_release (a);
+ gcry_mpi_release (b);
+ return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+ }
+
+ /*
+ * Recover Y. The Weierstrass curve: y^2 = x^3 + a*x + b
+ */
+
+ x3 = mpi_new (0);
+ t = mpi_new (0);
+ p1_4 = mpi_new (0);
+ y = mpi_new (0);
+
+ /* Compute right hand side. */
+ mpi_powm (x3, x, GCRYMPI_CONST_THREE, p);
+ mpi_mul (t, a, x);
+ mpi_mod (t, t, p);
+ mpi_add (t, t, b);
+ mpi_mod (t, t, p);
+ mpi_add (t, t, x3);
+ mpi_mod (t, t, p);
+
+ /*
+ * When p mod 4 = 3, modular square root of A can be computed by
+ * A^((p+1)/4) mod p
+ */
+
+ /* Compute (p+1)/4 into p1_4 */
+ mpi_rshift (p1_4, p, 2);
+ mpi_add_ui (p1_4, p1_4, 1);
+
+ mpi_powm (y, t, p1_4, p);
+
+ if (y_bit != mpi_test_bit (y, 0))
+ mpi_sub (y, p, y);
+
+ gcry_mpi_release (p1_4);
+ gcry_mpi_release (t);
+ gcry_mpi_release (x3);
+ gcry_mpi_release (a);
+ gcry_mpi_release (b);
+
+ err = ec2os (x, y, p, &qvalue, &qvaluelen);
+ gcry_mpi_release (x);
+ gcry_mpi_release (y);
+ gcry_mpi_release (p);
+ if (err)
+ return err;
+
+ snprintf (lenstr, sizeof lenstr, "%u:", (unsigned int)qvaluelen);
+ /* Note that for simplicity we do not subtract the old length of Q
+ * for the new buffer. */
+ *r_newkeydata = xtrymalloc (qvaluelen + strlen(lenstr) + qvaluelen);
+ if (!*r_newkeydata)
+ return gpg_error_from_syserror ();
+ dst = *r_newkeydata;
+
+ n = q_ptr - keydata;
+ memcpy (dst, keydata, n); /* Copy first part of original data. */
+ dst += n;
+
+ n = strlen (lenstr);
+ memcpy (dst, lenstr, n); /* Copy new prefix of Q's value. */
+ dst += n;
+
+ memcpy (dst, qvalue, qvaluelen); /* Copy new value of Q. */
+ dst += qvaluelen;
+
+ log_assert (q_toklen < q_ptrlen);
+ n = q_ptrlen - q_toklen;
+ memcpy (dst, q_ptr + q_toklen, n);/* Copy rest of original data. */
+ dst += n;
+
+ *r_newkeydatalen = dst - *r_newkeydata;
+
+ xfree (qvalue);
+
+ return 0;
+}
+
+
+/* Return the algo of a public KEY of SEXP. */
+int
+get_pk_algo_from_key (gcry_sexp_t key)
+{
+ gcry_sexp_t list;
+ const char *s;
+ size_t n;
+ char algoname[6];
+ int algo = 0;
+
+ list = gcry_sexp_nth (key, 1);
+ if (!list)
+ goto out;
+ s = gcry_sexp_nth_data (list, 0, &n);
+ if (!s)
+ goto out;
+ if (n >= sizeof (algoname))
+ goto out;
+ memcpy (algoname, s, n);
+ algoname[n] = 0;
+
+ algo = gcry_pk_map_name (algoname);
+ if (algo == GCRY_PK_ECC)
+ {
+ gcry_sexp_t l1 = gcry_sexp_find_token (list, "flags", 0);
+ int i;
+
+ for (i = l1 ? gcry_sexp_length (l1)-1 : 0; i > 0; i--)
+ {
+ s = gcry_sexp_nth_data (l1, i, &n);
+ if (!s)
+ continue; /* Not a data element. */
+
+ if (n == 5 && !memcmp (s, "eddsa", 5))
+ {
+ algo = GCRY_PK_EDDSA;
+ break;
+ }
+ }
+ gcry_sexp_release (l1);
+ }
+
+ out:
+ gcry_sexp_release (list);
+
+ return algo;
+}
+
+
+/* This is a variant of get_pk_algo_from_key but takes an canonical
+ * encoded S-expression as input. Returns a GCRYPT public key
+ * identiier or 0 on error. */
+int
+get_pk_algo_from_canon_sexp (const unsigned char *keydata, size_t keydatalen)
+{
+ gcry_sexp_t sexp;
+ int algo;
+
+ if (gcry_sexp_sscan (&sexp, NULL, keydata, keydatalen))
+ return 0;
+
+ algo = get_pk_algo_from_key (sexp);
+ gcry_sexp_release (sexp);
+ return algo;
+}
+
+
+/* Given the public key S_PKEY, return a new buffer with a descriptive
+ * string for its algorithm. This function may return NULL on memory
+ * error. If R_ALGOID is not NULL the gcrypt algo id is stored there. */
+char *
+pubkey_algo_string (gcry_sexp_t s_pkey, enum gcry_pk_algos *r_algoid)
+{
+ const char *prefix;
+ gcry_sexp_t l1;
+ char *algoname;
+ int algo;
+ char *result;
+
+ if (r_algoid)
+ *r_algoid = 0;
+
+ l1 = gcry_sexp_find_token (s_pkey, "public-key", 0);
+ if (!l1)
+ return xtrystrdup ("E_no_key");
+ {
+ gcry_sexp_t l_tmp = gcry_sexp_cadr (l1);
+ gcry_sexp_release (l1);
+ l1 = l_tmp;
+ }
+ algoname = gcry_sexp_nth_string (l1, 0);
+ gcry_sexp_release (l1);
+ if (!algoname)
+ return xtrystrdup ("E_no_algo");
+
+ algo = gcry_pk_map_name (algoname);
+ switch (algo)
+ {
+ case GCRY_PK_RSA: prefix = "rsa"; break;
+ case GCRY_PK_ELG: prefix = "elg"; break;
+ case GCRY_PK_DSA: prefix = "dsa"; break;
+ case GCRY_PK_ECC: prefix = ""; break;
+ default: prefix = NULL; break;
+ }
+
+ if (prefix && *prefix)
+ result = xtryasprintf ("%s%u", prefix, gcry_pk_get_nbits (s_pkey));
+ else if (prefix)
+ {
+ const char *curve = gcry_pk_get_curve (s_pkey, 0, NULL);
+ const char *name = openpgp_oid_to_curve
+ (openpgp_curve_to_oid (curve, NULL, NULL), 0);
+
+ if (name)
+ result = xtrystrdup (name);
+ else if (curve)
+ result = xtryasprintf ("X_%s", curve);
+ else
+ result = xtrystrdup ("E_unknown");
+ }
+ else
+ result = xtryasprintf ("X_algo_%d", algo);
+
+ if (r_algoid)
+ *r_algoid = algo;
+ xfree (algoname);
+ return result;
+}
+
+
+/* Map a pubkey algo id from gcrypt to a string. This is the same as
+ * gcry_pk_algo_name but makes sure that the ECC algo identifiers are
+ * not all mapped to "ECC". */
+const char *
+pubkey_algo_to_string (int algo)
+{
+ if (algo == GCRY_PK_ECDSA)
+ return "ECDSA";
+ else if (algo == GCRY_PK_ECDH)
+ return "ECDH";
+ else if (algo == GCRY_PK_EDDSA)
+ return "EdDSA";
+ else
+ return gcry_pk_algo_name (algo);
+}
+
+
+/* Map a hash algo id from gcrypt to a string. This is the same as
+ * gcry_md_algo_name but the returned string is lower case, as
+ * expected by libksba and it avoids some overhead. */
+const char *
+hash_algo_to_string (int algo)
+{
+ static const struct
+ {
+ const char *name;
+ int algo;
+ } hashnames[] =
+ {
+ { "sha256", GCRY_MD_SHA256 },
+ { "sha512", GCRY_MD_SHA512 },
+ { "sha1", GCRY_MD_SHA1 },
+ { "sha384", GCRY_MD_SHA384 },
+ { "sha224", GCRY_MD_SHA224 },
+ { "sha3-224", GCRY_MD_SHA3_224 },
+ { "sha3-256", GCRY_MD_SHA3_256 },
+ { "sha3-384", GCRY_MD_SHA3_384 },
+ { "sha3-512", GCRY_MD_SHA3_512 },
+ { "ripemd160", GCRY_MD_RMD160 },
+ { "rmd160", GCRY_MD_RMD160 },
+ { "md2", GCRY_MD_MD2 },
+ { "md4", GCRY_MD_MD4 },
+ { "tiger", GCRY_MD_TIGER },
+ { "haval", GCRY_MD_HAVAL },
+#if GCRYPT_VERSION_NUMBER >= 0x010900
+ { "sm3", GCRY_MD_SM3 },
+#endif
+ { "md5", GCRY_MD_MD5 }
+ };
+ int i;
+
+ for (i=0; i < DIM (hashnames); i++)
+ if (algo == hashnames[i].algo)
+ return hashnames[i].name;
+ return "?";
+}
+
+
+/* Map cipher modes to a string. */
+const char *
+cipher_mode_to_string (int mode)
+{
+ switch (mode)
+ {
+ case GCRY_CIPHER_MODE_CFB: return "CFB";
+ case GCRY_CIPHER_MODE_CBC: return "CBC";
+ case GCRY_CIPHER_MODE_GCM: return "GCM";
+ case GCRY_CIPHER_MODE_OCB: return "OCB";
+ case 14: return "EAX"; /* Only in gcrypt 1.9 */
+ default: return "[?]";
+ }
+}
diff --git a/common/shareddefs.h b/common/shareddefs.h
new file mode 100644
index 0000000..4b14421
--- /dev/null
+++ b/common/shareddefs.h
@@ -0,0 +1,61 @@
+/* shareddefs.h - Constants and helpers useful for all modules
+ * Copyright (C) 2013 Free Software Foundation, Inc.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_COMMON_SHAREDDEFS_H
+#define GNUPG_COMMON_SHAREDDEFS_H
+
+/* Values for the pinentry mode. */
+typedef enum
+ {
+ PINENTRY_MODE_ASK = 0, /* Ask via pinentry (default). */
+ PINENTRY_MODE_CANCEL, /* Always return a cancel error. */
+ PINENTRY_MODE_ERROR, /* Return error code for no pinentry. */
+ PINENTRY_MODE_LOOPBACK /* Use an inquiry to get the value. */
+ }
+pinentry_mode_t;
+
+
+/* Values for the request origin. */
+typedef enum
+ {
+ REQUEST_ORIGIN_LOCAL = 0,
+ REQUEST_ORIGIN_REMOTE,
+ REQUEST_ORIGIN_BROWSER
+ }
+request_origin_t;
+
+
+/*-- agent-opt.c --*/
+int parse_pinentry_mode (const char *value);
+const char *str_pinentry_mode (pinentry_mode_t mode);
+
+int parse_request_origin (const char *value);
+const char *str_request_origin (request_origin_t mode);
+
+
+
+#endif /*GNUPG_COMMON_SHAREDDEFS_H*/
diff --git a/common/signal.c b/common/signal.c
new file mode 100644
index 0000000..92925fd
--- /dev/null
+++ b/common/signal.c
@@ -0,0 +1,251 @@
+/* signal.c - signal handling
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002,
+ * 2005 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef HAVE_SIGNAL_H
+# include <signal.h>
+#endif
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "util.h"
+
+
+#ifndef HAVE_DOSISH_SYSTEM
+static volatile int caught_fatal_sig;
+static volatile int caught_sigusr1;
+#endif
+static void (*cleanup_fnc)(void);
+
+
+#ifndef HAVE_DOSISH_SYSTEM
+static void
+init_one_signal (int sig, RETSIGTYPE (*handler)(int), int check_ign )
+{
+# ifdef HAVE_SIGACTION
+ struct sigaction oact, nact;
+
+ if (check_ign)
+ {
+ /* we don't want to change an IGN handler */
+ sigaction (sig, NULL, &oact );
+ if (oact.sa_handler == SIG_IGN )
+ return;
+ }
+
+ nact.sa_handler = handler;
+ sigemptyset (&nact.sa_mask);
+ nact.sa_flags = 0;
+ sigaction ( sig, &nact, NULL);
+# else
+ RETSIGTYPE (*ohandler)(int);
+
+ ohandler = signal (sig, handler);
+ if (check_ign && ohandler == SIG_IGN)
+ {
+ /* Change it back if it was already set to IGN */
+ signal (sig, SIG_IGN);
+ }
+# endif
+}
+#endif /*!HAVE_DOSISH_SYSTEM*/
+
+#ifndef HAVE_DOSISH_SYSTEM
+static const char *
+get_signal_name( int signum )
+{
+ /* Note that we can't use strsignal(), because it is not
+ reentrant. */
+#if HAVE_SIGDESCR_NP
+ return sigdescr_np (signum);
+#elif HAVE_DECL_SYS_SIGLIST && defined(NSIG)
+ return (signum >= 0 && signum < NSIG) ? sys_siglist[signum] : "?";
+#else
+ return NULL;
+#endif
+}
+#endif /*!HAVE_DOSISH_SYSTEM*/
+
+#ifndef HAVE_DOSISH_SYSTEM
+static RETSIGTYPE
+got_fatal_signal (int sig)
+{
+ const char *s;
+
+ if (caught_fatal_sig)
+ raise (sig);
+ caught_fatal_sig = 1;
+
+ if (cleanup_fnc)
+ cleanup_fnc ();
+ /* Better don't translate these messages. */
+ (void)write (2, "\n", 1 );
+ s = log_get_prefix (NULL);
+ if (s)
+ (void)write(2, s, strlen (s));
+ (void)write (2, ": signal ", 9 );
+ s = get_signal_name(sig);
+ if (s)
+ (void) write (2, s, strlen(s) );
+ else
+ {
+ /* We are in a signal handler so we can't use any kind of printf
+ even not sprintf. So we use a straightforward algorithm. We
+ got a report that on one particular system, raising a signal
+ while in this handler, the parameter SIG get sclobbered and
+ things are messed up because we modify its value. Although
+ this is a bug in that system, we will protect against it. */
+ if (sig < 0 || sig >= 100000)
+ (void)write (2, "?", 1);
+ else
+ {
+ int i, value, any=0;
+
+ for (value=sig,i=10000; i; i /= 10)
+ {
+ if (value >= i || ((any || i==1) && !(value/i)))
+ {
+ (void)write (2, &"0123456789"[value/i], 1);
+ if ((value/i))
+ any = 1;
+ value %= i;
+ }
+ }
+ }
+ }
+ (void)write (2, " caught ... exiting\n", 20);
+
+ /* Reset action to default action and raise signal again */
+ init_one_signal (sig, SIG_DFL, 0);
+ /* Fixme: remove_lockfiles ();*/
+#ifdef __riscos__
+ close_fds ();
+#endif /* __riscos__ */
+ raise( sig );
+}
+#endif /*!HAVE_DOSISH_SYSTEM*/
+
+#ifndef HAVE_DOSISH_SYSTEM
+static RETSIGTYPE
+got_usr_signal (int sig)
+{
+ (void)sig;
+ caught_sigusr1 = 1;
+}
+#endif /*!HAVE_DOSISH_SYSTEM*/
+
+void
+gnupg_init_signals (int mode, void (*fast_cleanup)(void))
+{
+ assert (!mode);
+
+ cleanup_fnc = fast_cleanup;
+#ifndef HAVE_DOSISH_SYSTEM
+ init_one_signal (SIGINT, got_fatal_signal, 1 );
+ init_one_signal (SIGHUP, got_fatal_signal, 1 );
+ init_one_signal (SIGTERM, got_fatal_signal, 1 );
+ init_one_signal (SIGQUIT, got_fatal_signal, 1 );
+ init_one_signal (SIGSEGV, got_fatal_signal, 1 );
+ init_one_signal (SIGUSR1, got_usr_signal, 0 );
+ init_one_signal (SIGPIPE, SIG_IGN, 0 );
+#endif
+}
+
+
+static void
+do_block (int block)
+{
+#ifdef HAVE_DOSISH_SYSTEM
+ (void)block;
+#else /*!HAVE_DOSISH_SYSTEM*/
+ static int is_blocked;
+#ifdef HAVE_SIGPROCMASK
+ static sigset_t oldmask;
+
+ if (block)
+ {
+ sigset_t newmask;
+
+ if (is_blocked)
+ log_bug ("signals are already blocked\n");
+ sigfillset( &newmask );
+ sigprocmask( SIG_BLOCK, &newmask, &oldmask );
+ is_blocked = 1;
+ }
+ else
+ {
+ if (!is_blocked)
+ log_bug("signals are not blocked\n");
+ sigprocmask (SIG_SETMASK, &oldmask, NULL);
+ is_blocked = 0;
+ }
+#else /*!HAVE_SIGPROCMASK*/
+ static void (*disposition[MAXSIG])();
+ int sig;
+
+ if (block)
+ {
+ if (is_blocked)
+ log_bug("signals are already blocked\n");
+ for (sig=1; sig < MAXSIG; sig++)
+ {
+ disposition[sig] = sigset (sig, SIG_HOLD);
+ }
+ is_blocked = 1;
+ }
+ else
+ {
+ if (!is_blocked)
+ log_bug ("signals are not blocked\n");
+ for (sig=1; sig < MAXSIG; sig++) {
+ sigset (sig, disposition[sig]);
+ }
+ is_blocked = 0;
+ }
+#endif /*!HAVE_SIGPROCMASK*/
+#endif /*!HAVE_DOSISH_SYSTEM*/
+}
+
+
+void
+gnupg_block_all_signals ()
+{
+ do_block(1);
+}
+
+void
+gnupg_unblock_all_signals ()
+{
+ do_block(0);
+}
diff --git a/common/simple-pwquery.c b/common/simple-pwquery.c
new file mode 100644
index 0000000..b8ada42
--- /dev/null
+++ b/common/simple-pwquery.c
@@ -0,0 +1,495 @@
+/* simple-pwquery.c - A simple password query client for gpg-agent
+ * Copyright (C) 2002, 2004, 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+/* This module is intended as a simple client implementation to
+ gpg-agent's GET_PASSPHRASE command. It can only cope with an
+ already running gpg-agent. Some stuff is configurable in the
+ header file. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <assuan.h>
+#ifdef HAVE_W32_SYSTEM
+#include <winsock2.h>
+#else
+#include <sys/socket.h>
+#include <sys/un.h>
+#endif
+#ifdef HAVE_LOCALE_H
+#include <locale.h>
+#endif
+
+#define GNUPG_COMMON_NEED_AFLOCAL
+#include "../common/mischelp.h"
+#include "sysutils.h"
+#include "membuf.h"
+
+
+#define SIMPLE_PWQUERY_IMPLEMENTATION 1
+#include "simple-pwquery.h"
+
+#define SPWQ_OUT_OF_CORE gpg_error_from_errno (ENOMEM)
+#define SPWQ_IO_ERROR gpg_error_from_errno (EIO)
+#define SPWQ_PROTOCOL_ERROR gpg_error (GPG_ERR_PROTOCOL_VIOLATION)
+#define SPWQ_ERR_RESPONSE gpg_error (GPG_ERR_INV_RESPONSE)
+#define SPWQ_NO_AGENT gpg_error (GPG_ERR_NO_AGENT)
+#define SPWQ_SYS_ERROR gpg_error_from_syserror ()
+#define SPWQ_GENERAL_ERROR gpg_error (GPG_ERR_GENERAL)
+#define SPWQ_NO_PIN_ENTRY gpg_error (GPG_ERR_NO_PIN_ENTRY)
+
+#ifndef _
+#define _(a) (a)
+#endif
+
+#if !defined (hexdigitp) && !defined (xtoi_2)
+#define digitp(p) (*(p) >= '0' && *(p) <= '9')
+#define hexdigitp(a) (digitp (a) \
+ || (*(a) >= 'A' && *(a) <= 'F') \
+ || (*(a) >= 'a' && *(a) <= 'f'))
+#define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
+ *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
+#define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
+#endif
+
+
+/* Name of the socket to be used. This is a kludge to keep on using
+ the existsing code despite that we only support a standard socket. */
+static char *default_gpg_agent_info;
+
+
+
+
+
+#ifndef HAVE_STPCPY
+static char *
+my_stpcpy(char *a,const char *b)
+{
+ while( *b )
+ *a++ = *b++;
+ *a = 0;
+
+ return (char*)a;
+}
+#define stpcpy(a,b) my_stpcpy((a), (b))
+#endif
+
+
+/* Send an option to the agent */
+static int
+agent_send_option (assuan_context_t ctx, const char *name, const char *value)
+{
+ int err;
+ char *line;
+
+ line = spwq_malloc (7 + strlen (name) + 1 + strlen (value) + 2);
+ if (!line)
+ return SPWQ_OUT_OF_CORE;
+ strcpy (stpcpy (stpcpy (stpcpy (
+ stpcpy (line, "OPTION "), name), "="), value), "\n");
+
+ err = assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
+
+ spwq_free (line);
+ return err;
+}
+
+
+/* Send all available options to the agent. */
+static int
+agent_send_all_options (assuan_context_t ctx)
+{
+ char *dft_display = NULL;
+ char *dft_ttyname = NULL;
+ char *dft_ttytype = NULL;
+ char *dft_xauthority = NULL;
+ char *dft_pinentry_user_data = NULL;
+ int rc = 0;
+
+ dft_display = getenv ("DISPLAY");
+ if (dft_display)
+ {
+ if ((rc = agent_send_option (ctx, "display", dft_display)))
+ return rc;
+ }
+
+ dft_ttyname = getenv ("GPG_TTY");
+#if !defined(HAVE_W32_SYSTEM) && !defined(HAVE_BROKEN_TTYNAME)
+ if ((!dft_ttyname || !*dft_ttyname) && ttyname (0))
+ dft_ttyname = ttyname (0);
+#endif
+ if (dft_ttyname && *dft_ttyname)
+ {
+ if ((rc=agent_send_option (ctx, "ttyname", dft_ttyname)))
+ return rc;
+ }
+
+ dft_ttytype = getenv ("TERM");
+ if (dft_ttyname && dft_ttytype)
+ {
+ if ((rc = agent_send_option (ctx, "ttytype", dft_ttytype)))
+ return rc;
+ }
+
+#if defined(HAVE_SETLOCALE)
+ {
+ char *old_lc = NULL;
+ char *dft_lc = NULL;
+
+#if defined(LC_CTYPE)
+ old_lc = setlocale (LC_CTYPE, NULL);
+ if (old_lc)
+ {
+ char *p = spwq_malloc (strlen (old_lc)+1);
+ if (!p)
+ return SPWQ_OUT_OF_CORE;
+ strcpy (p, old_lc);
+ old_lc = p;
+ }
+ dft_lc = setlocale (LC_CTYPE, "");
+ if (dft_ttyname && dft_lc)
+ rc = agent_send_option (ctx, "lc-ctype", dft_lc);
+ if (old_lc)
+ {
+ setlocale (LC_CTYPE, old_lc);
+ spwq_free (old_lc);
+ }
+ if (rc)
+ return rc;
+#endif
+
+#if defined(LC_MESSAGES)
+ old_lc = setlocale (LC_MESSAGES, NULL);
+ if (old_lc)
+ {
+ char *p = spwq_malloc (strlen (old_lc)+1);
+ if (!p)
+ return SPWQ_OUT_OF_CORE;
+ strcpy (p, old_lc);
+ old_lc = p;
+ }
+ dft_lc = setlocale (LC_MESSAGES, "");
+ if (dft_ttyname && dft_lc)
+ rc = agent_send_option (ctx, "lc-messages", dft_lc);
+ if (old_lc)
+ {
+ setlocale (LC_MESSAGES, old_lc);
+ spwq_free (old_lc);
+ }
+ if (rc)
+ return rc;
+#endif
+ }
+#endif /*HAVE_SETLOCALE*/
+
+ /* Send the XAUTHORITY variable. */
+ dft_xauthority = getenv ("XAUTHORITY");
+ if (dft_xauthority)
+ {
+ /* We ignore errors here because older gpg-agents don't support
+ this option. */
+ agent_send_option (ctx, "xauthority", dft_xauthority);
+ }
+
+ /* Send the PINENTRY_USER_DATA variable. */
+ dft_pinentry_user_data = getenv ("PINENTRY_USER_DATA");
+ if (dft_pinentry_user_data)
+ {
+ /* We ignore errors here because older gpg-agents don't support
+ this option. */
+ agent_send_option (ctx, "pinentry-user-data", dft_pinentry_user_data);
+ }
+
+ /* Tell the agent that we support Pinentry notifications. No
+ error checking so that it will work with older agents. */
+ assuan_transact (ctx, "OPTION allow-pinentry-notify",
+ NULL, NULL, NULL, NULL, NULL, NULL);
+
+ return 0;
+}
+
+
+
+/* Try to open a connection to the agent, send all options and return
+ the file descriptor for the connection. Return -1 in case of
+ error. */
+static int
+agent_open (assuan_context_t *ctx)
+{
+ int rc;
+ char *infostr;
+
+ infostr = default_gpg_agent_info;
+ if ( !infostr || !*infostr )
+ {
+#ifdef SPWQ_USE_LOGGING
+ log_error (_("no gpg-agent running in this session\n"));
+#endif
+ *ctx = NULL;
+ return SPWQ_NO_AGENT;
+ }
+
+ rc = assuan_new (ctx);
+ if (rc)
+ return rc;
+
+ rc = assuan_socket_connect (*ctx, infostr, 0, 0);
+ if (rc)
+ {
+#ifdef SPWQ_USE_LOGGING
+ log_error (_("can't connect to '%s': %s\n"),
+ infostr, gpg_strerror (rc));
+#endif
+ goto errout;
+ }
+
+ rc = agent_send_all_options (*ctx);
+ if (rc)
+ {
+#ifdef SPWQ_USE_LOGGING
+ log_error (_("problem setting the gpg-agent options\n"));
+#endif
+ goto errout;
+ }
+
+ return 0;
+
+ errout:
+ assuan_release (*ctx);
+ *ctx = NULL;
+ return rc;
+}
+
+
+/* Copy text to BUFFER and escape as required. Return a pointer to
+ the end of the new buffer. Note that BUFFER must be large enough
+ to keep the entire text; allocataing it 3 times the size of TEXT
+ is sufficient. */
+static char *
+copy_and_escape (char *buffer, const char *text)
+{
+ int i;
+ const unsigned char *s = (unsigned char *)text;
+ char *p = buffer;
+
+
+ for (i=0; s[i]; i++)
+ {
+ if (s[i] < ' ' || s[i] == '+')
+ {
+ sprintf (p, "%%%02X", s[i]);
+ p += 3;
+ }
+ else if (s[i] == ' ')
+ *p++ = '+';
+ else
+ *p++ = s[i];
+ }
+ return p;
+}
+
+
+/* Set the name of the default socket to NAME. */
+int
+simple_pw_set_socket (const char *name)
+{
+ spwq_free (default_gpg_agent_info);
+ default_gpg_agent_info = NULL;
+ if (name)
+ {
+ default_gpg_agent_info = spwq_malloc (strlen (name) + 1);
+ if (!default_gpg_agent_info)
+ return SPWQ_OUT_OF_CORE;
+ strcpy (default_gpg_agent_info, name);
+ }
+
+ return 0;
+}
+
+
+/* This is the default inquiry callback. It merely handles the
+ Pinentry notification. */
+static gpg_error_t
+default_inq_cb (void *opaque, const char *line)
+{
+ (void)opaque;
+
+ if (!strncmp (line, "PINENTRY_LAUNCHED", 17) && (line[17]==' '||!line[17]))
+ {
+ gnupg_allow_set_foregound_window ((pid_t)strtoul (line+17, NULL, 10));
+ /* We do not return errors to avoid breaking other code. */
+ }
+ else
+ {
+#ifdef SPWQ_USE_LOGGING
+ log_debug ("ignoring gpg-agent inquiry '%s'\n", line);
+#endif
+ }
+
+ return 0;
+}
+
+
+/* Ask the gpg-agent for a passphrase and present the user with a
+ DESCRIPTION, a PROMPT and optionally with a TRYAGAIN extra text.
+ If a CACHEID is not NULL it is used to locate the passphrase in
+ the cache and store it under this ID. If OPT_CHECK is true
+ gpg-agent is asked to apply some checks on the passphrase security.
+ If ERRORCODE is not NULL it should point a variable receiving an
+ errorcode; this error code might be 0 if the user canceled the
+ operation. The function returns NULL to indicate an error. */
+char *
+simple_pwquery (const char *cacheid,
+ const char *tryagain,
+ const char *prompt,
+ const char *description,
+ int opt_check,
+ int *errorcode)
+{
+ int rc;
+ assuan_context_t ctx;
+ membuf_t data;
+ char *result = NULL;
+ char *pw = NULL;
+ char *p;
+ size_t n;
+
+
+ rc = agent_open (&ctx);
+ if (rc)
+ goto leave;
+
+ if (!cacheid)
+ cacheid = "X";
+ if (!tryagain)
+ tryagain = "X";
+ if (!prompt)
+ prompt = "X";
+ if (!description)
+ description = "X";
+
+ {
+ char *line;
+ /* We allocate 3 times the needed space so that there is enough
+ space for escaping. */
+ line = spwq_malloc (15 + 10
+ + 3*strlen (cacheid) + 1
+ + 3*strlen (tryagain) + 1
+ + 3*strlen (prompt) + 1
+ + 3*strlen (description) + 1
+ + 2);
+ if (!line)
+ {
+ rc = SPWQ_OUT_OF_CORE;
+ goto leave;
+ }
+ strcpy (line, "GET_PASSPHRASE ");
+ p = line+15;
+ if (opt_check)
+ p = stpcpy (p, "--check ");
+ p = copy_and_escape (p, cacheid);
+ *p++ = ' ';
+ p = copy_and_escape (p, tryagain);
+ *p++ = ' ';
+ p = copy_and_escape (p, prompt);
+ *p++ = ' ';
+ p = copy_and_escape (p, description);
+ *p++ = '\n';
+
+ init_membuf_secure (&data, 64);
+
+ rc = assuan_transact (ctx, line, put_membuf_cb, &data,
+ default_inq_cb, NULL, NULL, NULL);
+ spwq_free (line);
+
+ /* Older Pinentries return the old assuan error code for canceled
+ which gets translated by libassuan to GPG_ERR_ASS_CANCELED and
+ not to the code for a user cancel. Fix this here. */
+ if (rc && gpg_err_source (rc)
+ && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
+ rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
+
+ if (rc)
+ {
+ p = get_membuf (&data, &n);
+ if (p)
+ wipememory (p, n);
+ spwq_free (p);
+ }
+ else
+ {
+ put_membuf (&data, "", 1);
+ result = get_membuf (&data, NULL);
+ if (pw == NULL)
+ rc = gpg_error_from_syserror ();
+ }
+ }
+
+ leave:
+ if (errorcode)
+ *errorcode = rc;
+ assuan_release (ctx);
+ return result;
+}
+
+
+/* Ask the gpg-agent to clear the passphrase for the cache ID CACHEID. */
+int
+simple_pwclear (const char *cacheid)
+{
+ char line[500];
+ char *p;
+
+ /* We need not more than 50 characters for the command and the
+ terminating nul. */
+ if (strlen (cacheid) * 3 > sizeof (line) - 50)
+ return SPWQ_PROTOCOL_ERROR;
+
+ strcpy (line, "CLEAR_PASSPHRASE ");
+ p = line + 17;
+ p = copy_and_escape (p, cacheid);
+ *p++ = '\n';
+ *p++ = '\0';
+
+ return simple_query (line);
+}
+
+
+/* Perform the simple query QUERY (which must be new-line and 0
+ terminated) and return the error code. */
+int
+simple_query (const char *query)
+{
+ assuan_context_t ctx;
+ int rc;
+
+ rc = agent_open (&ctx);
+ if (rc)
+ return rc;
+
+ rc = assuan_transact (ctx, query, NULL, NULL, NULL, NULL, NULL, NULL);
+
+ assuan_release (ctx);
+ return rc;
+}
diff --git a/common/simple-pwquery.h b/common/simple-pwquery.h
new file mode 100644
index 0000000..9bbc53f
--- /dev/null
+++ b/common/simple-pwquery.h
@@ -0,0 +1,70 @@
+/* simple-pwquery.c - A simple password query client for gpg-agent
+ * Copyright (C) 2002 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef SIMPLE_PWQUERY_H
+#define SIMPLE_PWQUERY_H
+
+#ifdef SIMPLE_PWQUERY_IMPLEMENTATION /* Begin configuration stuff. */
+
+/* Include whatever files you need. */
+#include <gcrypt.h>
+#include "../common/logging.h"
+
+/* Try to write error message using the standard gnupg log mechanism. */
+#define SPWQ_USE_LOGGING 1
+
+/* Memory allocation functions used by the implementation. Note, that
+ the returned value is expected to be freed with
+ spwq_secure_free. */
+#define spwq_malloc(a) gcry_malloc (a)
+#define spwq_free(a) gcry_free (a)
+#define spwq_secure_malloc(a) gcry_malloc_secure (a)
+#define spwq_secure_free(a) gcry_free (a)
+
+#endif /*SIMPLE_PWQUERY_IMPLEMENTATION*/ /* End configuration stuff. */
+
+
+/* Ask the gpg-agent for a passphrase and present the user with a
+ DESCRIPTION, a PROMPT and optiaonlly with a TRYAGAIN extra text.
+ If a CACHEID is not NULL it is used to locate the passphrase in
+ the cache and store it under this ID. If OPT_CHECK is true
+ gpg-agent is asked to apply some checks on the passphrase security.
+ If ERRORCODE is not NULL it should point a variable receiving an
+ errorcode; this errocode might be 0 if the user canceled the
+ operation. The function returns NULL to indicate an error. */
+char *simple_pwquery (const char *cacheid,
+ const char *tryagain,
+ const char *prompt,
+ const char *description,
+ int opt_check,
+ int *errorcode);
+
+/* Ask the gpg-agent to clear the passphrase for the cache ID CACHEID. */
+int simple_pwclear (const char *cacheid);
+
+/* Perform the simple query QUERY (which must be new-line and 0
+ terminated) and return the error code. */
+int simple_query (const char *query);
+
+/* Set the name of the standard socket to be used if GPG_AGENT_INFO is
+ not defined. The use of this function is optional but if it needs
+ to be called before any other function. Returns 0 on success. */
+int simple_pw_set_socket (const char *name);
+
+#endif /*SIMPLE_PWQUERY_H*/
diff --git a/common/ssh-utils.c b/common/ssh-utils.c
new file mode 100644
index 0000000..013b28e
--- /dev/null
+++ b/common/ssh-utils.c
@@ -0,0 +1,354 @@
+/* ssh-utils.c - Secure Shell helper functions
+ * Copyright (C) 2011 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "util.h"
+#include "ssh-utils.h"
+
+
+/* Return true if KEYPARMS holds an EdDSA key. */
+static int
+is_eddsa (gcry_sexp_t keyparms)
+{
+ int result = 0;
+ gcry_sexp_t list;
+ const char *s;
+ size_t n;
+ int i;
+
+ list = gcry_sexp_find_token (keyparms, "flags", 0);
+ for (i = list ? gcry_sexp_length (list)-1 : 0; i > 0; i--)
+ {
+ s = gcry_sexp_nth_data (list, i, &n);
+ if (!s)
+ continue; /* Not a data element. */
+
+ if (n == 5 && !memcmp (s, "eddsa", 5))
+ {
+ result = 1;
+ break;
+ }
+ }
+ gcry_sexp_release (list);
+ return result;
+}
+
+/* Dummy functions for es_mopen. */
+static void *dummy_realloc (void *mem, size_t size) { (void) size; return mem; }
+static void dummy_free (void *mem) { (void) mem; }
+
+/* Return the Secure Shell type fingerprint for KEY using digest ALGO.
+ The length of the fingerprint is returned at R_LEN and the
+ fingerprint itself at R_FPR. In case of a error code is returned
+ and NULL stored at R_FPR. */
+static gpg_error_t
+get_fingerprint (gcry_sexp_t key, int algo,
+ void **r_fpr, size_t *r_len, int as_string)
+{
+ gpg_error_t err;
+ gcry_sexp_t list = NULL;
+ gcry_sexp_t l2 = NULL;
+ const char *s;
+ char *name = NULL;
+ int idx;
+ const char *elems;
+ gcry_md_hd_t md = NULL;
+ int blobmode = 0;
+
+ *r_fpr = NULL;
+ *r_len = 0;
+
+ /* Check that the first element is valid. */
+ list = gcry_sexp_find_token (key, "public-key", 0);
+ if (!list)
+ list = gcry_sexp_find_token (key, "private-key", 0);
+ if (!list)
+ list = gcry_sexp_find_token (key, "protected-private-key", 0);
+ if (!list)
+ list = gcry_sexp_find_token (key, "shadowed-private-key", 0);
+ if (!list)
+ {
+ err = gpg_err_make (default_errsource, GPG_ERR_UNKNOWN_SEXP);
+ goto leave;
+ }
+
+ l2 = gcry_sexp_cadr (list);
+ gcry_sexp_release (list);
+ list = l2;
+ l2 = NULL;
+
+ name = gcry_sexp_nth_string (list, 0);
+ if (!name)
+ {
+ err = gpg_err_make (default_errsource, GPG_ERR_INV_SEXP);
+ goto leave;
+ }
+
+ err = gcry_md_open (&md, algo, 0);
+ if (err)
+ goto leave;
+
+ switch (gcry_pk_map_name (name))
+ {
+ case GCRY_PK_RSA:
+ elems = "en";
+ gcry_md_write (md, "\0\0\0\x07ssh-rsa", 11);
+ break;
+
+ case GCRY_PK_DSA:
+ elems = "pqgy";
+ gcry_md_write (md, "\0\0\0\x07ssh-dss", 11);
+ break;
+
+ case GCRY_PK_ECC:
+ if (is_eddsa (list))
+ {
+ elems = "q";
+ blobmode = 1;
+ /* For now there is just one curve, thus no need to switch
+ on it. */
+ gcry_md_write (md, "\0\0\0\x0b" "ssh-ed25519", 15);
+ }
+ else
+ {
+ /* We only support the 3 standard curves for now. It is
+ just a quick hack. */
+ elems = "q";
+ gcry_md_write (md, "\0\0\0\x13" "ecdsa-sha2-nistp", 20);
+ l2 = gcry_sexp_find_token (list, "curve", 0);
+ if (!l2)
+ elems = "";
+ else
+ {
+ gcry_free (name);
+ name = gcry_sexp_nth_string (l2, 1);
+ gcry_sexp_release (l2);
+ l2 = NULL;
+ if (!name)
+ elems = "";
+ else if (!strcmp (name, "NIST P-256")||!strcmp (name, "nistp256"))
+ gcry_md_write (md, "256\0\0\0\x08nistp256", 15);
+ else if (!strcmp (name, "NIST P-384")||!strcmp (name, "nistp384"))
+ gcry_md_write (md, "384\0\0\0\x08nistp384", 15);
+ else if (!strcmp (name, "NIST P-521")||!strcmp (name, "nistp521"))
+ gcry_md_write (md, "521\0\0\0\x08nistp521", 15);
+ else
+ elems = "";
+ }
+ if (!*elems)
+ err = gpg_err_make (default_errsource, GPG_ERR_UNKNOWN_CURVE);
+ }
+ break;
+
+ default:
+ elems = "";
+ err = gpg_err_make (default_errsource, GPG_ERR_PUBKEY_ALGO);
+ break;
+ }
+ if (err)
+ goto leave;
+
+
+ for (idx = 0, s = elems; *s; s++, idx++)
+ {
+ l2 = gcry_sexp_find_token (list, s, 1);
+ if (!l2)
+ {
+ err = gpg_err_make (default_errsource, GPG_ERR_INV_SEXP);
+ goto leave;
+ }
+ if (blobmode)
+ {
+ const char *blob;
+ size_t bloblen;
+ unsigned char lenbuf[4];
+
+ blob = gcry_sexp_nth_data (l2, 1, &bloblen);
+ if (!blob)
+ {
+ err = gpg_err_make (default_errsource, GPG_ERR_INV_SEXP);
+ goto leave;
+ }
+ blob++;
+ bloblen--;
+ lenbuf[0] = bloblen >> 24;
+ lenbuf[1] = bloblen >> 16;
+ lenbuf[2] = bloblen >> 8;
+ lenbuf[3] = bloblen;
+ gcry_md_write (md, lenbuf, 4);
+ gcry_md_write (md, blob, bloblen);
+ }
+ else
+ {
+ gcry_mpi_t a;
+ unsigned char *buf;
+ size_t buflen;
+
+ a = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
+ gcry_sexp_release (l2);
+ l2 = NULL;
+ if (!a)
+ {
+ err = gpg_err_make (default_errsource, GPG_ERR_INV_SEXP);
+ goto leave;
+ }
+
+ err = gcry_mpi_aprint (GCRYMPI_FMT_SSH, &buf, &buflen, a);
+ gcry_mpi_release (a);
+ if (err)
+ goto leave;
+ gcry_md_write (md, buf, buflen);
+ gcry_free (buf);
+ }
+ }
+
+ if (as_string)
+ {
+ const char *algo_name;
+ char *fpr;
+
+ /* Prefix string with the algorithm name and a colon. */
+ algo_name = gcry_md_algo_name (algo);
+ *r_fpr = xtrymalloc (strlen (algo_name) + 1 + 3 * gcry_md_get_algo_dlen (algo) + 1);
+ if (*r_fpr == NULL)
+ {
+ err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
+ goto leave;
+ }
+
+ memcpy (*r_fpr, algo_name, strlen (algo_name));
+ fpr = (char *) *r_fpr + strlen (algo_name);
+ *fpr++ = ':';
+
+ if (algo == GCRY_MD_MD5)
+ {
+ bin2hexcolon (gcry_md_read (md, algo), gcry_md_get_algo_dlen (algo), fpr);
+ strlwr (fpr);
+ }
+ else
+ {
+ struct b64state b64s;
+ estream_t stream;
+ char *p;
+ long int len;
+
+ /* Write the base64-encoded hash to fpr. */
+ stream = es_mopen (fpr, 3 * gcry_md_get_algo_dlen (algo) + 1, 0,
+ 0, dummy_realloc, dummy_free, "w");
+ if (stream == NULL)
+ {
+ err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
+ goto leave;
+ }
+
+ err = b64enc_start_es (&b64s, stream, "");
+ if (err)
+ {
+ es_fclose (stream);
+ goto leave;
+ }
+
+ err = b64enc_write (&b64s,
+ gcry_md_read (md, algo), gcry_md_get_algo_dlen (algo));
+ if (err)
+ {
+ es_fclose (stream);
+ goto leave;
+ }
+
+ /* Finish, get the length, and close the stream. */
+ err = b64enc_finish (&b64s);
+ len = es_ftell (stream);
+ es_fclose (stream);
+ if (err)
+ goto leave;
+
+ /* Terminate. */
+ fpr[len] = 0;
+
+ /* Strip the trailing padding characters. */
+ for (p = fpr + len - 1; p > fpr && *p == '='; p--)
+ *p = 0;
+ }
+
+ *r_len = strlen (*r_fpr) + 1;
+ }
+ else
+ {
+ *r_len = gcry_md_get_algo_dlen (algo);
+ *r_fpr = xtrymalloc (*r_len);
+ if (!*r_fpr)
+ {
+ err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
+ goto leave;
+ }
+ memcpy (*r_fpr, gcry_md_read (md, algo), *r_len);
+ }
+ err = 0;
+
+ leave:
+ gcry_free (name);
+ gcry_sexp_release (l2);
+ gcry_md_close (md);
+ gcry_sexp_release (list);
+ return err;
+}
+
+/* Return the Secure Shell type fingerprint for KEY using digest ALGO.
+ The length of the fingerprint is returned at R_LEN and the
+ fingerprint itself at R_FPR. In case of an error an error code is
+ returned and NULL stored at R_FPR. */
+gpg_error_t
+ssh_get_fingerprint (gcry_sexp_t key, int algo,
+ void **r_fpr, size_t *r_len)
+{
+ return get_fingerprint (key, algo, r_fpr, r_len, 0);
+}
+
+
+/* Return the Secure Shell type fingerprint for KEY using digest ALGO
+ as a string. The fingerprint is mallcoed and stored at R_FPRSTR.
+ In case of an error an error code is returned and NULL stored at
+ R_FPRSTR. */
+gpg_error_t
+ssh_get_fingerprint_string (gcry_sexp_t key, int algo, char **r_fprstr)
+{
+ gpg_error_t err;
+ size_t dummy;
+ void *string;
+
+ err = get_fingerprint (key, algo, &string, &dummy, 1);
+ *r_fprstr = string;
+ return err;
+}
diff --git a/common/ssh-utils.h b/common/ssh-utils.h
new file mode 100644
index 0000000..53d9f55
--- /dev/null
+++ b/common/ssh-utils.h
@@ -0,0 +1,41 @@
+/* ssh-utils.c - Secure Shell helper function definitions
+ * Copyright (C) 2011 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_COMMON_SSH_UTILS_H
+#define GNUPG_COMMON_SSH_UTILS_H
+
+
+gpg_error_t ssh_get_fingerprint (gcry_sexp_t key, int algo,
+ void **r_fpr, size_t *r_len);
+
+gpg_error_t ssh_get_fingerprint_string (gcry_sexp_t key, int algo,
+ char **r_fprstr);
+
+
+#endif /*GNUPG_COMMON_SSH_UTILS_H*/
diff --git a/common/status-codes.h b/common/status-codes.h
new file mode 100644
index 0000000..0d1e6be
--- /dev/null
+++ b/common/status-codes.h
@@ -0,0 +1,248 @@
+/* Output of mkstrtable.awk. DO NOT EDIT. */
+
+/* status.h - Status codes
+ * Copyright (C) 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+/* The purpose of this complex string table is to produce
+ optimal code with a minimum of relocations. */
+
+static const char statusstr_msgstr[] =
+ "ENTER" "\0"
+ "LEAVE" "\0"
+ "ABORT" "\0"
+ "CANCELED_BY_USER" "\0"
+ "GOODSIG" "\0"
+ "BADSIG" "\0"
+ "ERRSIG" "\0"
+ "BADARMOR" "\0"
+ "TRUST_UNDEFINED" "\0"
+ "TRUST_NEVER" "\0"
+ "TRUST_MARGINAL" "\0"
+ "TRUST_FULLY" "\0"
+ "TRUST_ULTIMATE" "\0"
+ "NEED_PASSPHRASE" "\0"
+ "VALIDSIG" "\0"
+ "SIG_ID" "\0"
+ "ENC_TO" "\0"
+ "NODATA" "\0"
+ "BAD_PASSPHRASE" "\0"
+ "NO_PUBKEY" "\0"
+ "NO_SECKEY" "\0"
+ "NEED_PASSPHRASE_SYM" "\0"
+ "DECRYPTION_KEY" "\0"
+ "DECRYPTION_INFO" "\0"
+ "DECRYPTION_FAILED" "\0"
+ "DECRYPTION_OKAY" "\0"
+ "MISSING_PASSPHRASE" "\0"
+ "GOOD_PASSPHRASE" "\0"
+ "GOODMDC" "\0"
+ "BADMDC" "\0"
+ "ERRMDC" "\0"
+ "IMPORTED" "\0"
+ "IMPORT_OK" "\0"
+ "IMPORT_PROBLEM" "\0"
+ "IMPORT_RES" "\0"
+ "IMPORT_CHECK" "\0"
+ "EXPORTED" "\0"
+ "EXPORT_RES" "\0"
+ "FILE_START" "\0"
+ "FILE_DONE" "\0"
+ "FILE_ERROR" "\0"
+ "BEGIN_DECRYPTION" "\0"
+ "END_DECRYPTION" "\0"
+ "BEGIN_ENCRYPTION" "\0"
+ "END_ENCRYPTION" "\0"
+ "BEGIN_SIGNING" "\0"
+ "DELETE_PROBLEM" "\0"
+ "GET_BOOL" "\0"
+ "GET_LINE" "\0"
+ "GET_HIDDEN" "\0"
+ "GOT_IT" "\0"
+ "PROGRESS" "\0"
+ "SIG_CREATED" "\0"
+ "SESSION_KEY" "\0"
+ "NOTATION_NAME" "\0"
+ "NOTATION_FLAGS" "\0"
+ "NOTATION_DATA" "\0"
+ "POLICY_URL" "\0"
+ "KEY_CREATED" "\0"
+ "USERID_HINT" "\0"
+ "UNEXPECTED" "\0"
+ "INV_RECP" "\0"
+ "INV_SGNR" "\0"
+ "NO_RECP" "\0"
+ "NO_SGNR" "\0"
+ "KEY_CONSIDERED" "\0"
+ "ALREADY_SIGNED" "\0"
+ "KEYEXPIRED" "\0"
+ "KEYREVOKED" "\0"
+ "EXPSIG" "\0"
+ "EXPKEYSIG" "\0"
+ "ATTRIBUTE" "\0"
+ "REVKEYSIG" "\0"
+ "NEWSIG" "\0"
+ "SIG_SUBPACKET" "\0"
+ "PLAINTEXT" "\0"
+ "PLAINTEXT_LENGTH" "\0"
+ "KEY_NOT_CREATED" "\0"
+ "NEED_PASSPHRASE_PIN" "\0"
+ "CARDCTRL" "\0"
+ "SC_OP_FAILURE" "\0"
+ "SC_OP_SUCCESS" "\0"
+ "BACKUP_KEY_CREATED" "\0"
+ "PKA_TRUST_BAD" "\0"
+ "PKA_TRUST_GOOD" "\0"
+ "TOFU_USER" "\0"
+ "TOFU_STATS" "\0"
+ "TOFU_STATS_SHORT" "\0"
+ "TOFU_STATS_LONG" "\0"
+ "ENCRYPTION_COMPLIANCE_MODE" "\0"
+ "DECRYPTION_COMPLIANCE_MODE" "\0"
+ "VERIFICATION_COMPLIANCE_MODE" "\0"
+ "TRUNCATED" "\0"
+ "MOUNTPOINT" "\0"
+ "BLOCKDEV" "\0"
+ "PINENTRY_LAUNCHED" "\0"
+ "PLAINTEXT_FOLLOWS" "\0"
+ "ERROR" "\0"
+ "WARNING" "\0"
+ "SUCCESS" "\0"
+ "FAILURE" "\0"
+ "INQUIRE_MAXLEN";
+
+static const int statusstr_msgidx[] =
+ {
+ 0,
+ 6,
+ 12,
+ 18,
+ 35,
+ 43,
+ 50,
+ 57,
+ 66,
+ 82,
+ 94,
+ 109,
+ 121,
+ 136,
+ 152,
+ 161,
+ 168,
+ 175,
+ 182,
+ 197,
+ 207,
+ 217,
+ 237,
+ 252,
+ 268,
+ 286,
+ 302,
+ 321,
+ 337,
+ 345,
+ 352,
+ 359,
+ 368,
+ 378,
+ 393,
+ 404,
+ 417,
+ 426,
+ 437,
+ 448,
+ 458,
+ 469,
+ 486,
+ 501,
+ 518,
+ 533,
+ 547,
+ 562,
+ 571,
+ 580,
+ 591,
+ 598,
+ 607,
+ 619,
+ 631,
+ 645,
+ 660,
+ 674,
+ 685,
+ 697,
+ 709,
+ 720,
+ 729,
+ 738,
+ 746,
+ 754,
+ 769,
+ 784,
+ 795,
+ 806,
+ 813,
+ 823,
+ 833,
+ 843,
+ 850,
+ 864,
+ 874,
+ 891,
+ 907,
+ 927,
+ 936,
+ 950,
+ 964,
+ 983,
+ 997,
+ 1012,
+ 1022,
+ 1033,
+ 1050,
+ 1066,
+ 1093,
+ 1120,
+ 1149,
+ 1159,
+ 1170,
+ 1179,
+ 1197,
+ 1215,
+ 1221,
+ 1229,
+ 1237,
+ 1245,
+
+ };
+
+#define statusstr_msgidxof(code) (0 ? -1 \
+ : ((code >= 0) && (code <= 101)) ? (code - 0) \
+ : -1)
diff --git a/common/status.c b/common/status.c
new file mode 100644
index 0000000..50afce4
--- /dev/null
+++ b/common/status.c
@@ -0,0 +1,76 @@
+/* status.c - status code helper functions
+ * Copyright (C) 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+
+#include "util.h"
+#include "status.h"
+#include "status-codes.h"
+
+
+/* Return the status string for code NO. */
+const char *
+get_status_string ( int no )
+{
+ int idx = statusstr_msgidxof (no);
+ if (idx == -1)
+ return "?";
+ else
+ return statusstr_msgstr + statusstr_msgidx[idx];
+}
+
+
+const char *
+get_inv_recpsgnr_code (gpg_error_t err)
+{
+ const char *errstr;
+
+ switch (gpg_err_code (err))
+ {
+ case GPG_ERR_NO_PUBKEY: errstr = "1"; break;
+ case GPG_ERR_AMBIGUOUS_NAME: errstr = "2"; break;
+ case GPG_ERR_WRONG_KEY_USAGE: errstr = "3"; break;
+ case GPG_ERR_CERT_REVOKED: errstr = "4"; break;
+ case GPG_ERR_CERT_EXPIRED: errstr = "5"; break;
+ case GPG_ERR_NO_CRL_KNOWN: errstr = "6"; break;
+ case GPG_ERR_CRL_TOO_OLD: errstr = "7"; break;
+ case GPG_ERR_NO_POLICY_MATCH: errstr = "8"; break;
+
+ case GPG_ERR_UNUSABLE_SECKEY:
+ case GPG_ERR_NO_SECKEY: errstr = "9"; break;
+
+ case GPG_ERR_NOT_TRUSTED: errstr = "10"; break;
+ case GPG_ERR_MISSING_CERT: errstr = "11"; break;
+ case GPG_ERR_MISSING_ISSUER_CERT: errstr = "12"; break;
+ default: errstr = "0"; break;
+ }
+
+ return errstr;
+}
diff --git a/common/status.h b/common/status.h
new file mode 100644
index 0000000..d5564e4
--- /dev/null
+++ b/common/status.h
@@ -0,0 +1,170 @@
+/* status.h - Status codes
+ * Copyright (C) 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_COMMON_STATUS_H
+#define GNUPG_COMMON_STATUS_H
+
+enum
+ {
+ STATUS_ENTER,
+ STATUS_LEAVE,
+ STATUS_ABORT,
+ STATUS_CANCELED_BY_USER,
+
+ STATUS_GOODSIG,
+ STATUS_BADSIG,
+ STATUS_ERRSIG,
+
+ STATUS_BADARMOR,
+
+ STATUS_TRUST_UNDEFINED,
+ STATUS_TRUST_NEVER,
+ STATUS_TRUST_MARGINAL,
+ STATUS_TRUST_FULLY,
+ STATUS_TRUST_ULTIMATE,
+
+ STATUS_NEED_PASSPHRASE,
+ STATUS_VALIDSIG,
+ STATUS_SIG_ID,
+ STATUS_ENC_TO,
+ STATUS_NODATA,
+ STATUS_BAD_PASSPHRASE,
+ STATUS_NO_PUBKEY,
+ STATUS_NO_SECKEY,
+ STATUS_NEED_PASSPHRASE_SYM,
+ STATUS_DECRYPTION_KEY,
+ STATUS_DECRYPTION_INFO,
+ STATUS_DECRYPTION_FAILED,
+ STATUS_DECRYPTION_OKAY,
+ STATUS_MISSING_PASSPHRASE,
+ STATUS_GOOD_PASSPHRASE,
+ STATUS_GOODMDC,
+ STATUS_BADMDC,
+ STATUS_ERRMDC,
+
+ STATUS_IMPORTED,
+ STATUS_IMPORT_OK,
+ STATUS_IMPORT_PROBLEM,
+ STATUS_IMPORT_RES,
+ STATUS_IMPORT_CHECK,
+
+ STATUS_EXPORTED,
+ STATUS_EXPORT_RES,
+
+ STATUS_FILE_START,
+ STATUS_FILE_DONE,
+ STATUS_FILE_ERROR,
+
+ STATUS_BEGIN_DECRYPTION,
+ STATUS_END_DECRYPTION,
+ STATUS_BEGIN_ENCRYPTION,
+ STATUS_END_ENCRYPTION,
+ STATUS_BEGIN_SIGNING,
+
+ STATUS_DELETE_PROBLEM,
+
+ STATUS_GET_BOOL,
+ STATUS_GET_LINE,
+ STATUS_GET_HIDDEN,
+ STATUS_GOT_IT,
+
+ STATUS_PROGRESS,
+ STATUS_SIG_CREATED,
+ STATUS_SESSION_KEY,
+ STATUS_NOTATION_NAME,
+ STATUS_NOTATION_FLAGS,
+ STATUS_NOTATION_DATA,
+ STATUS_POLICY_URL,
+ STATUS_KEY_CREATED,
+ STATUS_USERID_HINT,
+ STATUS_UNEXPECTED,
+ STATUS_INV_RECP,
+ STATUS_INV_SGNR,
+ STATUS_NO_RECP,
+ STATUS_NO_SGNR,
+ STATUS_KEY_CONSIDERED,
+
+ STATUS_ALREADY_SIGNED,
+ STATUS_KEYEXPIRED,
+ STATUS_KEYREVOKED,
+ STATUS_EXPSIG,
+ STATUS_EXPKEYSIG,
+
+ STATUS_ATTRIBUTE,
+
+ STATUS_REVKEYSIG,
+
+ STATUS_NEWSIG,
+ STATUS_SIG_SUBPACKET,
+
+ STATUS_PLAINTEXT,
+ STATUS_PLAINTEXT_LENGTH,
+ STATUS_KEY_NOT_CREATED,
+ STATUS_NEED_PASSPHRASE_PIN,
+
+ STATUS_CARDCTRL,
+ STATUS_SC_OP_FAILURE,
+ STATUS_SC_OP_SUCCESS,
+
+ STATUS_BACKUP_KEY_CREATED,
+
+ STATUS_PKA_TRUST_BAD,
+ STATUS_PKA_TRUST_GOOD,
+
+ STATUS_TOFU_USER,
+ STATUS_TOFU_STATS,
+ STATUS_TOFU_STATS_SHORT,
+ STATUS_TOFU_STATS_LONG,
+
+ STATUS_ENCRYPTION_COMPLIANCE_MODE,
+ STATUS_DECRYPTION_COMPLIANCE_MODE,
+ STATUS_VERIFICATION_COMPLIANCE_MODE,
+
+ STATUS_TRUNCATED,
+ STATUS_MOUNTPOINT,
+ STATUS_BLOCKDEV,
+
+ STATUS_PINENTRY_LAUNCHED,
+
+ STATUS_PLAINTEXT_FOLLOWS, /* Used by g13-syshelp */
+
+ STATUS_ERROR,
+ STATUS_WARNING,
+ STATUS_SUCCESS,
+ STATUS_FAILURE,
+
+ STATUS_INQUIRE_MAXLEN
+ };
+
+
+const char *get_status_string (int code);
+const char *get_inv_recpsgnr_code (gpg_error_t err);
+
+
+#endif /*GNUPG_COMMON_STATUS_H*/
diff --git a/common/stringhelp.c b/common/stringhelp.c
new file mode 100644
index 0000000..5baaa1b
--- /dev/null
+++ b/common/stringhelp.c
@@ -0,0 +1,1795 @@
+/* stringhelp.c - standard string helper functions
+ * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007,
+ * 2008, 2009, 2010 Free Software Foundation, Inc.
+ * Copyright (C) 2014 Werner Koch
+ * Copyright (C) 2015, 2021 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute and/or modify this
+ * part of GnuPG under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * 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 copies of the GNU General Public License
+ * and the GNU Lesser General Public License along with this program;
+ * if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: (LGPL-3.0-or-later OR GPL-2.0-or-later)
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <errno.h>
+#ifdef HAVE_PWD_H
+# include <pwd.h>
+#endif
+#include <unistd.h>
+#include <sys/types.h>
+#ifdef HAVE_W32_SYSTEM
+# ifdef HAVE_WINSOCK2_H
+# include <winsock2.h>
+# endif
+# include <windows.h>
+#endif
+#include <limits.h>
+
+#include "util.h"
+#include "common-defs.h"
+#include "utf8conv.h"
+#include "sysutils.h"
+#include "stringhelp.h"
+
+#define tohex_lower(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'a'))
+
+
+/* Sometimes we want to avoid mixing slashes and backslashes on W32
+ and prefer backslashes. There is usual no problem with mixing
+ them, however a very few W32 API calls can't grok plain slashes.
+ Printing filenames with mixed slashes also looks a bit strange.
+ This function has no effext on POSIX. */
+static inline char *
+change_slashes (char *name)
+{
+#ifdef HAVE_DOSISH_SYSTEM
+ char *p;
+
+ if (strchr (name, '\\'))
+ {
+ for (p=name; *p; p++)
+ if (*p == '/')
+ *p = '\\';
+ }
+#endif /*HAVE_DOSISH_SYSTEM*/
+ return name;
+}
+
+
+/*
+ * Check whether STRING starts with KEYWORD. The keyword is
+ * delimited by end of string, a space or a tab. Returns NULL if not
+ * found or a pointer into STRING to the next non-space character
+ * after the KEYWORD (which may be end of string).
+ */
+char *
+has_leading_keyword (const char *string, const char *keyword)
+{
+ size_t n = strlen (keyword);
+
+ if (!strncmp (string, keyword, n)
+ && (!string[n] || string[n] == ' ' || string[n] == '\t'))
+ {
+ string += n;
+ while (*string == ' ' || *string == '\t')
+ string++;
+ return (char*)string;
+ }
+ return NULL;
+}
+
+
+/*
+ * Look for the substring SUB in buffer and return a pointer to that
+ * substring in BUFFER or NULL if not found.
+ * Comparison is case-insensitive.
+ */
+const char *
+memistr (const void *buffer, size_t buflen, const char *sub)
+{
+ const unsigned char *buf = buffer;
+ const unsigned char *t = (const unsigned char *)buffer;
+ const unsigned char *s = (const unsigned char *)sub;
+ size_t n = buflen;
+
+ for ( ; n ; t++, n-- )
+ {
+ if ( toupper (*t) == toupper (*s) )
+ {
+ for ( buf=t++, buflen = n--, s++;
+ n && toupper (*t) == toupper (*s); t++, s++, n-- )
+ ;
+ if (!*s)
+ return (const char*)buf;
+ t = buf;
+ s = (const unsigned char *)sub ;
+ n = buflen;
+ }
+ }
+ return NULL;
+}
+
+const char *
+ascii_memistr ( const void *buffer, size_t buflen, const char *sub )
+{
+ const unsigned char *buf = buffer;
+ const unsigned char *t = (const unsigned char *)buf;
+ const unsigned char *s = (const unsigned char *)sub;
+ size_t n = buflen;
+
+ for ( ; n ; t++, n-- )
+ {
+ if (ascii_toupper (*t) == ascii_toupper (*s) )
+ {
+ for ( buf=t++, buflen = n--, s++;
+ n && ascii_toupper (*t) == ascii_toupper (*s); t++, s++, n-- )
+ ;
+ if (!*s)
+ return (const char*)buf;
+ t = (const unsigned char *)buf;
+ s = (const unsigned char *)sub ;
+ n = buflen;
+ }
+ }
+ return NULL;
+}
+
+/* This function is similar to strncpy(). However it won't copy more
+ than N - 1 characters and makes sure that a '\0' is appended. With
+ N given as 0, nothing will happen. With DEST given as NULL, memory
+ will be allocated using xmalloc (i.e. if it runs out of core
+ the function terminates). Returns DES or a pointer to the
+ allocated memory.
+ */
+char *
+mem2str( char *dest , const void *src , size_t n )
+{
+ char *d;
+ const char *s;
+
+ if( n ) {
+ if( !dest )
+ dest = xmalloc( n ) ;
+ d = dest;
+ s = src ;
+ for(n--; n && *s; n-- )
+ *d++ = *s++;
+ *d = '\0' ;
+ }
+
+ return dest ;
+}
+
+
+/****************
+ * remove leading and trailing white spaces
+ */
+char *
+trim_spaces( char *str )
+{
+ char *string, *p, *mark;
+
+ string = str;
+ /* find first non space character */
+ for( p=string; *p && isspace( *(byte*)p ) ; p++ )
+ ;
+ /* move characters */
+ for( (mark = NULL); (*string = *p); string++, p++ )
+ if( isspace( *(byte*)p ) ) {
+ if( !mark )
+ mark = string ;
+ }
+ else
+ mark = NULL ;
+ if( mark )
+ *mark = '\0' ; /* remove trailing spaces */
+
+ return str ;
+}
+
+
+/* Same as trim_spaces but only consider, space, tab, cr and lf as space. */
+char *
+ascii_trim_spaces (char *str)
+{
+ char *string, *p, *mark;
+
+ string = str;
+
+ /* Find first non-ascii space character. */
+ for (p=string; *p && ascii_isspace (*p); p++)
+ ;
+ /* Move characters. */
+ for (mark=NULL; (*string = *p); string++, p++ )
+ {
+ if (ascii_isspace (*p))
+ {
+ if (!mark)
+ mark = string;
+ }
+ else
+ mark = NULL ;
+ }
+ if (mark)
+ *mark = '\0' ; /* Remove trailing spaces. */
+
+ return str ;
+}
+
+
+/****************
+ * remove trailing white spaces
+ */
+char *
+trim_trailing_spaces( char *string )
+{
+ char *p, *mark;
+
+ for( mark = NULL, p = string; *p; p++ ) {
+ if( isspace( *(byte*)p ) ) {
+ if( !mark )
+ mark = p;
+ }
+ else
+ mark = NULL;
+ }
+ if( mark )
+ *mark = '\0' ;
+
+ return string ;
+}
+
+
+unsigned
+trim_trailing_chars( byte *line, unsigned len, const char *trimchars )
+{
+ byte *p, *mark;
+ unsigned n;
+
+ for(mark=NULL, p=line, n=0; n < len; n++, p++ ) {
+ if( strchr(trimchars, *p ) ) {
+ if( !mark )
+ mark = p;
+ }
+ else
+ mark = NULL;
+ }
+
+ if( mark ) {
+ *mark = 0;
+ return mark - line;
+ }
+ return len;
+}
+
+/****************
+ * remove trailing white spaces and return the length of the buffer
+ */
+unsigned
+trim_trailing_ws( byte *line, unsigned len )
+{
+ return trim_trailing_chars( line, len, " \t\r\n" );
+}
+
+size_t
+length_sans_trailing_chars (const unsigned char *line, size_t len,
+ const char *trimchars )
+{
+ const unsigned char *p, *mark;
+ size_t n;
+
+ for( mark=NULL, p=line, n=0; n < len; n++, p++ )
+ {
+ if (strchr (trimchars, *p ))
+ {
+ if( !mark )
+ mark = p;
+ }
+ else
+ mark = NULL;
+ }
+
+ if (mark)
+ return mark - line;
+ return len;
+}
+
+/*
+ * Return the length of line ignoring trailing white-space.
+ */
+size_t
+length_sans_trailing_ws (const unsigned char *line, size_t len)
+{
+ return length_sans_trailing_chars (line, len, " \t\r\n");
+}
+
+
+
+/*
+ * Extract from a given path the filename component. This function
+ * terminates the process on memory shortage.
+ */
+char *
+make_basename(const char *filepath, const char *inputpath)
+{
+#ifdef __riscos__
+ return riscos_make_basename(filepath, inputpath);
+#else
+ char *p;
+
+ (void)inputpath; /* Only required for riscos. */
+
+ if ( !(p=strrchr(filepath, '/')) )
+#ifdef HAVE_DOSISH_SYSTEM
+ if ( !(p=strrchr(filepath, '\\')) )
+#endif
+#ifdef HAVE_DRIVE_LETTERS
+ if ( !(p=strrchr(filepath, ':')) )
+#endif
+ {
+ return xstrdup(filepath);
+ }
+
+ return xstrdup(p+1);
+#endif
+}
+
+
+
+/*
+ * Extract from a given filename the path prepended to it. If there
+ * isn't a path prepended to the filename, a dot is returned ('.').
+ * This function terminates the process on memory shortage.
+ */
+char *
+make_dirname(const char *filepath)
+{
+ char *dirname;
+ int dirname_length;
+ char *p;
+
+ if ( !(p=strrchr(filepath, '/')) )
+#ifdef HAVE_DOSISH_SYSTEM
+ if ( !(p=strrchr(filepath, '\\')) )
+#endif
+#ifdef HAVE_DRIVE_LETTERS
+ if ( !(p=strrchr(filepath, ':')) )
+#endif
+ {
+ return xstrdup(".");
+ }
+
+ dirname_length = p-filepath;
+ dirname = xmalloc(dirname_length+1);
+ strncpy(dirname, filepath, dirname_length);
+ dirname[dirname_length] = 0;
+
+ return dirname;
+}
+
+
+
+static char *
+get_pwdir (int xmode, const char *name)
+{
+ char *result = NULL;
+#ifdef HAVE_PWD_H
+ struct passwd *pwd = NULL;
+
+ if (name)
+ {
+#ifdef HAVE_GETPWNAM
+ /* Fixme: We should use getpwnam_r if available. */
+ pwd = getpwnam (name);
+#endif
+ }
+ else
+ {
+#ifdef HAVE_GETPWUID
+ /* Fixme: We should use getpwuid_r if available. */
+ pwd = getpwuid (getuid());
+#endif
+ }
+ if (pwd)
+ {
+ if (xmode)
+ result = xstrdup (pwd->pw_dir);
+ else
+ result = xtrystrdup (pwd->pw_dir);
+ }
+#else /*!HAVE_PWD_H*/
+ /* No support at all. */
+ (void)xmode;
+ (void)name;
+#endif /*HAVE_PWD_H*/
+ return result;
+}
+
+
+/* xmode 0 := Return NULL on error
+ 1 := Terminate on error
+ 2 := Make sure that name is absolute; return NULL on error
+ 3 := Make sure that name is absolute; terminate on error
+ */
+static char *
+do_make_filename (int xmode, const char *first_part, va_list arg_ptr)
+{
+ const char *argv[32];
+ int argc;
+ size_t n;
+ int skip = 1;
+ char *home_buffer = NULL;
+ char *name, *home, *p;
+ int want_abs;
+
+ want_abs = !!(xmode & 2);
+ xmode &= 1;
+
+ n = strlen (first_part) + 1;
+ argc = 0;
+ while ( (argv[argc] = va_arg (arg_ptr, const char *)) )
+ {
+ n += strlen (argv[argc]) + 1;
+ if (argc >= DIM (argv)-1)
+ {
+ if (xmode)
+ BUG ();
+ gpg_err_set_errno (EINVAL);
+ return NULL;
+ }
+ argc++;
+ }
+ n++;
+
+ home = NULL;
+ if (*first_part == '~')
+ {
+ if (first_part[1] == '/' || !first_part[1])
+ {
+ /* This is the "~/" or "~" case. */
+ home = getenv("HOME");
+ if (!home)
+ home = home_buffer = get_pwdir (xmode, NULL);
+ if (home && *home)
+ n += strlen (home);
+ }
+ else
+ {
+ /* This is the "~username/" or "~username" case. */
+ char *user;
+
+ if (xmode)
+ user = xstrdup (first_part+1);
+ else
+ {
+ user = xtrystrdup (first_part+1);
+ if (!user)
+ return NULL;
+ }
+ p = strchr (user, '/');
+ if (p)
+ *p = 0;
+ skip = 1 + strlen (user);
+
+ home = home_buffer = get_pwdir (xmode, user);
+ xfree (user);
+ if (home)
+ n += strlen (home);
+ else
+ skip = 1;
+ }
+ }
+
+ if (xmode)
+ name = xmalloc (n);
+ else
+ {
+ name = xtrymalloc (n);
+ if (!name)
+ {
+ xfree (home_buffer);
+ return NULL;
+ }
+ }
+
+ if (home)
+ p = stpcpy (stpcpy (name, home), first_part + skip);
+ else
+ p = stpcpy (name, first_part);
+
+ xfree (home_buffer);
+ for (argc=0; argv[argc]; argc++)
+ {
+ /* Avoid a leading double slash if the first part was "/". */
+ if (!argc && name[0] == '/' && !name[1])
+ p = stpcpy (p, argv[argc]);
+ else
+ p = stpcpy (stpcpy (p, "/"), argv[argc]);
+ }
+
+ if (want_abs)
+ {
+#ifdef HAVE_DRIVE_LETTERS
+ p = strchr (name, ':');
+ if (p)
+ p++;
+ else
+ p = name;
+#else
+ p = name;
+#endif
+ if (*p != '/'
+#ifdef HAVE_DRIVE_LETTERS
+ && *p != '\\'
+#endif
+ )
+ {
+ home = gnupg_getcwd ();
+ if (!home)
+ {
+ if (xmode)
+ {
+ fprintf (stderr, "\nfatal: getcwd failed: %s\n",
+ strerror (errno));
+ exit(2);
+ }
+ xfree (name);
+ return NULL;
+ }
+ n = strlen (home) + 1 + strlen (name) + 1;
+ if (xmode)
+ home_buffer = xmalloc (n);
+ else
+ {
+ home_buffer = xtrymalloc (n);
+ if (!home_buffer)
+ {
+ xfree (home);
+ xfree (name);
+ return NULL;
+ }
+ }
+ if (p == name)
+ p = home_buffer;
+ else /* Windows case. */
+ {
+ memcpy (home_buffer, p, p - name + 1);
+ p = home_buffer + (p - name + 1);
+ }
+
+ /* Avoid a leading double slash if the cwd is "/". */
+ if (home[0] == '/' && !home[1])
+ strcpy (stpcpy (p, "/"), name);
+ else
+ strcpy (stpcpy (stpcpy (p, home), "/"), name);
+
+ xfree (home);
+ xfree (name);
+ name = home_buffer;
+ /* Let's do a simple compression to catch the most common
+ case of using "." for gpg's --homedir option. */
+ n = strlen (name);
+ if (n > 2 && name[n-2] == '/' && name[n-1] == '.')
+ name[n-2] = 0;
+ }
+ }
+ return change_slashes (name);
+}
+
+/* Construct a filename from the NULL terminated list of parts. Tilde
+ expansion is done for the first argument. This function terminates
+ the process on memory shortage. */
+char *
+make_filename (const char *first_part, ... )
+{
+ va_list arg_ptr;
+ char *result;
+
+ va_start (arg_ptr, first_part);
+ result = do_make_filename (1, first_part, arg_ptr);
+ va_end (arg_ptr);
+ return result;
+}
+
+/* Construct a filename from the NULL terminated list of parts. Tilde
+ expansion is done for the first argument. This function may return
+ NULL on error. */
+char *
+make_filename_try (const char *first_part, ... )
+{
+ va_list arg_ptr;
+ char *result;
+
+ va_start (arg_ptr, first_part);
+ result = do_make_filename (0, first_part, arg_ptr);
+ va_end (arg_ptr);
+ return result;
+}
+
+/* Construct an absolute filename from the NULL terminated list of
+ parts. Tilde expansion is done for the first argument. This
+ function terminates the process on memory shortage. */
+char *
+make_absfilename (const char *first_part, ... )
+{
+ va_list arg_ptr;
+ char *result;
+
+ va_start (arg_ptr, first_part);
+ result = do_make_filename (3, first_part, arg_ptr);
+ va_end (arg_ptr);
+ return result;
+}
+
+/* Construct an absolute filename from the NULL terminated list of
+ parts. Tilde expansion is done for the first argument. This
+ function may return NULL on error. */
+char *
+make_absfilename_try (const char *first_part, ... )
+{
+ va_list arg_ptr;
+ char *result;
+
+ va_start (arg_ptr, first_part);
+ result = do_make_filename (2, first_part, arg_ptr);
+ va_end (arg_ptr);
+ return result;
+}
+
+
+
+/* Compare whether the filenames are identical. This is a
+ special version of strcmp() taking the semantics of filenames in
+ account. Note that this function works only on the supplied names
+ without considering any context like the current directory. See
+ also same_file_p(). */
+int
+compare_filenames (const char *a, const char *b)
+{
+#ifdef HAVE_DOSISH_SYSTEM
+ for ( ; *a && *b; a++, b++ )
+ {
+ if (*a != *b
+ && (toupper (*(const unsigned char*)a)
+ != toupper (*(const unsigned char*)b) )
+ && !((*a == '/' && *b == '\\') || (*a == '\\' && *b == '/')))
+ break;
+ }
+ if ((*a == '/' && *b == '\\') || (*a == '\\' && *b == '/'))
+ return 0;
+ else
+ return (toupper (*(const unsigned char*)a)
+ - toupper (*(const unsigned char*)b));
+#else
+ return strcmp(a,b);
+#endif
+}
+
+
+/* Convert a base-10 number in STRING into a 64 bit unsigned int
+ * value. Leading white spaces are skipped but no error checking is
+ * done. Thus it is similar to atoi(). */
+uint64_t
+string_to_u64 (const char *string)
+{
+ uint64_t val = 0;
+
+ while (spacep (string))
+ string++;
+ for (; digitp (string); string++)
+ {
+ val *= 10;
+ val += *string - '0';
+ }
+ return val;
+}
+
+
+/* Convert 2 hex characters at S to a byte value. Return this value
+ or -1 if there is an error. */
+int
+hextobyte (const char *s)
+{
+ int c;
+
+ if ( *s >= '0' && *s <= '9' )
+ c = 16 * (*s - '0');
+ else if ( *s >= 'A' && *s <= 'F' )
+ c = 16 * (10 + *s - 'A');
+ else if ( *s >= 'a' && *s <= 'f' )
+ c = 16 * (10 + *s - 'a');
+ else
+ return -1;
+ s++;
+ if ( *s >= '0' && *s <= '9' )
+ c += *s - '0';
+ else if ( *s >= 'A' && *s <= 'F' )
+ c += 10 + *s - 'A';
+ else if ( *s >= 'a' && *s <= 'f' )
+ c += 10 + *s - 'a';
+ else
+ return -1;
+ return c;
+}
+
+/* Given a string containing an UTF-8 encoded text, return the number
+ of characters in this string. It differs from strlen in that it
+ only counts complete UTF-8 characters. SIZE is the maximum length
+ of the string in bytes. If SIZE is -1, then a NUL character is
+ taken to be the end of the string. Note, that this function does
+ not take combined characters into account. */
+size_t
+utf8_charcount (const char *s, int len)
+{
+ size_t n;
+
+ if (len == 0)
+ return 0;
+
+ for (n=0; *s; s++)
+ {
+ if ( (*s&0xc0) != 0x80 ) /* Exclude continuation bytes: 10xxxxxx */
+ n++;
+
+ if (len != -1)
+ {
+ len --;
+ if (len == 0)
+ break;
+ }
+ }
+
+ return n;
+}
+
+
+/****************************************************
+ ********** W32 specific functions ****************
+ ****************************************************/
+
+#ifdef HAVE_W32_SYSTEM
+const char *
+w32_strerror (int ec)
+{
+ static char strerr[256];
+
+ if (ec == -1)
+ ec = (int)GetLastError ();
+#ifdef HAVE_W32CE_SYSTEM
+ /* There is only a wchar_t FormatMessage. It does not make much
+ sense to play the conversion game; we print only the code. */
+ snprintf (strerr, sizeof strerr, "ec=%d", (int)GetLastError ());
+#else
+ FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, ec,
+ MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
+ strerr, DIM (strerr)-1, NULL);
+ {
+ /* Strip the CR,LF - we want just the string. */
+ size_t n = strlen (strerr);
+ if (n > 2 && strerr[n-2] == '\r' && strerr[n-1] == '\n' )
+ strerr[n-2] = 0;
+ }
+#endif
+ return strerr;
+}
+#endif /*HAVE_W32_SYSTEM*/
+
+
+/****************************************************
+ ******** Locale insensitive ctype functions ********
+ ****************************************************/
+/* FIXME: replace them by a table lookup and macros */
+int
+ascii_isupper (int c)
+{
+ return c >= 'A' && c <= 'Z';
+}
+
+int
+ascii_islower (int c)
+{
+ return c >= 'a' && c <= 'z';
+}
+
+int
+ascii_toupper (int c)
+{
+ if (c >= 'a' && c <= 'z')
+ c &= ~0x20;
+ return c;
+}
+
+int
+ascii_tolower (int c)
+{
+ if (c >= 'A' && c <= 'Z')
+ c |= 0x20;
+ return c;
+}
+
+/* Lowercase all ASCII characters in S. */
+char *
+ascii_strlwr (char *s)
+{
+ char *p = s;
+
+ for (p=s; *p; p++ )
+ if (isascii (*p) && *p >= 'A' && *p <= 'Z')
+ *p |= 0x20;
+
+ return s;
+}
+
+/* Upcase all ASCII characters in S. */
+char *
+ascii_strupr (char *s)
+{
+ char *p = s;
+
+ for (p=s; *p; p++ )
+ if (isascii (*p) && *p >= 'a' && *p <= 'z')
+ *p &= ~0x20;
+
+ return s;
+}
+
+int
+ascii_strcasecmp( const char *a, const char *b )
+{
+ if (a == b)
+ return 0;
+
+ for (; *a && *b; a++, b++) {
+ if (*a != *b && ascii_toupper(*a) != ascii_toupper(*b))
+ break;
+ }
+ return *a == *b? 0 : (ascii_toupper (*a) - ascii_toupper (*b));
+}
+
+int
+ascii_strncasecmp (const char *a, const char *b, size_t n)
+{
+ const unsigned char *p1 = (const unsigned char *)a;
+ const unsigned char *p2 = (const unsigned char *)b;
+ unsigned char c1, c2;
+
+ if (p1 == p2 || !n )
+ return 0;
+
+ do
+ {
+ c1 = ascii_tolower (*p1);
+ c2 = ascii_tolower (*p2);
+
+ if ( !--n || c1 == '\0')
+ break;
+
+ ++p1;
+ ++p2;
+ }
+ while (c1 == c2);
+
+ return c1 - c2;
+}
+
+
+int
+ascii_memcasecmp (const void *a_arg, const void *b_arg, size_t n )
+{
+ const char *a = a_arg;
+ const char *b = b_arg;
+
+ if (a == b)
+ return 0;
+ for ( ; n; n--, a++, b++ )
+ {
+ if( *a != *b && ascii_toupper (*a) != ascii_toupper (*b) )
+ return *a == *b? 0 : (ascii_toupper (*a) - ascii_toupper (*b));
+ }
+ return 0;
+}
+
+int
+ascii_strcmp( const char *a, const char *b )
+{
+ if (a == b)
+ return 0;
+
+ for (; *a && *b; a++, b++) {
+ if (*a != *b )
+ break;
+ }
+ return *a == *b? 0 : (*(signed char *)a - *(signed char *)b);
+}
+
+
+void *
+ascii_memcasemem (const void *haystack, size_t nhaystack,
+ const void *needle, size_t nneedle)
+{
+
+ if (!nneedle)
+ return (void*)haystack; /* finding an empty needle is really easy */
+ if (nneedle <= nhaystack)
+ {
+ const char *a = haystack;
+ const char *b = a + nhaystack - nneedle;
+
+ for (; a <= b; a++)
+ {
+ if ( !ascii_memcasecmp (a, needle, nneedle) )
+ return (void *)a;
+ }
+ }
+ return NULL;
+}
+
+/*********************************************
+ ********** missing string functions *********
+ *********************************************/
+
+#ifndef HAVE_STPCPY
+char *
+stpcpy(char *a,const char *b)
+{
+ while( *b )
+ *a++ = *b++;
+ *a = 0;
+
+ return (char*)a;
+}
+#endif
+
+#ifndef HAVE_STRPBRK
+/* Find the first occurrence in S of any character in ACCEPT.
+ Code taken from glibc-2.6/string/strpbrk.c (LGPLv2.1+) and modified. */
+char *
+strpbrk (const char *s, const char *accept)
+{
+ while (*s != '\0')
+ {
+ const char *a = accept;
+ while (*a != '\0')
+ if (*a++ == *s)
+ return (char *) s;
+ ++s;
+ }
+
+ return NULL;
+}
+#endif /*!HAVE_STRPBRK*/
+
+
+#ifndef HAVE_STRSEP
+/* Code taken from glibc-2.2.1/sysdeps/generic/strsep.c. */
+char *
+strsep (char **stringp, const char *delim)
+{
+ char *begin, *end;
+
+ begin = *stringp;
+ if (begin == NULL)
+ return NULL;
+
+ /* A frequent case is when the delimiter string contains only one
+ character. Here we don't need to call the expensive 'strpbrk'
+ function and instead work using 'strchr'. */
+ if (delim[0] == '\0' || delim[1] == '\0')
+ {
+ char ch = delim[0];
+
+ if (ch == '\0')
+ end = NULL;
+ else
+ {
+ if (*begin == ch)
+ end = begin;
+ else if (*begin == '\0')
+ end = NULL;
+ else
+ end = strchr (begin + 1, ch);
+ }
+ }
+ else
+ /* Find the end of the token. */
+ end = strpbrk (begin, delim);
+
+ if (end)
+ {
+ /* Terminate the token and set *STRINGP past NUL character. */
+ *end++ = '\0';
+ *stringp = end;
+ }
+ else
+ /* No more delimiters; this is the last token. */
+ *stringp = NULL;
+
+ return begin;
+}
+#endif /*HAVE_STRSEP*/
+
+
+#ifndef HAVE_STRLWR
+char *
+strlwr(char *s)
+{
+ char *p;
+ for(p=s; *p; p++ )
+ *p = tolower(*p);
+ return s;
+}
+#endif
+
+
+#ifndef HAVE_STRCASECMP
+int
+strcasecmp( const char *a, const char *b )
+{
+ for( ; *a && *b; a++, b++ ) {
+ if( *a != *b && toupper(*a) != toupper(*b) )
+ break;
+ }
+ return *(const byte*)a - *(const byte*)b;
+}
+#endif
+
+
+/****************
+ * mingw32/cpd has a memicmp()
+ */
+#ifndef HAVE_MEMICMP
+int
+memicmp( const char *a, const char *b, size_t n )
+{
+ for( ; n; n--, a++, b++ )
+ if( *a != *b && toupper(*(const byte*)a) != toupper(*(const byte*)b) )
+ return *(const byte *)a - *(const byte*)b;
+ return 0;
+}
+#endif
+
+
+#ifndef HAVE_MEMRCHR
+void *
+memrchr (const void *buffer, int c, size_t n)
+{
+ const unsigned char *p = buffer;
+
+ for (p += n; n ; n--)
+ if (*--p == c)
+ return (void *)p;
+ return NULL;
+}
+#endif /*HAVE_MEMRCHR*/
+
+
+/* Percent-escape the string STR by replacing colons with '%3a'. If
+ EXTRA is not NULL all characters in EXTRA are also escaped. */
+static char *
+do_percent_escape (const char *str, const char *extra, int die)
+{
+ int i, j;
+ char *ptr;
+
+ if (!str)
+ return NULL;
+
+ for (i=j=0; str[i]; i++)
+ if (str[i] == ':' || str[i] == '%' || str[i] == '\n'
+ || (extra && strchr (extra, str[i])))
+ j++;
+ if (die)
+ ptr = xmalloc (i + 2 * j + 1);
+ else
+ {
+ ptr = xtrymalloc (i + 2 * j + 1);
+ if (!ptr)
+ return NULL;
+ }
+ i = 0;
+ while (*str)
+ {
+ if (*str == ':')
+ {
+ ptr[i++] = '%';
+ ptr[i++] = '3';
+ ptr[i++] = 'a';
+ }
+ else if (*str == '%')
+ {
+ ptr[i++] = '%';
+ ptr[i++] = '2';
+ ptr[i++] = '5';
+ }
+ else if (*str == '\n')
+ {
+ /* The newline is problematic in a line-based format. */
+ ptr[i++] = '%';
+ ptr[i++] = '0';
+ ptr[i++] = 'a';
+ }
+ else if (extra && strchr (extra, *str))
+ {
+ ptr[i++] = '%';
+ ptr[i++] = tohex_lower ((*str>>4)&15);
+ ptr[i++] = tohex_lower (*str&15);
+ }
+ else
+ ptr[i++] = *str;
+ str++;
+ }
+ ptr[i] = '\0';
+
+ return ptr;
+}
+
+/* Percent-escape the string STR by replacing colons with '%3a'. If
+ EXTRA is not NULL all characters in EXTRA are also escaped. This
+ function terminates the process on memory shortage. */
+char *
+percent_escape (const char *str, const char *extra)
+{
+ return do_percent_escape (str, extra, 1);
+}
+
+/* Same as percent_escape but return NULL instead of exiting on memory
+ error. */
+char *
+try_percent_escape (const char *str, const char *extra)
+{
+ return do_percent_escape (str, extra, 0);
+}
+
+
+/* Same as strconcat but takes a va_list. Returns EINVAL if the list
+ * is too long, all other errors are due to an ENOMEM condition. */
+char *
+vstrconcat (const char *s1, va_list arg_ptr)
+{
+ const char *argv[48];
+ size_t argc;
+ size_t needed;
+ char *buffer, *p;
+
+ argc = 0;
+ argv[argc++] = s1;
+ needed = strlen (s1);
+ while (((argv[argc] = va_arg (arg_ptr, const char *))))
+ {
+ needed += strlen (argv[argc]);
+ if (argc >= DIM (argv)-1)
+ {
+ gpg_err_set_errno (EINVAL);
+ return NULL;
+ }
+ argc++;
+ }
+ needed++;
+ buffer = xtrymalloc (needed);
+ if (buffer)
+ {
+ for (p = buffer, argc=0; argv[argc]; argc++)
+ p = stpcpy (p, argv[argc]);
+ }
+ return buffer;
+}
+
+
+/* Concatenate the string S1 with all the following strings up to a
+ NULL. Returns a malloced buffer with the new string or NULL on a
+ malloc error or if too many arguments are given. */
+char *
+strconcat (const char *s1, ...)
+{
+ va_list arg_ptr;
+ char *result;
+
+ if (!s1)
+ result = xtrystrdup ("");
+ else
+ {
+ va_start (arg_ptr, s1);
+ result = vstrconcat (s1, arg_ptr);
+ va_end (arg_ptr);
+ }
+ return result;
+}
+
+/* Same as strconcat but terminate the process with an error message
+ if something goes wrong. */
+char *
+xstrconcat (const char *s1, ...)
+{
+ va_list arg_ptr;
+ char *result;
+
+ if (!s1)
+ result = xstrdup ("");
+ else
+ {
+ va_start (arg_ptr, s1);
+ result = vstrconcat (s1, arg_ptr);
+ va_end (arg_ptr);
+ }
+ if (!result)
+ {
+ if (errno == EINVAL)
+ fputs ("\nfatal: too many args for xstrconcat\n", stderr);
+ else
+ fputs ("\nfatal: out of memory\n", stderr);
+ exit (2);
+ }
+ return result;
+}
+
+/* Split a string into fields at DELIM. REPLACEMENT is the character
+ to replace the delimiter with (normally: '\0' so that each field is
+ NUL terminated). The caller is responsible for freeing the result.
+ Note: this function modifies STRING! If you need the original
+ value, then you should pass a copy to this function.
+
+ If malloc fails, this function returns NULL. */
+char **
+strsplit (char *string, char delim, char replacement, int *count)
+{
+ int fields = 1;
+ char *t;
+ char **result;
+
+ /* First, count the number of fields. */
+ for (t = strchr (string, delim); t; t = strchr (t + 1, delim))
+ fields ++;
+
+ result = xtrycalloc ((fields + 1), sizeof (*result));
+ if (! result)
+ return NULL;
+
+ result[0] = string;
+ fields = 1;
+ for (t = strchr (string, delim); t; t = strchr (t + 1, delim))
+ {
+ result[fields ++] = t + 1;
+ *t = replacement;
+ }
+
+ if (count)
+ *count = fields;
+
+ return result;
+}
+
+
+/* Tokenize STRING using the set of delimiters in DELIM. Leading
+ * spaces and tabs are removed from all tokens. The caller must xfree
+ * the result.
+ *
+ * Returns: A malloced and NULL delimited array with the tokens. On
+ * memory error NULL is returned and ERRNO is set.
+ */
+static char **
+do_strtokenize (const char *string, const char *delim, int trim)
+{
+ const char *s;
+ size_t fields;
+ size_t bytes, n;
+ char *buffer;
+ char *p, *px, *pend;
+ char **result;
+
+ /* Count the number of fields. */
+ for (fields = 1, s = strpbrk (string, delim); s; s = strpbrk (s + 1, delim))
+ fields++;
+ fields++; /* Add one for the terminating NULL. */
+
+ /* Allocate an array for all fields, a terminating NULL, and space
+ for a copy of the string. */
+ bytes = fields * sizeof *result;
+ if (bytes / sizeof *result != fields)
+ {
+ gpg_err_set_errno (ENOMEM);
+ return NULL;
+ }
+ n = strlen (string) + 1;
+ bytes += n;
+ if (bytes < n)
+ {
+ gpg_err_set_errno (ENOMEM);
+ return NULL;
+ }
+ result = xtrymalloc (bytes);
+ if (!result)
+ return NULL;
+ buffer = (char*)(result + fields);
+
+ /* Copy and parse the string. */
+ strcpy (buffer, string);
+ for (n = 0, p = buffer; (pend = strpbrk (p, delim)); p = pend + 1)
+ {
+ *pend = 0;
+ if (trim)
+ {
+ while (spacep (p))
+ p++;
+ for (px = pend - 1; px >= p && spacep (px); px--)
+ *px = 0;
+ }
+ result[n++] = p;
+ }
+ if (trim)
+ {
+ while (spacep (p))
+ p++;
+ for (px = p + strlen (p) - 1; px >= p && spacep (px); px--)
+ *px = 0;
+ }
+ result[n++] = p;
+ result[n] = NULL;
+
+ log_assert ((char*)(result + n + 1) == buffer);
+
+ return result;
+}
+
+/* Tokenize STRING using the set of delimiters in DELIM. Leading
+ * spaces and tabs are removed from all tokens. The caller must xfree
+ * the result.
+ *
+ * Returns: A malloced and NULL delimited array with the tokens. On
+ * memory error NULL is returned and ERRNO is set.
+ */
+char **
+strtokenize (const char *string, const char *delim)
+{
+ return do_strtokenize (string, delim, 1);
+}
+
+/* Same as strtokenize but does not trim leading and trailing spaces
+ * from the fields. */
+char **
+strtokenize_nt (const char *string, const char *delim)
+{
+ return do_strtokenize (string, delim, 0);
+}
+
+
+/* Split a string into space delimited fields and remove leading and
+ * trailing spaces from each field. A pointer to each field is stored
+ * in ARRAY. Stop splitting at ARRAYSIZE fields. The function
+ * modifies STRING. The number of parsed fields is returned.
+ * Example:
+ *
+ * char *fields[2];
+ * if (split_fields (string, fields, DIM (fields)) < 2)
+ * return // Not enough args.
+ * foo (fields[0]);
+ * foo (fields[1]);
+ */
+int
+split_fields (char *string, char **array, int arraysize)
+{
+ int n = 0;
+ char *p, *pend;
+
+ for (p = string; *p == ' '; p++)
+ ;
+ do
+ {
+ if (n == arraysize)
+ break;
+ array[n++] = p;
+ pend = strchr (p, ' ');
+ if (!pend)
+ break;
+ *pend++ = 0;
+ for (p = pend; *p == ' '; p++)
+ ;
+ }
+ while (*p);
+
+ return n;
+}
+
+
+/* Split a string into colon delimited fields A pointer to each field
+ * is stored in ARRAY. Stop splitting at ARRAYSIZE fields. The
+ * function modifies STRING. The number of parsed fields is returned.
+ * Note that leading and trailing spaces are not removed from the fields.
+ * Example:
+ *
+ * char *fields[2];
+ * if (split_fields (string, fields, DIM (fields)) < 2)
+ * return // Not enough args.
+ * foo (fields[0]);
+ * foo (fields[1]);
+ */
+int
+split_fields_colon (char *string, char **array, int arraysize)
+{
+ int n = 0;
+ char *p, *pend;
+
+ p = string;
+ do
+ {
+ if (n == arraysize)
+ break;
+ array[n++] = p;
+ pend = strchr (p, ':');
+ if (!pend)
+ break;
+ *pend++ = 0;
+ p = pend;
+ }
+ while (*p);
+
+ return n;
+}
+
+
+
+/* Version number parsing. */
+
+/* This function parses the first portion of the version number S and
+ stores it in *NUMBER. On success, this function returns a pointer
+ into S starting with the first character, which is not part of the
+ initial number portion; on failure, NULL is returned. */
+static const char*
+parse_version_number (const char *s, int *number)
+{
+ int val = 0;
+
+ if (*s == '0' && digitp (s+1))
+ return NULL; /* Leading zeros are not allowed. */
+ for (; digitp (s); s++)
+ {
+ val *= 10;
+ val += *s - '0';
+ }
+ *number = val;
+ return val < 0 ? NULL : s;
+}
+
+
+/* This function breaks up the complete string-representation of the
+ version number S, which is of the following struture: <major
+ number>.<minor number>[.<micro number>]<patch level>. The major,
+ minor, and micro number components will be stored in *MAJOR, *MINOR
+ and *MICRO. If MICRO is not given 0 is used instead.
+
+ On success, the last component, the patch level, will be returned;
+ in failure, NULL will be returned. */
+static const char *
+parse_version_string (const char *s, int *major, int *minor, int *micro)
+{
+ s = parse_version_number (s, major);
+ if (!s || *s != '.')
+ return NULL;
+ s++;
+ s = parse_version_number (s, minor);
+ if (!s)
+ return NULL;
+ if (*s == '.')
+ {
+ s++;
+ s = parse_version_number (s, micro);
+ if (!s)
+ return NULL;
+ }
+ else
+ *micro = 0;
+ return s; /* Patchlevel. */
+}
+
+
+/* Compare the version string MY_VERSION to the version string
+ * REQ_VERSION. Returns -1, 0, or 1 if MY_VERSION is found,
+ * respectively, to be less than, to match, or be greater than
+ * REQ_VERSION. This function works for three and two part version
+ * strings; for a two part version string the micro part is assumed to
+ * be 0. Patch levels are compared as strings. If a version number
+ * is invalid INT_MIN is returned. If REQ_VERSION is given as NULL
+ * the function returns 0 if MY_VERSION is parsable version string. */
+int
+compare_version_strings (const char *my_version, const char *req_version)
+{
+ int my_major, my_minor, my_micro;
+ int rq_major, rq_minor, rq_micro;
+ const char *my_patch, *rq_patch;
+ int result;
+
+ if (!my_version)
+ return INT_MIN;
+
+ my_patch = parse_version_string (my_version, &my_major, &my_minor, &my_micro);
+ if (!my_patch)
+ return INT_MIN;
+ if (!req_version)
+ return 0; /* MY_VERSION can be parsed. */
+ rq_patch = parse_version_string (req_version, &rq_major, &rq_minor,&rq_micro);
+ if (!rq_patch)
+ return INT_MIN;
+
+ if (my_major == rq_major)
+ {
+ if (my_minor == rq_minor)
+ {
+ if (my_micro == rq_micro)
+ result = strcmp (my_patch, rq_patch);
+ else
+ result = my_micro - rq_micro;
+ }
+ else
+ result = my_minor - rq_minor;
+ }
+ else
+ result = my_major - rq_major;
+
+ return !result? 0 : result < 0 ? -1 : 1;
+}
+
+
+
+/* Format a string so that it fits within about TARGET_COLS columns.
+ * TEXT_IN is copied to a new buffer, which is returned. Normally,
+ * target_cols will be 72 and max_cols is 80. On error NULL is
+ * returned and ERRNO is set. */
+char *
+format_text (const char *text_in, int target_cols, int max_cols)
+{
+ /* const int do_debug = 0; */
+
+ /* The character under consideration. */
+ char *p;
+ /* The start of the current line. */
+ char *line;
+ /* The last space that we saw. */
+ char *last_space = NULL;
+ int last_space_cols = 0;
+ int copied_last_space = 0;
+ char *text;
+
+ text = xtrystrdup (text_in);
+ if (!text)
+ return NULL;
+
+ p = line = text;
+ while (1)
+ {
+ /* The number of columns including any trailing space. */
+ int cols;
+
+ p = p + strcspn (p, "\n ");
+ if (! p)
+ /* P now points to the NUL character. */
+ p = &text[strlen (text)];
+
+ if (*p == '\n')
+ /* Pass through any newlines. */
+ {
+ p ++;
+ line = p;
+ last_space = NULL;
+ last_space_cols = 0;
+ copied_last_space = 1;
+ continue;
+ }
+
+ /* Have a space or a NUL. Note: we don't count the trailing
+ space. */
+ cols = utf8_charcount (line, (uintptr_t) p - (uintptr_t) line);
+ if (cols < target_cols)
+ {
+ if (! *p)
+ /* Nothing left to break. */
+ break;
+
+ last_space = p;
+ last_space_cols = cols;
+ p ++;
+ /* Skip any immediately following spaces. If we break:
+ "... foo bar ..." between "foo" and "bar" then we want:
+ "... foo\nbar ...", which means that the left space has
+ to be the first space after foo, not the last space
+ before bar. */
+ while (*p == ' ')
+ p ++;
+ }
+ else
+ {
+ int cols_with_left_space;
+ int cols_with_right_space;
+ int left_penalty;
+ int right_penalty;
+
+ cols_with_left_space = last_space_cols;
+ cols_with_right_space = cols;
+
+ /* if (do_debug) */
+ /* log_debug ("Breaking: '%.*s'\n", */
+ /* (int) ((uintptr_t) p - (uintptr_t) line), line); */
+
+ /* The number of columns away from TARGET_COLS. We prefer
+ to underflow than to overflow. */
+ left_penalty = target_cols - cols_with_left_space;
+ right_penalty = 2 * (cols_with_right_space - target_cols);
+
+ if (cols_with_right_space > max_cols)
+ /* Add a large penalty for each column that exceeds
+ max_cols. */
+ right_penalty += 4 * (cols_with_right_space - max_cols);
+
+ /* if (do_debug) */
+ /* log_debug ("Left space => %d cols (penalty: %d); " */
+ /* "right space => %d cols (penalty: %d)\n", */
+ /* cols_with_left_space, left_penalty, */
+ /* cols_with_right_space, right_penalty); */
+ if (last_space_cols && left_penalty <= right_penalty)
+ {
+ /* Prefer the left space. */
+ /* if (do_debug) */
+ /* log_debug ("Breaking at left space.\n"); */
+ p = last_space;
+ }
+ else
+ {
+ /* if (do_debug) */
+ /* log_debug ("Breaking at right space.\n"); */
+ }
+
+ if (! *p)
+ break;
+
+ *p = '\n';
+ p ++;
+ if (*p == ' ')
+ {
+ int spaces;
+ for (spaces = 1; p[spaces] == ' '; spaces ++)
+ ;
+ memmove (p, &p[spaces], strlen (&p[spaces]) + 1);
+ }
+ line = p;
+ last_space = NULL;
+ last_space_cols = 0;
+ copied_last_space = 0;
+ }
+ }
+
+ /* Chop off any trailing space. */
+ trim_trailing_chars (text, strlen (text), " ");
+ /* If we inserted the trailing newline, then remove it. */
+ if (! copied_last_space && *text && text[strlen (text) - 1] == '\n')
+ text[strlen (text) - 1] = '\0';
+
+ return text;
+}
+
+
+/* Substitute environment variables in STRING and return a new string.
+ * On error the function returns NULL. */
+char *
+substitute_envvars (const char *string)
+{
+ char *line, *p, *pend;
+ const char *value;
+ size_t valuelen, n;
+ char *result = NULL;
+
+ result = line = xtrystrdup (string);
+ if (!result)
+ return NULL; /* Ooops */
+
+ while (*line)
+ {
+ p = strchr (line, '$');
+ if (!p)
+ goto leave; /* No or no more variables. */
+
+ if (p[1] == '$') /* Escaped dollar sign. */
+ {
+ memmove (p, p+1, strlen (p+1)+1);
+ line = p + 1;
+ continue;
+ }
+
+ if (p[1] == '{')
+ {
+ int count = 0;
+
+ for (pend=p+2; *pend; pend++)
+ {
+ if (*pend == '{')
+ count++;
+ else if (*pend == '}')
+ {
+ if (--count < 0)
+ break;
+ }
+ }
+ if (!*pend)
+ goto leave; /* Unclosed - don't substitute. */
+ }
+ else
+ {
+ for (pend = p+1; *pend && (alnump (pend) || *pend == '_'); pend++)
+ ;
+ }
+
+ if (p[1] == '{' && *pend == '}')
+ {
+ int save = *pend;
+ *pend = 0;
+ value = getenv (p+2);
+ *pend++ = save;
+ }
+ else
+ {
+ int save = *pend;
+ *pend = 0;
+ value = getenv (p+1);
+ *pend = save;
+ }
+
+ if (!value)
+ value = "";
+ valuelen = strlen (value);
+ if (valuelen <= pend - p)
+ {
+ memcpy (p, value, valuelen);
+ p += valuelen;
+ n = pend - p;
+ if (n)
+ memmove (p, p+n, strlen (p+n)+1);
+ line = p;
+ }
+ else
+ {
+ char *src = result;
+ char *dst;
+
+ dst = xtrymalloc (strlen (src) + valuelen + 1);
+ if (!dst)
+ {
+ xfree (result);
+ return NULL;
+ }
+ n = p - src;
+ memcpy (dst, src, n);
+ memcpy (dst + n, value, valuelen);
+ n += valuelen;
+ strcpy (dst + n, pend);
+ line = dst + n;
+ xfree (result);
+ result = dst;
+ }
+ }
+
+ leave:
+ return result;
+}
diff --git a/common/stringhelp.h b/common/stringhelp.h
new file mode 100644
index 0000000..84215c7
--- /dev/null
+++ b/common/stringhelp.h
@@ -0,0 +1,181 @@
+/* stringhelp.h
+ * Copyright (C) 1998, 1999, 2000, 2001, 2003,
+ * 2006, 2007, 2009 Free Software Foundation, Inc.
+ * 2015 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute and/or modify this
+ * part of GnuPG under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * 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 copies of the GNU General Public License
+ * and the GNU Lesser General Public License along with this program;
+ * if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_COMMON_STRINGHELP_H
+#define GNUPG_COMMON_STRINGHELP_H
+
+#include <stdint.h>
+#include "types.h"
+
+/*-- stringhelp.c --*/
+char *has_leading_keyword (const char *string, const char *keyword);
+
+const char *memistr (const void *buf, size_t buflen, const char *sub);
+char *mem2str( char *, const void *, size_t);
+char *trim_spaces( char *string );
+char *ascii_trim_spaces (char *string);
+char *trim_trailing_spaces( char *string );
+unsigned int trim_trailing_chars( unsigned char *line, unsigned len,
+ const char *trimchars);
+unsigned int trim_trailing_ws( unsigned char *line, unsigned len );
+size_t length_sans_trailing_chars (const unsigned char *line, size_t len,
+ const char *trimchars );
+size_t length_sans_trailing_ws (const unsigned char *line, size_t len);
+
+
+char *make_basename(const char *filepath, const char *inputpath);
+char *make_dirname(const char *filepath);
+char *make_filename( const char *first_part, ... ) GPGRT_ATTR_SENTINEL(0);
+char *make_filename_try (const char *first_part, ... ) GPGRT_ATTR_SENTINEL(0);
+char *make_absfilename (const char *first_part, ...) GPGRT_ATTR_SENTINEL(0);
+char *make_absfilename_try (const char *first_part,
+ ...) GPGRT_ATTR_SENTINEL(0);
+int compare_filenames( const char *a, const char *b );
+
+uint64_t string_to_u64 (const char *string);
+int hextobyte (const char *s);
+
+size_t utf8_charcount (const char *s, int len);
+
+
+#ifdef HAVE_W32_SYSTEM
+const char *w32_strerror (int ec);
+#endif
+
+
+int ascii_isupper (int c);
+int ascii_islower (int c);
+int ascii_toupper (int c);
+int ascii_tolower (int c);
+char *ascii_strlwr (char *s);
+char *ascii_strupr (char *s);
+int ascii_strcasecmp( const char *a, const char *b );
+int ascii_strncasecmp (const char *a, const char *b, size_t n);
+int ascii_memcasecmp( const void *a, const void *b, size_t n );
+const char *ascii_memistr ( const void *buf, size_t buflen, const char *sub);
+void *ascii_memcasemem (const void *haystack, size_t nhaystack,
+ const void *needle, size_t nneedle);
+
+
+#ifndef HAVE_MEMICMP
+int memicmp( const char *a, const char *b, size_t n );
+#endif
+#ifndef HAVE_STPCPY
+char *stpcpy(char *a,const char *b);
+#endif
+#ifndef HAVE_STRPBRK
+char *strpbrk (const char *s, const char *accept);
+#endif
+#ifndef HAVE_STRSEP
+char *strsep (char **stringp, const char *delim);
+#endif
+#ifndef HAVE_STRLWR
+char *strlwr(char *a);
+#endif
+#ifndef HAVE_STRTOUL
+# define strtoul(a,b,c) ((unsigned long)strtol((a),(b),(c)))
+#endif
+#ifndef HAVE_MEMMOVE
+# define memmove(d, s, n) bcopy((s), (d), (n))
+#endif
+#ifndef HAVE_STRICMP
+# define stricmp(a,b) strcasecmp( (a), (b) )
+#endif
+#ifndef HAVE_MEMRCHR
+void *memrchr (const void *buffer, int c, size_t n);
+#endif
+
+
+#ifndef HAVE_ISASCII
+static inline int
+isascii (int c)
+{
+ return (((c) & ~0x7f) == 0);
+}
+#endif /* !HAVE_ISASCII */
+
+
+#ifndef STR
+# define STR(v) #v
+#endif
+#define STR2(v) STR(v)
+
+/* Percent-escape the string STR by replacing colons with '%3a'. If
+ EXTRA is not NULL, also replace all characters given in EXTRA. The
+ "try_" variant fails with NULL if not enough memory can be
+ allocated. */
+char *percent_escape (const char *str, const char *extra);
+char *try_percent_escape (const char *str, const char *extra);
+
+
+/* Concatenate the string S1 with all the following strings up to a
+ NULL. Returns a malloced buffer with the new string or NULL on a
+ malloc error or if too many arguments are given. */
+char *strconcat (const char *s1, ...) GPGRT_ATTR_SENTINEL(0);
+/* Same but taking a va_list. */
+char *vstrconcat (const char *s1, va_list arg_ptr);
+/* Ditto, but die on error. */
+char *xstrconcat (const char *s1, ...) GPGRT_ATTR_SENTINEL(0);
+
+
+char **strsplit (char *string, char delim, char replacement, int *count);
+
+/* Tokenize STRING using the set of delimiters in DELIM. */
+char **strtokenize (const char *string, const char *delim);
+/* Tokenize STRING using the set of delimiters in DELIM but do not
+ * trim the tokens. */
+char **strtokenize_nt (const char *string, const char *delim);
+
+/* Split STRING into space delimited fields and store them in the
+ * provided ARRAY. */
+int split_fields (char *string, char **array, int arraysize);
+
+/* Split STRING into colon delimited fields and store them in the
+ * provided ARRAY. */
+int split_fields_colon (char *string, char **array, int arraysize);
+
+/* Return True if MYVERSION is greater or equal than REQ_VERSION. */
+int compare_version_strings (const char *my_version, const char *req_version);
+
+/* Format a string so that it fits within about TARGET_COLS columns. */
+char *format_text (const char *text, int target_cols, int max_cols);
+
+/* Substitute environmen variabales in STRING. */
+char *substitute_envvars (const char *string);
+
+
+/*-- mapstrings.c --*/
+const char *map_static_macro_string (const char *string);
+const char *map_static_strings (const char *domain, int key1, int key2,
+ const char *string1, ...);
+
+#endif /*GNUPG_COMMON_STRINGHELP_H*/
diff --git a/common/strlist.c b/common/strlist.c
new file mode 100644
index 0000000..6feb3a4
--- /dev/null
+++ b/common/strlist.c
@@ -0,0 +1,281 @@
+/* strlist.c - string helpers
+ * Copyright (C) 1998, 2000, 2001, 2006 Free Software Foundation, Inc.
+ * Copyright (C) 2015 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute and/or modify this
+ * part of GnuPG under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * 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 copies of the GNU General Public License
+ * and the GNU Lesser General Public License along with this program;
+ * if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <ctype.h>
+
+#include "util.h"
+#include "common-defs.h"
+#include "strlist.h"
+#include "utf8conv.h"
+#include "mischelp.h"
+
+void
+free_strlist( strlist_t sl )
+{
+ strlist_t sl2;
+
+ for(; sl; sl = sl2 ) {
+ sl2 = sl->next;
+ xfree(sl);
+ }
+}
+
+
+void
+free_strlist_wipe (strlist_t sl)
+{
+ strlist_t sl2;
+
+ for(; sl; sl = sl2 ) {
+ sl2 = sl->next;
+ wipememory (sl, sizeof *sl + strlen (sl->d));
+ xfree(sl);
+ }
+}
+
+
+/* Add STRING to the LIST at the front. This function terminates the
+ process on memory shortage. */
+strlist_t
+add_to_strlist( strlist_t *list, const char *string )
+{
+ strlist_t sl;
+
+ sl = xmalloc( sizeof *sl + strlen(string));
+ sl->flags = 0;
+ strcpy(sl->d, string);
+ sl->next = *list;
+ *list = sl;
+ return sl;
+}
+
+
+/* Add STRING to the LIST at the front. This function returns NULL
+ and sets ERRNO on memory shortage. */
+strlist_t
+add_to_strlist_try (strlist_t *list, const char *string)
+{
+ strlist_t sl;
+
+ sl = xtrymalloc (sizeof *sl + strlen (string));
+ if (sl)
+ {
+ sl->flags = 0;
+ strcpy (sl->d, string);
+ sl->next = *list;
+ *list = sl;
+ }
+ return sl;
+}
+
+
+/* Same as add_to_strlist() but if IS_UTF8 is *not* set, a conversion
+ to UTF-8 is done. This function terminates the process on memory
+ shortage. */
+strlist_t
+add_to_strlist2( strlist_t *list, const char *string, int is_utf8 )
+{
+ strlist_t sl;
+
+ if (is_utf8)
+ sl = add_to_strlist( list, string );
+ else
+ {
+ char *p = native_to_utf8( string );
+ sl = add_to_strlist( list, p );
+ xfree ( p );
+ }
+ return sl;
+}
+
+
+/* Add STRING to the LIST at the end. This function terminates the
+ process on memory shortage. */
+strlist_t
+append_to_strlist( strlist_t *list, const char *string )
+{
+ strlist_t sl;
+ sl = append_to_strlist_try (list, string);
+ if (!sl)
+ xoutofcore ();
+ return sl;
+}
+
+
+/* Add STRING to the LIST at the end. */
+strlist_t
+append_to_strlist_try (strlist_t *list, const char *string)
+{
+ strlist_t r, sl;
+
+ sl = xtrymalloc( sizeof *sl + strlen(string));
+ if (sl == NULL)
+ return NULL;
+
+ sl->flags = 0;
+ strcpy(sl->d, string);
+ sl->next = NULL;
+ if( !*list )
+ *list = sl;
+ else {
+ for( r = *list; r->next; r = r->next )
+ ;
+ r->next = sl;
+ }
+ return sl;
+}
+
+
+strlist_t
+append_to_strlist2( strlist_t *list, const char *string, int is_utf8 )
+{
+ strlist_t sl;
+
+ if( is_utf8 )
+ sl = append_to_strlist( list, string );
+ else
+ {
+ char *p = native_to_utf8 (string);
+ sl = append_to_strlist( list, p );
+ xfree( p );
+ }
+ return sl;
+}
+
+
+/* Return a copy of LIST. This function terminates the process on
+ memory shortage.*/
+strlist_t
+strlist_copy (strlist_t list)
+{
+ strlist_t newlist = NULL, sl, *last;
+
+ last = &newlist;
+ for (; list; list = list->next)
+ {
+ sl = xmalloc (sizeof *sl + strlen (list->d));
+ sl->flags = list->flags;
+ strcpy(sl->d, list->d);
+ sl->next = NULL;
+ *last = sl;
+ last = &sl;
+ }
+ return newlist;
+}
+
+
+
+strlist_t
+strlist_prev( strlist_t head, strlist_t node )
+{
+ strlist_t n;
+
+ for(n=NULL; head && head != node; head = head->next )
+ n = head;
+ return n;
+}
+
+strlist_t
+strlist_last( strlist_t node )
+{
+ if( node )
+ for( ; node->next ; node = node->next )
+ ;
+ return node;
+}
+
+
+/* Remove the first item from LIST and return its content in an
+ allocated buffer. This function terminates the process on memory
+ shortage. */
+char *
+strlist_pop (strlist_t *list)
+{
+ char *str=NULL;
+ strlist_t sl=*list;
+
+ if(sl)
+ {
+ str = xmalloc(strlen(sl->d)+1);
+ strcpy(str,sl->d);
+
+ *list=sl->next;
+ xfree(sl);
+ }
+
+ return str;
+}
+
+/* Return the first element of the string list HAYSTACK whose string
+ matches NEEDLE. If no elements match, return NULL. */
+strlist_t
+strlist_find (strlist_t haystack, const char *needle)
+{
+ for (;
+ haystack;
+ haystack = haystack->next)
+ if (strcmp (haystack->d, needle) == 0)
+ return haystack;
+ return NULL;
+}
+
+int
+strlist_length (strlist_t list)
+{
+ int i;
+ for (i = 0; list; list = list->next)
+ i ++;
+
+ return i;
+}
+
+/* Reverse the list *LIST in place. */
+strlist_t
+strlist_rev (strlist_t *list)
+{
+ strlist_t l = *list;
+ strlist_t lrev = NULL;
+
+ while (l)
+ {
+ strlist_t tail = l->next;
+ l->next = lrev;
+ lrev = l;
+ l = tail;
+ }
+
+ *list = lrev;
+ return lrev;
+}
diff --git a/common/strlist.h b/common/strlist.h
new file mode 100644
index 0000000..641ea06
--- /dev/null
+++ b/common/strlist.h
@@ -0,0 +1,69 @@
+/* strlist.h
+ * Copyright (C) 1998, 2000, 2001, 2006 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute and/or modify this
+ * part of GnuPG under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * 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 copies of the GNU General Public License
+ * and the GNU Lesser General Public License along with this program;
+ * if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_COMMON_STRLIST_H
+#define GNUPG_COMMON_STRLIST_H
+
+struct string_list
+{
+ struct string_list *next;
+ unsigned int flags;
+ char d[1];
+};
+typedef struct string_list *strlist_t;
+
+void free_strlist (strlist_t sl);
+void free_strlist_wipe (strlist_t sl);
+
+strlist_t add_to_strlist (strlist_t *list, const char *string);
+strlist_t add_to_strlist_try (strlist_t *list, const char *string);
+
+strlist_t add_to_strlist2( strlist_t *list, const char *string, int is_utf8);
+
+strlist_t append_to_strlist (strlist_t *list, const char *string);
+strlist_t append_to_strlist_try (strlist_t *list, const char *string);
+strlist_t append_to_strlist2 (strlist_t *list, const char *string,
+ int is_utf8);
+
+strlist_t strlist_copy (strlist_t list);
+
+strlist_t strlist_prev (strlist_t head, strlist_t node);
+strlist_t strlist_last (strlist_t node);
+char * strlist_pop (strlist_t *list);
+
+strlist_t strlist_find (strlist_t haystack, const char *needle);
+int strlist_length (strlist_t list);
+
+strlist_t strlist_rev (strlist_t *haystack);
+
+#define FREE_STRLIST(a) do { free_strlist((a)); (a) = NULL ; } while(0)
+
+
+#endif /*GNUPG_COMMON_STRLIST_H*/
diff --git a/common/sysutils.c b/common/sysutils.c
new file mode 100644
index 0000000..5f54ae1
--- /dev/null
+++ b/common/sysutils.c
@@ -0,0 +1,1951 @@
+/* sysutils.c - system helpers
+ * Copyright (C) 1991-2001, 2003-2004,
+ * 2006-2008 Free Software Foundation, Inc.
+ * Copyright (C) 2013-2016 Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#ifdef WITHOUT_NPTH /* Give the Makefile a chance to build without Pth. */
+# undef HAVE_NPTH
+# undef USE_NPTH
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#ifdef HAVE_PWD_H
+# include <pwd.h>
+#endif
+#include <unistd.h>
+#include <errno.h>
+#ifdef HAVE_STAT
+# include <sys/stat.h>
+#endif
+#if defined(__linux__) && defined(__alpha__) && __GLIBC__ < 2
+# include <asm/sysinfo.h>
+# include <asm/unistd.h>
+#endif
+#include <time.h>
+#ifdef HAVE_SETRLIMIT
+# include <sys/time.h>
+# include <sys/resource.h>
+#endif
+#ifdef HAVE_W32_SYSTEM
+# if WINVER < 0x0500
+# define WINVER 0x0500 /* Required for AllowSetForegroundWindow. */
+# endif
+# ifdef HAVE_WINSOCK2_H
+# include <winsock2.h>
+# endif
+# include <windows.h>
+#else /*!HAVE_W32_SYSTEM*/
+# include <sys/socket.h>
+# include <sys/un.h>
+#endif
+#ifdef HAVE_INOTIFY_INIT
+# include <sys/inotify.h>
+#endif /*HAVE_INOTIFY_INIT*/
+#ifdef HAVE_NPTH
+# include <npth.h>
+#endif
+#include <fcntl.h>
+#include <dirent.h>
+
+#include <assuan.h>
+
+#include "util.h"
+#include "i18n.h"
+
+#include "sysutils.h"
+
+#define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A'))
+
+
+/* The object used with our opendir functions. We need to define our
+ * own so that we can properly handle Unicode on Windows. */
+struct gnupg_dir_s
+{
+#ifdef HAVE_W32_SYSTEM
+ _WDIR *dir; /* The system's DIR pointer. */
+#else
+ DIR *dir; /* The system's DIR pointer. */
+#endif
+ struct gnupg_dirent_s dirent; /* The current dirent. */
+ size_t namesize; /* If not 0 the allocated size of dirent.d_name. */
+ char name[256]; /* Only used if NAMESIZE is 0. */
+};
+
+
+/* Flag to tell whether special file names are enabled. See gpg.c for
+ * an explanation of these file names. */
+static int allow_special_filenames;
+
+
+static GPGRT_INLINE gpg_error_t
+my_error_from_syserror (void)
+{
+ return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
+}
+
+static GPGRT_INLINE gpg_error_t
+my_error (int e)
+{
+ return gpg_err_make (default_errsource, (e));
+}
+
+
+
+#if defined(__linux__) && defined(__alpha__) && __GLIBC__ < 2
+#warning using trap_unaligned
+static int
+setsysinfo(unsigned long op, void *buffer, unsigned long size,
+ int *start, void *arg, unsigned long flag)
+{
+ return syscall(__NR_osf_setsysinfo, op, buffer, size, start, arg, flag);
+}
+
+void
+trap_unaligned(void)
+{
+ unsigned int buf[2];
+
+ buf[0] = SSIN_UACPROC;
+ buf[1] = UAC_SIGBUS | UAC_NOPRINT;
+ setsysinfo(SSI_NVPAIRS, buf, 1, 0, 0, 0);
+}
+#else
+void
+trap_unaligned(void)
+{ /* dummy */
+}
+#endif
+
+
+int
+disable_core_dumps (void)
+{
+#ifdef HAVE_DOSISH_SYSTEM
+ return 0;
+#else
+# ifdef HAVE_SETRLIMIT
+ struct rlimit limit;
+
+ /* We only set the current limit unless we were not able to
+ retrieve the old value. */
+ if (getrlimit (RLIMIT_CORE, &limit))
+ limit.rlim_max = 0;
+ limit.rlim_cur = 0;
+ if( !setrlimit (RLIMIT_CORE, &limit) )
+ return 0;
+ if( errno != EINVAL && errno != ENOSYS )
+ log_fatal (_("can't disable core dumps: %s\n"), strerror(errno) );
+#endif
+ return 1;
+#endif
+}
+
+int
+enable_core_dumps (void)
+{
+#ifdef HAVE_DOSISH_SYSTEM
+ return 0;
+#else
+# ifdef HAVE_SETRLIMIT
+ struct rlimit limit;
+
+ if (getrlimit (RLIMIT_CORE, &limit))
+ return 1;
+ limit.rlim_cur = limit.rlim_max;
+ setrlimit (RLIMIT_CORE, &limit);
+ return 1; /* We always return true because this function is
+ merely a debugging aid. */
+# endif
+ return 1;
+#endif
+}
+
+#ifdef HAVE_W32_SYSTEM
+static int
+any8bitchar (const char *string)
+{
+ if (string)
+ for ( ; *string; string++)
+ if ((*string & 0x80))
+ return 1;
+ return 0;
+}
+#endif /*HAVE_W32_SYSTEM*/
+
+
+/* Helper for gnupg_w32_set_errno. */
+#ifdef HAVE_W32_SYSTEM
+static int
+map_w32_to_errno (DWORD w32_err)
+{
+ switch (w32_err)
+ {
+ case 0:
+ return 0;
+
+ case ERROR_FILE_NOT_FOUND:
+ return ENOENT;
+
+ case ERROR_PATH_NOT_FOUND:
+ return ENOENT;
+
+ case ERROR_ACCESS_DENIED:
+ return EPERM; /* ReactOS uses EACCES ("Permission denied") and
+ * is likely right because they used an
+ * undocumented function to associate the error
+ * codes. However we have always used EPERM
+ * ("Operation not permitted", e.g. function is
+ * required to be called by root) and we better
+ * stick to that to avoid surprising bugs. */
+
+ case ERROR_INVALID_HANDLE:
+ return EBADF;
+
+ case ERROR_INVALID_BLOCK:
+ return ENOMEM;
+
+ case ERROR_NOT_ENOUGH_MEMORY:
+ return ENOMEM;
+
+ case ERROR_NO_DATA:
+ return EPIPE;
+
+ case ERROR_ALREADY_EXISTS:
+ return EEXIST;
+
+ /* This mapping has been taken from reactOS. */
+ case ERROR_TOO_MANY_OPEN_FILES: return EMFILE;
+ case ERROR_ARENA_TRASHED: return ENOMEM;
+ case ERROR_BAD_ENVIRONMENT: return E2BIG;
+ case ERROR_BAD_FORMAT: return ENOEXEC;
+ case ERROR_INVALID_DRIVE: return ENOENT;
+ case ERROR_CURRENT_DIRECTORY: return EACCES;
+ case ERROR_NOT_SAME_DEVICE: return EXDEV;
+ case ERROR_NO_MORE_FILES: return ENOENT;
+ case ERROR_WRITE_PROTECT: return EACCES;
+ case ERROR_BAD_UNIT: return EACCES;
+ case ERROR_NOT_READY: return EACCES;
+ case ERROR_BAD_COMMAND: return EACCES;
+ case ERROR_CRC: return EACCES;
+ case ERROR_BAD_LENGTH: return EACCES;
+ case ERROR_SEEK: return EACCES;
+ case ERROR_NOT_DOS_DISK: return EACCES;
+ case ERROR_SECTOR_NOT_FOUND: return EACCES;
+ case ERROR_OUT_OF_PAPER: return EACCES;
+ case ERROR_WRITE_FAULT: return EACCES;
+ case ERROR_READ_FAULT: return EACCES;
+ case ERROR_GEN_FAILURE: return EACCES;
+ case ERROR_SHARING_VIOLATION: return EACCES;
+ case ERROR_LOCK_VIOLATION: return EACCES;
+ case ERROR_WRONG_DISK: return EACCES;
+ case ERROR_SHARING_BUFFER_EXCEEDED: return EACCES;
+ case ERROR_BAD_NETPATH: return ENOENT;
+ case ERROR_NETWORK_ACCESS_DENIED: return EACCES;
+ case ERROR_BAD_NET_NAME: return ENOENT;
+ case ERROR_FILE_EXISTS: return EEXIST;
+ case ERROR_CANNOT_MAKE: return EACCES;
+ case ERROR_FAIL_I24: return EACCES;
+ case ERROR_NO_PROC_SLOTS: return EAGAIN;
+ case ERROR_DRIVE_LOCKED: return EACCES;
+ case ERROR_BROKEN_PIPE: return EPIPE;
+ case ERROR_DISK_FULL: return ENOSPC;
+ case ERROR_INVALID_TARGET_HANDLE: return EBADF;
+ case ERROR_WAIT_NO_CHILDREN: return ECHILD;
+ case ERROR_CHILD_NOT_COMPLETE: return ECHILD;
+ case ERROR_DIRECT_ACCESS_HANDLE: return EBADF;
+ case ERROR_SEEK_ON_DEVICE: return EACCES;
+ case ERROR_DIR_NOT_EMPTY: return ENOTEMPTY;
+ case ERROR_NOT_LOCKED: return EACCES;
+ case ERROR_BAD_PATHNAME: return ENOENT;
+ case ERROR_MAX_THRDS_REACHED: return EAGAIN;
+ case ERROR_LOCK_FAILED: return EACCES;
+ case ERROR_INVALID_STARTING_CODESEG: return ENOEXEC;
+ case ERROR_INVALID_STACKSEG: return ENOEXEC;
+ case ERROR_INVALID_MODULETYPE: return ENOEXEC;
+ case ERROR_INVALID_EXE_SIGNATURE: return ENOEXEC;
+ case ERROR_EXE_MARKED_INVALID: return ENOEXEC;
+ case ERROR_BAD_EXE_FORMAT: return ENOEXEC;
+ case ERROR_ITERATED_DATA_EXCEEDS_64k: return ENOEXEC;
+ case ERROR_INVALID_MINALLOCSIZE: return ENOEXEC;
+ case ERROR_DYNLINK_FROM_INVALID_RING: return ENOEXEC;
+ case ERROR_IOPL_NOT_ENABLED: return ENOEXEC;
+ case ERROR_INVALID_SEGDPL: return ENOEXEC;
+ case ERROR_AUTODATASEG_EXCEEDS_64k: return ENOEXEC;
+ case ERROR_RING2SEG_MUST_BE_MOVABLE: return ENOEXEC;
+ case ERROR_RELOC_CHAIN_XEEDS_SEGLIM: return ENOEXEC;
+ case ERROR_INFLOOP_IN_RELOC_CHAIN: return ENOEXEC;
+ case ERROR_FILENAME_EXCED_RANGE: return ENOENT;
+ case ERROR_NESTING_NOT_ALLOWED: return EAGAIN;
+ case ERROR_NOT_ENOUGH_QUOTA: return ENOMEM;
+
+ default:
+ return EIO;
+ }
+}
+#endif /*HAVE_W32_SYSTEM*/
+
+
+/* Set ERRNO from the Windows error. EC may be -1 to use the last error. */
+#ifdef HAVE_W32_SYSTEM
+void
+gnupg_w32_set_errno (int ec)
+{
+ /* FIXME: Replace by gpgrt_w32_set_errno. */
+ if (ec == -1)
+ ec = GetLastError ();
+ _set_errno (map_w32_to_errno (ec));
+}
+#endif /*HAVE_W32_SYSTEM*/
+
+
+
+/* Allow the use of special "-&nnn" style file names. */
+void
+enable_special_filenames (void)
+{
+ allow_special_filenames = 1;
+}
+
+
+/* Return a string which is used as a kind of process ID. */
+const byte *
+get_session_marker (size_t *rlen)
+{
+ static byte marker[SIZEOF_UNSIGNED_LONG*2];
+ static int initialized;
+
+ if (!initialized)
+ {
+ gcry_create_nonce (marker, sizeof marker);
+ initialized = 1;
+ }
+ *rlen = sizeof (marker);
+ return marker;
+}
+
+/* Return a random number in an unsigned int. */
+unsigned int
+get_uint_nonce (void)
+{
+ unsigned int value;
+
+ gcry_create_nonce (&value, sizeof value);
+ return value;
+}
+
+
+
+#if 0 /* not yet needed - Note that this will require inclusion of
+ cmacros.am in Makefile.am */
+int
+check_permissions(const char *path,int extension,int checkonly)
+{
+#if defined(HAVE_STAT) && !defined(HAVE_DOSISH_SYSTEM)
+ char *tmppath;
+ struct stat statbuf;
+ int ret=1;
+ int isdir=0;
+
+ if(opt.no_perm_warn)
+ return 0;
+
+ if(extension && path[0]!=DIRSEP_C)
+ {
+ if(strchr(path,DIRSEP_C))
+ tmppath=make_filename(path,NULL);
+ else
+ tmppath=make_filename(GNUPG_LIBDIR,path,NULL);
+ }
+ else
+ tmppath=m_strdup(path);
+
+ /* It's okay if the file doesn't exist */
+ if(stat(tmppath,&statbuf)!=0)
+ {
+ ret=0;
+ goto end;
+ }
+
+ isdir=S_ISDIR(statbuf.st_mode);
+
+ /* Per-user files must be owned by the user. Extensions must be
+ owned by the user or root. */
+ if((!extension && statbuf.st_uid != getuid()) ||
+ (extension && statbuf.st_uid!=0 && statbuf.st_uid!=getuid()))
+ {
+ if(!checkonly)
+ log_info(_("Warning: unsafe ownership on %s \"%s\"\n"),
+ isdir?"directory":extension?"extension":"file",path);
+ goto end;
+ }
+
+ /* This works for both directories and files - basically, we don't
+ care what the owner permissions are, so long as the group and
+ other permissions are 0 for per-user files, and non-writable for
+ extensions. */
+ if((extension && (statbuf.st_mode & (S_IWGRP|S_IWOTH)) !=0) ||
+ (!extension && (statbuf.st_mode & (S_IRWXG|S_IRWXO)) != 0))
+ {
+ char *dir;
+
+ /* However, if the directory the directory/file is in is owned
+ by the user and is 700, then this is not a problem.
+ Theoretically, we could walk this test up to the root
+ directory /, but for the sake of sanity, I'm stopping at one
+ level down. */
+
+ dir= make_dirname (tmppath);
+ if(stat(dir,&statbuf)==0 && statbuf.st_uid==getuid() &&
+ S_ISDIR(statbuf.st_mode) && (statbuf.st_mode & (S_IRWXG|S_IRWXO))==0)
+ {
+ xfree (dir);
+ ret=0;
+ goto end;
+ }
+
+ m_free(dir);
+
+ if(!checkonly)
+ log_info(_("Warning: unsafe permissions on %s \"%s\"\n"),
+ isdir?"directory":extension?"extension":"file",path);
+ goto end;
+ }
+
+ ret=0;
+
+ end:
+ m_free(tmppath);
+
+ return ret;
+
+#endif /* HAVE_STAT && !HAVE_DOSISH_SYSTEM */
+
+ return 0;
+}
+#endif
+
+
+/* Wrapper around the usual sleep function. This one won't wake up
+ before the sleep time has really elapsed. When build with Pth it
+ merely calls pth_sleep and thus suspends only the current
+ thread. */
+void
+gnupg_sleep (unsigned int seconds)
+{
+#ifdef USE_NPTH
+ npth_sleep (seconds);
+#else
+ /* Fixme: make sure that a sleep won't wake up to early. */
+# ifdef HAVE_W32_SYSTEM
+ Sleep (seconds*1000);
+# else
+ sleep (seconds);
+# endif
+#endif
+}
+
+
+/* Wrapper around the platforms usleep function. This one won't wake
+ * up before the sleep time has really elapsed. When build with nPth
+ * it merely calls npth_usleep and thus suspends only the current
+ * thread. */
+void
+gnupg_usleep (unsigned int usecs)
+{
+#if defined(USE_NPTH)
+
+ npth_usleep (usecs);
+
+#elif defined(HAVE_W32_SYSTEM)
+
+ Sleep ((usecs + 999) / 1000);
+
+#elif defined(HAVE_NANOSLEEP)
+
+ if (usecs)
+ {
+ struct timespec req;
+ struct timespec rem;
+
+ req.tv_sec = usecs / 1000000;
+ req.tv_nsec = (usecs % 1000000) * 1000;
+ while (nanosleep (&req, &rem) < 0 && errno == EINTR)
+ req = rem;
+ }
+
+#else /*Standard Unix*/
+
+ if (usecs)
+ {
+ struct timeval tv;
+
+ tv.tv_sec = usecs / 1000000;
+ tv.tv_usec = usecs % 1000000;
+ select (0, NULL, NULL, NULL, &tv);
+ }
+
+#endif
+}
+
+
+/* This function is a NOP for POSIX systems but required under Windows
+ as the file handles as returned by OS calls (like CreateFile) are
+ different from the libc file descriptors (like open). This function
+ translates system file handles to libc file handles. FOR_WRITE
+ gives the direction of the handle. */
+int
+translate_sys2libc_fd (gnupg_fd_t fd, int for_write)
+{
+#if defined(HAVE_W32CE_SYSTEM)
+ (void)for_write;
+ return (int) fd;
+#elif defined(HAVE_W32_SYSTEM)
+ int x;
+
+ if (fd == GNUPG_INVALID_FD)
+ return -1;
+
+ /* Note that _open_osfhandle is currently defined to take and return
+ a long. */
+ x = _open_osfhandle ((long)fd, for_write ? 1 : 0);
+ if (x == -1)
+ log_error ("failed to translate osfhandle %p\n", (void *) fd);
+ return x;
+#else /*!HAVE_W32_SYSTEM */
+ (void)for_write;
+ return fd;
+#endif
+}
+
+/* This is the same as translate_sys2libc_fd but takes an integer
+ which is assumed to be such an system handle. On WindowsCE the
+ passed FD is a rendezvous ID and the function finishes the pipe
+ creation. */
+int
+translate_sys2libc_fd_int (int fd, int for_write)
+{
+#if HAVE_W32CE_SYSTEM
+ fd = (int) _assuan_w32ce_finish_pipe (fd, for_write);
+ return translate_sys2libc_fd ((void*)fd, for_write);
+#elif HAVE_W32_SYSTEM
+ if (fd <= 2)
+ return fd; /* Do not do this for error, stdin, stdout, stderr. */
+
+ return translate_sys2libc_fd ((void*)fd, for_write);
+#else
+ (void)for_write;
+ return fd;
+#endif
+}
+
+
+/* Check whether FNAME has the form "-&nnnn", where N is a non-zero
+ * number. Returns this number or -1 if it is not the case. If the
+ * caller wants to use the file descriptor for writing FOR_WRITE shall
+ * be set to 1. If NOTRANSLATE is set the Windows specific mapping is
+ * not done. */
+int
+check_special_filename (const char *fname, int for_write, int notranslate)
+{
+ if (allow_special_filenames
+ && fname && *fname == '-' && fname[1] == '&')
+ {
+ int i;
+
+ fname += 2;
+ for (i=0; digitp (fname+i); i++ )
+ ;
+ if (!fname[i])
+ return notranslate? atoi (fname)
+ /**/ : translate_sys2libc_fd_int (atoi (fname), for_write);
+ }
+ return -1;
+}
+
+
+/* Replacement for tmpfile(). This is required because the tmpfile
+ function of Windows' runtime library is broken, insecure, ignores
+ TMPDIR and so on. In addition we create a file with an inheritable
+ handle. */
+FILE *
+gnupg_tmpfile (void)
+{
+#ifdef HAVE_W32_SYSTEM
+ int attempts, n;
+#ifdef HAVE_W32CE_SYSTEM
+ wchar_t buffer[MAX_PATH+7+12+1];
+# define mystrlen(a) wcslen (a)
+ wchar_t *name, *p;
+#else
+ char buffer[MAX_PATH+7+12+1];
+# define mystrlen(a) strlen (a)
+ char *name, *p;
+#endif
+ HANDLE file;
+ int pid = GetCurrentProcessId ();
+ unsigned int value;
+ int i;
+ SECURITY_ATTRIBUTES sec_attr;
+
+ memset (&sec_attr, 0, sizeof sec_attr );
+ sec_attr.nLength = sizeof sec_attr;
+ sec_attr.bInheritHandle = TRUE;
+
+ n = GetTempPath (MAX_PATH+1, buffer);
+ if (!n || n > MAX_PATH || mystrlen (buffer) > MAX_PATH)
+ {
+ gpg_err_set_errno (ENOENT);
+ return NULL;
+ }
+ p = buffer + mystrlen (buffer);
+#ifdef HAVE_W32CE_SYSTEM
+ wcscpy (p, L"_gnupg");
+ p += 7;
+#else
+ p = stpcpy (p, "_gnupg");
+#endif
+ /* We try to create the directory but don't care about an error as
+ it may already exist and the CreateFile would throw an error
+ anyway. */
+ CreateDirectory (buffer, NULL);
+ *p++ = '\\';
+ name = p;
+ for (attempts=0; attempts < 10; attempts++)
+ {
+ p = name;
+ value = (GetTickCount () ^ ((pid<<16) & 0xffff0000));
+ for (i=0; i < 8; i++)
+ {
+ *p++ = tohex (((value >> 28) & 0x0f));
+ value <<= 4;
+ }
+#ifdef HAVE_W32CE_SYSTEM
+ wcscpy (p, L".tmp");
+#else
+ strcpy (p, ".tmp");
+#endif
+ file = CreateFile (buffer,
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ &sec_attr,
+ CREATE_NEW,
+ FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
+ NULL);
+ if (file != INVALID_HANDLE_VALUE)
+ {
+ FILE *fp;
+#ifdef HAVE_W32CE_SYSTEM
+ int fd = (int)file;
+ fp = _wfdopen (fd, L"w+b");
+#else
+ int fd = _open_osfhandle ((long)file, 0);
+ if (fd == -1)
+ {
+ CloseHandle (file);
+ return NULL;
+ }
+ fp = fdopen (fd, "w+b");
+#endif
+ if (!fp)
+ {
+ int save = errno;
+ close (fd);
+ gpg_err_set_errno (save);
+ return NULL;
+ }
+ return fp;
+ }
+ Sleep (1); /* One ms as this is the granularity of GetTickCount. */
+ }
+ gpg_err_set_errno (ENOENT);
+ return NULL;
+#undef mystrlen
+#else /*!HAVE_W32_SYSTEM*/
+ return tmpfile ();
+#endif /*!HAVE_W32_SYSTEM*/
+}
+
+
+/* Make sure that the standard file descriptors are opened. Obviously
+ some folks close them before an exec and the next file we open will
+ get one of them assigned and thus any output (i.e. diagnostics) end
+ up in that file (e.g. the trustdb). Not actually a gpg problem as
+ this will happen with almost all utilities when called in a wrong
+ way. However we try to minimize the damage here and raise
+ awareness of the problem.
+
+ Must be called before we open any files! */
+void
+gnupg_reopen_std (const char *pgmname)
+{
+#ifdef F_GETFD
+ int did_stdin = 0;
+ int did_stdout = 0;
+ int did_stderr = 0;
+ FILE *complain;
+
+ if (fcntl (STDIN_FILENO, F_GETFD) == -1 && errno ==EBADF)
+ {
+ if (open ("/dev/null",O_RDONLY) == STDIN_FILENO)
+ did_stdin = 1;
+ else
+ did_stdin = 2;
+ }
+
+ if (fcntl (STDOUT_FILENO, F_GETFD) == -1 && errno == EBADF)
+ {
+ if (open ("/dev/null",O_WRONLY) == STDOUT_FILENO)
+ did_stdout = 1;
+ else
+ did_stdout = 2;
+ }
+
+ if (fcntl (STDERR_FILENO, F_GETFD)==-1 && errno==EBADF)
+ {
+ if (open ("/dev/null", O_WRONLY) == STDERR_FILENO)
+ did_stderr = 1;
+ else
+ did_stderr = 2;
+ }
+
+ /* It's hard to log this sort of thing since the filehandle we would
+ complain to may be closed... */
+ if (!did_stderr)
+ complain = stderr;
+ else if (!did_stdout)
+ complain = stdout;
+ else
+ complain = NULL;
+
+ if (complain)
+ {
+ if (did_stdin == 1)
+ fprintf (complain, "%s: WARNING: standard input reopened\n", pgmname);
+ if (did_stdout == 1)
+ fprintf (complain, "%s: WARNING: standard output reopened\n", pgmname);
+ if (did_stderr == 1)
+ fprintf (complain, "%s: WARNING: standard error reopened\n", pgmname);
+
+ if (did_stdin == 2 || did_stdout == 2 || did_stderr == 2)
+ fprintf(complain,"%s: fatal: unable to reopen standard input,"
+ " output, or error\n", pgmname);
+ }
+
+ if (did_stdin == 2 || did_stdout == 2 || did_stderr == 2)
+ exit (3);
+#else /* !F_GETFD */
+ (void)pgmname;
+#endif
+}
+
+
+/* Hack required for Windows. */
+void
+gnupg_allow_set_foregound_window (pid_t pid)
+{
+ if (!pid)
+ log_info ("%s called with invalid pid %lu\n",
+ "gnupg_allow_set_foregound_window", (unsigned long)pid);
+#if defined(HAVE_W32_SYSTEM) && !defined(HAVE_W32CE_SYSTEM)
+ else if (!AllowSetForegroundWindow ((pid_t)pid == (pid_t)(-1)?ASFW_ANY:pid))
+ {
+ char *flags = getenv ("GNUPG_EXEC_DEBUG_FLAGS");
+ if (flags && (atoi (flags) & 2))
+ log_info ("AllowSetForegroundWindow(%lu) failed: %s\n",
+ (unsigned long)pid, w32_strerror (-1));
+ }
+#endif
+}
+
+int
+gnupg_remove (const char *fname)
+{
+#ifdef HAVE_W32_SYSTEM
+ int rc;
+ wchar_t *wfname;
+
+ wfname = utf8_to_wchar (fname);
+ if (!wfname)
+ rc = 0;
+ else
+ {
+ rc = DeleteFileW (wfname);
+ if (!rc)
+ gnupg_w32_set_errno (-1);
+ xfree (wfname);
+ }
+ if (!rc)
+ return -1;
+ return 0;
+#else
+ return remove (fname);
+#endif
+}
+
+
+/* Helper for gnupg_rename_file. */
+#ifdef HAVE_W32_SYSTEM
+static int
+w32_rename (const char *oldname, const char *newname)
+{
+ if (any8bitchar (oldname) || any8bitchar (newname))
+ {
+ wchar_t *woldname, *wnewname;
+ int ret;
+
+ woldname = utf8_to_wchar (oldname);
+ if (!woldname)
+ return -1;
+ wnewname = utf8_to_wchar (newname);
+ if (!wnewname)
+ {
+ xfree (wnewname);
+ return -1;
+ }
+ ret = _wrename (woldname, wnewname);
+ xfree (wnewname);
+ xfree (woldname);
+ return ret;
+ }
+ else
+ return rename (oldname, newname);
+}
+#endif /*HAVE_W32_SYSTEM*/
+
+
+/* Wrapper for rename(2) to handle Windows peculiarities. If
+ * BLOCK_SIGNALS is not NULL and points to a variable set to true, all
+ * signals will be blocked by calling gnupg_block_all_signals; the
+ * caller needs to call gnupg_unblock_all_signals if that variable is
+ * still set to true on return. */
+gpg_error_t
+gnupg_rename_file (const char *oldname, const char *newname, int *block_signals)
+{
+ gpg_error_t err = 0;
+
+ if (block_signals && *block_signals)
+ gnupg_block_all_signals ();
+
+#ifdef HAVE_DOSISH_SYSTEM
+ {
+ int wtime = 0;
+
+ gnupg_remove (newname);
+ again:
+ if (w32_rename (oldname, newname))
+ {
+ if (GetLastError () == ERROR_SHARING_VIOLATION)
+ {
+ /* Another process has the file open. We do not use a
+ * lock for read but instead we wait until the other
+ * process has closed the file. This may take long but
+ * that would also be the case with a dotlock approach for
+ * read and write. Note that we don't need this on Unix
+ * due to the inode concept.
+ *
+ * So let's wait until the rename has worked. The retry
+ * intervals are 50, 100, 200, 400, 800, 50ms, ... */
+ if (!wtime || wtime >= 800)
+ wtime = 50;
+ else
+ wtime *= 2;
+
+ if (wtime >= 800)
+ log_info (_("waiting for file '%s' to become accessible ...\n"),
+ oldname);
+
+ Sleep (wtime);
+ goto again;
+ }
+ err = my_error_from_syserror ();
+ }
+ }
+#else /* Unix */
+ {
+#ifdef __riscos__
+ gnupg_remove (newname);
+#endif
+ if (rename (oldname, newname) )
+ err = my_error_from_syserror ();
+ }
+#endif /* Unix */
+
+ if (block_signals && *block_signals && err)
+ {
+ gnupg_unblock_all_signals ();
+ *block_signals = 0;
+ }
+
+ if (err)
+ log_error (_("renaming '%s' to '%s' failed: %s\n"),
+ oldname, newname, gpg_strerror (err));
+ return err;
+}
+
+
+#ifndef HAVE_W32_SYSTEM
+static mode_t
+modestr_to_mode (const char *modestr, mode_t oldmode)
+{
+ static struct {
+ char letter;
+ mode_t value;
+ } table[] = { { '-', 0 },
+ { 'r', S_IRUSR }, { 'w', S_IWUSR }, { 'x', S_IXUSR },
+ { 'r', S_IRGRP }, { 'w', S_IWGRP }, { 'x', S_IXGRP },
+ { 'r', S_IROTH }, { 'w', S_IWOTH }, { 'x', S_IXOTH } };
+ int idx;
+ mode_t mode = 0;
+
+ /* For now we only support a string as used by ls(1) and no octal
+ * numbers. The first character must be a dash. */
+ for (idx=0; idx < 10 && *modestr; idx++, modestr++)
+ {
+ if (*modestr == table[idx].letter)
+ mode |= table[idx].value;
+ else if (*modestr == '.')
+ {
+ if (!idx)
+ ; /* Skip the dummy. */
+ else if ((oldmode & table[idx].value))
+ mode |= (oldmode & table[idx].value);
+ else
+ mode &= ~(oldmode & table[idx].value);
+ }
+ else if (*modestr != '-')
+ break;
+ }
+
+
+ return mode;
+}
+#endif
+
+
+/* A wrapper around mkdir which takes a string for the mode argument.
+ This makes it easier to handle the mode argument which is not
+ defined on all systems. The format of the modestring is
+
+ "-rwxrwxrwx"
+
+ '-' is a don't care or not set. 'r', 'w', 'x' are read allowed,
+ write allowed, execution allowed with the first group for the user,
+ the second for the group and the third for all others. If the
+ string is shorter than above the missing mode characters are meant
+ to be not set. */
+int
+gnupg_mkdir (const char *name, const char *modestr)
+{
+#if GPG_ERROR_VERSION_NUMBER < 0x011c00 /* 1.28 */
+ #ifdef HAVE_W32CE_SYSTEM
+ wchar_t *wname;
+ (void)modestr;
+
+ wname = utf8_to_wchar (name);
+ if (!wname)
+ return -1;
+ if (!CreateDirectoryW (wname, NULL))
+ {
+ xfree (wname);
+ return -1; /* ERRNO is automagically provided by gpg-error.h. */
+ }
+ xfree (wname);
+ return 0;
+ #elif MKDIR_TAKES_ONE_ARG
+ (void)modestr;
+ /* Note: In the case of W32 we better use CreateDirectory and try to
+ set appropriate permissions. However using mkdir is easier
+ because this sets ERRNO. */
+ return mkdir (name);
+ #else
+ return mkdir (name, modestr_to_mode (modestr, 0));
+ #endif
+#else
+ /* Note that gpgrt_mkdir also sets ERRNO in addition to returing an
+ * gpg-error style error code. */
+ return gpgrt_mkdir (name, modestr);
+#endif
+}
+
+
+/* A simple wrapper around chdir. NAME is expected to be utf8
+ * encoded. */
+int
+gnupg_chdir (const char *name)
+{
+#if GPG_ERROR_VERSION_NUMBER < 0x011c00 /* 1.28 */
+ return chdir (name);
+#else /* Use the improved version from libgpg_error. */
+ /* Note that gpgrt_chdir also sets ERRNO in addition to returning a
+ * gpg-error style error code. */
+ return gpgrt_chdir (name);
+#endif
+}
+
+
+/* A wrapper around rmdir. NAME is expected to be utf8 encoded. */
+int
+gnupg_rmdir (const char *name)
+{
+#ifdef HAVE_W32_SYSTEM
+ int rc;
+ wchar_t *wfname;
+
+ wfname = utf8_to_wchar (name);
+ if (!wfname)
+ rc = 0;
+ else
+ {
+ rc = RemoveDirectoryW (wfname);
+ if (!rc)
+ gnupg_w32_set_errno (-1);
+ xfree (wfname);
+ }
+ if (!rc)
+ return -1;
+ return 0;
+#else
+ return rmdir (name);
+#endif
+}
+
+
+/* A wrapper around chmod which takes a string for the mode argument.
+ This makes it easier to handle the mode argument which is not
+ defined on all systems. The format of the modestring is the same
+ as for gnupg_mkdir with extra feature that a '.' keeps the original
+ mode bit. */
+int
+gnupg_chmod (const char *name, const char *modestr)
+{
+#ifdef HAVE_W32_SYSTEM
+ (void)name;
+ (void)modestr;
+ return 0;
+#else
+ mode_t oldmode;
+ if (strchr (modestr, '.'))
+ {
+ /* Get the old mode so that a '.' can copy that bit. */
+ struct stat st;
+
+ if (stat (name, &st))
+ return -1;
+ oldmode = st.st_mode;
+ }
+ else
+ oldmode = 0;
+ return chmod (name, modestr_to_mode (modestr, oldmode));
+#endif
+}
+
+
+/* Our version of mkdtemp. The API is identical to POSIX.1-2008
+ version. We do not use a system provided mkdtemp because we have a
+ good RNG instantly available and this way we don't have diverging
+ versions. */
+char *
+gnupg_mkdtemp (char *tmpl)
+{
+ /* A lower bound on the number of temporary files to attempt to
+ generate. The maximum total number of temporary file names that
+ can exist for a given template is 62**6 (5*36**3 for Windows).
+ It should never be necessary to try all these combinations.
+ Instead if a reasonable number of names is tried (we define
+ reasonable as 62**3 or 5*36**3) fail to give the system
+ administrator the chance to remove the problems. */
+#ifdef HAVE_W32_SYSTEM
+ static const char letters[] =
+ "abcdefghijklmnopqrstuvwxyz0123456789";
+# define NUMBER_OF_LETTERS 36
+# define ATTEMPTS_MIN (5 * 36 * 36 * 36)
+#else
+ static const char letters[] =
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+# define NUMBER_OF_LETTERS 62
+# define ATTEMPTS_MIN (62 * 62 * 62)
+#endif
+ int len;
+ char *XXXXXX;
+ uint64_t value;
+ unsigned int count;
+ int save_errno = errno;
+ /* The number of times to attempt to generate a temporary file. To
+ conform to POSIX, this must be no smaller than TMP_MAX. */
+#if ATTEMPTS_MIN < TMP_MAX
+ unsigned int attempts = TMP_MAX;
+#else
+ unsigned int attempts = ATTEMPTS_MIN;
+#endif
+
+ len = strlen (tmpl);
+ if (len < 6 || strcmp (&tmpl[len - 6], "XXXXXX"))
+ {
+ gpg_err_set_errno (EINVAL);
+ return NULL;
+ }
+
+ /* This is where the Xs start. */
+ XXXXXX = &tmpl[len - 6];
+
+ /* Get a random start value. */
+ gcry_create_nonce (&value, sizeof value);
+
+ /* Loop until a directory was created. */
+ for (count = 0; count < attempts; value += 7777, ++count)
+ {
+ uint64_t v = value;
+
+ /* Fill in the random bits. */
+ XXXXXX[0] = letters[v % NUMBER_OF_LETTERS];
+ v /= NUMBER_OF_LETTERS;
+ XXXXXX[1] = letters[v % NUMBER_OF_LETTERS];
+ v /= NUMBER_OF_LETTERS;
+ XXXXXX[2] = letters[v % NUMBER_OF_LETTERS];
+ v /= NUMBER_OF_LETTERS;
+ XXXXXX[3] = letters[v % NUMBER_OF_LETTERS];
+ v /= NUMBER_OF_LETTERS;
+ XXXXXX[4] = letters[v % NUMBER_OF_LETTERS];
+ v /= NUMBER_OF_LETTERS;
+ XXXXXX[5] = letters[v % NUMBER_OF_LETTERS];
+
+ if (!gnupg_mkdir (tmpl, "-rwx"))
+ {
+ gpg_err_set_errno (save_errno);
+ return tmpl;
+ }
+ if (errno != EEXIST)
+ return NULL;
+ }
+
+ /* We got out of the loop because we ran out of combinations to try. */
+ gpg_err_set_errno (EEXIST);
+ return NULL;
+}
+
+
+int
+gnupg_setenv (const char *name, const char *value, int overwrite)
+{
+#ifdef HAVE_W32CE_SYSTEM
+ (void)name;
+ (void)value;
+ (void)overwrite;
+ return 0;
+#else /*!W32CE*/
+# ifdef HAVE_W32_SYSTEM
+ /* Windows maintains (at least) two sets of environment variables.
+ One set can be accessed by GetEnvironmentVariable and
+ SetEnvironmentVariable. This set is inherited by the children.
+ The other set is maintained in the C runtime, and is accessed
+ using getenv and putenv. We try to keep them in sync by
+ modifying both sets. */
+ {
+ int exists;
+ char tmpbuf[10];
+ exists = GetEnvironmentVariable (name, tmpbuf, sizeof tmpbuf);
+
+ if ((! exists || overwrite) && !SetEnvironmentVariable (name, value))
+ {
+ gpg_err_set_errno (EINVAL); /* (Might also be ENOMEM.) */
+ return -1;
+ }
+ }
+# endif /*W32*/
+
+# ifdef HAVE_SETENV
+ return setenv (name, value, overwrite);
+# else /*!HAVE_SETENV*/
+ if (! getenv (name) || overwrite)
+ {
+ char *buf;
+
+ (void)overwrite;
+ if (!name || !value)
+ {
+ gpg_err_set_errno (EINVAL);
+ return -1;
+ }
+ buf = strconcat (name, "=", value, NULL);
+ if (!buf)
+ return -1;
+# if __GNUC__
+# warning no setenv - using putenv but leaking memory.
+# endif
+ return putenv (buf);
+ }
+ return 0;
+# endif /*!HAVE_SETENV*/
+#endif /*!W32CE*/
+}
+
+
+int
+gnupg_unsetenv (const char *name)
+{
+#ifdef HAVE_W32CE_SYSTEM
+ (void)name;
+ return 0;
+#else /*!W32CE*/
+# ifdef HAVE_W32_SYSTEM
+ /* Windows maintains (at least) two sets of environment variables.
+ One set can be accessed by GetEnvironmentVariable and
+ SetEnvironmentVariable. This set is inherited by the children.
+ The other set is maintained in the C runtime, and is accessed
+ using getenv and putenv. We try to keep them in sync by
+ modifying both sets. */
+ if (!SetEnvironmentVariable (name, NULL))
+ {
+ gpg_err_set_errno (EINVAL); /* (Might also be ENOMEM.) */
+ return -1;
+ }
+# endif /*W32*/
+
+# ifdef HAVE_UNSETENV
+ return unsetenv (name);
+# else /*!HAVE_UNSETENV*/
+ {
+ char *buf;
+
+ if (!name)
+ {
+ gpg_err_set_errno (EINVAL);
+ return -1;
+ }
+ buf = xtrystrdup (name);
+ if (!buf)
+ return -1;
+# if __GNUC__
+# warning no unsetenv - trying putenv but leaking memory.
+# endif
+ return putenv (buf);
+ }
+# endif /*!HAVE_UNSETENV*/
+#endif /*!W32CE*/
+}
+
+
+/* Return the current working directory as a malloced string. Return
+ NULL and sets ERRNO on error. */
+char *
+gnupg_getcwd (void)
+{
+#if GPGRT_VERSION_NUMBER < 0x012800 /* 1.40 */
+# ifdef HAVE_W32_SYSTEM
+ wchar_t wbuffer[MAX_PATH + sizeof(wchar_t)];
+ DWORD wlen;
+ char *buf, *p;
+
+ wlen = GetCurrentDirectoryW (MAX_PATH, wbuffer);
+ if (!wlen)
+ {
+ gpg_err_set_errno (EINVAL);
+ return NULL;
+
+ }
+ else if (wlen > MAX_PATH)
+ {
+ gpg_err_set_errno (ENAMETOOLONG);
+ return NULL;
+ }
+ buf = wchar_to_utf8 (wbuffer);
+ if (buf)
+ {
+ for (p=buf; *p; p++)
+ if (*p == '\\')
+ *p = '/';
+ }
+ return buf;
+
+# else /*Unix*/
+ char *buffer;
+ size_t size = 100;
+
+ for (;;)
+ {
+ buffer = xtrymalloc (size+1);
+ if (!buffer)
+ return NULL;
+ if (getcwd (buffer, size) == buffer)
+ return buffer;
+ xfree (buffer);
+ if (errno != ERANGE)
+ return NULL;
+ size *= 2;
+ }
+# endif /*Unix*/
+#else
+ return gpgrt_getcwd ();
+#endif
+}
+
+
+/* A simple wrapper around access. NAME is expected to be utf8
+ * encoded. This function returns an error code and sets ERRNO. */
+gpg_err_code_t
+gnupg_access (const char *name, int mode)
+{
+#if GPGRT_VERSION_NUMBER < 0x012800 /* 1.40 */
+# ifdef HAVE_W32_SYSTEM
+ wchar_t *wfname;
+ gpg_err_code_t ec;
+
+ wfname = utf8_to_wchar (name);
+ if (!wfname)
+ ec = gpg_err_code_from_syserror ();
+ else
+ {
+ ec = _waccess (wfname, mode)? gpg_err_code_from_syserror () : 0;
+ xfree (wfname);
+ }
+ return ec;
+# else
+ return access (name, mode)? gpg_err_code_from_syserror () : 0;
+# endif
+#else /* gpgrt 1.40 or newer. */
+ return gpgrt_access (name, mode);
+#endif
+}
+
+
+/* A wrapper around stat to handle Unicode file names under Windows. */
+#ifdef HAVE_STAT
+int
+gnupg_stat (const char *name, struct stat *statbuf)
+{
+# ifdef HAVE_W32_SYSTEM
+ if (any8bitchar (name))
+ {
+ wchar_t *wname;
+ struct _stat32 st32;
+ int ret;
+
+ wname = utf8_to_wchar (name);
+ if (!wname)
+ return -1;
+ ret = _wstat (wname, &st32);
+ xfree (wname);
+ if (!ret)
+ {
+ statbuf->st_dev = st32.st_dev;
+ statbuf->st_ino = st32.st_ino;
+ statbuf->st_mode = st32.st_mode;
+ statbuf->st_nlink = st32.st_nlink;
+ statbuf->st_uid = st32.st_uid;
+ statbuf->st_gid = st32.st_gid;
+ statbuf->st_rdev = st32.st_rdev;
+ statbuf->st_size = st32.st_size;
+ statbuf->st_atime = st32.st_atime;
+ statbuf->st_mtime = st32.st_mtime;
+ statbuf->st_ctime = st32.st_ctime;
+ }
+ return ret;
+ }
+ else
+ return stat (name, statbuf);
+# else
+ return stat (name, statbuf);
+# endif
+}
+#endif /*HAVE_STAT*/
+
+
+/* Wrapper around fopen for the cases where we have not yet switched
+ * to es_fopen. Note that for convenience the prototype is in util.h */
+FILE *
+gnupg_fopen (const char *fname, const char *mode)
+{
+#ifdef HAVE_W32_SYSTEM
+ if (any8bitchar (fname))
+ {
+ wchar_t *wfname;
+ const wchar_t *wmode;
+ wchar_t *wmodebuf = NULL;
+ FILE *ret;
+
+ wfname = utf8_to_wchar (fname);
+ if (!wfname)
+ return NULL;
+ if (!strcmp (mode, "r"))
+ wmode = L"r";
+ else if (!strcmp (mode, "rb"))
+ wmode = L"rb";
+ else if (!strcmp (mode, "w"))
+ wmode = L"w";
+ else if (!strcmp (mode, "wb"))
+ wmode = L"wb";
+ else
+ {
+ wmodebuf = utf8_to_wchar (mode);
+ if (!wmodebuf)
+ {
+ xfree (wfname);
+ return NULL;
+ }
+ wmode = wmodebuf;
+ }
+ ret = _wfopen (wfname, wmode);
+ xfree (wfname);
+ xfree (wmodebuf);
+ return ret;
+ }
+ else
+ return fopen (fname, mode);
+
+#else /*Unix*/
+ return fopen (fname, mode);
+#endif /*Unix*/
+}
+
+
+
+/* A wrapper around open to handle Unicode file names under Windows. */
+int
+gnupg_open (const char *name, int flags, unsigned int mode)
+{
+#ifdef HAVE_W32_SYSTEM
+ if (any8bitchar (name))
+ {
+ wchar_t *wname;
+ int ret;
+
+ wname = utf8_to_wchar (name);
+ if (!wname)
+ return -1;
+ ret = _wopen (wname, flags, mode);
+ xfree (wname);
+ return ret;
+ }
+ else
+ return open (name, flags, mode);
+#else
+ return open (name, flags, mode);
+#endif
+}
+
+
+/* A wrapper around opendir to handle Unicode file names under
+ * Windows. This assumes the mingw toolchain. */
+gnupg_dir_t
+gnupg_opendir (const char *name)
+{
+#ifdef HAVE_W32_SYSTEM
+ _WDIR *dir;
+ wchar_t *wname;
+#else
+ DIR *dir;
+#endif
+ gnupg_dir_t gdir;
+
+#ifdef HAVE_W32_SYSTEM
+ /* Note: See gpgtar-create for an alternative implementation which
+ * could be used here to avoid a mingw dependency. */
+ wname = utf8_to_wchar (name);
+ if (!wname)
+ return NULL;
+ dir = _wopendir (wname);
+ xfree (wname);
+#else
+ dir = opendir (name);
+#endif
+
+ if (!dir)
+ return NULL;
+
+ gdir = xtrymalloc (sizeof *gdir);
+ if (!gdir)
+ {
+ int save_errno = errno;
+#ifdef HAVE_W32_SYSTEM
+ _wclosedir (dir);
+#else
+ closedir (dir);
+#endif
+ gpg_err_set_errno (save_errno);
+ return NULL;
+ }
+ gdir->dir = dir;
+ gdir->namesize = 0;
+ gdir->dirent.d_name = gdir->name;
+
+ return gdir;
+}
+
+
+gnupg_dirent_t
+gnupg_readdir (gnupg_dir_t gdir)
+{
+#ifdef HAVE_W32_SYSTEM
+ char *namebuffer = NULL;
+ struct _wdirent *de;
+#else
+ struct dirent *de;
+#endif
+ size_t n;
+ gnupg_dirent_t gde;
+ const char *name;
+
+ if (!gdir)
+ {
+ gpg_err_set_errno (EINVAL);
+ return 0;
+ }
+
+#ifdef HAVE_W32_SYSTEM
+ de = _wreaddir (gdir->dir);
+ if (!de)
+ return NULL;
+ namebuffer = wchar_to_utf8 (de->d_name);
+ if (!namebuffer)
+ return NULL;
+ name = namebuffer;
+#else
+ de = readdir (gdir->dir);
+ if (!de)
+ return NULL;
+ name = de->d_name;
+#endif
+
+ gde = &gdir->dirent;
+ n = strlen (name);
+ if (gdir->namesize)
+ {
+ /* Use allocated buffer. */
+ if (n+1 >= gdir->namesize || !gde->d_name)
+ {
+ gdir->namesize = n + 256;
+ xfree (gde->d_name);
+ gde->d_name = xtrymalloc (gdir->namesize);
+ if (!gde->d_name)
+ return NULL; /* ERRNO is already set. */
+ }
+ strcpy (gde->d_name, name);
+ }
+ else if (n+1 >= sizeof (gdir->name))
+ {
+ /* Switch to allocated buffer. */
+ gdir->namesize = n + 256;
+ gde->d_name = xtrymalloc (gdir->namesize);
+ if (!gde->d_name)
+ return NULL; /* ERRNO is already set. */
+ strcpy (gde->d_name, name);
+ }
+ else
+ {
+ /* Use static buffer. */
+ gde->d_name = gdir->name;
+ strcpy (gde->d_name, name);
+ }
+
+#ifdef HAVE_W32_SYSTEM
+ xfree (namebuffer);
+#endif
+
+ return gde;
+}
+
+
+int
+gnupg_closedir (gnupg_dir_t gdir)
+{
+#ifdef HAVE_W32_SYSTEM
+ _WDIR *dir;
+#else
+ DIR *dir;
+#endif
+
+ if (!gdir)
+ return 0;
+ dir = gdir->dir;
+ if (gdir->namesize)
+ xfree (gdir->dirent.d_name);
+ xfree (gdir);
+
+#ifdef HAVE_W32_SYSTEM
+ return _wclosedir (dir);
+#else
+ return closedir (dir);
+#endif
+}
+
+
+
+#ifdef HAVE_W32CE_SYSTEM
+/* There is a isatty function declaration in cegcc but it does not
+ make sense, thus we redefine it. */
+int
+_gnupg_isatty (int fd)
+{
+ (void)fd;
+ return 0;
+}
+#endif
+
+
+#ifdef HAVE_W32CE_SYSTEM
+/* Replacement for getenv which takes care of the our use of getenv.
+ The code is not thread safe but we expect it to work in all cases
+ because it is called for the first time early enough. */
+char *
+_gnupg_getenv (const char *name)
+{
+ static int initialized;
+ static char *assuan_debug;
+
+ if (!initialized)
+ {
+ assuan_debug = read_w32_registry_string (NULL,
+ "\\Software\\GNU\\libassuan",
+ "debug");
+ initialized = 1;
+ }
+
+ if (!strcmp (name, "ASSUAN_DEBUG"))
+ return assuan_debug;
+ else
+ return NULL;
+}
+
+#endif /*HAVE_W32CE_SYSTEM*/
+
+
+#ifdef HAVE_W32_SYSTEM
+/* Return the user's security identifier from the current process. */
+PSID
+w32_get_user_sid (void)
+{
+ int okay = 0;
+ HANDLE proc = NULL;
+ HANDLE token = NULL;
+ TOKEN_USER *user = NULL;
+ PSID sid = NULL;
+ DWORD tokenlen, sidlen;
+
+ proc = OpenProcess (PROCESS_QUERY_INFORMATION, FALSE, GetCurrentProcessId());
+ if (!proc)
+ goto leave;
+
+ if (!OpenProcessToken (proc, TOKEN_QUERY, &token))
+ goto leave;
+
+ if (!GetTokenInformation (token, TokenUser, NULL, 0, &tokenlen)
+ && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+ goto leave;
+
+ user = xtrymalloc (tokenlen);
+ if (!user)
+ goto leave;
+
+ if (!GetTokenInformation (token, TokenUser, user, tokenlen, &tokenlen))
+ goto leave;
+ if (!IsValidSid (user->User.Sid))
+ goto leave;
+ sidlen = GetLengthSid (user->User.Sid);
+ sid = xtrymalloc (sidlen);
+ if (!sid)
+ goto leave;
+ if (!CopySid (sidlen, sid, user->User.Sid))
+ goto leave;
+ okay = 1;
+
+ leave:
+ xfree (user);
+ if (token)
+ CloseHandle (token);
+ if (proc)
+ CloseHandle (proc);
+
+ if (!okay)
+ {
+ xfree (sid);
+ sid = NULL;
+ }
+ return sid;
+}
+#endif /*HAVE_W32_SYSTEM*/
+
+
+
+/* Support for inotify under Linux. */
+
+/* Store a new inotify file handle for FNAME at R_FD or return an
+ * error code. This file descriptor watch the removal of FNAME. */
+gpg_error_t
+gnupg_inotify_watch_delete_self (int *r_fd, const char *fname)
+{
+#if HAVE_INOTIFY_INIT
+ gpg_error_t err;
+ int fd;
+
+ *r_fd = -1;
+
+ if (!fname)
+ return my_error (GPG_ERR_INV_VALUE);
+
+ fd = inotify_init ();
+ if (fd == -1)
+ return my_error_from_syserror ();
+
+ if (inotify_add_watch (fd, fname, IN_DELETE_SELF) == -1)
+ {
+ err = my_error_from_syserror ();
+ close (fd);
+ return err;
+ }
+
+ *r_fd = fd;
+ return 0;
+#else /*!HAVE_INOTIFY_INIT*/
+
+ (void)fname;
+ *r_fd = -1;
+ return my_error (GPG_ERR_NOT_SUPPORTED);
+
+#endif /*!HAVE_INOTIFY_INIT*/
+}
+
+
+/* Store a new inotify file handle for SOCKET_NAME at R_FD or return
+ * an error code. */
+gpg_error_t
+gnupg_inotify_watch_socket (int *r_fd, const char *socket_name)
+{
+#if HAVE_INOTIFY_INIT
+ gpg_error_t err;
+ char *fname;
+ int fd;
+ char *p;
+
+ *r_fd = -1;
+
+ if (!socket_name)
+ return my_error (GPG_ERR_INV_VALUE);
+
+ fname = xtrystrdup (socket_name);
+ if (!fname)
+ return my_error_from_syserror ();
+
+ fd = inotify_init ();
+ if (fd == -1)
+ {
+ err = my_error_from_syserror ();
+ xfree (fname);
+ return err;
+ }
+
+ /* We need to watch the directory for the file because there won't
+ * be an IN_DELETE_SELF for a socket file. To handle a removal of
+ * the directory we also watch the directory itself. */
+ p = strrchr (fname, '/');
+ if (p)
+ *p = 0;
+ if (inotify_add_watch (fd, fname,
+ (IN_DELETE|IN_DELETE_SELF|IN_EXCL_UNLINK)) == -1)
+ {
+ err = my_error_from_syserror ();
+ close (fd);
+ xfree (fname);
+ return err;
+ }
+
+ xfree (fname);
+
+ *r_fd = fd;
+ return 0;
+#else /*!HAVE_INOTIFY_INIT*/
+
+ (void)socket_name;
+ *r_fd = -1;
+ return my_error (GPG_ERR_NOT_SUPPORTED);
+
+#endif /*!HAVE_INOTIFY_INIT*/
+}
+
+
+/* Read an inotify event and return true if it matches NAME or if it
+ * sees an IN_DELETE_SELF event for the directory of NAME. */
+int
+gnupg_inotify_has_name (int fd, const char *name)
+{
+#if USE_NPTH && HAVE_INOTIFY_INIT
+#define BUFSIZE_FOR_INOTIFY (sizeof (struct inotify_event) + 255 + 1)
+ union {
+ struct inotify_event ev;
+ char _buf[sizeof (struct inotify_event) + 255 + 1];
+ } buf;
+ struct inotify_event *evp;
+ int n;
+
+ n = npth_read (fd, &buf, sizeof buf);
+ /* log_debug ("notify read: n=%d\n", n); */
+ evp = &buf.ev;
+ while (n >= sizeof (struct inotify_event))
+ {
+ /* log_debug (" mask=%x len=%u name=(%s)\n", */
+ /* evp->mask, (unsigned int)evp->len, evp->len? evp->name:""); */
+ if ((evp->mask & IN_UNMOUNT))
+ {
+ /* log_debug (" found (dir unmounted)\n"); */
+ return 3; /* Directory was unmounted. */
+ }
+ if ((evp->mask & IN_DELETE_SELF))
+ {
+ /* log_debug (" found (dir removed)\n"); */
+ return 2; /* Directory was removed. */
+ }
+ if ((evp->mask & IN_DELETE))
+ {
+ if (evp->len >= strlen (name) && !strcmp (evp->name, name))
+ {
+ /* log_debug (" found (file removed)\n"); */
+ return 1; /* File was removed. */
+ }
+ }
+ n -= sizeof (*evp) + evp->len;
+ evp = (struct inotify_event *)(void *)
+ ((char *)evp + sizeof (*evp) + evp->len);
+ }
+
+#else /*!(USE_NPTH && HAVE_INOTIFY_INIT)*/
+
+ (void)fd;
+ (void)name;
+
+#endif /*!(USE_NPTH && HAVE_INOTIFY_INIT)*/
+
+ return 0; /* Not found. */
+}
+
+
+/* Return a malloc'ed string that is the path to the passed
+ * unix-domain socket (or return NULL if this is not a valid
+ * unix-domain socket). We use a plain int here because it is only
+ * used on Linux.
+ *
+ * FIXME: This function needs to be moved to libassuan. */
+#ifndef HAVE_W32_SYSTEM
+char *
+gnupg_get_socket_name (int fd)
+{
+ struct sockaddr_un un;
+ socklen_t len = sizeof(un);
+ char *name = NULL;
+
+ if (getsockname (fd, (struct sockaddr*)&un, &len) != 0)
+ log_error ("could not getsockname(%d): %s\n", fd,
+ gpg_strerror (my_error_from_syserror ()));
+ else if (un.sun_family != AF_UNIX)
+ log_error ("file descriptor %d is not a unix-domain socket\n", fd);
+ else if (len <= offsetof (struct sockaddr_un, sun_path))
+ log_error ("socket name not present for file descriptor %d\n", fd);
+ else if (len > sizeof(un))
+ log_error ("socket name for file descriptor %d was truncated "
+ "(passed %zu bytes, wanted %u)\n", fd, sizeof(un), len);
+ else
+ {
+ size_t namelen = len - offsetof (struct sockaddr_un, sun_path);
+
+ /* log_debug ("file descriptor %d has path %s (%zu octets)\n", fd, */
+ /* un.sun_path, namelen); */
+ name = xtrymalloc (namelen + 1);
+ if (!name)
+ log_error ("failed to allocate memory for name of fd %d: %s\n",
+ fd, gpg_strerror (my_error_from_syserror ()));
+ else
+ {
+ memcpy (name, un.sun_path, namelen);
+ name[namelen] = 0;
+ }
+ }
+
+ return name;
+}
+#endif /*!HAVE_W32_SYSTEM*/
+
+/* Check whether FD is valid. */
+int
+gnupg_fd_valid (int fd)
+{
+ int d = dup (fd);
+ if (d < 0)
+ return 0;
+ close (d);
+ return 1;
+}
+
+
+/* Return a malloced copy of the current user's account name; this may
+ * return NULL on memory failure. Note that this should eventually be
+ * replaced by a gpgrt function. */
+char *
+gnupg_getusername (void)
+{
+ char *result = NULL;
+
+#ifdef HAVE_W32_SYSTEM
+ wchar_t wtmp[1];
+ wchar_t *wbuf;
+ DWORD wsize = 1;
+
+ GetUserNameW (wtmp, &wsize);
+ wbuf = xtrymalloc (wsize * sizeof *wbuf);
+ if (!wbuf)
+ {
+ gpg_err_set_errno (ENOMEM);
+ return NULL;
+ }
+ if (!GetUserNameW (wbuf, &wsize))
+ {
+ gpg_err_set_errno (EINVAL);
+ xfree (wbuf);
+ return NULL;
+ }
+ result= wchar_to_utf8 (wbuf);
+ xfree (wbuf);
+
+#else /* !HAVE_W32_SYSTEM */
+
+# if defined(HAVE_PWD_H) && defined(HAVE_GETPWUID)
+ struct passwd *pwd;
+
+ pwd = getpwuid (getuid());
+ if (pwd)
+ result = xtrystrdup (pwd->pw_name);
+
+# endif /*HAVE_PWD_H*/
+
+#endif /* !HAVE_W32_SYSTEM */
+
+ return result;
+}
diff --git a/common/sysutils.h b/common/sysutils.h
new file mode 100644
index 0000000..e22156b
--- /dev/null
+++ b/common/sysutils.h
@@ -0,0 +1,117 @@
+/* sysutils.h - System utility functions for Gnupg
+ * Copyright (C) 2002 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_COMMON_SYSUTILS_H
+#define GNUPG_COMMON_SYSUTILS_H
+
+/* Because we use system handles and not libc low level file
+ descriptors on W32, we need to declare them as HANDLE (which
+ actually is a plain pointer). This is required to eventually
+ support 64 bits Windows systems. */
+#ifdef HAVE_W32_SYSTEM
+typedef void *gnupg_fd_t;
+#define GNUPG_INVALID_FD ((void*)(-1))
+#define INT2FD(s) ((void *)(s))
+#define FD2INT(h) ((unsigned int)(h))
+#else
+typedef int gnupg_fd_t;
+#define GNUPG_INVALID_FD (-1)
+#define INT2FD(s) (s)
+#define FD2INT(h) (h)
+#endif
+
+#ifdef HAVE_STAT
+# include <sys/stat.h>
+#endif
+
+struct gnupg_dir_s;
+typedef struct gnupg_dir_s *gnupg_dir_t;
+struct gnupg_dirent_s
+{
+ /* We don't have a d_ino because that can't be used on Windows
+ * anyway. D_NAME is a pointer into the gnupg_dir_s which has a
+ * static buffer or allocates sufficient space as needed. This is
+ * only valid after gnupg_readdir. */
+ char *d_name;
+};
+typedef struct gnupg_dirent_s *gnupg_dirent_t;
+
+
+void trap_unaligned (void);
+int disable_core_dumps (void);
+int enable_core_dumps (void);
+void enable_special_filenames (void);
+const unsigned char *get_session_marker (size_t *rlen);
+unsigned int get_uint_nonce (void);
+/*int check_permissions (const char *path,int extension,int checkonly);*/
+void gnupg_sleep (unsigned int seconds);
+void gnupg_usleep (unsigned int usecs);
+int translate_sys2libc_fd (gnupg_fd_t fd, int for_write);
+int translate_sys2libc_fd_int (int fd, int for_write);
+int check_special_filename (const char *fname, int for_write, int notranslate);
+FILE *gnupg_tmpfile (void);
+void gnupg_reopen_std (const char *pgmname);
+void gnupg_allow_set_foregound_window (pid_t pid);
+int gnupg_remove (const char *fname);
+gpg_error_t gnupg_rename_file (const char *oldname, const char *newname,
+ int *block_signals);
+int gnupg_mkdir (const char *name, const char *modestr);
+int gnupg_chdir (const char *name);
+int gnupg_rmdir (const char *name);
+int gnupg_chmod (const char *name, const char *modestr);
+char *gnupg_mkdtemp (char *template);
+int gnupg_setenv (const char *name, const char *value, int overwrite);
+int gnupg_unsetenv (const char *name);
+char *gnupg_getcwd (void);
+gpg_err_code_t gnupg_access (const char *name, int mode);
+#ifdef HAVE_STAT
+int gnupg_stat (const char *name, struct stat *statbuf);
+#endif /*HAVE_STAT*/
+int gnupg_open (const char *name, int flags, unsigned int mode);
+gnupg_dir_t gnupg_opendir (const char *name);
+gnupg_dirent_t gnupg_readdir (gnupg_dir_t gdir);
+int gnupg_closedir (gnupg_dir_t gdir);
+char *gnupg_get_socket_name (int fd);
+int gnupg_fd_valid (int fd);
+char *gnupg_getusername (void);
+
+gpg_error_t gnupg_inotify_watch_delete_self (int *r_fd, const char *fname);
+gpg_error_t gnupg_inotify_watch_socket (int *r_fd, const char *socket_name);
+int gnupg_inotify_has_name (int fd, const char *name);
+
+
+#ifdef HAVE_W32_SYSTEM
+void gnupg_w32_set_errno (int ec);
+void *w32_get_user_sid (void);
+
+#include "../common/w32help.h"
+
+#endif /*HAVE_W32_SYSTEM*/
+
+#endif /*GNUPG_COMMON_SYSUTILS_H*/
diff --git a/common/t-b64.c b/common/t-b64.c
new file mode 100644
index 0000000..3b63872
--- /dev/null
+++ b/common/t-b64.c
@@ -0,0 +1,181 @@
+/* t-b64.c - Module tests for b64enc.c and b64dec.c
+ * Copyright (C) 2008 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+/*
+
+ As of now this is only a test program for manual tests.
+
+ */
+
+
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "util.h"
+
+#define pass() do { ; } while(0)
+#define fail(a) do { fprintf (stderr, "%s:%d: test %d failed\n",\
+ __FILE__,__LINE__, (a)); \
+ errcount++; \
+ } while(0)
+
+static int verbose;
+static int errcount;
+
+static void
+test_b64enc_pgp (const char *string)
+{
+ gpg_error_t err;
+ struct b64state state;
+
+ if (!string)
+ string = "a";
+
+ err = b64enc_start (&state, stdout, "PGP MESSAGE");
+ if (err)
+ fail (1);
+
+ err = b64enc_write (&state, string, strlen (string));
+ if (err)
+ fail (2);
+
+ err = b64enc_finish (&state);
+ if (err)
+ fail (3);
+
+ pass ();
+}
+
+
+static void
+test_b64enc_file (const char *fname)
+{
+ gpg_error_t err;
+ struct b64state state;
+ FILE *fp;
+ char buffer[50];
+ size_t nread;
+
+ fp = fname ? fopen (fname, "r") : stdin;
+ if (!fp)
+ {
+ fprintf (stderr, "%s:%d: can't open '%s': %s\n",
+ __FILE__, __LINE__, fname? fname:"[stdin]", strerror (errno));
+ fail (0);
+ }
+
+ err = b64enc_start (&state, stdout, "DATA");
+ if (err)
+ fail (1);
+
+ while ( (nread = fread (buffer, 1, sizeof buffer, fp)) )
+ {
+ err = b64enc_write (&state, buffer, nread);
+ if (err)
+ fail (2);
+ }
+
+ err = b64enc_finish (&state);
+ if (err)
+ fail (3);
+
+ fclose (fp);
+ pass ();
+}
+
+static void
+test_b64dec_file (const char *fname)
+{
+ gpg_error_t err;
+ struct b64state state;
+ FILE *fp;
+ char buffer[50];
+ size_t nread, nbytes;
+
+ fp = fname ? fopen (fname, "r") : stdin;
+ if (!fp)
+ {
+ fprintf (stderr, "%s:%d: can't open '%s': %s\n",
+ __FILE__, __LINE__, fname? fname:"[stdin]", strerror (errno));
+ fail (0);
+ }
+
+ err = b64dec_start (&state, "");
+ if (err)
+ fail (1);
+
+ while ( (nread = fread (buffer, 1, sizeof buffer, fp)) )
+ {
+ err = b64dec_proc (&state, buffer, nread, &nbytes);
+ if (err)
+ {
+ if (gpg_err_code (err) == GPG_ERR_EOF)
+ break;
+ fail (2);
+ }
+ else if (nbytes)
+ fwrite (buffer, 1, nbytes, stdout);
+ }
+
+ err = b64dec_finish (&state);
+ if (err)
+ fail (3);
+
+ fclose (fp);
+ pass ();
+}
+
+
+
+int
+main (int argc, char **argv)
+{
+ int do_encode = 0;
+ int do_decode = 0;
+
+ if (argc)
+ { argc--; argv++; }
+ if (argc && !strcmp (argv[0], "--verbose"))
+ {
+ verbose = 1;
+ argc--; argv++;
+ }
+
+ if (argc && !strcmp (argv[0], "--encode"))
+ {
+ do_encode = 1;
+ argc--; argv++;
+ }
+ else if (argc && !strcmp (argv[0], "--decode"))
+ {
+ do_decode = 1;
+ argc--; argv++;
+ }
+
+ if (do_encode)
+ test_b64enc_file (argc? *argv: NULL);
+ else if (do_decode)
+ test_b64dec_file (argc? *argv: NULL);
+ else
+ test_b64enc_pgp (argc? *argv: NULL);
+
+ return !!errcount;
+}
diff --git a/common/t-ccparray.c b/common/t-ccparray.c
new file mode 100644
index 0000000..eb96526
--- /dev/null
+++ b/common/t-ccparray.c
@@ -0,0 +1,93 @@
+/* t-ccparray.c - Module test for ccparray.c
+ * Copyright (C) 2016 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "util.h"
+#include "ccparray.h"
+
+#define pass() do { ; } while(0)
+#define fail(a) do { fprintf (stderr, "%s:%d: test %d failed\n",\
+ __FILE__,__LINE__, (a)); \
+ exit (1); \
+ } while(0)
+
+
+static void
+run_test_1 (void)
+{
+ ccparray_t ccp;
+ const char **argv;
+ size_t nelem;
+
+ ccparray_init (&ccp, 0);
+ ccparray_put (&ccp, "First arg");
+ ccparray_put (&ccp, "Second arg");
+ ccparray_put (&ccp, NULL);
+ ccparray_put (&ccp, "Fourth arg");
+ argv = ccparray_get (&ccp, &nelem);
+ if (!argv)
+ {
+ fprintf (stderr, "error building array: %s\n", strerror (errno));
+ exit (1);
+ }
+
+ if (nelem != 4)
+ fail (1);
+
+ /* for (i=0; argv[i]; i++) */
+ /* printf ("[%d] = '%s'\n", i, argv[i]); */
+ xfree (argv);
+}
+
+
+static void
+run_test_var (int count)
+{
+ ccparray_t ccp;
+ size_t nelem;
+ int i;
+
+ ccparray_init (&ccp, 0);
+ for (i=0; i < count; i++)
+ ccparray_put (&ccp, "An arg");
+ xfree (ccparray_get (&ccp, &nelem));
+ if (nelem != i)
+ fail (2);
+}
+
+
+int
+main (int argc, char **argv)
+{
+ (void)argc;
+ (void)argv;
+
+ run_test_1 ();
+ run_test_var (0);
+ run_test_var (7);
+ run_test_var (8);
+ run_test_var (9);
+ run_test_var (4096);
+
+ return 0;
+}
diff --git a/common/t-convert.c b/common/t-convert.c
new file mode 100644
index 0000000..e25de90
--- /dev/null
+++ b/common/t-convert.c
@@ -0,0 +1,463 @@
+/* t-convert.c - Module test for convert.c
+ * Copyright (C) 2006, 2008 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "util.h"
+
+#define pass() do { ; } while(0)
+#define fail(a) do { fprintf (stderr, "%s:%d: test %d failed\n",\
+ __FILE__,__LINE__, (a)); \
+ /*exit (1)*/; \
+ } while(0)
+
+
+static void
+test_hex2bin (void)
+{
+ static const char *valid[] = {
+ "00112233445566778899aabbccddeeff11223344",
+ "00112233445566778899AABBCCDDEEFF11223344",
+ "00112233445566778899AABBCCDDEEFF11223344 blah",
+ "00112233445566778899AABBCCDDEEFF11223344\tblah",
+ "00112233445566778899AABBCCDDEEFF11223344\nblah",
+ NULL
+ };
+ static const char *invalid[] = {
+ "00112233445566778899aabbccddeeff1122334",
+ "00112233445566778899AABBCCDDEEFF1122334",
+ "00112233445566778899AABBCCDDEEFG11223344",
+ "00 112233445566778899aabbccddeeff11223344",
+ "00:112233445566778899aabbccddeeff11223344",
+ ":00112233445566778899aabbccddeeff11223344",
+ "0:0112233445566778899aabbccddeeff11223344",
+ "00112233445566778899aabbccddeeff11223344:",
+ "00112233445566778899aabbccddeeff112233445",
+ "00112233445566778899aabbccddeeff1122334455",
+ "00112233445566778899aabbccddeeff11223344blah",
+ NULL
+ };
+ static const char *valid2[] = {
+ "00",
+ "00 x",
+ NULL
+ };
+ static const char *invalid2[] = {
+ "",
+ "0",
+ "00:",
+ "00x",
+ " 00",
+ NULL
+ };
+ unsigned char buffer[20];
+ int len;
+ int i;
+
+
+ for (i=0; valid[i]; i++)
+ {
+ len = hex2bin (valid[i], buffer, sizeof buffer);
+ if (len < 0)
+ fail (i);
+ if (memcmp (buffer, ("\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa"
+ "\xbb\xcc\xdd\xee\xff\x11\x22\x33\x44"), 20))
+ fail (i);
+ }
+ if (hex2bin (valid[0], buffer, sizeof buffer) != 40)
+ fail (0);
+ if (hex2bin (valid[2], buffer, sizeof buffer) != 41)
+ fail (0);
+
+ for (i=0; invalid[i]; i++)
+ {
+ len = hex2bin (invalid[i], buffer, sizeof buffer);
+ if (!(len < 0))
+ fail (i);
+ }
+
+ for (i=0; valid2[i]; i++)
+ {
+ len = hex2bin (valid2[i], buffer, 1);
+ if (len < 0)
+ fail (i);
+ if (memcmp (buffer, "\x00", 1))
+ fail (i);
+ }
+ if (hex2bin (valid2[0], buffer, 1) != 2)
+ fail (0);
+ if (hex2bin (valid2[1], buffer, 1) != 3)
+ fail (0);
+
+ for (i=0; invalid2[i]; i++)
+ {
+ len = hex2bin (invalid2[i], buffer, 1);
+ if (!(len < 0))
+ fail (i);
+ }
+}
+
+
+
+static void
+test_hexcolon2bin (void)
+{
+ static const char *valid[] = {
+ "00112233445566778899aabbccddeeff11223344",
+ "00112233445566778899AABBCCDDEEFF11223344",
+ "00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:11:22:33:44",
+ "00112233445566778899AABBCCDDEEFF11223344 blah",
+ "00112233445566778899AABBCCDDEEFF11223344\tblah",
+ "00112233445566778899AABBCCDDEEFF11223344\nblah",
+ NULL
+ };
+ static const char *invalid[] = {
+ "00112233445566778899aabbccddeeff1122334",
+ "00112233445566778899AABBCCDDEEFF1122334",
+ "00112233445566778899AABBCCDDEEFG11223344",
+ ":00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:11:22:33:44",
+ "00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:11:22:33:44:",
+ "00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:11:22:3344",
+ "00:1122:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:11:22:33:44",
+ "0011:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:11:22:33:44",
+ "00 11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:11:22:33:44",
+ "00:11 22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:11:22:33:44",
+ "00112233445566778899aabbccddeeff112233445",
+ "00112233445566778899aabbccddeeff1122334455",
+ "00112233445566778899aabbccddeeff11223344blah",
+ NULL
+ };
+ static const char *valid2[] = {
+ "00",
+ "00 x",
+ NULL
+ };
+ static const char *invalid2[] = {
+ "",
+ "0",
+ "00:",
+ ":00",
+ "0:0",
+ "00x",
+ " 00",
+ NULL
+ };
+ unsigned char buffer[20];
+ int len;
+ int i;
+
+
+ for (i=0; valid[i]; i++)
+ {
+ len = hexcolon2bin (valid[i], buffer, sizeof buffer);
+ if (len < 0)
+ fail (i);
+ if (memcmp (buffer, ("\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa"
+ "\xbb\xcc\xdd\xee\xff\x11\x22\x33\x44"), 20))
+ fail (i);
+ }
+ if (hexcolon2bin (valid[0], buffer, sizeof buffer) != 40)
+ fail (0);
+ if (hexcolon2bin (valid[3], buffer, sizeof buffer) != 41)
+ fail (0);
+
+ for (i=0; invalid[i]; i++)
+ {
+ len = hexcolon2bin (invalid[i], buffer, sizeof buffer);
+ if (!(len < 0))
+ fail (i);
+ }
+
+ for (i=0; valid2[i]; i++)
+ {
+ len = hexcolon2bin (valid2[i], buffer, 1);
+ if (len < 0)
+ fail (i);
+ if (memcmp (buffer, "\x00", 1))
+ fail (i);
+ }
+ if (hexcolon2bin (valid2[0], buffer, 1) != 2)
+ fail (0);
+ if (hexcolon2bin (valid2[1], buffer, 1) != 3)
+ fail (0);
+
+ for (i=0; invalid2[i]; i++)
+ {
+ len = hexcolon2bin (invalid2[i], buffer, 1);
+ if (!(len < 0))
+ fail (i);
+ }
+
+
+}
+
+
+
+static void
+test_bin2hex (void)
+{
+ char stuff[20+1] = ("\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa"
+ "\xbb\xcc\xdd\xee\xff\x01\x10\x02\xa3");
+ char hexstuff[] = "00112233445566778899AABBCCDDEEFF011002A3";
+ char buffer[2*20+1];
+ char *p;
+
+ p = bin2hex (stuff, 20, buffer);
+ if (!p)
+ fail (0);
+ if (p != buffer)
+ fail (0);
+ if (strcmp (buffer, hexstuff))
+ fail (0);
+
+ p = bin2hex (stuff, 20, NULL);
+ if (!p)
+ fail (0);
+ else if (strcmp (p, hexstuff))
+ fail (0);
+ xfree (p);
+
+ p = bin2hex (stuff, (size_t)(-1), NULL);
+ if (p)
+ fail (0);
+ else if (errno != ENOMEM)
+ fail (1);
+}
+
+
+static void
+test_bin2hexcolon (void)
+{
+ char stuff[20+1] = ("\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa"
+ "\xbb\xcc\xdd\xee\xff\x01\x10\x02\xa3");
+ char hexstuff[] = ("00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF"
+ ":01:10:02:A3");
+ char buffer[3*20+1];
+ char *p;
+
+ p = bin2hexcolon (stuff, 20, buffer);
+ if (!p)
+ fail (0);
+ if (p != buffer)
+ fail (0);
+ if (strcmp (buffer, hexstuff))
+ fail (0);
+
+ p = bin2hexcolon (stuff, 20, NULL);
+ if (!p)
+ fail (0);
+ else if (strcmp (p, hexstuff))
+ fail (0);
+ xfree (p);
+
+ p = bin2hexcolon (stuff, (size_t)(-1), NULL);
+ if (p)
+ fail (0);
+ else if (errno != ENOMEM)
+ fail (1);
+}
+
+
+
+static void
+test_hex2str (void)
+{
+ static struct {
+ const char *hex;
+ const char *str;
+ int len; /* Length of STR. This may included embedded nuls. */
+ int off;
+ int no_alloc_test;
+ } tests[] = {
+ /* Simple tests. */
+ { "112233445566778899aabbccddeeff1122",
+ "\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff\x11\x22",
+ 17, 34 },
+ { "112233445566778899aabbccddeeff1122 blah",
+ "\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff\x11\x22",
+ 17, 34 },
+ { "112233445566778899aabbccddeeff1122\tblah",
+ "\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff\x11\x22",
+ 17, 34 },
+ { "112233445566778899aabbccddeeff1122\nblah",
+ "\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff\x11\x22",
+ 17, 34 },
+ /* Valid tests yielding an empty string. */
+ { "00",
+ "",
+ 1, 2 },
+ { "00 x",
+ "",
+ 1, 2 },
+ { "",
+ "",
+ 0, 0 },
+ { " ",
+ "",
+ 0, 0 },
+ /* Test trailing Nul feature. */
+ { "112233445566778899aabbccddeeff1100",
+ "\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff\x11\x00",
+ 17, 34 },
+ { "112233445566778899aabbccddeeff1100 ",
+ "\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff\x11\x00",
+ 17, 34 },
+ /* Test buffer size. (buffer is of length 20) */
+ { "6162636465666768696A6b6c6D6e6f70717273",
+ "abcdefghijklmnopqrs",
+ 19, 38 },
+ { "6162636465666768696A6b6c6D6e6f7071727300",
+ "abcdefghijklmnopqrs",
+ 20, 40 },
+ { "6162636465666768696A6b6c6D6e6f7071727374",
+ NULL,
+ 0, 0, 1 },
+ { "6162636465666768696A6b6c6D6e6f707172737400",
+ NULL,
+ 0, 0, 1 },
+ { "6162636465666768696A6b6c6D6e6f707172737475",
+ NULL,
+ 0, 0, 1 },
+
+ /* Invalid tests. */
+ { "112233445566778899aabbccddeeff1122334", NULL, 0, 0 },
+ { "112233445566778899AABBCCDDEEFF1122334", NULL, 0, 0 },
+ { "112233445566778899AABBCCDDEEFG11223344", NULL, 0, 0 },
+ { "0:0112233445566778899aabbccddeeff11223344", NULL, 0, 0 },
+ { "112233445566778899aabbccddeeff11223344:", NULL, 0, 0 },
+ { "112233445566778899aabbccddeeff112233445", NULL, 0, 0 },
+ { "112233445566778899aabbccddeeff1122334455", NULL, 0, 0, 1 },
+ { "112233445566778899aabbccddeeff11223344blah", NULL, 0, 0 },
+ { "0", NULL, 0, 0 },
+ { "00:", NULL, 0, 0 },
+ { "00x", NULL, 0, 0 },
+
+ { NULL, NULL, 0, 0 }
+ };
+
+ int idx;
+ char buffer[20];
+ const char *tail;
+ size_t count;
+ char *result;
+
+ for (idx=0; tests[idx].hex; idx++)
+ {
+ tail = hex2str (tests[idx].hex, buffer, sizeof buffer, &count);
+ if (tests[idx].str)
+ {
+ /* Good case test. */
+ if (!tail)
+ fail (idx);
+ else if (strcmp (tests[idx].str, buffer))
+ fail (idx);
+ else if (tail - tests[idx].hex != tests[idx].off)
+ fail (idx);
+ else if (tests[idx].len != count)
+ fail (idx);
+ }
+ else
+ {
+ /* Bad case test. */
+ if (tail)
+ fail (idx);
+ }
+ }
+
+ /* Same tests again using in-place conversion. */
+ for (idx=0; tests[idx].hex; idx++)
+ {
+ char tmpbuf[100];
+
+ assert (strlen (tests[idx].hex)+1 < sizeof tmpbuf);
+ strcpy (tmpbuf, tests[idx].hex);
+
+ /* Note: we still need to use 20 as buffer length because our
+ tests assume that. */
+ tail = hex2str (tmpbuf, tmpbuf, 20, &count);
+ if (tests[idx].str)
+ {
+ /* Good case test. */
+ if (!tail)
+ fail (idx);
+ else if (strcmp (tests[idx].str, tmpbuf))
+ fail (idx);
+ else if (tail - tmpbuf != tests[idx].off)
+ fail (idx);
+ else if (tests[idx].len != count)
+ fail (idx);
+ }
+ else
+ {
+ /* Bad case test. */
+ if (tail)
+ fail (idx);
+ if (strcmp (tmpbuf, tests[idx].hex))
+ fail (idx); /* Buffer was modified. */
+ }
+ }
+
+ /* Test the allocation variant. */
+ for (idx=0; tests[idx].hex; idx++)
+ {
+ if (tests[idx].no_alloc_test)
+ continue;
+
+ result = hex2str_alloc (tests[idx].hex, &count);
+ if (tests[idx].str)
+ {
+ /* Good case test. */
+ if (!result)
+ fail (idx);
+ else if (strcmp (tests[idx].str, result))
+ fail (idx);
+ else if (count != tests[idx].off)
+ fail (idx);
+ }
+ else
+ {
+ /* Bad case test. */
+ if (result)
+ fail (idx);
+ }
+ xfree (result);
+ }
+}
+
+
+
+
+
+int
+main (int argc, char **argv)
+{
+ (void)argc;
+ (void)argv;
+
+ test_hex2bin ();
+ test_hexcolon2bin ();
+ test_bin2hex ();
+ test_bin2hexcolon ();
+ test_hex2str ();
+
+ return 0;
+}
diff --git a/common/t-exechelp.c b/common/t-exechelp.c
new file mode 100644
index 0000000..cf967fc
--- /dev/null
+++ b/common/t-exechelp.c
@@ -0,0 +1,188 @@
+/* t-exechelp.c - Module test for exechelp.c
+ * Copyright (C) 2009 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+#include <unistd.h>
+
+#include "util.h"
+#include "exechelp.h"
+
+static int verbose;
+
+
+static void
+print_open_fds (int *array)
+{
+ int n;
+
+ if (!verbose)
+ return;
+
+ for (n=0; array[n] != -1; n++)
+ ;
+ printf ("open file descriptors: %d", n);
+ putchar (' ');
+ putchar (' ');
+ putchar ('(');
+ for (n=0; array[n] != -1; n++)
+ printf ("%d%s", array[n], array[n+1] == -1?"":" ");
+ putchar (')');
+ putchar ('\n');
+}
+
+
+static int *
+xget_all_open_fds (void)
+{
+ int *array;
+
+ array = get_all_open_fds ();
+ if (!array)
+ {
+ fprintf (stderr, "%s:%d: get_all_open_fds failed: %s\n",
+ __FILE__, __LINE__, strerror (errno));
+ exit (1);
+ }
+ return array;
+}
+
+
+/* That is a very crude test. To do a proper test we would need to
+ fork a test process and best return information by some other means
+ than file descriptors. */
+static void
+test_close_all_fds (void)
+{
+ int max_fd = get_max_fds ();
+ int *array;
+ int fd;
+ int initial_count, count, n;
+#if 0
+ char buffer[100];
+
+ snprintf (buffer, sizeof buffer, "/bin/ls -l /proc/%d/fd", (int)getpid ());
+ system (buffer);
+#endif
+
+ if (verbose)
+ printf ("max. file descriptors: %d\n", max_fd);
+ array = xget_all_open_fds ();
+ print_open_fds (array);
+ for (initial_count=n=0; array[n] != -1; n++)
+ initial_count++;
+ free (array);
+
+ /* Some dups to get more file descriptors and close one. */
+ dup (1);
+ dup (1);
+ fd = dup (1);
+ dup (1);
+ close (fd);
+
+ array = xget_all_open_fds ();
+ if (verbose)
+ print_open_fds (array);
+ for (count=n=0; array[n] != -1; n++)
+ count++;
+ if (count != initial_count+3)
+ {
+ fprintf (stderr, "%s:%d: dup or close failed\n",
+ __FILE__, __LINE__);
+ exit (1);
+ }
+ free (array);
+
+ /* Close the non standard ones. */
+ close_all_fds (3, NULL);
+
+ /* Get a list to check whether they are all closed. */
+ array = xget_all_open_fds ();
+ if (verbose)
+ print_open_fds (array);
+ for (count=n=0; array[n] != -1; n++)
+ count++;
+ if (count > initial_count)
+ {
+ fprintf (stderr, "%s:%d: not all files were closed\n",
+ __FILE__, __LINE__);
+ exit (1);
+ }
+ initial_count = count;
+ free (array);
+
+ /* Now let's check the realloc we use. We do this and the next
+ tests only if we are allowed to open enought descriptors. */
+ if (get_max_fds () > 32)
+ {
+ int except[] = { 20, 23, 24, -1 };
+
+ for (n=initial_count; n < 31; n++)
+ dup (1);
+ array = xget_all_open_fds ();
+ if (verbose)
+ print_open_fds (array);
+ free (array);
+ for (n=0; n < 5; n++)
+ {
+ dup (1);
+ array = xget_all_open_fds ();
+ if (verbose)
+ print_open_fds (array);
+ free (array);
+ }
+
+ /* Check whether the except list works. */
+ close_all_fds (3, except);
+ array = xget_all_open_fds ();
+ if (verbose)
+ print_open_fds (array);
+ for (count=n=0; array[n] != -1; n++)
+ count++;
+ free (array);
+
+ if (count != initial_count + DIM(except)-1)
+ {
+ fprintf (stderr, "%s:%d: close_all_fds failed\n",
+ __FILE__, __LINE__);
+ exit (1);
+ }
+ }
+
+}
+
+
+int
+main (int argc, char **argv)
+{
+ if (argc)
+ { argc--; argv++; }
+ if (argc && !strcmp (argv[0], "--verbose"))
+ {
+ verbose = 1;
+ argc--; argv++;
+ }
+
+ test_close_all_fds ();
+
+ return 0;
+}
diff --git a/common/t-exectool.c b/common/t-exectool.c
new file mode 100644
index 0000000..e1fffdc
--- /dev/null
+++ b/common/t-exectool.c
@@ -0,0 +1,237 @@
+/* t-exectool.c - Module test for exectool.c
+ * Copyright (C) 2016 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+#include <unistd.h>
+
+#include "util.h"
+#include "exectool.h"
+
+static int verbose;
+
+#define fail(msg, err) \
+ do { fprintf (stderr, "%s:%d: %s failed: %s\n", \
+ __FILE__,__LINE__, (msg), gpg_strerror (err)); \
+ exit (1); \
+ } while(0)
+
+static void
+test_executing_true (void)
+{
+ gpg_error_t err;
+ const char *pgmname = "/bin/true";
+ const char *alt_pgmname = "/usr/bin/true";
+ const char *argv[] = { NULL, NULL };
+ char *result;
+ size_t len;
+
+ /* Fixme: We should use gpgrt_access here. */
+ if (access (pgmname, X_OK))
+ {
+ if (access (alt_pgmname, X_OK))
+ {
+ fprintf (stderr, "skipping test: %s not executable: %s\n",
+ pgmname, strerror (errno));
+ return;
+ }
+ pgmname = alt_pgmname;
+ }
+
+ if (verbose)
+ fprintf (stderr, "Executing %s...\n", pgmname);
+
+ err = gnupg_exec_tool (pgmname, argv, "", &result, &len);
+ if (err)
+ fail ("gnupg_exec_tool", err);
+
+ assert (result);
+ assert (len == 0);
+ free (result);
+}
+
+static void
+test_executing_false (void)
+{
+ gpg_error_t err;
+ const char *pgmname = "/bin/false";
+ const char *alt_pgmname = "/usr/bin/false";
+ const char *argv[] = { NULL, NULL };
+ char *result;
+ size_t len;
+
+ if (access (pgmname, X_OK))
+ {
+ if (access (alt_pgmname, X_OK))
+ {
+ fprintf (stderr, "skipping test: %s not executable: %s\n",
+ pgmname, strerror (errno));
+ return;
+ }
+ pgmname = alt_pgmname;
+ }
+
+ if (verbose)
+ fprintf (stderr, "Executing %s...\n", pgmname);
+
+ err = gnupg_exec_tool (pgmname, argv, "", &result, &len);
+ assert (err == GPG_ERR_GENERAL);
+}
+
+
+static void
+test_executing_cat (const char *vector)
+{
+ gpg_error_t err;
+ const char *argv[] = { "/bin/cat", NULL };
+ char *result;
+ size_t len;
+
+ if (access (argv[0], X_OK))
+ {
+ fprintf (stderr, "skipping test: %s not executable: %s\n",
+ argv[0], strerror (errno));
+ return;
+ }
+
+ if (verbose)
+ fprintf (stderr, "Executing %s...\n", argv[0]);
+
+ err = gnupg_exec_tool (argv[0], &argv[1], vector, &result, &len);
+ if (err)
+ fail ("gnupg_exec_tool", err);
+
+ assert (result);
+
+ /* gnupg_exec_tool returns the correct length... */
+ assert (len == strlen (vector));
+ /* ... but 0-terminates data for ease of use. */
+ assert (result[len] == 0);
+
+ assert (strcmp (result, vector) == 0);
+ free (result);
+}
+
+
+static void
+test_catting_cat (void)
+{
+ gpg_error_t err;
+ const char *argv[] = { "/bin/cat", "/bin/cat", NULL };
+ char *result;
+ size_t len;
+ estream_t in;
+ char *reference, *p;
+ size_t reference_len;
+
+ if (access (argv[0], X_OK))
+ {
+ fprintf (stderr, "skipping test: %s not executable: %s\n",
+ argv[0], strerror (errno));
+ return;
+ }
+
+ in = es_fopen (argv[1], "r");
+ if (in == NULL)
+ {
+ fprintf (stderr, "skipping test: could not open %s: %s\n",
+ argv[1], strerror (errno));
+ return;
+ }
+
+ err = es_fseek (in, 0L, SEEK_END);
+ if (err)
+ {
+ fprintf (stderr, "skipping test: could not seek in %s: %s\n",
+ argv[1], gpg_strerror (err));
+ return;
+ }
+
+ reference_len = es_ftell (in);
+ err = es_fseek (in, 0L, SEEK_SET);
+ assert (!err || !"rewinding failed");
+
+ reference = malloc (reference_len);
+ assert (reference || !"allocating reference buffer failed");
+
+ for (p = reference; p - reference < reference_len; )
+ {
+ size_t bytes_read, left;
+ left = reference_len - (p - reference);
+ if (left > 4096)
+ left = 4096;
+ err = es_read (in, p, left, &bytes_read);
+ if (err)
+ {
+ fprintf (stderr, "error reading %s: %s",
+ argv[1], gpg_strerror (err));
+ exit (1);
+ }
+
+ p += bytes_read;
+ }
+ es_fclose (in);
+
+ if (verbose)
+ fprintf (stderr, "Executing %s %s...\n", argv[0], argv[1]);
+
+ err = gnupg_exec_tool (argv[0], &argv[1], "", &result, &len);
+ if (err)
+ fail ("gnupg_exec_tool", err);
+
+ assert (result);
+
+ /* gnupg_exec_tool returns the correct length... */
+ assert (len == reference_len);
+ assert (memcmp (result, reference, reference_len) == 0);
+ free (reference);
+ free (result);
+}
+
+
+int
+main (int argc, char **argv)
+{
+ int i;
+ char binjunk[256];
+
+ if (argc)
+ { argc--; argv++; }
+ if (argc && !strcmp (argv[0], "--verbose"))
+ {
+ verbose = 1;
+ argc--; argv++;
+ }
+
+ test_executing_true ();
+ test_executing_false ();
+ test_executing_cat ("Talking to myself here...");
+
+ for (i = 0; i < 255 /* one less */; i++)
+ binjunk[i] = i + 1; /* avoid 0 */
+ binjunk[255] = 0;
+
+ test_executing_cat (binjunk);
+ test_catting_cat ();
+
+ return 0;
+}
diff --git a/common/t-gettime.c b/common/t-gettime.c
new file mode 100644
index 0000000..13cb1a2
--- /dev/null
+++ b/common/t-gettime.c
@@ -0,0 +1,277 @@
+/* t-gettime.c - Module test for gettime.c
+ * Copyright (C) 2007, 2011 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+
+#include "util.h"
+
+/* In case we do not have stdint.h and no other version of that
+ * conversion macro provide shortcut it. */
+#ifndef UINTMAX_C
+#define UINTMAX_C (c) (c)
+#endif
+
+#define pass() do { ; } while(0)
+#define fail(a) do { fprintf (stderr, "%s:%d: test %d failed\n",\
+ __FILE__,__LINE__, (a)); \
+ errcount++; \
+ } while(0)
+
+static int verbose;
+static int errcount;
+#define INVALID ((time_t)(-1))
+
+
+static void
+test_isotime2epoch (void)
+{
+ struct { const char *string; time_t expected; } array [] = {
+ { "19700101T000001", 1 },
+ { "19700101T235959", 86399 },
+ { "19980815T143712", 903191832 },
+ { "19700101T000000", 0 },
+ { "19691231T235959", INVALID },
+ { "19000101T000000", INVALID },
+ { "", INVALID },
+ { "19000101T00000", INVALID },
+ { "20010101t123456", INVALID },
+ { "20010101T123456", 978352496 },
+ { "20070629T160000", 1183132800 },
+ { "20070629T160000:", 1183132800 },
+ { "20070629T160000,", 1183132800 },
+ { "20070629T160000 ", 1183132800 },
+ { "20070629T160000\n", 1183132800 },
+ { "20070629T160000.", INVALID },
+#if SIZEOF_TIME_T > 4
+ { "21060207T062815", (time_t)UINTMAX_C(0x0ffffffff) },
+ { "21060207T062816", (time_t)UINTMAX_C(0x100000000) },
+ { "21060207T062817", (time_t)UINTMAX_C(0x100000001) },
+ { "21060711T120001", (time_t)UINTMAX_C(4308292801) },
+#endif /*SIZEOF_TIME_T > 4*/
+ { NULL, 0 }
+ };
+ int idx;
+ time_t val;
+ gnupg_isotime_t tbuf;
+
+ for (idx=0; array[idx].string; idx++)
+ {
+ val = isotime2epoch (array[idx].string);
+ if (val != array[idx].expected )
+ {
+ fail (idx);
+ if (verbose)
+ fprintf (stderr, "string '%s' exp: %ld got: %ld\n",
+ array[idx].string, (long)array[idx].expected,
+ (long)val);
+ }
+ if (array[idx].expected != INVALID)
+ {
+ epoch2isotime (tbuf, val);
+ if (strlen (tbuf) != 15)
+ {
+ if (verbose)
+ fprintf (stderr, "string '%s', time-t %ld, revert: '%s'\n",
+ array[idx].string, (long)val, tbuf);
+ fail (idx);
+ }
+ if (strncmp (array[idx].string, tbuf, 15))
+ fail (idx);
+ }
+ }
+}
+
+
+
+static void
+test_string2isotime (void)
+{
+ struct {
+ const char *string;
+ size_t result;
+ const char *expected;
+ } array [] = {
+ { "19700101T000001", 15, "19700101T000001" },
+ { "19700101T235959", 15, "19700101T235959" },
+ { "19980815T143712", 15, "19980815T143712" },
+ { "19700101T000000", 15, "19700101T000000" },
+ { "19691231T235959", 15, "19691231T235959" },
+ { "19000101T000000", 15, "19000101T000000" },
+ { "", 0, "" },
+ { "19000101T00000", 0, "" },
+ { "20010101t123456", 0, "" },
+ { "20010101T123456", 15, "20010101T123456" },
+ { "20070629T160000", 15, "20070629T160000" },
+ { "20070629T160000:", 15, "20070629T160000" },
+ { "20070629T160000,", 15, "20070629T160000" },
+ { "20070629T160000 ", 15, "20070629T160000" },
+ { "20070629T160000\n", 15,"20070629T160000" },
+ { "20070629T160000.", 0, "" },
+ { "1066-03-20", 10, "10660320T000000" },
+ { "1066-03-20,", 10, "10660320T000000" },
+ { "1066-03-20:", 0, "" },
+ { "1066-03-20 00", 13, "10660320T000000" },
+ { "1066-03-20 01", 13, "10660320T010000" },
+ { "1066-03-20 23", 13, "10660320T230000" },
+ { "1066-03-20 24", 0, "" },
+ { "1066-03-20 00:", 0, "" },
+ { "1066-03-20 00:3", 0, "" },
+ { "1066-03-20 00:31", 16, "10660320T003100" },
+ { "1066-03-20 00:31:47", 19, "10660320T003147" },
+ { "1066-03-20 00:31:47 ", 19, "10660320T003147" },
+ { "1066-03-20 00:31:47,", 19, "10660320T003147" },
+ { "1066-03-20 00:31:47:", 0, "" },
+ { "1-03-20 00:31:47:", 0, "" },
+ { "10-03-20 00:31:47:", 0, "" },
+ { "106-03-20 00:31:47:", 0, "" },
+ { "1066-23-20 00:31:47:", 0, "" },
+ { "1066-00-20 00:31:47:", 0, "" },
+ { "1066-0-20 00:31:47:", 0, "" },
+ { "1066-01-2 00:31:47:", 0, "" },
+ { "1066-01-2 00:31:47:", 0, "" },
+ { "1066-01-32 00:31:47:", 0, "" },
+ { "1066-01-00 00:31:47:", 0, "" },
+ { "1066-03-20 00:31:47:",11, "10660320T000000" },
+ { "1066-03-2000:31:47:", 0, "" },
+ { "10666-03-20 00:31:47:", 0, "" },
+ { NULL, 0 }
+ };
+ int idx;
+ size_t result;
+ gnupg_isotime_t tbuf;
+
+ for (idx=0; array[idx].string; idx++)
+ {
+ result = string2isotime (tbuf, array[idx].string);
+ if (result != array[idx].result)
+ {
+ fail (idx);
+ if (verbose)
+ fprintf (stderr, "string '%s' expected: %d, got: %d\n",
+ array[idx].string, (int)array[idx].result, (int)result);
+ }
+ else if (result && strlen (tbuf) != 15)
+ {
+ fail (idx);
+ if (verbose)
+ fprintf (stderr, "string '%s' invalid isotime returned\n",
+ array[idx].string);
+ }
+ else if (result && strcmp (array[idx].expected, tbuf))
+ {
+ fail (idx);
+ if (verbose)
+ fprintf (stderr, "string '%s' bad isotime '%s' returned\n",
+ array[idx].string, tbuf);
+ }
+ }
+}
+
+
+static void
+test_isodate_human_to_tm (void)
+{
+ struct {
+ const char *string;
+ int okay;
+ int year, mon, mday;
+ } array [] = {
+ { "1970-01-01", 1, 1970, 1, 1 },
+ { "1970-02-01", 1, 1970, 2, 1 },
+ { "1970-12-31", 1, 1970, 12, 31 },
+ { "1971-01-01", 1, 1971, 1, 1 },
+ { "1998-08-15", 1, 1998, 8, 15 },
+ { "2015-04-10", 1, 2015, 4, 10 },
+ { "2015-04-10 11:30",1, 2015, 4, 10 },
+ { "1969-12-31", 0, 0, 0, 0 },
+ { "1900-01-01", 0, 0, 0, 0 },
+ { "", 0, 0, 0, 0 },
+ { "1970-12-32", 0, 0, 0, 0 },
+ { "1970-13-01", 0, 0, 0, 0 },
+ { "1970-01-00", 0, 0, 0, 0 },
+ { "1970-00-01", 0, 0, 0, 0 },
+ { "1970-00-01", 0, 0, 0, 0 },
+ { "1970", 0, 0, 0, 0 },
+ { "1970-01", 0, 0, 0, 0 },
+ { "1970-01-1", 0, 0, 0, 0 },
+ { "1970-1--01", 0, 0, 0, 0 },
+ { "1970-01-01,", 1, 1970, 1, 1 },
+ { "1970-01-01 ", 1, 1970, 1, 1 },
+ { "1970-01-01\t", 1, 1970, 1, 1 },
+ { "1970-01-01;", 0, 0, 0, 0 },
+ { "1970-01-01:", 0, 0, 0, 0 },
+ { "1970_01-01", 0, 0, 0, 0 },
+ { "1970-01_01", 0, 0, 0, 0 },
+ { NULL, 0 }
+ };
+ int idx;
+ int okay;
+ struct tm tmbuf;
+
+ for (idx=0; array[idx].string; idx++)
+ {
+ okay = !isodate_human_to_tm (array[idx].string, &tmbuf);
+ if (okay != array[idx].okay)
+ {
+ fail (idx);
+ if (verbose)
+ fprintf (stderr, "string '%s' expected: %d, got: %d\n",
+ array[idx].string, (int)array[idx].okay, okay);
+ }
+ else if (!okay)
+ ;
+ else if (tmbuf.tm_year + 1900 != array[idx].year
+ || tmbuf.tm_mon +1 != array[idx].mon
+ || tmbuf.tm_mday != array[idx].mday)
+ {
+ fail (idx);
+ if (verbose)
+ fprintf (stderr, "string '%s' returned %04d-%02d-%02d\n",
+ array[idx].string,
+ tmbuf.tm_year + 1900, tmbuf.tm_mon + 1, tmbuf.tm_mday);
+ }
+ else if (tmbuf.tm_sec || tmbuf.tm_min || tmbuf.tm_hour
+ || tmbuf.tm_isdst != -1)
+ {
+ fail (idx);
+ if (verbose)
+ fprintf (stderr, "string '%s' returned bad time part\n",
+ array[idx].string);
+ }
+ }
+}
+
+
+int
+main (int argc, char **argv)
+{
+ if (argc > 1 && !strcmp (argv[1], "--verbose"))
+ verbose = 1;
+
+ test_isotime2epoch ();
+ test_string2isotime ();
+ test_isodate_human_to_tm ();
+
+ return !!errcount;
+}
diff --git a/common/t-helpfile.c b/common/t-helpfile.c
new file mode 100644
index 0000000..0e2c79f
--- /dev/null
+++ b/common/t-helpfile.c
@@ -0,0 +1,66 @@
+/* t-helpfile.c - Module test for helpfile.c
+ * Copyright (C) 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "util.h"
+#include "i18n.h"
+
+/* #define pass() do { ; } while(0) */
+/* #define fail(a) do { fprintf (stderr, "%s:%d: test %d failed\n",\ */
+/* __FILE__,__LINE__, (a)); \ */
+/* errcount++; \ */
+/* } while(0) */
+
+static int verbose;
+static int errcount;
+
+
+
+int
+main (int argc, char **argv)
+{
+ char *result;
+
+ if (argc)
+ { argc--; argv++; }
+ i18n_init ();
+ if (argc && !strcmp (argv[0], "--verbose"))
+ {
+ verbose = 1;
+ argc--; argv++;
+ }
+
+ result = gnupg_get_help_string (argc? argv[0]:NULL, 0);
+ if (!result)
+ {
+ fprintf (stderr,
+ "Error: nothing found for '%s'\n", argc?argv[0]:"(null)");
+ errcount++;
+ }
+ else
+ {
+ printf ("key '%s' result='%s'\n", argc?argv[0]:"(null)", result);
+ xfree (result);
+ }
+
+ return !!errcount;
+}
diff --git a/common/t-iobuf.c b/common/t-iobuf.c
new file mode 100644
index 0000000..bdeab99
--- /dev/null
+++ b/common/t-iobuf.c
@@ -0,0 +1,394 @@
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#include "iobuf.h"
+#include "stringhelp.h"
+
+/* Return every other byte. In particular, reads two bytes, returns
+ the second one. */
+static int
+every_other_filter (void *opaque, int control,
+ iobuf_t chain, byte *buf, size_t *len)
+{
+ (void) opaque;
+
+ if (control == IOBUFCTRL_DESC)
+ {
+ mem2str (buf, "every_other_filter", *len);
+ }
+ if (control == IOBUFCTRL_UNDERFLOW)
+ {
+ int c = iobuf_readbyte (chain);
+ int c2;
+ if (c == -1)
+ c2 = -1;
+ else
+ c2 = iobuf_readbyte (chain);
+
+ /* printf ("Discarding %d (%c); return %d (%c)\n", c, c, c2, c2); */
+
+ if (c2 == -1)
+ {
+ *len = 0;
+ return -1;
+ }
+
+ *buf = c2;
+ *len = 1;
+
+ return 0;
+ }
+
+ return 0;
+}
+
+static int
+double_filter (void *opaque, int control,
+ iobuf_t chain, byte *buf, size_t *len)
+{
+ (void) opaque;
+
+ if (control == IOBUFCTRL_DESC)
+ {
+ mem2str (buf, "double_filter", *len);
+ }
+ if (control == IOBUFCTRL_FLUSH)
+ {
+ int i;
+
+ for (i = 0; i < *len; i ++)
+ {
+ int rc;
+
+ rc = iobuf_writebyte (chain, buf[i]);
+ if (rc)
+ return rc;
+ rc = iobuf_writebyte (chain, buf[i]);
+ if (rc)
+ return rc;
+ }
+ }
+
+ return 0;
+}
+
+struct content_filter_state
+{
+ int pos;
+ int len;
+ const char *buffer;
+};
+
+static struct content_filter_state *
+content_filter_new (const char *buffer)
+{
+ struct content_filter_state *state
+ = malloc (sizeof (struct content_filter_state));
+
+ state->pos = 0;
+ state->len = strlen (buffer);
+ state->buffer = buffer;
+
+ return state;
+}
+
+static int
+content_filter (void *opaque, int control,
+ iobuf_t chain, byte *buf, size_t *len)
+{
+ struct content_filter_state *state = opaque;
+
+ (void) chain;
+
+ if (control == IOBUFCTRL_UNDERFLOW)
+ {
+ int remaining = state->len - state->pos;
+ int toread = *len;
+ assert (toread > 0);
+
+ if (toread > remaining)
+ toread = remaining;
+
+ memcpy (buf, &state->buffer[state->pos], toread);
+
+ state->pos += toread;
+
+ *len = toread;
+
+ if (toread == 0)
+ return -1;
+ return 0;
+ }
+
+ return 0;
+}
+
+int
+main (int argc, char *argv[])
+{
+ (void) argc;
+ (void) argv;
+
+ /* A simple test to make sure filters work. We use a static buffer
+ and then add a filter in front of it that returns every other
+ character. */
+ {
+ char *content = "0123456789abcdefghijklm";
+ iobuf_t iobuf;
+ int c;
+ int n;
+ int rc;
+
+ iobuf = iobuf_temp_with_content (content, strlen (content));
+ rc = iobuf_push_filter (iobuf, every_other_filter, NULL);
+ assert (rc == 0);
+
+ n = 0;
+ while ((c = iobuf_readbyte (iobuf)) != -1)
+ {
+ /* printf ("%d: %c\n", n + 1, (char) c); */
+ assert (content[2 * n + 1] == c);
+ n ++;
+ }
+ /* printf ("Got EOF after reading %d bytes (content: %d)\n", */
+ /* n, strlen (content)); */
+ assert (n == strlen (content) / 2);
+
+ iobuf_close (iobuf);
+ }
+
+ /* A simple test to check buffering. Make sure that when we add a
+ filter to a pipeline, any buffered data gets processed by the */
+ {
+ char *content = "0123456789abcdefghijklm";
+ iobuf_t iobuf;
+ int c;
+ int n;
+ int rc;
+ int i;
+
+ iobuf = iobuf_temp_with_content (content, strlen (content));
+
+ n = 0;
+ for (i = 0; i < 10; i ++)
+ {
+ c = iobuf_readbyte (iobuf);
+ assert (content[i] == c);
+ n ++;
+ }
+
+ rc = iobuf_push_filter (iobuf, every_other_filter, NULL);
+ assert (rc == 0);
+
+ while ((c = iobuf_readbyte (iobuf)) != -1)
+ {
+ /* printf ("%d: %c\n", n + 1, (char) c); */
+ assert (content[2 * (n - 5) + 1] == c);
+ n ++;
+ }
+ assert (n == 10 + (strlen (content) - 10) / 2);
+
+ iobuf_close (iobuf);
+ }
+
+
+ /* A simple test to check that iobuf_read_line works. */
+ {
+ /* - 3 characters plus new line
+ - 4 characters plus new line
+ - 5 characters plus new line
+ - 5 characters, no new line
+ */
+ char *content = "abc\ndefg\nhijkl\nmnopq";
+ iobuf_t iobuf;
+ byte *buffer;
+ unsigned size;
+ unsigned max_len;
+ int n;
+
+ iobuf = iobuf_temp_with_content (content, strlen(content));
+
+ /* We read a line with 3 characters plus a newline. If we
+ allocate a buffer that is 5 bytes long, then no reallocation
+ should be required. */
+ size = 5;
+ buffer = malloc (size);
+ assert (buffer);
+ max_len = 100;
+ n = iobuf_read_line (iobuf, &buffer, &size, &max_len);
+ assert (n == 4);
+ assert (strcmp (buffer, "abc\n") == 0);
+ assert (size == 5);
+ assert (max_len == 100);
+ free (buffer);
+
+ /* We now read a line with 4 characters plus a newline. This
+ requires 6 bytes of storage. We pass a buffer that is 5 bytes
+ large and we allow the buffer to be grown. */
+ size = 5;
+ buffer = malloc (size);
+ max_len = 100;
+ n = iobuf_read_line (iobuf, &buffer, &size, &max_len);
+ assert (n == 5);
+ assert (strcmp (buffer, "defg\n") == 0);
+ assert (size >= 6);
+ /* The string shouldn't have been truncated (max_len == 0). */
+ assert (max_len == 100);
+ free (buffer);
+
+ /* We now read a line with 5 characters plus a newline. This
+ requires 7 bytes of storage. We pass a buffer that is 5 bytes
+ large and we don't allow the buffer to be grown. */
+ size = 5;
+ buffer = malloc (size);
+ max_len = 5;
+ n = iobuf_read_line (iobuf, &buffer, &size, &max_len);
+ assert (n == 4);
+ /* Note: the string should still have a trailing \n. */
+ assert (strcmp (buffer, "hij\n") == 0);
+ assert (size == 5);
+ /* The string should have been truncated (max_len == 0). */
+ assert (max_len == 0);
+ free (buffer);
+
+ /* We now read a line with 6 characters without a newline. This
+ requires 7 bytes of storage. We pass a NULL buffer and we
+ don't allow the buffer to be grown larger than 5 bytes. */
+ size = 5;
+ buffer = NULL;
+ max_len = 5;
+ n = iobuf_read_line (iobuf, &buffer, &size, &max_len);
+ assert (n == 4);
+ /* Note: the string should still have a trailing \n. */
+ assert (strcmp (buffer, "mno\n") == 0);
+ assert (size == 5);
+ /* The string should have been truncated (max_len == 0). */
+ assert (max_len == 0);
+ free (buffer);
+
+ iobuf_close (iobuf);
+ }
+
+ {
+ /* - 10 characters, EOF
+ - 17 characters, EOF
+ */
+ char *content = "abcdefghijklmnopq";
+ char *content2 = "0123456789";
+ iobuf_t iobuf;
+ int rc;
+ int c;
+ int n;
+ int lastc = 0;
+ struct content_filter_state *state;
+
+ iobuf = iobuf_temp_with_content (content, strlen(content));
+ rc = iobuf_push_filter (iobuf,
+ content_filter,
+ state=content_filter_new (content2));
+ assert (rc == 0);
+
+ n = 0;
+ while (1)
+ {
+ c = iobuf_readbyte (iobuf);
+ if (c == -1 && lastc == -1)
+ {
+ /* printf("Two EOFs in a row. Done.\n"); */
+ assert (n == 27);
+ break;
+ }
+
+ lastc = c;
+
+ if (c == -1)
+ {
+ /* printf("After %d bytes, got EOF.\n", n); */
+ assert (n == 10 || n == 27);
+ }
+ else
+ {
+ n ++;
+ /* printf ("%d: '%c' (%d)\n", n, c, c); */
+ }
+ }
+
+ iobuf_close (iobuf);
+ free (state);
+ }
+
+ /* Write some data to a temporary filter. Push a new filter. The
+ already written data should not be processed by the new
+ filter. */
+ {
+ iobuf_t iobuf;
+ int rc;
+ char *content = "0123456789";
+ char *content2 = "abc";
+ char buffer[4096];
+ int n;
+
+ iobuf = iobuf_temp ();
+ assert (iobuf);
+
+ rc = iobuf_write (iobuf, content, strlen (content));
+ assert (rc == 0);
+
+ rc = iobuf_push_filter (iobuf, double_filter, NULL);
+ assert (rc == 0);
+
+ /* Include a NUL. */
+ rc = iobuf_write (iobuf, content2, strlen (content2) + 1);
+ assert (rc == 0);
+
+ n = iobuf_temp_to_buffer (iobuf, buffer, sizeof (buffer));
+#if 0
+ printf ("Got %d bytes\n", n);
+ printf ("buffer: `");
+ fwrite (buffer, n, 1, stdout);
+ fputc ('\'', stdout);
+ fputc ('\n', stdout);
+#endif
+
+ assert (n == strlen (content) + 2 * (strlen (content2) + 1));
+ assert (strcmp (buffer, "0123456789aabbcc") == 0);
+
+ iobuf_close (iobuf);
+ }
+
+ {
+ iobuf_t iobuf;
+ int rc;
+ char content[] = "0123456789";
+ int n;
+ int c;
+ char buffer[10];
+
+ assert (sizeof buffer == sizeof content - 1);
+
+ iobuf = iobuf_temp_with_content (content, strlen (content));
+ assert (iobuf);
+
+ rc = iobuf_push_filter (iobuf, every_other_filter, NULL);
+ assert (rc == 0);
+ rc = iobuf_push_filter (iobuf, every_other_filter, NULL);
+ assert (rc == 0);
+
+ for (n = 0; (c = iobuf_get (iobuf)) != -1; n ++)
+ {
+ /* printf ("%d: `%c'\n", n, c); */
+ buffer[n] = c;
+ }
+
+ assert (n == 2);
+ assert (buffer[0] == '3');
+ assert (buffer[1] == '7');
+
+ iobuf_close (iobuf);
+ }
+
+ return 0;
+}
diff --git a/common/t-mapstrings.c b/common/t-mapstrings.c
new file mode 100644
index 0000000..7dc6221
--- /dev/null
+++ b/common/t-mapstrings.c
@@ -0,0 +1,126 @@
+/* t-mapstrings.c - Regression tests for mapstrings.c
+ * Copyright (C) 2014 Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "t-support.h"
+#include "stringhelp.h"
+
+static void
+test_map_static_macro_string (void)
+{
+ static struct {
+ const char *string;
+ const char *expected;
+ const char *lastresult;
+ } tests[] = {
+ { "@GPG@ (@GNUPG@)",
+ GPG_NAME " (" GNUPG_NAME ")" },
+ { "@GPG@(@GNUPG@)",
+ GPG_NAME "(" GNUPG_NAME ")" },
+ { "@GPG@@GNUPG@",
+ GPG_NAME GNUPG_NAME },
+ { " @GPG@@GNUPG@",
+ " " GPG_NAME GNUPG_NAME },
+ { " @GPG@@GNUPG@ ",
+ " " GPG_NAME GNUPG_NAME " " },
+ { " @GPG@GNUPG@ ",
+ " " GPG_NAME "GNUPG@ " },
+ { " @ GPG@GNUPG@ ",
+ " @ GPG" GNUPG_NAME " " },
+ { "--@GPGTAR@",
+ "--" GPGTAR_NAME }
+ };
+ int testno;
+ const char *result;
+
+ for (testno=0; testno < DIM(tests); testno++)
+ {
+ result = map_static_macro_string (tests[testno].string);
+ if (!result)
+ fail (testno);
+ else if (strcmp (result, tests[testno].expected))
+ fail (testno);
+ if (!tests[testno].lastresult)
+ tests[testno].lastresult = result;
+ }
+
+ /* A second time to check that the same string is been returned. */
+ for (testno=0; testno < DIM(tests); testno++)
+ {
+ result = map_static_macro_string (tests[testno].string);
+ if (!result)
+ fail (testno);
+ else if (strcmp (result, tests[testno].expected))
+ fail (testno);
+ if (result != tests[testno].lastresult)
+ fail (testno);
+ }
+}
+
+
+static void
+test_map_static_strings (void)
+{
+ const char *s, *s1;
+
+ s1 = map_static_strings ("mydomain", 0, 42,
+ "This", " ", "is", " ", "my"," ","string", NULL);
+ if (strcmp (s1, "This is my string"))
+ fail (1);
+ s = map_static_strings ("mydomain", 0, 42,
+ "This", " ", "is", " ", "my"," ","string", NULL);
+ if (strcmp (s1, s))
+ fail (2);
+ s = map_static_strings ("mydomain", 0, 42, "foo", NULL);
+ if (strcmp (s1, s))
+ fail (3);
+ s = map_static_strings ("mydomain", 1, 42, "foo 1.42", NULL);
+ if (!strcmp (s1, s))
+ fail (4);
+ s = map_static_strings ("xdomain", 1, 42, "foo 1.42 other domain", NULL);
+ if (!strcmp (s1, s))
+ fail (5);
+}
+
+
+int
+main (int argc, char **argv)
+{
+ (void)argc;
+ (void)argv;
+
+ test_map_static_macro_string ();
+ test_map_static_strings ();
+
+ return 0;
+}
diff --git a/common/t-mbox-util.c b/common/t-mbox-util.c
new file mode 100644
index 0000000..fb1ac12
--- /dev/null
+++ b/common/t-mbox-util.c
@@ -0,0 +1,156 @@
+/* t-mbox-util.c - Module test for mbox-util.c
+ * Copyright (C) 2015 Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "util.h"
+#include "mbox-util.h"
+
+#define pass() do { ; } while(0)
+#define fail(a) do { fprintf (stderr, "%s:%d: test %d failed\n",\
+ __FILE__,__LINE__, (a)); \
+ exit (1); \
+ } while(0)
+
+
+static void
+run_mbox_test (void)
+{
+ static struct
+ {
+ const char *userid;
+ const char *mbox;
+ } testtbl[] =
+ {
+ { "Werner Koch <wk@gnupg.org>", "wk@gnupg.org" },
+ { "<wk@gnupg.org>", "wk@gnupg.org" },
+ { "wk@gnupg.org", "wk@gnupg.org" },
+ { "wk@gnupg.org ", NULL },
+ { " wk@gnupg.org", NULL },
+ { "Werner Koch (test) <wk@gnupg.org>", "wk@gnupg.org" },
+ { "Werner Koch <wk@gnupg.org> (test)", "wk@gnupg.org" },
+ { "Werner Koch <wk@gnupg.org (test)", NULL },
+ { "Werner Koch <wk@gnupg.org >", NULL },
+ { "Werner Koch <wk@gnupg.org", NULL },
+ { "", NULL },
+ { "@", NULL },
+ { "bar <>", NULL },
+ { "<foo@example.org>", "foo@example.org" },
+ { "<foo.@example.org>", "foo.@example.org" },
+ { "<.foo.@example.org>", ".foo.@example.org" },
+ { "<foo..@example.org>", "foo..@example.org" },
+ { "<foo..bar@example.org>", "foo..bar@example.org" },
+ { "<foo@example.org.>", NULL },
+ { "<foo@example..org>", NULL },
+ { "<foo@.>", NULL },
+ { "<@example.org>", NULL },
+ { "<foo@@example.org>", NULL },
+ { "<@foo@example.org>", NULL },
+ { "<foo@example.org> ()", "foo@example.org" },
+ { "<fo()o@example.org> ()", "fo()o@example.org" },
+ { "<fo()o@example.org> ()", "fo()o@example.org" },
+ { "fo()o@example.org", NULL},
+ { "Mr. Foo <foo@example.org><bar@example.net>", "foo@example.org"},
+ { NULL, NULL }
+ };
+ int idx;
+
+ for (idx=0; testtbl[idx].userid; idx++)
+ {
+ char *mbox = mailbox_from_userid (testtbl[idx].userid);
+
+ if (!testtbl[idx].mbox)
+ {
+ if (mbox)
+ fail (idx);
+ }
+ else if (!mbox)
+ fail (idx);
+ else if (strcmp (mbox, testtbl[idx].mbox))
+ fail (idx);
+
+ xfree (mbox);
+ }
+}
+
+
+static void
+run_dns_test (void)
+{
+ static struct
+ {
+ const char *name;
+ int valid;
+ } testtbl[] =
+ {
+ { "", 0 },
+ { ".", 0 },
+ { "-", 0 },
+ { "a", 1 },
+ { "ab", 1 },
+ { "a.b", 1 },
+ { "a.b.", 1 },
+ { ".a.b.", 0 },
+ { ".a.b", 0 },
+ { "-a.b", 0 },
+ { "a-.b", 0 },
+ { "a.-b", 0 },
+ { "a.b-", 0 },
+ { "a.b-.", 0 },
+ { "a..b", 0 },
+ { "ab.c", 1 },
+ { "a-b.c", 1 },
+ { "a-b-.c", 0 },
+ { "-a-b.c", 0 },
+ { "example.org", 1 },
+ { "x.example.org", 1 },
+ { "xy.example.org", 1 },
+ { "Xy.example.org", 1 },
+ { "-Xy.example.org", 0 },
+ { "Xy.example-.org", 0 },
+ { "foo.example.org..", 0 },
+ { "foo.example.org.", 1 },
+ { ".foo.example.org.", 0 },
+ { "..foo.example.org.", 0 },
+ { NULL, 0 }
+ };
+ int idx;
+
+ for (idx=0; testtbl[idx].name; idx++)
+ {
+ if (is_valid_domain_name (testtbl[idx].name) != testtbl[idx].valid)
+ fail (idx);
+ }
+}
+
+
+int
+main (int argc, char **argv)
+{
+ (void)argc;
+ (void)argv;
+
+ run_mbox_test ();
+ run_dns_test ();
+
+ return 0;
+}
diff --git a/common/t-name-value.c b/common/t-name-value.c
new file mode 100644
index 0000000..57f685f
--- /dev/null
+++ b/common/t-name-value.c
@@ -0,0 +1,593 @@
+/* t-name-value.c - Module test for name-value.c
+ * Copyright (C) 2016 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include "util.h"
+#include "name-value.h"
+
+static int verbose;
+static int private_key_mode;
+
+
+static nvc_t
+my_nvc_new (void)
+{
+ if (private_key_mode)
+ return nvc_new_private_key ();
+ else
+ return nvc_new ();
+}
+
+
+void
+test_getting_values (nvc_t pk)
+{
+ nve_t e;
+
+ e = nvc_lookup (pk, "Comment:");
+ assert (e);
+
+ /* Names are case-insensitive. */
+ e = nvc_lookup (pk, "comment:");
+ assert (e);
+ e = nvc_lookup (pk, "COMMENT:");
+ assert (e);
+
+ e = nvc_lookup (pk, "SomeOtherName:");
+ assert (e);
+}
+
+
+void
+test_key_extraction (nvc_t pk)
+{
+ gpg_error_t err;
+ gcry_sexp_t key;
+
+ if (private_key_mode)
+ {
+ err = nvc_get_private_key (pk, &key);
+ assert (err == 0);
+ assert (key);
+
+ if (verbose)
+ gcry_sexp_dump (key);
+
+ gcry_sexp_release (key);
+ }
+ else
+ {
+ err = nvc_get_private_key (pk, &key);
+ assert (gpg_err_code (err) == GPG_ERR_MISSING_KEY);
+ }
+}
+
+
+void
+test_iteration (nvc_t pk)
+{
+ int i;
+ nve_t e;
+
+ i = 0;
+ for (e = nvc_first (pk); e; e = nve_next (e))
+ i++;
+ assert (i == 4);
+
+ i = 0;
+ for (e = nvc_lookup (pk, "Comment:");
+ e;
+ e = nve_next_value (e, "Comment:"))
+ i++;
+ assert (i == 3);
+}
+
+
+void
+test_whitespace (nvc_t pk)
+{
+ nve_t e;
+
+ e = nvc_lookup (pk, "One:");
+ assert (e);
+ assert (strcmp (nve_value (e), "WithoutWhitespace") == 0);
+
+ e = nvc_lookup (pk, "Two:");
+ assert (e);
+ assert (strcmp (nve_value (e), "With Whitespace") == 0);
+
+ e = nvc_lookup (pk, "Three:");
+ assert (e);
+ assert (strcmp (nve_value (e),
+ "Blank lines in continuations encode newlines.\n"
+ "Next paragraph.") == 0);
+}
+
+
+struct
+{
+ char *value;
+ void (*test_func) (nvc_t);
+} tests[] =
+ {
+ {
+ "# This is a comment followed by an empty line\n"
+ "\n",
+ NULL,
+ },
+ {
+ "# This is a comment followed by two empty lines, Windows style\r\n"
+ "\r\n"
+ "\r\n",
+ NULL,
+ },
+ {
+ "# Some name,value pairs\n"
+ "Comment: Some comment.\n"
+ "SomeOtherName: Some value.\n",
+ test_getting_values,
+ },
+ {
+ " # Whitespace is preserved as much as possible\r\n"
+ "Comment:Some comment.\n"
+ "SomeOtherName: Some value. \n",
+ test_getting_values,
+ },
+ {
+ "# Values may be continued in the next line as indicated by leading\n"
+ "# space\n"
+ "Comment: Some rather long\n"
+ " comment that is continued in the next line.\n"
+ "\n"
+ " Blank lines with or without whitespace are allowed within\n"
+ " continuations to allow paragraphs.\n"
+ "SomeOtherName: Some value.\n",
+ test_getting_values,
+ },
+ {
+ "# Names may be given multiple times forming an array of values\n"
+ "Comment: Some comment, element 0.\n"
+ "Comment: Some comment, element 1.\n"
+ "Comment: Some comment, element 2.\n"
+ "SomeOtherName: Some value.\n",
+ test_iteration,
+ },
+ {
+ "# One whitespace at the beginning of a continuation is swallowed.\n"
+ "One: Without\n"
+ " Whitespace\n"
+ "Two: With\n"
+ " Whitespace\n"
+ "Three: Blank lines in continuations encode newlines.\n"
+ "\n"
+ " Next paragraph.\n",
+ test_whitespace,
+ },
+ {
+ "Description: Key to sign all GnuPG released tarballs.\n"
+ " The key is actually stored on a smart card.\n"
+ "Use-for-ssh: yes\n"
+ "OpenSSH-cert: long base64 encoded string wrapped so that this\n"
+ " key file can be easily edited with a standard editor.\n"
+ "Key: (shadowed-private-key\n"
+ " (rsa\n"
+ " (n #00AA1AD2A55FD8C8FDE9E1941772D9CC903FA43B268CB1B5A1BAFDC900\n"
+ " 2961D8AEA153424DC851EF13B83AC64FBE365C59DC1BD3E83017C90D4365B4\n"
+ " 83E02859FC13DB5842A00E969480DB96CE6F7D1C03600392B8E08EF0C01FC7\n"
+ " 19F9F9086B25AD39B4F1C2A2DF3E2BE317110CFFF21D4A11455508FE407997\n"
+ " 601260816C8422297C0637BB291C3A079B9CB38A92CE9E551F80AA0EBF4F0E\n"
+ " 72C3F250461E4D31F23A7087857FC8438324A013634563D34EFDDCBF2EA80D\n"
+ " F9662C9CCD4BEF2522D8BDFED24CEF78DC6B309317407EAC576D889F88ADA0\n"
+ " 8C4FFB480981FB68C5C6CA27503381D41018E6CDC52AAAE46B166BDC10637A\n"
+ " E186A02BA2497FDC5D1221#)\n"
+ " (e #00010001#)\n"
+ " (shadowed t1-v1\n"
+ " (#D2760001240102000005000011730000# OPENPGP.1)\n"
+ " )))\n",
+ test_key_extraction,
+ },
+ };
+
+
+static char *
+nvc_to_string (nvc_t pk)
+{
+ gpg_error_t err;
+ char *buf;
+ size_t len;
+ estream_t sink;
+
+ sink = es_fopenmem (0, "rw");
+ assert (sink);
+
+ err = nvc_write (pk, sink);
+ assert (err == 0);
+
+ len = es_ftell (sink);
+ buf = xmalloc (len+1);
+ assert (buf);
+
+ es_fseek (sink, 0, SEEK_SET);
+ es_read (sink, buf, len, NULL);
+ buf[len] = 0;
+
+ es_fclose (sink);
+ return buf;
+}
+
+
+void dummy_free (void *p) { (void) p; }
+void *dummy_realloc (void *p, size_t s) { (void) s; return p; }
+
+void
+run_tests (void)
+{
+ gpg_error_t err;
+ nvc_t pk;
+
+ int i;
+ for (i = 0; i < DIM (tests); i++)
+ {
+ estream_t source;
+ char *buf;
+ size_t len;
+
+ len = strlen (tests[i].value);
+ source = es_mopen (tests[i].value, len, len,
+ 0, dummy_realloc, dummy_free, "r");
+ assert (source);
+
+ if (private_key_mode)
+ err = nvc_parse_private_key (&pk, NULL, source);
+ else
+ err = nvc_parse (&pk, NULL, source);
+ assert (err == 0);
+ assert (pk);
+
+ if (verbose)
+ {
+ err = nvc_write (pk, es_stderr);
+ assert (err == 0);
+ }
+
+ buf = nvc_to_string (pk);
+ assert (memcmp (tests[i].value, buf, len) == 0);
+
+ es_fclose (source);
+ xfree (buf);
+
+ if (tests[i].test_func)
+ tests[i].test_func (pk);
+
+ nvc_release (pk);
+ }
+}
+
+
+void
+run_modification_tests (void)
+{
+ gpg_error_t err;
+ nvc_t pk;
+ gcry_sexp_t key;
+ char *buf;
+
+ pk = my_nvc_new ();
+ assert (pk);
+
+ nvc_set (pk, "Foo:", "Bar");
+ buf = nvc_to_string (pk);
+ assert (strcmp (buf, "Foo: Bar\n") == 0);
+ xfree (buf);
+
+ nvc_set (pk, "Foo:", "Baz");
+ buf = nvc_to_string (pk);
+ assert (strcmp (buf, "Foo: Baz\n") == 0);
+ xfree (buf);
+
+ nvc_set (pk, "Bar:", "Bazzel");
+ buf = nvc_to_string (pk);
+ assert (strcmp (buf, "Foo: Baz\nBar: Bazzel\n") == 0);
+ xfree (buf);
+
+ nvc_add (pk, "Foo:", "Bar");
+ buf = nvc_to_string (pk);
+ assert (strcmp (buf, "Foo: Baz\nFoo: Bar\nBar: Bazzel\n") == 0);
+ xfree (buf);
+
+ nvc_add (pk, "DontExistYet:", "Bar");
+ buf = nvc_to_string (pk);
+ assert (strcmp (buf, "Foo: Baz\nFoo: Bar\nBar: Bazzel\nDontExistYet: Bar\n")
+ == 0);
+ xfree (buf);
+
+ nvc_delete (pk, nvc_lookup (pk, "DontExistYet:"));
+ buf = nvc_to_string (pk);
+ assert (strcmp (buf, "Foo: Baz\nFoo: Bar\nBar: Bazzel\n") == 0);
+ xfree (buf);
+
+ nvc_delete (pk, nve_next_value (nvc_lookup (pk, "Foo:"), "Foo:"));
+ buf = nvc_to_string (pk);
+ assert (strcmp (buf, "Foo: Baz\nBar: Bazzel\n") == 0);
+ xfree (buf);
+
+ nvc_delete (pk, nvc_lookup (pk, "Foo:"));
+ buf = nvc_to_string (pk);
+ assert (strcmp (buf, "Bar: Bazzel\n") == 0);
+ xfree (buf);
+
+ nvc_delete (pk, nvc_first (pk));
+ buf = nvc_to_string (pk);
+ assert (strcmp (buf, "") == 0);
+ xfree (buf);
+
+ nvc_set (pk, "Foo:", "A really long value spanning across multiple lines"
+ " that has to be wrapped at a convenient space.");
+ buf = nvc_to_string (pk);
+ assert (strcmp (buf, "Foo: A really long value spanning across multiple"
+ " lines that has to be\n wrapped at a convenient space.\n")
+ == 0);
+ xfree (buf);
+
+ nvc_set (pk, "Foo:", "XA really long value spanning across multiple lines"
+ " that has to be wrapped at a convenient space.");
+ buf = nvc_to_string (pk);
+ assert (strcmp (buf, "Foo: XA really long value spanning across multiple"
+ " lines that has to\n be wrapped at a convenient space.\n")
+ == 0);
+ xfree (buf);
+
+ nvc_set (pk, "Foo:", "XXXXA really long value spanning across multiple lines"
+ " that has to be wrapped at a convenient space.");
+ buf = nvc_to_string (pk);
+ assert (strcmp (buf, "Foo: XXXXA really long value spanning across multiple"
+ " lines that has\n to be wrapped at a convenient space.\n")
+ == 0);
+ xfree (buf);
+
+ nvc_set (pk, "Foo:", "Areallylongvaluespanningacrossmultiplelines"
+ "thathastobewrappedataconvenientspacethatisnotthere.");
+ buf = nvc_to_string (pk);
+ assert (strcmp (buf, "Foo: Areallylongvaluespanningacrossmultiplelinesthat"
+ "hastobewrappedataco\n nvenientspacethatisnotthere.\n")
+ == 0);
+ xfree (buf);
+ nvc_release (pk);
+
+ pk = my_nvc_new ();
+ assert (pk);
+
+ err = gcry_sexp_build (&key, NULL, "(hello world)");
+ assert (err == 0);
+ assert (key);
+
+ if (private_key_mode)
+ {
+ err = nvc_set_private_key (pk, key);
+ assert (err == 0);
+
+ buf = nvc_to_string (pk);
+ assert (strcmp (buf, "Key: (hello world)\n") == 0);
+ xfree (buf);
+ }
+ else
+ {
+ err = nvc_set_private_key (pk, key);
+ assert (gpg_err_code (err) == GPG_ERR_MISSING_KEY);
+ }
+ gcry_sexp_release (key);
+ nvc_release (pk);
+}
+
+
+void
+convert (const char *fname)
+{
+ gpg_error_t err;
+ estream_t source;
+ gcry_sexp_t key;
+ char *buf;
+ size_t buflen;
+ struct stat st;
+ nvc_t pk;
+
+ source = es_fopen (fname, "rb");
+ if (source == NULL)
+ goto leave;
+
+ if (fstat (es_fileno (source), &st))
+ goto leave;
+
+ buflen = st.st_size;
+ buf = xtrymalloc (buflen+1);
+ assert (buf);
+
+ if (es_fread (buf, buflen, 1, source) != 1)
+ goto leave;
+
+ err = gcry_sexp_sscan (&key, NULL, buf, buflen);
+ if (err)
+ {
+ fprintf (stderr, "malformed s-expression in %s\n", fname);
+ exit (1);
+ }
+
+ pk = my_nvc_new ();
+ assert (pk);
+
+ err = nvc_set_private_key (pk, key);
+ assert (err == 0);
+
+ err = nvc_write (pk, es_stdout);
+ assert (err == 0);
+
+ return;
+
+ leave:
+ perror (fname);
+ exit (1);
+}
+
+
+void
+parse (const char *fname)
+{
+ gpg_error_t err;
+ estream_t source;
+ char *buf;
+ nvc_t pk_a, pk_b;
+ nve_t e;
+ int line;
+
+ source = es_fopen (fname, "rb");
+ if (source == NULL)
+ {
+ perror (fname);
+ exit (1);
+ }
+
+ if (private_key_mode)
+ err = nvc_parse_private_key (&pk_a, &line, source);
+ else
+ err = nvc_parse (&pk_a, &line, source);
+ if (err)
+ {
+ fprintf (stderr, "failed to parse %s line %d: %s\n",
+ fname, line, gpg_strerror (err));
+ exit (1);
+ }
+
+ buf = nvc_to_string (pk_a);
+ xfree (buf);
+
+ pk_b = my_nvc_new ();
+ assert (pk_b);
+
+ for (e = nvc_first (pk_a); e; e = nve_next (e))
+ {
+ gcry_sexp_t key = NULL;
+
+ if (private_key_mode && !strcasecmp (nve_name (e), "Key:"))
+ {
+ err = nvc_get_private_key (pk_a, &key);
+ if (err)
+ key = NULL;
+ }
+
+ if (key)
+ {
+ err = nvc_set_private_key (pk_b, key);
+ assert (err == 0);
+ }
+ else
+ {
+ err = nvc_add (pk_b, nve_name (e), nve_value (e));
+ assert (err == 0);
+ }
+ }
+
+ buf = nvc_to_string (pk_b);
+ if (verbose)
+ fprintf (stdout, "%s", buf);
+ xfree (buf);
+}
+
+
+void
+print_usage (void)
+{
+ fprintf (stderr,
+ "usage: t-private-keys [--verbose]"
+ " [--convert <private-key-file>"
+ " || --parse-key <extended-private-key-file>"
+ " || --parse <file> ]\n");
+ exit (2);
+}
+
+
+int
+main (int argc, char **argv)
+{
+ enum { TEST, CONVERT, PARSE, PARSEKEY } command = TEST;
+
+ if (argc)
+ { argc--; argv++; }
+ if (argc && !strcmp (argv[0], "--verbose"))
+ {
+ verbose = 1;
+ argc--; argv++;
+ }
+
+ if (argc && !strcmp (argv[0], "--convert"))
+ {
+ command = CONVERT;
+ argc--; argv++;
+ if (argc != 1)
+ print_usage ();
+ }
+
+ if (argc && !strcmp (argv[0], "--parse-key"))
+ {
+ command = PARSEKEY;
+ argc--; argv++;
+ if (argc != 1)
+ print_usage ();
+ }
+
+ if (argc && !strcmp (argv[0], "--parse"))
+ {
+ command = PARSE;
+ argc--; argv++;
+ if (argc != 1)
+ print_usage ();
+ }
+
+ switch (command)
+ {
+ case TEST:
+ run_tests ();
+ run_modification_tests ();
+ private_key_mode = 1;
+ run_tests ();
+ run_modification_tests ();
+ break;
+
+ case CONVERT:
+ convert (*argv);
+ break;
+
+ case PARSEKEY:
+ private_key_mode = 1;
+ parse (*argv);
+ break;
+
+ case PARSE:
+ parse (*argv);
+ break;
+ }
+
+ return 0;
+}
diff --git a/common/t-openpgp-oid.c b/common/t-openpgp-oid.c
new file mode 100644
index 0000000..fd9de5d
--- /dev/null
+++ b/common/t-openpgp-oid.c
@@ -0,0 +1,246 @@
+/* t-openpgp-oid.c - Module test for openpgp-oid.c
+ * Copyright (C) 2011 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "util.h"
+
+#define pass() do { ; } while(0)
+#define fail(a,e) \
+ do { fprintf (stderr, "%s:%d: test %d failed (%s)\n", \
+ __FILE__,__LINE__, (a), gpg_strerror (e)); \
+ exit (1); \
+ } while(0)
+
+
+#define BADOID "1.3.6.1.4.1.11591.2.12242973"
+
+
+static int verbose;
+
+
+
+static void
+test_openpgp_oid_from_str (void)
+{
+ static char *sample_oids[] =
+ {
+ "0.0",
+ "1.0",
+ "1.2.3",
+ "1.2.840.10045.3.1.7",
+ "1.3.132.0.34",
+ "1.3.132.0.35",
+ NULL
+ };
+ gpg_error_t err;
+ gcry_mpi_t a;
+ int idx;
+ char *string;
+ unsigned char *p;
+ unsigned int nbits;
+ size_t length;
+
+ err = openpgp_oid_from_str ("", &a);
+ if (gpg_err_code (err) != GPG_ERR_INV_VALUE)
+ fail (0, err);
+ gcry_mpi_release (a);
+
+ err = openpgp_oid_from_str (".", &a);
+ if (gpg_err_code (err) != GPG_ERR_INV_OID_STRING)
+ fail (0, err);
+ gcry_mpi_release (a);
+
+ err = openpgp_oid_from_str ("0", &a);
+ if (gpg_err_code (err) != GPG_ERR_INV_OID_STRING)
+ fail (0, err);
+ gcry_mpi_release (a);
+
+ for (idx=0; sample_oids[idx]; idx++)
+ {
+ err = openpgp_oid_from_str (sample_oids[idx], &a);
+ if (err)
+ fail (idx, err);
+
+ string = openpgp_oid_to_str (a);
+ if (!string)
+ fail (idx, gpg_error_from_syserror ());
+ if (strcmp (string, sample_oids[idx]))
+ fail (idx, 0);
+ xfree (string);
+
+ p = gcry_mpi_get_opaque (a, &nbits);
+ length = (nbits+7)/8;
+ if (!p || !length || p[0] != length - 1)
+ fail (idx, 0);
+
+ gcry_mpi_release (a);
+ }
+
+}
+
+
+static void
+test_openpgp_oid_to_str (void)
+{
+ static struct {
+ const char *string;
+ unsigned char der[10];
+ } samples[] = {
+ { "1.2.840.10045.3.1.7",
+ {8, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07 }},
+
+ { "1.3.132.0.34",
+ {5, 0x2B, 0x81, 0x04, 0x00, 0x22 }},
+
+ { "1.3.132.0.35",
+ { 5, 0x2B, 0x81, 0x04, 0x00, 0x23 }},
+
+ { BADOID,
+ { 9, 0x80, 0x02, 0x70, 0x50, 0x25, 0x46, 0xfd, 0x0c, 0xc0 }},
+
+ { BADOID,
+ { 1, 0x80 }},
+
+ { NULL }};
+ gcry_mpi_t a;
+ int idx;
+ char *string;
+ unsigned char *p;
+
+ for (idx=0; samples[idx].string; idx++)
+ {
+ p = xmalloc (samples[idx].der[0]+1);
+ memcpy (p, samples[idx].der, samples[idx].der[0]+1);
+ a = gcry_mpi_set_opaque (NULL, p, (samples[idx].der[0]+1)*8);
+ if (!a)
+ fail (idx, gpg_error_from_syserror ());
+
+ string = openpgp_oid_to_str (a);
+ if (!string)
+ fail (idx, gpg_error_from_syserror ());
+ if (strcmp (string, samples[idx].string))
+ fail (idx, 0);
+ xfree (string);
+ gcry_mpi_release (a);
+
+ /* Again using the buffer variant. */
+ string = openpgp_oidbuf_to_str (samples[idx].der, samples[idx].der[0]+1);
+ if (!string)
+ fail (idx, gpg_error_from_syserror ());
+ if (strcmp (string, samples[idx].string))
+ fail (idx, 0);
+ xfree (string);
+}
+
+}
+
+
+static void
+test_openpgp_oid_is_ed25519 (void)
+{
+ static struct
+ {
+ int yes;
+ const char *oidstr;
+ } samples[] = {
+ { 0, "0.0" },
+ { 0, "1.3.132.0.35" },
+ { 0, "1.3.6.1.4.1.3029.1.5.0" },
+ { 0, "1.3.6.1.4.1.3029.1.5.1" }, /* Used during Libgcrypt development. */
+ { 0, "1.3.6.1.4.1.3029.1.5.2" },
+ { 0, "1.3.6.1.4.1.3029.1.5.1.0" },
+ { 0, "1.3.6.1.4.1.3029.1.5" },
+ { 0, "1.3.6.1.4.1.11591.15.0" },
+ { 1, "1.3.6.1.4.1.11591.15.1" }, /* Your the one we want. */
+ { 0, "1.3.6.1.4.1.11591.15.2" },
+ { 0, "1.3.6.1.4.1.11591.15.1.0" },
+ { 0, "1.3.6.1.4.1.11591.15" },
+ { 0, NULL },
+ };
+ gpg_error_t err;
+ gcry_mpi_t a;
+ int idx;
+
+ for (idx=0; samples[idx].oidstr; idx++)
+ {
+ err = openpgp_oid_from_str (samples[idx].oidstr, &a);
+ if (err)
+ fail (idx, err);
+
+ if (openpgp_oid_is_ed25519 (a) != samples[idx].yes)
+ fail (idx, 0);
+
+ gcry_mpi_release (a);
+ }
+
+}
+
+
+static void
+test_openpgp_enum_curves (void)
+{
+ int iter = 0;
+ const char *name;
+ int p256 = 0;
+ int p384 = 0;
+ int p521 = 0;
+
+ while ((name = openpgp_enum_curves (&iter)))
+ {
+ if (verbose)
+ printf ("curve: %s\n", name);
+ if (!strcmp (name, "nistp256"))
+ p256++;
+ else if (!strcmp (name, "nistp384"))
+ p384++;
+ else if (!strcmp (name, "nistp521"))
+ p521++;
+ }
+
+ if (p256 != 1 || p384 != 1 || p521 != 1)
+ {
+ /* We can only check the basic RFC-6637 requirements. */
+ fputs ("standard ECC curve missing\n", stderr);
+ exit (1);
+ }
+}
+
+
+int
+main (int argc, char **argv)
+{
+ if (argc)
+ { argc--; argv++; }
+ if (argc && !strcmp (argv[0], "--verbose"))
+ {
+ verbose = 1;
+ argc--; argv++;
+ }
+
+ test_openpgp_oid_from_str ();
+ test_openpgp_oid_to_str ();
+ test_openpgp_oid_is_ed25519 ();
+ test_openpgp_enum_curves ();
+
+ return 0;
+}
diff --git a/common/t-percent.c b/common/t-percent.c
new file mode 100644
index 0000000..145a89b
--- /dev/null
+++ b/common/t-percent.c
@@ -0,0 +1,114 @@
+/* t-percent.c - Module test for percent.c
+ * Copyright (C) 2008 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "util.h"
+
+#define pass() do { ; } while(0)
+#define fail(a) do { fprintf (stderr, "%s:%d: test %d failed\n",\
+ __FILE__,__LINE__, (a)); \
+ exit (1); \
+ } while(0)
+
+static void
+test_percent_plus_escape (void)
+{
+ static struct {
+ const char *string;
+ const char *expect;
+ } tbl[] = {
+ {
+ "",
+ ""
+ }, {
+ "a",
+ "a",
+ }, {
+ " ",
+ "+",
+ }, {
+ " ",
+ "++"
+ }, {
+ "+ +",
+ "%2B+%2B"
+ }, {
+ "\" \"",
+ "%22+%22"
+ }, {
+ "%22",
+ "%2522"
+ }, {
+ "%% ",
+ "%25%25+"
+ }, {
+ "\n ABC\t",
+ "%0A+ABC%09"
+ }, { NULL, NULL }
+ };
+ char *buf, *buf2;
+ int i;
+ size_t len;
+
+ for (i=0; tbl[i].string; i++)
+ {
+ buf = percent_plus_escape (tbl[i].string);
+ if (!buf)
+ {
+ fprintf (stderr, "out of core: %s\n", strerror (errno));
+ exit (2);
+ }
+ if (strcmp (buf, tbl[i].expect))
+ fail (i);
+ buf2 = percent_plus_unescape (buf, 0);
+ if (!buf2)
+ {
+ fprintf (stderr, "out of core: %s\n", strerror (errno));
+ exit (2);
+ }
+ if (strcmp (buf2, tbl[i].string))
+ fail (i);
+ xfree (buf2);
+ /* Now test the inplace conversion. */
+ len = percent_plus_unescape_inplace (buf, 0);
+ buf[len] = 0;
+ if (strcmp (buf, tbl[i].string))
+ fail (i);
+ xfree (buf);
+ }
+}
+
+
+
+int
+main (int argc, char **argv)
+{
+ (void)argc;
+ (void)argv;
+
+ /* FIXME: We escape_unescape is not tested - only
+ percent_plus_unescape. */
+ test_percent_plus_escape ();
+
+ return 0;
+}
diff --git a/common/t-recsel.c b/common/t-recsel.c
new file mode 100644
index 0000000..f52d085
--- /dev/null
+++ b/common/t-recsel.c
@@ -0,0 +1,438 @@
+/* t-recsel.c - Module test for recsel.c
+ * Copyright (C) 2016 Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "util.h"
+#include "init.h"
+#include "recsel.h"
+
+#define PGM "t-recsel"
+
+#define pass() do { ; } while(0)
+#define fail(a,e) do { log_error ("line %d: test %d failed: %s\n", \
+ __LINE__, (a), gpg_strerror ((e))); \
+ exit (1); \
+ } while(0)
+
+static int verbose;
+static int debug;
+
+
+#define FREEEXPR() do { recsel_release (se); se = NULL; } while (0)
+#define ADDEXPR(a) do { \
+ err = recsel_parse_expr (&se, (a)); \
+ if (err) \
+ fail (0, err); \
+ } while (0)
+
+
+static const char *
+test_1_getval (void *cookie, const char *name)
+{
+ if (strcmp (name, "uid"))
+ fail (0, 0);
+ return cookie;
+}
+
+static void
+run_test_1 (void)
+{
+ static const char *expr[] = {
+ "uid =~ Alfa",
+ "&& uid !~ Test ",
+ "|| uid =~ Alpha",
+ " uid !~ Test"
+ };
+ gpg_error_t err;
+ recsel_expr_t se = NULL;
+ int i;
+
+ for (i=0; i < DIM (expr); i++)
+ {
+ err = recsel_parse_expr (&se, expr[i]);
+ if (err)
+ fail (i, err);
+ }
+
+ if (debug)
+ recsel_dump (se);
+
+ /* The example from recsel.c in several variants. */
+ if (!recsel_select (se, test_1_getval, "Alfa"))
+ fail (0, 0);
+ if (!recsel_select (se, test_1_getval, "Alpha"))
+ fail (0, 0);
+ if (recsel_select (se, test_1_getval, "Alfa Test"))
+ fail (0, 0);
+ if (recsel_select (se, test_1_getval, "Alpha Test"))
+ fail (0, 0);
+
+ /* Some modified versions from above. */
+ if (!recsel_select (se, test_1_getval, " AlfA Tes"))
+ fail (0, 0);
+ if (!recsel_select (se, test_1_getval, " AlfA Tes "))
+ fail (0, 0);
+ if (!recsel_select (se, test_1_getval, " Tes AlfA"))
+ fail (0, 0);
+ if (!recsel_select (se, test_1_getval, "TesAlfA"))
+ fail (0, 0);
+
+ /* Simple cases. */
+ if (recsel_select (se, NULL, NULL))
+ fail (0, 0);
+ if (recsel_select (se, test_1_getval, NULL))
+ fail (0, 0);
+ if (recsel_select (se, test_1_getval, ""))
+ fail (0, 0);
+
+ FREEEXPR();
+}
+
+
+/* Same as test1 but using a combined expression.. */
+static void
+run_test_1b (void)
+{
+ gpg_error_t err;
+ recsel_expr_t se = NULL;
+
+ err = recsel_parse_expr
+ (&se, "uid =~ Alfa && uid !~ Test || uid =~ Alpha && uid !~ Test" );
+ if (err)
+ fail (0, err);
+
+ if (debug)
+ recsel_dump (se);
+
+ /* The example from recsel.c in several variants. */
+ if (!recsel_select (se, test_1_getval, "Alfa"))
+ fail (0, 0);
+ if (!recsel_select (se, test_1_getval, "Alpha"))
+ fail (0, 0);
+ if (recsel_select (se, test_1_getval, "Alfa Test"))
+ fail (0, 0);
+ if (recsel_select (se, test_1_getval, "Alpha Test"))
+ fail (0, 0);
+
+ /* Some modified versions from above. */
+ if (!recsel_select (se, test_1_getval, " AlfA Tes"))
+ fail (0, 0);
+ if (!recsel_select (se, test_1_getval, " AlfA Tes "))
+ fail (0, 0);
+ if (!recsel_select (se, test_1_getval, " Tes AlfA"))
+ fail (0, 0);
+ if (!recsel_select (se, test_1_getval, "TesAlfA"))
+ fail (0, 0);
+
+ /* Simple cases. */
+ if (recsel_select (se, NULL, NULL))
+ fail (0, 0);
+ if (recsel_select (se, test_1_getval, NULL))
+ fail (0, 0);
+ if (recsel_select (se, test_1_getval, ""))
+ fail (0, 0);
+
+ FREEEXPR();
+}
+
+
+static const char *
+test_2_getval (void *cookie, const char *name)
+{
+ if (!strcmp (name, "uid"))
+ return "foo@example.org";
+ else if (!strcmp (name, "keyid"))
+ return "0x12345678";
+ else if (!strcmp (name, "zero"))
+ return "0";
+ else if (!strcmp (name, "one"))
+ return "1";
+ else if (!strcmp (name, "blanks"))
+ return " ";
+ else if (!strcmp (name, "letters"))
+ return "abcde";
+ else if (!strcmp (name, "str1"))
+ return "aaa";
+ else
+ return cookie;
+}
+
+static void
+run_test_2 (void)
+{
+ gpg_error_t err;
+ recsel_expr_t se = NULL;
+
+ ADDEXPR ("uid = foo@example.org");
+ if (!recsel_select (se, test_2_getval, NULL))
+ fail (0, 0);
+ FREEEXPR();
+ ADDEXPR ("uid = Foo@example.org");
+ if (!recsel_select (se, test_2_getval, NULL))
+ fail (0, 0);
+ FREEEXPR();
+ ADDEXPR ("-c uid = Foo@example.org");
+ if (recsel_select (se, test_2_getval, NULL))
+ fail (0, 0);
+
+ FREEEXPR();
+ ADDEXPR ("uid =~ foo@example.org");
+ if (!recsel_select (se, test_2_getval, NULL))
+ fail (0, 0);
+ FREEEXPR();
+ ADDEXPR ("uid =~ Foo@example.org");
+ if (!recsel_select (se, test_2_getval, NULL))
+ fail (0, 0);
+ FREEEXPR();
+ ADDEXPR ("-c uid =~ Foo@example.org");
+ if (recsel_select (se, test_2_getval, NULL))
+ fail (0, 0);
+
+ FREEEXPR();
+ ADDEXPR ("uid !~ foo@example.org");
+ if (recsel_select (se, test_2_getval, NULL))
+ fail (0, 0);
+ FREEEXPR();
+ ADDEXPR ("uid !~ Foo@example.org");
+ if (recsel_select (se, test_2_getval, NULL))
+ fail (0, 0);
+ FREEEXPR();
+ ADDEXPR ("-c uid !~ Foo@example.org");
+ if (!recsel_select (se, test_2_getval, NULL))
+ fail (0, 0);
+
+ FREEEXPR();
+ ADDEXPR ("uid =~ @");
+ if (!recsel_select (se, test_2_getval, NULL))
+ fail (0, 0);
+ FREEEXPR();
+ ADDEXPR ("uid =~ @");
+ if (!recsel_select (se, test_2_getval, NULL))
+ fail (0, 0);
+
+ FREEEXPR();
+ ADDEXPR ("keyid == 0x12345678");
+ if (!recsel_select (se, test_2_getval, NULL))
+ fail (0, 0);
+ FREEEXPR();
+ ADDEXPR ("keyid != 0x12345678");
+ if (recsel_select (se, test_2_getval, NULL))
+ fail (0, 0);
+ FREEEXPR();
+ ADDEXPR ("keyid >= 0x12345678");
+ if (!recsel_select (se, test_2_getval, NULL))
+ fail (0, 0);
+ FREEEXPR();
+ ADDEXPR ("keyid <= 0x12345678");
+ if (!recsel_select (se, test_2_getval, NULL))
+ fail (0, 0);
+ FREEEXPR();
+ ADDEXPR ("keyid > 0x12345677");
+ if (!recsel_select (se, test_2_getval, NULL))
+ fail (0, 0);
+ FREEEXPR();
+ ADDEXPR ("keyid < 0x12345679");
+ if (!recsel_select (se, test_2_getval, NULL))
+ fail (0, 0);
+
+ FREEEXPR();
+ ADDEXPR ("keyid > 0x12345678");
+ if (recsel_select (se, test_2_getval, NULL))
+ fail (0, 0);
+ FREEEXPR();
+ ADDEXPR ("keyid < 0x12345678");
+ if (recsel_select (se, test_2_getval, NULL))
+ fail (0, 0);
+
+
+ FREEEXPR();
+ ADDEXPR ("str1 -gt aa");
+ if (!recsel_select (se, test_2_getval, NULL))
+ fail (0, 0);
+ FREEEXPR();
+ ADDEXPR ("str1 -gt aaa");
+ if (recsel_select (se, test_2_getval, NULL))
+ fail (0, 0);
+ FREEEXPR();
+ ADDEXPR ("str1 -ge aaa");
+ if (!recsel_select (se, test_2_getval, NULL))
+ fail (0, 0);
+ FREEEXPR();
+ ADDEXPR ("str1 -lt aab");
+ if (!recsel_select (se, test_2_getval, NULL))
+ fail (0, 0);
+ FREEEXPR();
+ ADDEXPR ("str1 -le aaa");
+ if (!recsel_select (se, test_2_getval, NULL))
+ fail (0, 0);
+
+ FREEEXPR();
+ ADDEXPR ("-c str1 -lt AAB");
+ if (recsel_select (se, test_2_getval, NULL))
+ fail (0, 0);
+ FREEEXPR();
+ ADDEXPR ("str1 -lt AAB");
+ if (!recsel_select (se, test_2_getval, NULL))
+ fail (0, 0);
+
+
+ FREEEXPR();
+ ADDEXPR ("uid -n");
+ if (!recsel_select (se, test_2_getval, NULL))
+ fail (0, 0);
+ FREEEXPR();
+ ADDEXPR ("uid -z");
+ if (recsel_select (se, test_2_getval, NULL))
+ fail (0, 0);
+
+ FREEEXPR();
+ ADDEXPR ("nothing -z");
+ if (!recsel_select (se, test_2_getval, NULL))
+ fail (0, 0);
+ FREEEXPR();
+ ADDEXPR ("nothing -n");
+ if (recsel_select (se, test_2_getval, NULL))
+ fail (0, 0);
+
+ FREEEXPR();
+ ADDEXPR ("blanks -n");
+ if (!recsel_select (se, test_2_getval, NULL))
+ fail (0, 0);
+ FREEEXPR();
+ ADDEXPR ("blanks -z");
+ if (recsel_select (se, test_2_getval, NULL))
+ fail (0, 0);
+
+ FREEEXPR();
+ ADDEXPR ("letters -n");
+ if (!recsel_select (se, test_2_getval, NULL))
+ fail (0, 0);
+ FREEEXPR();
+ ADDEXPR ("letters -z");
+ if (recsel_select (se, test_2_getval, NULL))
+ fail (0, 0);
+
+
+ FREEEXPR();
+ ADDEXPR ("nothing -f");
+ if (!recsel_select (se, test_2_getval, NULL))
+ fail (0, 0);
+ FREEEXPR();
+ ADDEXPR ("nothing -t");
+ if (recsel_select (se, test_2_getval, NULL))
+ fail (0, 0);
+
+ FREEEXPR();
+ ADDEXPR ("zero -f");
+ if (!recsel_select (se, test_2_getval, NULL))
+ fail (0, 0);
+ FREEEXPR();
+ ADDEXPR ("zero -t");
+ if (recsel_select (se, test_2_getval, NULL))
+ fail (0, 0);
+
+ FREEEXPR();
+ ADDEXPR ("one -t");
+ if (!recsel_select (se, test_2_getval, NULL))
+ fail (0, 0);
+ FREEEXPR();
+ ADDEXPR ("one -f");
+ if (recsel_select (se, test_2_getval, NULL))
+ fail (0, 0);
+
+ FREEEXPR();
+ ADDEXPR ("blanks -f");
+ if (!recsel_select (se, test_2_getval, NULL))
+ fail (0, 0);
+ FREEEXPR();
+ ADDEXPR ("blanks -t");
+ if (recsel_select (se, test_2_getval, NULL))
+ fail (0, 0);
+
+ FREEEXPR();
+ ADDEXPR ("letter -f");
+ if (!recsel_select (se, test_2_getval, NULL))
+ fail (0, 0);
+ FREEEXPR();
+ ADDEXPR ("letters -t");
+ if (recsel_select (se, test_2_getval, NULL))
+ fail (0, 0);
+
+
+ FREEEXPR();
+}
+
+
+
+int
+main (int argc, char **argv)
+{
+ int last_argc = -1;
+
+ log_set_prefix (PGM, GPGRT_LOG_WITH_PREFIX);
+ init_common_subsystems (&argc, &argv);
+
+ if (argc)
+ { argc--; argv++; }
+ while (argc && last_argc != argc )
+ {
+ last_argc = argc;
+ if (!strcmp (*argv, "--"))
+ {
+ argc--; argv++;
+ break;
+ }
+ else if (!strcmp (*argv, "--help"))
+ {
+ fputs ("usage: " PGM " [options]\n"
+ "Options:\n"
+ " --verbose print timings etc.\n"
+ " --debug flyswatter\n",
+ stdout);
+ exit (0);
+ }
+ else if (!strcmp (*argv, "--verbose"))
+ {
+ verbose++;
+ argc--; argv++;
+ }
+ else if (!strcmp (*argv, "--debug"))
+ {
+ verbose += 2;
+ debug++;
+ argc--; argv++;
+ }
+ else if (!strncmp (*argv, "--", 2))
+ {
+ log_error ("unknown option '%s'\n", *argv);
+ exit (2);
+ }
+ }
+
+ run_test_1 ();
+ run_test_1b ();
+ run_test_2 ();
+ /* Fixme: We should add test for complex conditions. */
+
+ return 0;
+}
diff --git a/common/t-session-env.c b/common/t-session-env.c
new file mode 100644
index 0000000..e2b942c
--- /dev/null
+++ b/common/t-session-env.c
@@ -0,0 +1,304 @@
+/* t-session-env.c - Module test for session-env.c
+ * Copyright (C) 2009 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "util.h"
+#include "session-env.h"
+
+#define pass() do { ; } while(0)
+#define fail(e) do { fprintf (stderr, "%s:%d: function failed: %s\n", \
+ __FILE__,__LINE__, gpg_strerror (e)); \
+ exit (1); \
+ } while(0)
+
+static int verbose;
+
+static void
+listall (session_env_t se)
+{
+ int iterator = 0;
+ const char *name, *value;
+ int def;
+
+ if (verbose)
+ printf ("environment of %p\n", se);
+ while ( (name = session_env_listenv (se, &iterator, &value, &def)) )
+ if (verbose)
+ printf (" %s%s=%s\n", def? "[def] ":" ", name, value);
+
+}
+
+
+static void
+show_stdnames (void)
+{
+ const char *name, *assname;
+ int iterator = 0;
+ int count;
+
+ printf (" > Known envvars:");
+ count = 20;
+ while ((name = session_env_list_stdenvnames (&iterator, &assname)))
+ {
+ if (count > 60)
+ {
+ printf ("\n >");
+ count = 7;
+ }
+ printf ( " %s", name);
+ count += strlen (name) + 1;
+ if (assname)
+ {
+ printf ( "(%s)", assname);
+ count += strlen (assname) + 2;
+ }
+ }
+ putchar('\n');
+}
+
+
+static void
+test_all (void)
+{
+ gpg_error_t err;
+ session_env_t se_0, se;
+ const char *s, *s2;
+ int idx;
+
+ se_0 = session_env_new ();
+ if (!se_0)
+ fail (gpg_error_from_syserror ());
+ se = session_env_new ();
+ if (!se)
+ fail (gpg_error_from_syserror ());
+
+ err = session_env_putenv (se, NULL);
+ if (gpg_err_code (err) != GPG_ERR_INV_VALUE)
+ fail (err);
+ err = session_env_putenv (se, "");
+ if (gpg_err_code (err) != GPG_ERR_INV_VALUE)
+ fail (err);
+ err = session_env_putenv (se, "=");
+ if (gpg_err_code (err) != GPG_ERR_INV_VALUE)
+ fail (err);
+
+ /* Delete some nonexistent variables. */
+ err = session_env_putenv (se, "A");
+ if (err)
+ fail (err);
+ err = session_env_putenv (se, "a");
+ if (err)
+ fail (err);
+ err = session_env_putenv (se, "_aaaa aaaaaasssssssssssss\nddd");
+ if (err)
+ fail (err);
+
+ /* Create a few variables. */
+ err = session_env_putenv (se, "EMPTY=");
+ if (err)
+ fail (err);
+ err = session_env_putenv (se, "foo=value_of_foo");
+ if (err)
+ fail (err);
+ err = session_env_putenv (se, "bar=the value_of_bar");
+ if (err)
+ fail (err);
+ err = session_env_putenv (se, "baz=this-is-baz");
+ if (err)
+ fail (err);
+ err = session_env_putenv (se, "BAZ=this-is-big-baz");
+ if (err)
+ fail (err);
+
+ listall (se);
+
+ /* Update one. */
+ err = session_env_putenv (se, "baz=this-is-another-baz");
+ if (err)
+ fail (err);
+
+ listall (se);
+
+ /* Delete one. */
+ err = session_env_putenv (se, "bar");
+ if (err)
+ fail (err);
+
+ listall (se);
+
+ /* Insert a new one. */
+ err = session_env_putenv (se, "FOO=value_of_foo");
+ if (err)
+ fail (err);
+
+ listall (se);
+
+ /* Retrieve a default one. */
+ s = session_env_getenv_or_default (se, "HOME", NULL);
+ if (!s)
+ {
+ fprintf (stderr, "failed to get default of HOME\n");
+ exit (1);
+ }
+
+ s = session_env_getenv (se, "HOME");
+ if (s)
+ fail(0); /* This is a default value, thus we should not see it. */
+
+ s = session_env_getenv_or_default (se, "HOME", NULL);
+ if (!s)
+ fail(0); /* But here we should see it. */
+
+ /* Add a few more. */
+ err = session_env_putenv (se, "X1=A value");
+ if (err)
+ fail (err);
+ err = session_env_putenv (se, "X2=Another value");
+ if (err)
+ fail (err);
+ err = session_env_putenv (se, "X3=A value");
+ if (err)
+ fail (err);
+
+ listall (se);
+
+ /* Check that we can overwrite a default value. */
+ err = session_env_putenv (se, "HOME=/this/is/my/new/home");
+ if (err)
+ fail (err);
+ /* And that we get this string back. */
+ s = session_env_getenv (se, "HOME");
+ if (!s)
+ fail (0);
+ if (strcmp (s, "/this/is/my/new/home"))
+ fail (0);
+ /* A new get default should return the very same string. */
+ s2 = session_env_getenv_or_default (se, "HOME", NULL);
+ if (!s2)
+ fail (0);
+ if (s2 != s)
+ fail (0);
+
+ listall (se);
+
+ /* Check that the other object is clean. */
+ {
+ int iterator = 0;
+
+ if (session_env_listenv (se_0, &iterator, NULL, NULL))
+ fail (0);
+ }
+
+
+ session_env_release (se);
+
+ /* Use a new session for quick mass test. */
+ se = session_env_new ();
+ if (!se)
+ fail (gpg_error_from_syserror ());
+
+ /* Create. */
+ for (idx=0; idx < 500; idx++)
+ {
+ char buf[100];
+
+ snprintf (buf, sizeof buf, "FOO_%d=Value for %x", idx, idx);
+ err = session_env_putenv (se, buf);
+ if (err)
+ fail (err);
+ }
+ err = session_env_setenv (se, "TEST1", "value1");
+ if (err)
+ fail (err);
+ err = session_env_setenv (se, "TEST1", "value1-updated");
+ if (err)
+ fail (err);
+
+ listall (se);
+
+ /* Delete all. */
+ for (idx=0; idx < 500; idx++)
+ {
+ char buf[100];
+
+ snprintf (buf, sizeof buf, "FOO_%d", idx);
+ err = session_env_putenv (se, buf);
+ if (err)
+ fail (err);
+ }
+ err = session_env_setenv (se, "TEST1", NULL);
+ if (err)
+ fail (err);
+
+ /* Check that all are deleted. */
+ {
+ int iterator = 0;
+
+ if (session_env_listenv (se, &iterator, NULL, NULL))
+ fail (0);
+ }
+
+ /* Add a few strings again. */
+ for (idx=0; idx < 500; idx++)
+ {
+ char buf[100];
+
+ if (!(idx % 10))
+ {
+ if ( !(idx % 3))
+ snprintf (buf, sizeof buf, "FOO_%d=", idx);
+ else
+ snprintf (buf, sizeof buf, "FOO_%d=new value for %x", idx, idx);
+ err = session_env_putenv (se, buf);
+ if (err)
+ fail (err);
+ }
+ }
+
+ listall (se);
+
+ session_env_release (se);
+
+ session_env_release (se_0);
+}
+
+
+
+int
+main (int argc, char **argv)
+{
+ if (argc)
+ { argc--; argv++; }
+ if (argc && !strcmp (argv[0], "--verbose"))
+ {
+ verbose = 1;
+ argc--; argv++;
+ }
+
+
+ show_stdnames ();
+ test_all ();
+
+ return 0;
+}
diff --git a/common/t-sexputil.c b/common/t-sexputil.c
new file mode 100644
index 0000000..8da9760
--- /dev/null
+++ b/common/t-sexputil.c
@@ -0,0 +1,511 @@
+/* t-sexputil.c - Module test for sexputil.c
+ * Copyright (C) 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "util.h"
+
+#define pass() do { ; } while(0)
+#define fail(a) do { fprintf (stderr, "%s:%d: test %d failed\n",\
+ __FILE__,__LINE__, (a)); \
+ exit (1); \
+ } while(0)
+#define fail2(a,e) do { fprintf (stderr, "%s:%d: test %d failed: %s\n", \
+ __FILE__,__LINE__, (a), gpg_strerror ((e))); \
+ exit (1); \
+ } while(0)
+
+
+static void
+test_hash_algo_from_sigval (void)
+{
+ int algo;
+ /* A real world example. */
+ unsigned char example1_rsa_sha1[] =
+ ("\x28\x37\x3A\x73\x69\x67\x2D\x76\x61\x6C\x28\x33\x3A\x72\x73\x61"
+ "\x28\x31\x3A\x73\x31\x32\x38\x3A\x17\xD2\xE9\x5F\xB4\x24\xD4\x1E"
+ "\x8C\xEE\x94\xDA\x41\x42\x1F\x26\x5E\xF4\x6D\xEC\x5B\xBD\x5B\x89"
+ "\x7A\x69\x11\x43\xE9\xD2\x23\x21\x25\x64\xA6\xB0\x56\xEF\xB4\xE9"
+ "\x06\xB2\x44\xF6\x80\x1E\xFF\x41\x23\xEB\xC9\xFA\xFD\x09\xBF\x9C"
+ "\x8E\xCF\x7F\xC3\x7F\x3A\x40\x48\x89\xDC\xBA\xB7\xDB\x9E\xF1\xBA"
+ "\x7C\x08\xEA\x74\x1D\x49\xE7\x65\xEF\x67\x79\xBC\x23\xD9\x49\xCD"
+ "\x05\x99\xD3\xD8\xB7\x7B\xC7\x0E\xF2\xB3\x01\x48\x0F\xC8\xEB\x05"
+ "\x7B\xFB\x61\xCC\x41\x04\x74\x6D\x33\x84\xB1\xE6\x6A\xD8\x0F\xBC"
+ "\x27\xAC\x43\x45\xFA\x04\xD1\x22\x29\x29\x28\x34\x3A\x68\x61\x73"
+ "\x68\x34\x3A\x73\x68\x61\x31\x29\x29");
+ /* The same but without the hash algo. */
+ unsigned char example1_rsa[] =
+ ("\x28\x37\x3A\x73\x69\x67\x2D\x76\x61\x6C\x28\x33\x3A\x72\x73\x61"
+ "\x28\x31\x3A\x73\x31\x32\x38\x3A\x17\xD2\xE9\x5F\xB4\x24\xD4\x1E"
+ "\x8C\xEE\x94\xDA\x41\x42\x1F\x26\x5E\xF4\x6D\xEC\x5B\xBD\x5B\x89"
+ "\x7A\x69\x11\x43\xE9\xD2\x23\x21\x25\x64\xA6\xB0\x56\xEF\xB4\xE9"
+ "\x06\xB2\x44\xF6\x80\x1E\xFF\x41\x23\xEB\xC9\xFA\xFD\x09\xBF\x9C"
+ "\x8E\xCF\x7F\xC3\x7F\x3A\x40\x48\x89\xDC\xBA\xB7\xDB\x9E\xF1\xBA"
+ "\x7C\x08\xEA\x74\x1D\x49\xE7\x65\xEF\x67\x79\xBC\x23\xD9\x49\xCD"
+ "\x05\x99\xD3\xD8\xB7\x7B\xC7\x0E\xF2\xB3\x01\x48\x0F\xC8\xEB\x05"
+ "\x7B\xFB\x61\xCC\x41\x04\x74\x6D\x33\x84\xB1\xE6\x6A\xD8\x0F\xBC"
+ "\x27\xAC\x43\x45\xFA\x04\xD1\x22\x29\x29\x29");
+
+ algo = hash_algo_from_sigval (example1_rsa_sha1);
+ if (algo != GCRY_MD_SHA1)
+ fail (0);
+ algo = hash_algo_from_sigval (example1_rsa);
+ if (algo)
+ fail (0);
+}
+
+
+static void
+test_make_canon_sexp_from_rsa_pk (void)
+{
+ struct {
+ unsigned char *m;
+ size_t mlen;
+ unsigned char *e;
+ size_t elen;
+ unsigned char *result;
+ size_t resultlen;
+ gpg_err_code_t reverr; /* Expected error from the reverse function. */
+ } tests[] = {
+ {
+ "\x82\xB4\x12\x48\x08\x48\xC0\x76\xAA\x8E\xF1\xF8\x7F\x5E\x9B\x89"
+ "\xA9\x62\x92\xA2\x16\x1B\xF5\x9F\xE1\x41\xF3\xF0\x42\xB5\x5C\x46"
+ "\xB8\x83\x9F\x39\x97\x73\xFF\xC5\xB2\xF4\x59\x5F\xBA\xC7\x0E\x03"
+ "\x9D\x27\xC0\x86\x37\x31\x46\xE0\xA1\xFE\xA1\x41\xD4\xE3\xE9\xB3"
+ "\x9B\xD5\x84\x65\xA5\x37\x35\x34\x07\x58\xB6\xBA\x21\xCA\x21\x72"
+ "\x4C\xF3\xFC\x91\x47\xD1\x3C\x1D\xA5\x9C\x38\x4D\x58\x39\x92\x16"
+ "\xB1\xE5\x43\xFE\xB5\x46\x4B\x43\xD1\x47\xB0\xE8\x2A\xDB\xF8\x34"
+ "\xB0\x5A\x22\x3D\x14\xBB\xEA\x63\x65\xA7\xF1\xF2\xF8\x97\x74\xA7",
+ 128,
+ "\x40\x00\x00\x81",
+ 4,
+ "\x28\x31\x30\x3a\x70\x75\x62\x6c\x69\x63\x2d\x6b\x65\x79\x28\x33"
+ "\x3a\x72\x73\x61\x28\x31\x3a\x6e\x31\x32\x39\x3a\x00\x82\xb4\x12"
+ "\x48\x08\x48\xc0\x76\xaa\x8e\xf1\xf8\x7f\x5e\x9b\x89\xa9\x62\x92"
+ "\xa2\x16\x1b\xf5\x9f\xe1\x41\xf3\xf0\x42\xb5\x5c\x46\xb8\x83\x9f"
+ "\x39\x97\x73\xff\xc5\xb2\xf4\x59\x5f\xba\xc7\x0e\x03\x9d\x27\xc0"
+ "\x86\x37\x31\x46\xe0\xa1\xfe\xa1\x41\xd4\xe3\xe9\xb3\x9b\xd5\x84"
+ "\x65\xa5\x37\x35\x34\x07\x58\xb6\xba\x21\xca\x21\x72\x4c\xf3\xfc"
+ "\x91\x47\xd1\x3c\x1d\xa5\x9c\x38\x4d\x58\x39\x92\x16\xb1\xe5\x43"
+ "\xfe\xb5\x46\x4b\x43\xd1\x47\xb0\xe8\x2a\xdb\xf8\x34\xb0\x5a\x22"
+ "\x3d\x14\xbb\xea\x63\x65\xa7\xf1\xf2\xf8\x97\x74\xa7\x29\x28\x31"
+ "\x3a\x65\x34\x3a\x40\x00\x00\x81\x29\x29\x29",
+ 171
+ },
+ {
+ "\x63\xB4\x12\x48\x08\x48\xC0\x76\xAA\x8E\xF1\xF8\x7F\x5E\x9B\x89",
+ 16,
+ "\x03",
+ 1,
+ "\x28\x31\x30\x3a\x70\x75\x62\x6c\x69\x63\x2d\x6b\x65\x79\x28\x33"
+ "\x3a\x72\x73\x61\x28\x31\x3a\x6e\x31\x36\x3a\x63\xb4\x12\x48\x08"
+ "\x48\xc0\x76\xaa\x8e\xf1\xf8\x7f\x5e\x9b\x89\x29\x28\x31\x3a\x65"
+ "\x31\x3a\x03\x29\x29\x29",
+ 54,
+ },
+ {
+ "",
+ 0,
+ "",
+ 0,
+ "\x28\x31\x30\x3a\x70\x75\x62\x6c\x69\x63\x2d\x6b\x65\x79\x28\x33"
+ "\x3a\x72\x73\x61\x28\x31\x3a\x6e\x31\x3a\x00\x29\x28\x31\x3a\x65"
+ "\x31\x3a\x00\x29\x29\x29",
+ 38,
+ GPG_ERR_BAD_PUBKEY
+ },
+ {
+ NULL
+ }
+ };
+ int idx;
+ gpg_error_t err;
+ unsigned char *sexp;
+ size_t length;
+ const unsigned char *rsa_n, *rsa_e;
+ size_t rsa_n_len, rsa_e_len;
+
+ for (idx=0; tests[idx].m; idx++)
+ {
+ sexp = make_canon_sexp_from_rsa_pk (tests[idx].m, tests[idx].mlen,
+ tests[idx].e, tests[idx].elen,
+ &length);
+ if (!sexp)
+ {
+ fprintf (stderr, "%s:%d: out of core\n", __FILE__, __LINE__);
+ exit (1);
+ }
+
+ if (length != tests[idx].resultlen)
+ fail (idx);
+ if (memcmp (sexp, tests[idx].result, tests[idx].resultlen))
+ fail (idx);
+
+ /* Test the reverse function. */
+ err = get_rsa_pk_from_canon_sexp (sexp, length,
+ &rsa_n, &rsa_n_len,
+ &rsa_e, &rsa_e_len);
+ if (gpg_err_code (err) != tests[idx].reverr)
+ fail (idx);
+ if (!err)
+ {
+ if (tests[idx].mlen != rsa_n_len)
+ fail (idx);
+ if (memcmp (tests[idx].m, rsa_n, rsa_n_len))
+ fail (idx);
+ if (tests[idx].elen != rsa_e_len)
+ fail (idx);
+ if (memcmp (tests[idx].e, rsa_e, rsa_e_len))
+ fail (idx);
+ }
+
+ xfree (sexp);
+ }
+}
+
+
+/* Communiacation object for tcmp. */
+struct tcmp_parm_s {
+ int curve_seen;
+};
+
+/* Helper for test_cmp_canon_sexp. */
+static int
+tcmp1 (void *opaque, int depth,
+ const unsigned char *aval, size_t alen,
+ const unsigned char *bval, size_t blen)
+{
+ struct tcmp_parm_s *parm = opaque;
+
+ (void)depth;
+
+ if (parm->curve_seen)
+ {
+ /* Last token was "curve", canonicalize its argument. */
+ parm->curve_seen = 0;
+
+ if (alen == 8 && !memcmp (aval, "nistp256", alen))
+ {
+ alen = 19;
+ aval = "1.2.840.10045.3.1.7";
+ }
+
+ if (blen == 8 && !memcmp (bval, "nistp256", blen))
+ {
+ blen = 19;
+ bval = "1.2.840.10045.3.1.7";
+ }
+ }
+ else if (alen == 5 && !memcmp (aval, "curve", 5))
+ parm->curve_seen = 1;
+ else
+ parm->curve_seen = 0;
+
+ if (alen > blen)
+ return 1;
+ else if (alen < blen)
+ return -1;
+ else
+ return memcmp (aval, bval, alen);
+}
+
+
+static void
+test_cmp_canon_sexp (void)
+{
+ struct {
+ unsigned char *a;
+ unsigned char *b;
+ int expected0; /* Expected result without compare function. */
+ int expected1; /* Expected result with compare function tcmp1. */
+ }
+ tests[] = {
+ {
+ "(10:public-key(3:ecc(5:curve8:nistp256)(1:q10:qqqqqqqqqq)))",
+ "(10:public-key(3:ecc(5:curve8:nistp256)(1:q10:qqqqqqqqqq)))",
+ 0, 0
+ },
+ {
+ "(10:public-key(3:ecc(5:curve19:1.2.840.10045.3.1.7)(1:q10:qqqqqqqqqq)))",
+ "(10:public-key(3:ecc(5:curve19:1.2.840.10045.3.1.7)(1:q10:qqqqqqqqqq)))",
+ 0, 0
+ },
+ {
+ "(10:public-key(3:ecc(5:curve8:nistp256)(1:q10:qqqqqqqqqq)))",
+ "(10:public-key(3:ecc(5:curve19:1.2.840.10045.3.1.7)(1:q10:qqqqqqqqqq)))",
+ -1, 0
+ },
+ {
+ "(10:public-key(3:ecc(5:curve19:1.2.840.10045.3.1.7)(1:q10:qqqqqqqqqq)))",
+ "(10:public-key(3:ecc(5:curve8:nistp256)(1:q10:qqqqqqqqqq)))",
+ 1, 0
+ },
+ {
+ NULL
+ }
+ };
+ struct tcmp_parm_s parm = {0};
+ int idx;
+ int res;
+
+ for (idx=0; tests[idx].a; idx++)
+ {
+ res = cmp_canon_sexp (tests[idx].a, strlen (tests[idx].a),
+ tests[idx].b, strlen (tests[idx].b),
+ NULL, NULL);
+ if (res != tests[idx].expected0)
+ fail (idx);
+ res = cmp_canon_sexp (tests[idx].a, strlen (tests[idx].a),
+ tests[idx].b, strlen (tests[idx].b),
+ tcmp1, &parm);
+ if (res != tests[idx].expected1)
+ fail (idx);
+ }
+}
+
+
+static void
+test_ecc_uncompress (void)
+{
+ struct {
+ const char *a; /* Uncompressed. */
+ const char *b; /* Compressed. */
+ }
+ tests[] = {
+ {
+ "(public-key"
+ " (ecc"
+ " (curve brainpoolP256r1)"
+ " (q #042ECD8679930BE2DB4AD42B8600BA3F80"
+ /* */"2D4D539BFF2F69B83EC9B7BBAA7F3406"
+ /* */"436DD11A1756AFE56CD93408410FCDA9"
+ /* */"BA95024EB613BD481A14FCFEC27A448A#)))",
+ /* The same in compressed form. */
+ "(public-key"
+ " (ecc"
+ " (curve brainpoolP256r1)"
+ " (q #022ECD8679930BE2DB4AD42B8600BA3F80"
+ /* */"2D4D539BFF2F69B83EC9B7BBAA7F3406#)))"
+ },
+ {
+ "(public-key"
+ " (ecc"
+ " (curve brainpoolP256r1)"
+ " (q #045B784CA008EE64AB3D85017EE0D2BE87"
+ /* */"558762C7300E0C8E06B1F9AF7C031458"
+ /* */"9EBBA41915313417BA54218EB0569C59"
+ /* */"0B156C76DBCAB6E84575E6EF68CE7B87#)))",
+ /* The same in compressed form. */
+ "(public-key"
+ " (ecc"
+ " (curve brainpoolP256r1)"
+ " (q #035B784CA008EE64AB3D85017EE0D2BE87"
+ /* */"558762C7300E0C8E06B1F9AF7C031458#)))"
+ },
+ { /* A key which does not require a conversion. */
+ "(public-key"
+ " (ecdsa"
+ " (p #00FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF#)"
+ " (curve \"NIST P-256\")"
+ " (b #5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B#)"
+ " (g #046B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C2964FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5#)"
+ " (n #00FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551#)"
+ " (h #000000000000000000000000000000000000000000000000000000000000000001#)"
+ " (q #04C8A4CEC2E9A9BC8E173531A67B0840DF345C32E261ADD780E6D83D56EFADFD5DE872F8B854819B59543CE0B7F822330464FBC4E6324DADDCD9D059554F63B344#)))"
+ },
+ { /* Nothing to do for an RSA private key. */
+ "(private-key"
+ " (rsa"
+ " (n #00B6B509596A9ECABC939212F891E656A626BA07DA8521A9CAD4C08E640C04052FBB87F424EF1A0275A48A9299AC9DB69ABE3D0124E6C756B1F7DFB9B842D6251AEA6EE85390495CADA73D671537FCE5850A932F32BAB60AB1AC1F852C1F83C625E7A7D70CDA9EF16D5C8E47739D77DF59261ABE8454807FF441E143FBD37F8545#)"
+ " (e #010001#)"
+ " (d #077AD3DE284245F4806A1B82B79E616FBDE821C82D691A65665E57B5FAD3F34E67F401E7BD2E28699E89D9C496CF821945AE83AC7A1231176A196BA6027E77D85789055D50404A7A2A95B1512F91F190BBAEF730ED550D227D512F89C0CDB31AC06FA9A19503DDF6B66D0B42B9691BFD6140EC1720FFC48AE00C34796DC899E5#)"
+ " (p #00D586C78E5F1B4BF2E7CD7A04CA091911706F19788B93E44EE20AAF462E8363E98A72253ED845CCBF2481BB351E8557C85BCFFF0DABDBFF8E26A79A0938096F27#)"
+ " (q #00DB0CDF60F26F2A296C88D6BF9F8E5BE45C0DDD713C96CC73EBCB48B061740943F21D2A93D6E42A7211E7F02A95DCED6C390A67AD21ECF739AE8A0CA46FF2EBB3#)"
+ " (u #33149195F16912DB20A48D020DBC3B9E3881B39D722BF79378F6340F43148A6E9FC5F53E2853B7387BA4443BA53A52FCA8173DE6E85B42F9783D4A7817D0680B#)))"
+ },
+ { /* Nothing to do dor a DSA key. */
+ " (public-key"
+ " (dsa"
+ " (p #0084E4C626E16005770BD9509ABF7354492E85B8C0060EFAAAEC617F725B592FAA59DF5460575F41022776A9718CE62EDD542AB73C7720869EBDBC834D174ADCD7136827DF51E2613545A25CA573BC502A61B809000B6E35F5EB7FD6F18C35678C23EA1C3638FB9CFDBA2800EE1B62F41A4479DE824F2834666FBF8DC5B53C2617#)"
+ " (q #00B0E6F710051002A9F425D98A677B18E0E5B038AB#)"
+ " (g #44370CEE0FE8609994183DBFEBA7EEA97D466838BCF65EFF506E35616DA93FA4E572A2F08886B74977BC00CA8CD3DBEA7AEB7DB8CBB180E6975E0D2CA76E023E6DE9F8CCD8826EBA2F72B8516532F6001DEFFAE76AA5E59E0FA33DBA3999B4E92D1703098CDEDCC416CF008801964084CDE1980132B2B78CB4CE9C15A559528B#)"
+ " (y #3D5DD14AFA2BF24A791E285B90232213D0E3BA74AB1109E768AED19639A322F84BB7D959E2BA92EF73DE4C7F381AA9F4053CFA3CD4527EF9043E304E5B95ED0A3A5A9D590AA641C13DB2B6E32B9B964A6A2C730DD3EA7C8E13F7A140AFF1A91CE375E9B9B960384779DC4EA180FA1F827C52288F366C0770A220F50D6D8FD6F6#)))"
+ },
+ { /* Nothing to do for an ECDSA key w/o curvename. */
+ "(public-key"
+ " (ecdsa(flags param)"
+ " (p #00FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF#)"
+ " (a #00FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC#)"
+ " (b #5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B#)"
+ " (g #046B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C2964FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5#)"
+ " (n #00FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551#)"
+ " (h #000000000000000000000000000000000000000000000000000000000000000001#)"
+ " (q #04C8A4CEC2E9A9BC8E173531A67B0840DF345C32E261ADD780E6D83D56EFADFD5DE872F8B854819B59543CE0B7F822330464FBC4E6324DADDCD9D059554F63B344#)))"
+ },
+ { /* Nothing to do for Ed25519 key. */
+ "(public-key"
+ " (ecc"
+ " (curve Ed25519)"
+ " (q #04"
+ " 1CC662926E7EFF4982B7FB8B928E61CD74CCDD85277CC57196C3AD20B611085F"
+ " 47BD24842905C049257673B3F5249524E0A41FAA17B25B818D0F97E625F1A1D0#)"
+ " ))"
+ },
+ { /* Nothing to do for Ed25519 with EdDSA key. */
+ "(public-key"
+ " (ecc"
+ " (curve Ed25519)(flags eddsa)"
+ " (q #773E72848C1FD5F9652B29E2E7AF79571A04990E96F2016BF4E0EC1890C2B7DB#)"
+ " ))"
+ },
+ { /* Nothing to do for Ed25519 with EdDSA key with prefix. */
+ "(public-key"
+ " (ecc"
+ " (curve Ed25519)(flags eddsa)"
+ " (q #40"
+ " 773E72848C1FD5F9652B29E2E7AF79571A04990E96F2016BF4E0EC1890C2B7DB#)"
+ " ))"
+ },
+ { /* Nothing to do for Ed25519 with EdDSA key with uncompress prefix. */
+ "(public-key"
+ " (ecc"
+ " (curve Ed25519)(flags eddsa)"
+ " (q #04"
+ " 629ad237d1ed04dcd4abe1711dd699a1cf51b1584c4de7a4ef8b8a640180b26f"
+ " 5bb7c29018ece0f46b01f2960e99041a5779afe7e2292b65f9d51f8c84723e77#)"
+ " ))"
+ },
+ { /* Noting to do for a Cv25519 tweaked key. */
+ "(public-key"
+ " (ecc"
+ " (curve Curve25519)(flags djb-tweak)"
+ " (q #40"
+ " 918C1733127F6BF2646FAE3D081A18AE77111C903B906310B077505EFFF12740#)"
+ " ))"
+ },
+ { /* Nothing to do for a shadowed key. */
+ "(shadowed-private-key"
+ " (rsa"
+ " (n #00B493C79928398DA9D99AC0E949FE6EB62F683CB974FFFBFBC01066F5C9A89B"
+ " D3DC48EAD7C65F36EA943C2B2C865C26C4884FF9EDFDA8C99C855B737D77EEF6"
+ " B85DBC0CCEC0E900C1F89A6893A2A93E8B31028469B6927CEB2F08687E547C68"
+ " 6B0A2F7E50A194FF7AB7637E03DE0912EF7F6E5F1EC37625BD1620CCC2E7A564"
+ " 31E168CDAFBD1D9E61AE47A69A6FA03EF22F844528A710B2392F262B95A3078C"
+ " F321DC8325F92A5691EF69F34FD0DE0B22C79D29DC87723FCADE463829E8E5F7"
+ " D196D73D6C9C180F6A6A0DDBF7B9D8F7FA293C36163B12199EF6A1A95CAE4051"
+ " E3069C522CC6C4A7110F663A5DAD20F66C13A1674D050088208FAE4F33B3AB51"
+ " 03#)"
+ " (e #00010001#)"
+ " (shadowed t1-v1"
+ " (#D2760001240102000005000123350000# OPENPGP.1)"
+ ")))"
+ },
+ {
+ NULL
+ }};
+ gpg_error_t err;
+ int idx;
+ gcry_sexp_t sexp;
+ unsigned char *abuf, *bbuf, *rbuf;
+ size_t abuflen, bbuflen, rbuflen;
+
+
+ for (idx=0; tests[idx].a; idx++)
+ {
+ err = gcry_sexp_new (&sexp, tests[idx].a, 0, 1);
+ if (err)
+ fail2 (idx,err);
+ err = make_canon_sexp (sexp, &abuf, &abuflen);
+ if (err)
+ fail2 (idx,err);
+ gcry_sexp_release (sexp);
+
+ if (tests[idx].b)
+ {
+ err = gcry_sexp_new (&sexp, tests[idx].b, 0, 1);
+ if (err)
+ fail2 (idx,err);
+ err = make_canon_sexp (sexp, &bbuf, &bbuflen);
+ if (err)
+ fail2 (idx,err);
+ gcry_sexp_release (sexp);
+ }
+ else
+ bbuf = NULL;
+
+ err = uncompress_ecc_q_in_canon_sexp (abuf, abuflen, &rbuf, &rbuflen);
+ if (err)
+ fail2 (idx,err);
+ if (rbuf)
+ fail (idx); /* Converted without a need. */
+
+ if (bbuf)
+ {
+ err = uncompress_ecc_q_in_canon_sexp (bbuf, bbuflen, &rbuf, &rbuflen);
+ if (gpg_err_code (err) == GPG_ERR_UNKNOWN_CURVE)
+ {
+ static int shown;
+ fprintf (stderr, "%s:%d: test %d failed: %s - ignored\n",
+ __FILE__,__LINE__, idx, gpg_strerror (err));
+ if (!shown)
+ {
+ shown = 1;
+ fprintf (stderr, "This is likely due to a patched"
+ " version of Libgcrypt with removed support"
+ " for Brainpool curves\n");
+ }
+ }
+ else
+ {
+ if (err)
+ fail2 (idx,err);
+ if (!rbuf)
+ fail (idx); /* Not converted despite a need for it. */
+
+ /* log_printcanon (" orig:", abuf, abuflen); */
+ /* log_printcanon (" comp:", bbuf, bbuflen); */
+ /* log_printcanon ("uncomp:", rbuf, rbuflen); */
+
+ if (rbuflen != abuflen || memcmp (rbuf, abuf, abuflen))
+ fail (idx);
+ }
+ }
+
+ xfree (abuf);
+ xfree (bbuf);
+ xfree (rbuf);
+ }
+}
+
+
+int
+main (int argc, char **argv)
+{
+ (void)argc;
+ (void)argv;
+
+ test_hash_algo_from_sigval ();
+ test_make_canon_sexp_from_rsa_pk ();
+ test_cmp_canon_sexp ();
+ test_ecc_uncompress ();
+
+ return 0;
+}
diff --git a/common/t-ssh-utils.c b/common/t-ssh-utils.c
new file mode 100644
index 0000000..1c9b87b
--- /dev/null
+++ b/common/t-ssh-utils.c
@@ -0,0 +1,391 @@
+/* t-ssh-utils.c - Module test for ssh-utils.c
+ * Copyright (C) 2011 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "util.h"
+#include "ssh-utils.h"
+
+
+static struct
+{
+ const char *key;
+ const char *fpr_md5;
+ const char *fpr_sha256;
+} sample_keys[] = {
+ { "(protected-private-key "
+ "(rsa "
+ "(n #"
+ "00D88E47BCE0DA99D6180E8A9F4E6A673CC16F5BB6CF930E0E868BAABA715A8E1D3E2BEA"
+ "5477170E1F6CAFC0F8907B9892993C70AC476BBB301669F68EE0593532FB522DD60755A3"
+ "2F8B08649E856271A7F9BCB25F29554DF11707F812EA377683A99DD4698C4DBF797A0ABF"
+ "43C8EBB364B9FFC9EE78CBEA348C590507A4EA390312153DDD905EC4F1A63D5DA56C08FD"
+ "C3F6E5707BFC5DBDC09D19723B1AC6E466906F13AA2ECDBD258148F86C980D45CF233415"
+ "38C5857C2CF0B4C9AB2B4E6A4517FF084FDB009A33553A68907A29691B6FAE994E864F78"
+ "7B83F714730BEDB0AF1723D636E034D73EB7EC9BA127BB4BE80FD805813E3F45E7FAE514"
+ "AD2ECA9607#)"
+ "(e \"#\")"
+ "(protected openpgp-s2k3-sha1-aes-cbc "
+ "("
+ "(sha1 #B5847F9A2DB4E0C5# \"5242880\")"
+ "#342D81BDE21301F18FDCE169A99A47C5#)"
+ "#23512602219EC7A97DBA89347CCD59D2072D80CE3F7DD6C97A058B83DAB3C829D97DF5"
+ "DFE9181F27DBF58258C4CDBD562A5B20BB5BC35EDCA7B1E57B8CDBF92D798F46EE5567BD"
+ "8A67EF3BE09908A49D41AA166A3398B64227BC75021C69A8FE8354E2903EF52DC91B1FE3"
+ "EF9558E5C2D34CF38BFC29E99A49AE30B0C22CE81EE14FC71E986E7C7CB5FCF807433FDA"
+ "EF1D00985767265BA0BE333754E44CCF622CBB98A029D78A6A9AADBC24613127B6448350"
+ "23DA355ED31CF089DD11A7FC6003CEEB53FB327A05604D053C99996F9E01CB355983F66E"
+ "7BEB9687A9277BBF440ED5FAF1A8396C9B06C9B47BA7A994E1931B08DAD34449952CD343"
+ "9A691477682C324EA07CCCE5DF0F0E9DAEFAE3A4717AACA6DC18ED91DD5A820C924BD36B"
+ "B3BA85BD63B3180C7F94EE58956940621280B9628FA5CC560BB14331AF1A7B5B499F8F03"
+ "0ED464ABD4E26C5FD610697EDD0FD1203983E73418F3776568A613D3CEFF17199473052A"
+ "18807A6F5C52A2A643185801D087EE4DC930ABEEB67C5B8A1CB2F29D0ACBD855972BEC0B"
+ "DE6E52387CFCC54B4C2B87EE947C97173BFCAE3E2658EB819D87F542C9A9FE6C410D08F5"
+ "3CD5451FB50253F4A848DFE136B3A5861D58B76A26A7E3E4E7A8F8D4BD5B80430674A6B9"
+ "A2C8EDD53DB37865D1ACBB07E1758DFF64A944E0126F948BF088C0FC0C3607E39522EC94"
+ "91483A90D9498D7F6C3C8720124C7E3F6E271E78E1CFFB4EF64F070F7424F30372A07D02"
+ "2355D8B17BB0DEBCBE101F621E0526551A35A56830D74E0F5BD6313DF114D1E46D4844AA"
+ "E4EB6268637D04B27D200D7F40AFA9AD2CFAA5415E5FC08358FFA79A9E743CCDF6668FE5"
+ "D79FA03D61941E57244F066A31F1C9D6A34DC62BC738C52B604F00B19EB9FD0173F3B139"
+ "42932066B7DC94DC4C563392F798A1CE2D5D75B8FF93E440433263CFB7016143A9923CD9"
+ "634E964A8056946F462B06F320F44449D85B07FA26A324505C858274F89EDBD8346950DE"
+ "5F#)"
+ "(protected-at \"20110720T135431\")"
+ ")"
+ "(comment passphrase_is_abc)"
+ ")",
+ "MD5:c7:c6:a7:ec:04:6c:87:59:54:f2:88:58:09:e0:f2:b1",
+ "SHA256:ksKb4DKk2SFX56GRtpt0szBnyjiYARSb2FNlUb7snnE"
+ },
+ {
+ "(protected-private-key "
+ "(dsa "
+ "(p #00FC7DC086F4517079BCCFA7FD229477FE88B0231038DFC21B29CCBD74C6F6FE04FD"
+ "7248C0473D5028BE106D7A7C8F54B269225789E781763527D1432CD46E416C2D14DDCA70"
+ "27DA4B92D1E222B5BDF4B9C8C761CACCFBD108F7729412E8835653BE5073447287A6BDEB"
+ "4645A5411752405EE7F503E44B1DFDCA6054CD3C44630B#)"
+ "(q #00D498505BF0E7EE01239EB51F2B400B8EF6329B17#)"
+ "(g #00A127B3DD5106F0A463312E42ECB83790E6F3BEA7AC3FAF7A42FB2C00F376323676"
+ "C9E48984F0D4AC3FE5856F1C2765E9BC3C8A5C9C9CD3166C057E82569D187C48591AA66B"
+ "8966BFF2B827BE36BD0BA4B895B42136F1381D52DDA708B2A3D181F648228DFFFEB153DA"
+ "ACCAEBB51EF08A7807CD628024CEFF96FEE97DE95C8CBE#)"
+ "(y #008E2B0915A3A299D83B4333C848C5D312F25903773E8C4D50691CAF81C3B768FA41"
+ "7D19F0FD437B377CCF51D3AE598649656D4D74D210CDBC2B76209B16EAAFCB14D6F4D691"
+ "20164885852AF1CEBB4D8602AD6755DFA7163645B4DB7926CD44D2DD9F840BFEF57F3DB0"
+ "933C85EB6B0AAC20BC67E73F47B8DDBEC8EFAA64286EF1#)"
+ "(protected openpgp-s2k3-sha1-aes-cbc "
+ "("
+ "(sha1 \"ü¿jy²üa4\" \"5242880\")"
+ "#FF12BEE0B03F842349717AE1AB6D7AC2#)"
+ "#95570487C8B5C49492D4E662259F2CF9B6D7E64F728F17A1FE1B2DA616E5976FE32861E"
+ "C4B1F0DA03D9006C432CF2136871266E9444377ACEF04340B36B4550B5C1E4CC69AD4380"
+ "A709FB0DAA5104A8B#)"
+ "(protected-at \"20110720T142801\")"
+ ")"
+ "(comment sample_dsa_passphrase_is_abc)"
+ ")",
+ "MD5:2d:b1:70:1a:04:9e:41:a3:ce:27:a5:c7:22:fe:3a:a3",
+ "SHA256:z8+8HEuD/5QpegGS4tSK02dJF+a6o2V67VM2gOPz9oQ"
+ },
+ { /* OpenSSH 6.7p1 generated key: */
+ "(protected-private-key "
+ "(ecdsa "
+ "(curve \"NIST P-256\")"
+ "(q #041F17ED5E3D637181DFA68157270F94A46C089B6F5D4518564600551C0A60A063B3"
+ "31EDE027A23CAB58A5BAD469600229DC8DED06380A92F86460ED400F963319#)"
+ "(protected openpgp-s2k3-sha1-aes-cbc "
+ "("
+ "(sha1 #43F887516D94A502# \"20971520\")"
+ "#B135DEDA02CF36F126BA661FB22A35CF#)"
+ "#37E74BEC054B17723C106BA69214CFDA245512E40F4848ECF5719E3700002C940BC7EEC"
+ "283537CA4D8779107E07F03AAA9FAF155BA9BF6286080C35EF72DDAAF303FD9069475B03"
+ "C99D9FC93C58CD83A852964D2C7BFD1D803E2ECD1331937C3#)"
+ "(protected-at \"20150922T071259\")"
+ ")"
+ "(comment \"ecdsa w/o comment\")"
+ ")", /* Passphrase="abc" */
+ "MD5:93:4f:08:02:7d:cb:16:9b:0c:39:21:4b:cf:28:5a:19",
+ "SHA256:zSj4uXfE1hlQnESD2LO723fMGXsNwzHrfqOfqep37is"
+ },
+ { /* OpenSSH 6.7p1 generated key: */
+ "(protected-private-key "
+ "(ecdsa "
+ "(curve \"NIST P-384\") "
+ "(q #04B6E747AC2F179F96088D1DB58EB8600BB23FAEF5F58EFE712A7478FB7BF735"
+ "B015EA2DFBBA965D8C6EB135A2B9B9599D65BF0167D2DB6ABF00F641F0F5FC15A4C3"
+ "EFE432DA331B7C8A66D6C4C2B0EBB5ED11A80301C4E57C1EBD25665CEBF123#)"
+ "(protected openpgp-s2k3-sha1-aes-cbc "
+ "("
+ "(sha1 #3B13710B67D756EA# \"20971520\")"
+ "#720599AC095BF1BD73ED72F49FB77BFA#)"
+ "#F1A522F4533E3A6E40821D67CEA6C28A7FF07ACA4BEE81E0F39193B2E469E0C583D"
+ "A42E0E2D52ADB5ACFAB9C4CA7F1C3556FD7FD2770717FB3CE7C59474A3E2A7AF3D93"
+ "9EC01E067DAAA60D3D355D9BABCCD1F013E8637C555DDFA61F8FA5AFB010FF02979D"
+ "35BBBEED71BFD8BB508F7#)"
+ "(protected-at \"20150922T070806\")"
+ ")"
+ "(comment \"ecdsa w/o comment\")"
+ ")", /* Passphrase="abc" */
+ "MD5:a3:cb:44:c8:56:15:25:62:85:fd:e8:04:7a:26:dc:76",
+ "SHA256:JuQh5fjduynuuTEwI9C6yAKK1NnLX9PPd7TP0qZfbGs"
+ },
+ { /* OpenSSH 6.7p1 generated key: */
+ "(protected-private-key "
+ "(ecdsa "
+ "(curve \"NIST P-521\")"
+ "(q #04005E460058F37DB5ADA670040203C4D7E18D9FC8A7087165904A4E25EE5EEE"
+ "3046406D922616DA7E71016A1CB9E57A45E3D3727D7C8DF0F11AE2BD75FAD3355CAA"
+ "E1019D89D33CC77424E5DA233588207444FC9F67BBE428A9528B7DC77AF8261A1D45"
+ "ACC1A657C99E361E93C1E5C0F214104C18807670F4CDC1E038B7C950FDBAAECB40#)"
+ "(protected openpgp-s2k3-sha1-aes-cbc "
+ "("
+ "(sha1 #FB2E36984DE2E17C# \"19737600\")"
+ "#85DB6445B37012F9A449E5AC0D5017E9#)"
+ "#B4C7CCDFE9B5D32B31BA7C763B80485A62EBF34FD68D8E306DA75FD2BDDBABAA098"
+ "9B51972BA3B731DA5261E0ADC3FAEF9BB4C8284C53D3E88E738AEF1490941903A5B2"
+ "9F3747E83C4D80B6A89E0B7BDEE5C6638332F4AAEA5983F760B2887A43A1C4BE0564"
+ "3F72C6943987D97FDAA7D9C235C6D31973A2400DA9BAB564A16EA#)"
+ "(protected-at \"20150922T075611\")"
+ ")"
+ "(comment \"ecdsa w/o comment\")"
+ ")", /* Passphrase="abc" */
+ "MD5:1e:a6:94:ab:bd:81:73:5f:22:bc:0e:c7:89:f6:68:df",
+ "SHA256:+pbRyYa2UBwDki1k4Wziu2CKrdJIbZM/hOWOQ/sNe/0"
+ },
+ { /* OpenSSH 6.7p1 generated key: */
+ "(protected-private-key "
+ "(ecc "
+ "(curve Ed25519)"
+ "(flags eddsa)"
+ "(q #40A3577AA7830C50EBC15B538E9505DB2F0D2FFCD57EA477DD83dcaea530f3c277#)"
+ "(protected openpgp-s2k3-sha1-aes-cbc "
+ "("
+ "(sha1 #FA8123F1A37CBC1F# \"3812352\")"
+ "#7671C7387E2DD931CC62C35CBBE08A28#)"
+ "#75e928f4698172b61dffe9ef2ada1d3473f690f3879c5386e2717e5b2fa46884"
+ "b189ee409827aab0ff37f62996e040b5fa7e75fc4d8152c8734e2e648dff90c9"
+ "e8c3e39ea7485618d05c34b1b74ff59676e9a3d932245cc101b5904777a09f86#)"
+ "(protected-at \"20150928T050210\")"
+ ")"
+ "(comment \"eddsa w/o comment\")"
+ ")", /* Passphrase="abc" */
+ "MD5:f1:fa:c8:a6:40:bb:b9:a1:65:d7:62:65:ac:26:78:0e",
+ "SHA256:yhwBfYnTOnSXcWf1EOPo+oIIpNJ6w/bG36udZ96MmsQ"
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+
+
+static char *
+read_file (const char *fname, size_t *r_length)
+{
+ FILE *fp;
+ char *buf;
+ size_t buflen;
+ struct stat st;
+
+ fp = fopen (fname, "rb");
+ if (!fp)
+ {
+ fprintf (stderr, "%s:%d: can't open '%s': %s\n",
+ __FILE__, __LINE__, fname, strerror (errno));
+ exit (1);
+ }
+
+ if (fstat (fileno(fp), &st))
+ {
+ fprintf (stderr, "%s:%d: can't stat '%s': %s\n",
+ __FILE__, __LINE__, fname, strerror (errno));
+ exit (1);
+ }
+
+ buflen = st.st_size;
+ buf = xmalloc (buflen+1);
+ if (fread (buf, buflen, 1, fp) != 1)
+ {
+ fprintf (stderr, "%s:%d: error reading '%s': %s\n",
+ __FILE__, __LINE__, fname, strerror (errno));
+ exit (1);
+ }
+ fclose (fp);
+
+ *r_length = buflen;
+ return buf;
+}
+
+
+static gcry_sexp_t
+read_key (const char *fname)
+{
+ gpg_error_t err;
+ char *buf;
+ size_t buflen;
+ gcry_sexp_t key;
+
+ buf = read_file (fname, &buflen);
+
+ err = gcry_sexp_sscan (&key, NULL, buf, buflen);
+ if (err)
+ {
+ fprintf (stderr, "%s:%d: gcry_sexp_sscan failed: %s\n",
+ __FILE__, __LINE__, gpg_strerror (err));
+ exit (1); \
+ }
+
+ xfree (buf);
+ return key;
+}
+
+
+int
+main (int argc, char **argv)
+{
+ gpg_error_t err;
+ gcry_sexp_t key;
+ char *string;
+ int idx;
+
+ /* --dump-keys dumps the keys as KEYGRIP.key.IDX. Useful to compute
+ fingerprints to enhance the test vectors. */
+ if (argc == 2 && strcmp (argv[1], "--dump-keys") == 0)
+ for (idx=0; sample_keys[idx].key; idx++)
+ {
+ FILE *s;
+ char *name;
+ char grip[20];
+ char *hexgrip;
+
+ err = keygrip_from_canon_sexp (sample_keys[idx].key,
+ strlen (sample_keys[idx].key),
+ grip);
+ if (err)
+ {
+ fprintf (stderr, "%s:%d: error computing keygrip: %s\n",
+ __FILE__, __LINE__, gpg_strerror (err));
+ exit (1);
+ }
+ hexgrip = bin2hex (grip, 20, NULL);
+
+ name = xtryasprintf ("%s.key.%d", hexgrip, idx);
+ s = fopen (name, "w");
+ if (s == NULL)
+ {
+ fprintf (stderr, "%s:%d: error opening file: %s\n",
+ __FILE__, __LINE__, gpg_strerror (gpg_error_from_syserror ()));
+ exit (1);
+ }
+ xfree (name);
+ fprintf (s, "%s", sample_keys[idx].key);
+ fclose (s);
+ }
+ else if (argc == 2)
+ {
+ key = read_key (argv[1]);
+
+ err = ssh_get_fingerprint_string (key, GCRY_MD_MD5, &string);
+ if (err)
+ {
+ fprintf (stderr, "%s:%d: error getting fingerprint: %s\n",
+ __FILE__, __LINE__, gpg_strerror (err));
+ exit (1);
+ }
+ puts (string);
+ xfree (string);
+
+ err = ssh_get_fingerprint_string (key, GCRY_MD_SHA256, &string);
+ if (err)
+ {
+ fprintf (stderr, "%s:%d: error getting fingerprint: %s\n",
+ __FILE__, __LINE__, gpg_strerror (err));
+ exit (1);
+ }
+ puts (string);
+ xfree (string);
+
+ gcry_sexp_release (key);
+ }
+ else
+ {
+ for (idx=0; sample_keys[idx].key; idx++)
+ {
+ err = gcry_sexp_sscan (&key, NULL, sample_keys[idx].key,
+ strlen (sample_keys[idx].key));
+ if (err)
+ {
+ fprintf (stderr, "%s:%d: gcry_sexp_sscan failed for "
+ "sample key %d: %s\n",
+ __FILE__, __LINE__, idx, gpg_strerror (err));
+ exit (1);
+ }
+
+ err = ssh_get_fingerprint_string (key, GCRY_MD_MD5, &string);
+ if (err)
+ {
+ fprintf (stderr, "%s:%d: error getting fingerprint for "
+ "sample key %d: %s\n",
+ __FILE__, __LINE__, idx, gpg_strerror (err));
+ exit (1);
+ }
+
+ if (strcmp (string, sample_keys[idx].fpr_md5))
+ {
+ fprintf (stderr, "%s:%d: fingerprint mismatch for "
+ "sample key %d\n",
+ __FILE__, __LINE__, idx);
+ fprintf (stderr, "want: %s\n got: %s\n",
+ sample_keys[idx].fpr_md5, string);
+ exit (1);
+ }
+ xfree (string);
+
+ err = ssh_get_fingerprint_string (key, GCRY_MD_SHA256, &string);
+ if (err)
+ {
+ fprintf (stderr, "%s:%d: error getting fingerprint for "
+ "sample key %d: %s\n",
+ __FILE__, __LINE__, idx, gpg_strerror (err));
+ exit (1);
+ }
+
+ if (strcmp (string, sample_keys[idx].fpr_sha256))
+ {
+ fprintf (stderr, "%s:%d: fingerprint mismatch for "
+ "sample key %d\n",
+ __FILE__, __LINE__, idx);
+ fprintf (stderr, "want: %s\n got: %s\n",
+ sample_keys[idx].fpr_sha256, string);
+ exit (1);
+ }
+ xfree (string);
+
+ gcry_sexp_release (key);
+ }
+ }
+
+ return 0;
+}
diff --git a/common/t-stringhelp.c b/common/t-stringhelp.c
new file mode 100644
index 0000000..d76991f
--- /dev/null
+++ b/common/t-stringhelp.c
@@ -0,0 +1,1319 @@
+/* t-stringhelp.c - Regression tests for stringhelp.c
+ * Copyright (C) 2007 Free Software Foundation, Inc.
+ * 2015, 2021 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute and/or modify this
+ * part of GnuPG under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * 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 copies of the GNU General Public License
+ * and the GNU Lesser General Public License along with this program;
+ * if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: (LGPL-3.0-or-later OR GPL-2.0-or-later)
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#ifdef HAVE_PWD_H
+# include <pwd.h>
+#endif
+#include <unistd.h>
+#include <sys/types.h>
+#include <limits.h>
+#include <assert.h>
+
+#include "t-support.h"
+#include "sysutils.h"
+#include "stringhelp.h"
+
+
+static char *home_buffer;
+
+
+const char *
+gethome (void)
+{
+ if (!home_buffer)
+ {
+ char *home = getenv("HOME");
+
+ if(home)
+ home_buffer = xstrdup (home);
+#if defined(HAVE_GETPWUID) && defined(HAVE_PWD_H)
+ else
+ {
+ struct passwd *pwd;
+
+ pwd = getpwuid (getuid());
+ if (pwd)
+ home_buffer = xstrdup (pwd->pw_dir);
+ }
+#endif
+ }
+ return home_buffer;
+}
+
+
+static char *
+mygetcwd (void)
+{
+ char *buffer;
+ size_t size = 100;
+
+ for (;;)
+ {
+ buffer = xmalloc (size+1);
+#ifdef HAVE_W32CE_SYSTEM
+ strcpy (buffer, "/"); /* Always "/". */
+ return buffer;
+#else
+ if (getcwd (buffer, size) == buffer)
+ return buffer;
+ xfree (buffer);
+ if (errno != ERANGE)
+ {
+ fprintf (stderr,"error getting current cwd: %s\n",
+ strerror (errno));
+ exit (2);
+ }
+ size *= 2;
+#endif
+ }
+}
+
+
+static void
+test_percent_escape (void)
+{
+ char *result;
+ static struct {
+ const char *extra;
+ const char *value;
+ const char *expected;
+ } tests[] =
+ {
+ { NULL, "", "" },
+ { NULL, "%", "%25" },
+ { NULL, "%%", "%25%25" },
+ { NULL, " %", " %25" },
+ { NULL, ":", "%3a" },
+ { NULL, " :", " %3a" },
+ { NULL, ": ", "%3a " },
+ { NULL, " : ", " %3a " },
+ { NULL, "::", "%3a%3a" },
+ { NULL, ": :", "%3a %3a" },
+ { NULL, "%:", "%25%3a" },
+ { NULL, ":%", "%3a%25" },
+ { "\\\n:", ":%", "%3a%25" },
+ { "\\\n:", "\\:%", "%5c%3a%25" },
+ { "\\\n:", "\n:%", "%0a%3a%25" },
+ { "\\\n:", "\xff:%", "\xff%3a%25" },
+ { "\\\n:", "\xfe:%", "\xfe%3a%25" },
+ { "\\\n:", "\x01:%", "\x01%3a%25" },
+ { "\x01", "\x01:%", "%01%3a%25" },
+ { "\xfe", "\xfe:%", "%fe%3a%25" },
+ { "\xfe", "\xff:%", "\xff%3a%25" },
+
+ { NULL, NULL, NULL }
+ };
+ int testno;
+
+ result = percent_escape (NULL, NULL);
+ if (result)
+ fail (0);
+ for (testno=0; tests[testno].value; testno++)
+ {
+ result = percent_escape (tests[testno].value, tests[testno].extra);
+ if (!result)
+ fail (testno);
+ else if (strcmp (result, tests[testno].expected))
+ fail (testno);
+ xfree (result);
+ }
+
+}
+
+
+static void
+test_compare_filenames (void)
+{
+ struct {
+ const char *a;
+ const char *b;
+ int result;
+ } tests[] = {
+ { "", "", 0 },
+ { "", "a", -1 },
+ { "a", "", 1 },
+ { "a", "a", 0 },
+ { "a", "aa", -1 },
+ { "aa", "a", 1 },
+ { "a", "b", -1 },
+
+#ifdef HAVE_W32_SYSTEM
+ { "a", "A", 0 },
+ { "A", "a", 0 },
+ { "foo/bar", "foo\\bar", 0 },
+ { "foo\\bar", "foo/bar", 0 },
+ { "foo\\", "foo/", 0 },
+ { "foo/", "foo\\", 0 },
+#endif /*HAVE_W32_SYSTEM*/
+ { NULL, NULL, 0}
+ };
+ int testno, result;
+
+ for (testno=0; tests[testno].a; testno++)
+ {
+ result = compare_filenames (tests[testno].a, tests[testno].b);
+ result = result < 0? -1 : result > 0? 1 : 0;
+ if (result != tests[testno].result)
+ fail (testno);
+ }
+}
+
+
+static void
+test_strconcat (void)
+{
+ char *out;
+
+ out = strconcat ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "1", "2", "3", "4", "5", "6", "7", NULL);
+ if (!out)
+ fail (0);
+ else
+ xfree (out);
+ out = strconcat ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "1", "2", "3", "4", "5", "6", "7", "8", NULL);
+ if (out)
+ fail (0);
+ else if (errno != EINVAL)
+ fail (0);
+
+ out = strconcat ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "1", "2", "3", "4", "5", "6", "7", "8", "9", NULL);
+ if (out)
+ fail (0);
+ else if (errno != EINVAL)
+ fail (0);
+ xfree (out);
+
+#if __GNUC__ < 4 /* gcc 4.0 has a sentinel attribute. */
+ out = strconcat (NULL);
+ if (!out || *out)
+ fail (1);
+#endif
+ out = strconcat (NULL, NULL);
+ if (!out || *out)
+ fail (1);
+ xfree (out);
+
+ out = strconcat ("", NULL);
+ if (!out || *out)
+ fail (1);
+ xfree (out);
+
+ out = strconcat ("", "", NULL);
+ if (!out || *out)
+ fail (2);
+ xfree (out);
+
+ out = strconcat ("a", "b", NULL);
+ if (!out || strcmp (out, "ab"))
+ fail (3);
+ xfree (out);
+ out = strconcat ("a", "b", "c", NULL);
+ if (!out || strcmp (out, "abc"))
+ fail (3);
+ xfree (out);
+
+ out = strconcat ("a", "b", "cc", NULL);
+ if (!out || strcmp (out, "abcc"))
+ fail (4);
+ xfree (out);
+ out = strconcat ("a1", "b1", "c1", NULL);
+ if (!out || strcmp (out, "a1b1c1"))
+ fail (4);
+ xfree (out);
+
+ out = strconcat ("", " long b ", "", "--even-longer--", NULL);
+ if (!out || strcmp (out, " long b --even-longer--"))
+ fail (5);
+ xfree (out);
+
+ out = strconcat ("", " long b ", "", "--even-longer--", NULL);
+ if (!out || strcmp (out, " long b --even-longer--"))
+ fail (5);
+ xfree (out);
+}
+
+static void
+test_xstrconcat (void)
+{
+ char *out;
+
+ out = xstrconcat ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "1", "2", "3", "4", "5", "6", "7", NULL);
+ if (!out)
+ fail (0);
+ xfree (out);
+
+#if __GNUC__ < 4 /* gcc 4.0 has a sentinel attribute. */
+ out = xstrconcat (NULL);
+ if (!out)
+ fail (1);
+#endif
+ out = xstrconcat (NULL, NULL);
+ if (!out)
+ fail (1);
+ xfree (out);
+
+ out = xstrconcat ("", NULL);
+ if (!out || *out)
+ fail (1);
+ xfree (out);
+
+ out = xstrconcat ("", "", NULL);
+ if (!out || *out)
+ fail (2);
+ xfree (out);
+
+ out = xstrconcat ("a", "b", NULL);
+ if (!out || strcmp (out, "ab"))
+ fail (3);
+ xfree (out);
+ out = xstrconcat ("a", "b", "c", NULL);
+ if (!out || strcmp (out, "abc"))
+ fail (3);
+ xfree (out);
+
+ out = xstrconcat ("a", "b", "cc", NULL);
+ if (!out || strcmp (out, "abcc"))
+ fail (4);
+ xfree (out);
+ out = xstrconcat ("a1", "b1", "c1", NULL);
+ if (!out || strcmp (out, "a1b1c1"))
+ fail (4);
+ xfree (out);
+
+ out = xstrconcat ("", " long b ", "", "--even-longer--", NULL);
+ if (!out || strcmp (out, " long b --even-longer--"))
+ fail (5);
+ xfree (out);
+
+ out = xstrconcat ("", " long b ", "", "--even-longer--", NULL);
+ if (!out || strcmp (out, " long b --even-longer--"))
+ fail (5);
+ xfree (out);
+}
+
+
+static void
+test_make_filename_try (void)
+{
+ char *out;
+ const char *home = gethome ();
+ size_t homelen = home? strlen (home):0;
+
+ out = make_filename_try ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "1", "2", "3", NULL);
+ if (out)
+ fail (0);
+ else if (errno != EINVAL)
+ fail (0);
+ xfree (out);
+ out = make_filename_try ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "1", "2", "3", "4", NULL);
+ if (out)
+ fail (0);
+ else if (errno != EINVAL)
+ fail (0);
+ xfree (out);
+
+ out = make_filename_try ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
+ "1", "2", NULL);
+ if (!out || strcmp (out,
+ "1/2/3/4/5/6/7/8/9/10/"
+ "1/2/3/4/5/6/7/8/9/10/"
+ "1/2/3/4/5/6/7/8/9/10/"
+ "1/2"))
+ fail (0);
+ xfree (out);
+
+ out = make_filename_try ("foo", "~/bar", "baz/cde", NULL);
+ if (!out || strcmp (out, "foo/~/bar/baz/cde"))
+ fail (1);
+ xfree (out);
+
+ out = make_filename_try ("foo", "~/bar", "baz/cde/", NULL);
+ if (!out || strcmp (out, "foo/~/bar/baz/cde/"))
+ fail (1);
+ xfree (out);
+
+ out = make_filename_try ("/foo", "~/bar", "baz/cde/", NULL);
+ if (!out || strcmp (out, "/foo/~/bar/baz/cde/"))
+ fail (1);
+ xfree (out);
+
+ out = make_filename_try ("//foo", "~/bar", "baz/cde/", NULL);
+ if (!out || strcmp (out, "//foo/~/bar/baz/cde/"))
+ fail (1);
+ xfree (out);
+
+ out = make_filename_try ("", "~/bar", "baz/cde", NULL);
+ if (!out || strcmp (out, "/~/bar/baz/cde"))
+ fail (1);
+ xfree (out);
+
+
+ out = make_filename_try ("~/foo", "bar", NULL);
+ if (!out)
+ fail (2);
+ else if (home)
+ {
+ if (strlen (out) < homelen + 7)
+ fail (2);
+ else if (strncmp (out, home, homelen))
+ fail (2);
+ else if (strcmp (out+homelen, "/foo/bar"))
+ fail (2);
+ }
+ else
+ {
+ if (strcmp (out, "~/foo/bar"))
+ fail (2);
+ }
+ xfree (out);
+
+ out = make_filename_try ("~", "bar", NULL);
+ if (!out)
+ fail (2);
+ else if (home)
+ {
+ if (strlen (out) < homelen + 3)
+ fail (2);
+ else if (strncmp (out, home, homelen))
+ fail (2);
+ else if (strcmp (out+homelen, "/bar"))
+ fail (2);
+ }
+ else
+ {
+ if (strcmp (out, "~/bar"))
+ fail (2);
+ }
+ xfree (out);
+}
+
+
+static void
+test_make_absfilename_try (void)
+{
+ char *out;
+ char *cwd = mygetcwd ();
+ size_t cwdlen = strlen (cwd);
+
+ out = make_absfilename_try ("foo", "bar", NULL);
+ if (!out)
+ fail (0);
+ else if (strlen (out) < cwdlen + 7)
+ fail (0);
+ else if (strncmp (out, cwd, cwdlen))
+ fail (0);
+ else if (strcmp (out+cwdlen, "/foo/bar"))
+ fail (0);
+ xfree (out);
+
+ out = make_absfilename_try ("./foo", NULL);
+ if (!out)
+ fail (1);
+ else if (strlen (out) < cwdlen + 5)
+ fail (1);
+ else if (strncmp (out, cwd, cwdlen))
+ fail (1);
+ else if (strcmp (out+cwdlen, "/./foo"))
+ fail (1);
+ xfree (out);
+
+ out = make_absfilename_try (".", NULL);
+ if (!out)
+ fail (2);
+ else if (strlen (out) < cwdlen)
+ fail (2);
+ else if (strncmp (out, cwd, cwdlen))
+ fail (2);
+ else if (strcmp (out+cwdlen, ""))
+ fail (2);
+ xfree (out);
+
+ xfree (cwd);
+}
+
+static void
+test_strsplit (void)
+{
+ struct {
+ const char *s;
+ char delim;
+ char replacement;
+ const char *fields_expected[10];
+ } tv[] = {
+ {
+ "a:bc:cde:fghi:jklmn::foo:", ':', '\0',
+ { "a", "bc", "cde", "fghi", "jklmn", "", "foo", "", NULL }
+ },
+ {
+ ",a,bc,,def,", ',', '!',
+ { "!a!bc!!def!", "a!bc!!def!", "bc!!def!", "!def!", "def!", "", NULL }
+ },
+ {
+ "", ':', ',',
+ { "", NULL }
+ }
+ };
+
+ int tidx;
+
+ for (tidx = 0; tidx < DIM(tv); tidx++)
+ {
+ char *s2;
+ int field_count;
+ char **fields;
+ int field_count_expected;
+ int i;
+
+ /* Count the fields. */
+ for (field_count_expected = 0;
+ tv[tidx].fields_expected[field_count_expected];
+ field_count_expected ++)
+ ;
+
+ /* We need to copy s since strsplit modifies it in place. */
+ s2 = xstrdup (tv[tidx].s);
+ fields = strsplit (s2, tv[tidx].delim, tv[tidx].replacement,
+ &field_count);
+
+ if (field_count != field_count_expected)
+ fail (tidx * 1000);
+
+ for (i = 0; i < field_count_expected; i ++)
+ if (strcmp (tv[tidx].fields_expected[i], fields[i]) != 0)
+ {
+ printf ("For field %d, expected '%s', but got '%s'\n",
+ i, tv[tidx].fields_expected[i], fields[i]);
+ fail (tidx * 1000 + i + 1);
+ }
+
+ xfree (fields);
+ xfree (s2);
+ }
+}
+
+
+
+static void
+test_strtokenize (void)
+{
+ struct {
+ const char *s;
+ const char *delim;
+ const char *fields_expected[10];
+ } tv[] = {
+ {
+ "", ":",
+ { "", NULL }
+ },
+ {
+ "a", ":",
+ { "a", NULL }
+ },
+ {
+ ":", ":",
+ { "", "", NULL }
+ },
+ {
+ "::", ":",
+ { "", "", "", NULL }
+ },
+ {
+ "a:b:c", ":",
+ { "a", "b", "c", NULL }
+ },
+ {
+ "a:b:", ":",
+ { "a", "b", "", NULL }
+ },
+ {
+ "a:b", ":",
+ { "a", "b", NULL }
+ },
+ {
+ "aa:b:cd", ":",
+ { "aa", "b", "cd", NULL }
+ },
+ {
+ "aa::b:cd", ":",
+ { "aa", "", "b", "cd", NULL }
+ },
+ {
+ "::b:cd", ":",
+ { "", "", "b", "cd", NULL }
+ },
+ {
+ "aa: : b:cd ", ":",
+ { "aa", "", "b", "cd", NULL }
+ },
+ {
+ " aa: : b: cd ", ":",
+ { "aa", "", "b", "cd", NULL }
+ },
+ {
+ " ", ":",
+ { "", NULL }
+ },
+ {
+ " :", ":",
+ { "", "", NULL }
+ },
+ {
+ " : ", ":",
+ { "", "", NULL }
+ },
+ {
+ ": ", ":",
+ { "", "", NULL }
+ },
+ {
+ ": x ", ":",
+ { "", "x", NULL }
+ },
+ {
+ "a:bc:cde:fghi:jklmn::foo:", ":",
+ { "a", "bc", "cde", "fghi", "jklmn", "", "foo", "", NULL }
+ },
+ {
+ ",a,bc,,def,", ",",
+ { "", "a", "bc", "", "def", "", NULL }
+ },
+ {
+ " a ", " ",
+ { "", "a", "", NULL }
+ },
+ {
+ " ", " ",
+ { "", "", NULL }
+ },
+ {
+ "", " ",
+ { "", NULL }
+ }
+ };
+
+ int tidx;
+
+ for (tidx = 0; tidx < DIM(tv); tidx++)
+ {
+ char **fields;
+ int field_count;
+ int field_count_expected;
+ int i;
+
+ for (field_count_expected = 0;
+ tv[tidx].fields_expected[field_count_expected];
+ field_count_expected ++)
+ ;
+
+ fields = strtokenize (tv[tidx].s, tv[tidx].delim);
+ if (!fields)
+ fail (tidx * 1000);
+ else
+ {
+ for (field_count = 0; fields[field_count]; field_count++)
+ ;
+ if (field_count != field_count_expected)
+ fail (tidx * 1000);
+ else
+ {
+ for (i = 0; i < field_count_expected; i++)
+ if (strcmp (tv[tidx].fields_expected[i], fields[i]))
+ {
+ printf ("For field %d, expected '%s', but got '%s'\n",
+ i, tv[tidx].fields_expected[i], fields[i]);
+ fail (tidx * 1000 + i + 1);
+ }
+ }
+ }
+
+ xfree (fields);
+ }
+}
+
+
+static void
+test_strtokenize_nt (void)
+{
+ struct {
+ const char *s;
+ const char *delim;
+ const char *fields_expected[10];
+ } tv[] = {
+ {
+ "", ":",
+ { "", NULL }
+ },
+ {
+ "a", ":",
+ { "a", NULL }
+ },
+ {
+ ":", ":",
+ { "", "", NULL }
+ },
+ {
+ "::", ":",
+ { "", "", "", NULL }
+ },
+ {
+ "a:b:c", ":",
+ { "a", "b", "c", NULL }
+ },
+ {
+ "a:b:", ":",
+ { "a", "b", "", NULL }
+ },
+ {
+ "a:b", ":",
+ { "a", "b", NULL }
+ },
+ {
+ "aa:b:cd", ":",
+ { "aa", "b", "cd", NULL }
+ },
+ {
+ "aa::b:cd", ":",
+ { "aa", "", "b", "cd", NULL }
+ },
+ {
+ "::b:cd", ":",
+ { "", "", "b", "cd", NULL }
+ },
+ {
+ "aa: : b:cd ", ":",
+ { "aa", " ", " b", "cd ", NULL }
+ },
+ {
+ " aa: : b: cd ", ":",
+ { " aa", " ", " b", " cd ", NULL }
+ },
+ {
+ " ", ":",
+ { " ", NULL }
+ },
+ {
+ " :", ":",
+ { " ", "", NULL }
+ },
+ {
+ " : ", ":",
+ { " ", " ", NULL }
+ },
+ {
+ ": ", ":",
+ { "", " ", NULL }
+ },
+ {
+ ": x ", ":",
+ { "", " x ", NULL }
+ },
+ {
+ "a:bc:cde:fghi:jklmn::foo:", ":",
+ { "a", "bc", "cde", "fghi", "jklmn", "", "foo", "", NULL }
+ },
+ {
+ ",a,bc,,def,", ",",
+ { "", "a", "bc", "", "def", "", NULL }
+ },
+ {
+ " a ", " ",
+ { "", "a", "", NULL }
+ },
+ {
+ " ", " ",
+ { "", "", NULL }
+ },
+ {
+ "", " ",
+ { "", NULL }
+ }
+ };
+
+ int tidx;
+
+ for (tidx = 0; tidx < DIM(tv); tidx++)
+ {
+ char **fields;
+ int field_count;
+ int field_count_expected;
+ int i;
+
+ for (field_count_expected = 0;
+ tv[tidx].fields_expected[field_count_expected];
+ field_count_expected ++)
+ ;
+
+ fields = strtokenize_nt (tv[tidx].s, tv[tidx].delim);
+ if (!fields)
+ fail (tidx * 1000);
+ else
+ {
+ for (field_count = 0; fields[field_count]; field_count++)
+ ;
+ if (field_count != field_count_expected)
+ fail (tidx * 1000);
+ else
+ {
+ for (i = 0; i < field_count_expected; i++)
+ if (strcmp (tv[tidx].fields_expected[i], fields[i]))
+ {
+ printf ("For field %d, expected '%s', but got '%s'\n",
+ i, tv[tidx].fields_expected[i], fields[i]);
+ fail (tidx * 1000 + i + 1);
+ }
+ }
+ }
+
+ xfree (fields);
+ }
+}
+
+
+static void
+test_split_fields (void)
+{
+ struct {
+ const char *s;
+ int nfields;
+ const char *fields_expected[10];
+ } tv[] = {
+ {
+ "a bc cde fghi jklmn foo ", 6,
+ { "a", "bc", "cde", "fghi", "jklmn", "foo", NULL }
+ },
+ {
+ " a bc def ", 2,
+ { "a", "bc", "def", NULL }
+ },
+ {
+ " a bc def ", 3,
+ { "a", "bc", "def", NULL }
+ },
+ {
+ " a bc def ", 4,
+ { "a", "bc", "def", NULL }
+ },
+ {
+ "", 0,
+ { NULL }
+ }
+ };
+
+ int tidx;
+ char *fields[10];
+ int field_count_expected, nfields, field_count, i;
+ char *s2;
+
+ for (tidx = 0; tidx < DIM(tv); tidx++)
+ {
+ nfields = tv[tidx].nfields;
+ assert (nfields <= DIM (fields));
+
+ /* Count the fields. */
+ for (field_count_expected = 0;
+ tv[tidx].fields_expected[field_count_expected];
+ field_count_expected ++)
+ ;
+ if (field_count_expected > nfields)
+ field_count_expected = nfields;
+
+ /* We need to copy s since split_fields modifies in place. */
+ s2 = xstrdup (tv[tidx].s);
+ field_count = split_fields (s2, fields, nfields);
+
+ if (field_count != field_count_expected)
+ {
+ printf ("%s: tidx %d: expected %d, got %d\n",
+ __func__, tidx, field_count_expected, field_count);
+ fail (tidx * 1000);
+ }
+ else
+ {
+ for (i = 0; i < field_count_expected; i ++)
+ if (strcmp (tv[tidx].fields_expected[i], fields[i]))
+ {
+ printf ("%s: tidx %d, field %d: expected '%s', got '%s'\n",
+ __func__,
+ tidx, i, tv[tidx].fields_expected[i], fields[i]);
+ fail (tidx * 1000 + i + 1);
+ }
+ }
+
+ xfree (s2);
+ }
+}
+
+
+static void
+test_split_fields_colon (void)
+{
+ struct {
+ const char *s;
+ int nfields;
+ const char *fields_expected[10];
+ } tv[] = {
+ {
+ "a:bc:cde:fghi:jklmn: foo ", 6,
+ { "a", "bc", "cde", "fghi", "jklmn", " foo ", NULL }
+ },
+ {
+ " a:bc: def ", 2,
+ { " a", "bc", NULL }
+ },
+ {
+ " a:bc :def ", 3,
+ { " a", "bc ", "def ", NULL }
+ },
+ {
+ " a:bc: def ", 4,
+ { " a", "bc", " def ", NULL }
+ },
+ {
+ "", 0,
+ { NULL }
+ }
+ };
+
+ int tidx;
+ char *fields[10];
+ int field_count_expected, nfields, field_count, i;
+ char *s2;
+
+ for (tidx = 0; tidx < DIM(tv); tidx++)
+ {
+ nfields = tv[tidx].nfields;
+ assert (nfields <= DIM (fields));
+
+ /* Count the fields. */
+ for (field_count_expected = 0;
+ tv[tidx].fields_expected[field_count_expected];
+ field_count_expected ++)
+ ;
+ if (field_count_expected > nfields)
+ field_count_expected = nfields;
+
+ /* We need to copy s since split_fields modifies in place. */
+ s2 = xstrdup (tv[tidx].s);
+ field_count = split_fields_colon (s2, fields, nfields);
+
+ if (field_count != field_count_expected)
+ {
+ printf ("%s: tidx %d: expected %d, got %d\n",
+ __func__, tidx, field_count_expected, field_count);
+ fail (tidx * 1000);
+ }
+ else
+ {
+ for (i = 0; i < field_count_expected; i ++)
+ if (strcmp (tv[tidx].fields_expected[i], fields[i]))
+ {
+ printf ("%s: tidx %d, field %d: expected '%s', got '%s'\n",
+ __func__,
+ tidx, i, tv[tidx].fields_expected[i], fields[i]);
+ fail (tidx * 1000 + i + 1);
+ }
+ }
+
+ xfree (s2);
+ }
+}
+
+
+static char *
+stresc (char *s)
+{
+ char *p;
+ int l = strlen (s) + 1;
+
+ for (p = s; *p; p ++)
+ if (*p == '\n')
+ l ++;
+
+ p = xmalloc (l);
+ for (l = 0; *s; s ++, l ++)
+ {
+ if (*s == ' ')
+ p[l] = '_';
+ else if (*p == '\n')
+ {
+ p[l ++] = '\\';
+ p[l ++] = 'n';
+ p[l] = '\n';
+ }
+ else
+ p[l] = *s;
+ }
+ p[l] = *s;
+
+ return p;
+}
+
+
+static void
+test_format_text (void)
+{
+ struct test
+ {
+ int target_cols, max_cols;
+ char *input;
+ char *expected;
+ };
+
+ struct test tests[] = {
+ {
+ 10, 12,
+ "",
+ "",
+ },
+ {
+ 10, 12,
+ " ",
+ "",
+ },
+ {
+ 10, 12,
+ " ",
+ "",
+ },
+ {
+ 10, 12,
+ " \n ",
+ " \n",
+ },
+ {
+ 10, 12,
+ " \n \n ",
+ " \n \n",
+ },
+ {
+ 10, 12,
+ "0123456789 0123456789 0",
+ "0123456789\n0123456789\n0",
+ },
+ {
+ 10, 12,
+ " 0123456789 0123456789 0 ",
+ " 0123456789\n0123456789\n0",
+ },
+ {
+ 10, 12,
+ "01 34 67 90 23 56 89 12 45 67 89 1",
+ "01 34 67\n90 23 56\n89 12 45\n67 89 1"
+ },
+ {
+ 10, 12,
+ "01 34 67 90 23 56 89 12 45 67 89 1",
+ "01 34 67\n90 23 56\n89 12 45\n67 89 1"
+ },
+ {
+ 72, 80,
+ "Warning: if you think you've seen more than 10 messages "
+ "signed by this key, then this key might be a forgery! "
+ "Carefully examine the email address for small variations "
+ "(e.g., additional white space). If the key is suspect, "
+ "then use 'gpg --tofu-policy bad \"FINGERPRINT\"' to mark it as being bad.\n",
+ "Warning: if you think you've seen more than 10 messages signed by this\n"
+ "key, then this key might be a forgery! Carefully examine the email\n"
+ "address for small variations (e.g., additional white space). If the key\n"
+ "is suspect, then use 'gpg --tofu-policy bad \"FINGERPRINT\"' to mark it as\n"
+ "being bad.\n"
+
+ },
+ {
+ 72, 80,
+ "Normally, there is only a single key associated with an email "
+ "address. However, people sometimes generate a new key if "
+ "their key is too old or they think it might be compromised. "
+ "Alternatively, a new key may indicate a man-in-the-middle "
+ "attack! Before accepting this key, you should talk to or "
+ "call the person to make sure this new key is legitimate.",
+ "Normally, there is only a single key associated with an email "
+ "address.\nHowever, people sometimes generate a new key if "
+ "their key is too old or\nthey think it might be compromised. "
+ "Alternatively, a new key may indicate\na man-in-the-middle "
+ "attack! Before accepting this key, you should talk\nto or "
+ "call the person to make sure this new key is legitimate.",
+ }
+ };
+
+ int i;
+ int failed = 0;
+
+ for (i = 0; i < sizeof (tests) / sizeof (tests[0]); i ++)
+ {
+ struct test *test = &tests[i];
+ char *result =
+ format_text (test->input, test->target_cols, test->max_cols);
+ if (!result)
+ {
+ fail (1);
+ exit (2);
+ }
+ if (strcmp (result, test->expected) != 0)
+ {
+ printf ("%s: Test #%d failed.\nExpected: '%s'\nResult: '%s'\n",
+ __func__, i + 1, stresc (test->expected), stresc (result));
+ failed ++;
+ }
+ xfree (result);
+ }
+
+ if (failed)
+ fail(0);
+}
+
+
+static void
+test_compare_version_strings (void)
+{
+ struct { const char *a; const char *b; int okay; } tests[] = {
+ { "1.0.0", "1.0.0", 0 },
+ { "1.0.0-", "1.0.0", 1 },
+ { "1.0.0-1", "1.0.0", 1 },
+ { "1.0.0.1", "1.0.0", 1 },
+ { "1.0.0", "1.0.1", -1 },
+ { "1.0.0-", "1.0.1", -1 },
+ { "1.0.0-1", "1.0.1", -1 },
+ { "1.0.0.1", "1.0.1", -1 },
+ { "1.0.0", "1.1.0", -1 },
+ { "1.0.0-", "1.1.0", -1 },
+ { "1.0.0-1", "1.1.0", -1 },
+ { "1.0.0.1", "1.1.0", -1 },
+
+ { "1.0.0", "1.0.0-", -1 },
+ { "1.0.0", "1.0.0-1", -1 },
+ { "1.0.0", "1.0.0.1", -1 },
+ { "1.1.0", "1.0.0", 1 },
+ { "1.1.1", "1.1.0", 1 },
+ { "1.1.2", "1.1.2", 0 },
+ { "1.1.2", "1.0.2", 1 },
+ { "1.1.2", "0.0.2", 1 },
+ { "1.1.2", "1.1.3", -1 },
+
+ { "0.99.1", "0.9.9", 1 },
+ { "0.9.1", "0.91.0", -1 },
+
+ { "1.5.3", "1.5", 1 },
+ { "1.5.0", "1.5", 0 },
+ { "1.4.99", "1.5", -1 },
+ { "1.5", "1.4.99", 1 },
+ { "1.5", "1.5.0", 0 },
+ { "1.5", "1.5.1", -1 },
+
+ { "1.5.3-x17", "1.5-23", 1 },
+
+ { "1.5.3a", "1.5.3", 1 },
+ { "1.5.3a", "1.5.3b", -1 },
+
+ { "3.1.4-ab", "3.1.4-ab", 0 },
+ { "3.1.4-ab", "3.1.4-ac", -1 },
+ { "3.1.4-ac", "3.1.4-ab", 1 },
+ { "3.1.4-ab", "3.1.4-abb", -1 },
+ { "3.1.4-abb", "3.1.4-ab", 1 },
+
+ { "", "", INT_MIN },
+ { NULL, "", INT_MIN },
+ { "1.2.3", "", INT_MIN },
+ { "1.2.3", "2", INT_MIN },
+
+ /* Test cases for validity of A. */
+ { "", NULL, INT_MIN },
+ { "1", NULL, INT_MIN },
+ { "1.", NULL, 0 },
+ { "1.0", NULL, 0 },
+ { "1.0.", NULL, 0 },
+ { "a1.2", NULL, INT_MIN },
+ { NULL, NULL, INT_MIN }
+ };
+ int idx;
+ int res;
+
+ for (idx=0; idx < DIM(tests); idx++)
+ {
+ res = compare_version_strings (tests[idx].a, tests[idx].b);
+ /* printf ("test %d: '%s' '%s' %d -> %d\n", */
+ /* idx, tests[idx].a, tests[idx].b, tests[idx].okay, res); */
+ if (res != tests[idx].okay)
+ fail (idx);
+ }
+}
+
+
+static void
+test_substitute_envvars (void)
+{
+ struct {
+ const char *name;
+ const char *value;
+ } envvars[] = {
+ { "HOME", "/home/joe" },
+ { "AVAR", "avar" },
+ { "AVAR1", "avarx" },
+ { "AVAR2", "avarxy" },
+ { "AVAR3", "avarxyz" },
+ { "AVAR0", "ava" },
+ { "MY_VAR", "my_vars_value" },
+ { "STRANGE{X}VAR", "strange{x}vars-value" },
+ { "ZERO", "" }
+ };
+ struct {
+ const char *string;
+ const char *result;
+ } tests[] = {
+ { "foo bar",
+ "foo bar"
+ },
+ { "foo $HOME",
+ "foo /home/joe"
+ },
+ { "foo $HOME ",
+ "foo /home/joe "
+ },
+ { "foo $HOME$$",
+ "foo /home/joe$"
+ },
+ { "foo ${HOME}/.ssh",
+ "foo /home/joe/.ssh"
+ },
+ { "foo $HOME/.ssh",
+ "foo /home/joe/.ssh"
+ },
+ { "foo $HOME_/.ssh",
+ "foo /.ssh"
+ },
+ { "foo $HOME/.ssh/$MY_VAR:1",
+ "foo /home/joe/.ssh/my_vars_value:1"
+ },
+ { "foo $HOME${MY_VAR}:1",
+ "foo /home/joemy_vars_value:1"
+ },
+ { "${STRANGE{X}VAR}-bla",
+ "strange{x}vars-value-bla"
+ },
+ { "${STRANGE{X}{VAR}-bla", /* missing "}" */
+ "${STRANGE{X}{VAR}-bla"
+ },
+ { "zero->$ZERO<-",
+ "zero-><-"
+ },
+ { "->$AVAR.$AVAR1.$AVAR2.$AVAR3.$AVAR0<-",
+ "->avar.avarx.avarxy.avarxyz.ava<-"
+ },
+ { "",
+ ""
+ }
+ };
+ int idx;
+ char *res;
+
+ for (idx=0; idx < DIM(envvars); idx++)
+ if (gnupg_setenv (envvars[idx].name, envvars[idx].value, 1))
+ {
+ fprintf (stderr,"error setting envvar '%s' to '%s': %s\n",
+ envvars[idx].name, envvars[idx].value,
+ strerror (errno));
+ exit (2);
+ }
+
+ for (idx=0; idx < DIM(tests); idx++)
+ {
+ res = substitute_envvars (tests[idx].string);
+ if (!res)
+ {
+ fprintf (stderr,"error substituting '%s' (test %d): %s\n",
+ tests[idx].string, idx, strerror (errno));
+ exit (2);
+ }
+ if (strcmp (res, tests[idx].result))
+ {
+ fprintf (stderr, "substituted '%s'\n", tests[idx].string);
+ fprintf (stderr, " wanted '%s'\n", tests[idx].result);
+ fprintf (stderr, " got '%s'\n", res);
+ fail (idx);
+ }
+ xfree (res);
+ }
+}
+
+
+int
+main (int argc, char **argv)
+{
+ (void)argc;
+ (void)argv;
+
+ test_percent_escape ();
+ test_compare_filenames ();
+ test_strconcat ();
+ test_xstrconcat ();
+ test_make_filename_try ();
+ test_make_absfilename_try ();
+ test_strsplit ();
+ test_strtokenize ();
+ test_strtokenize_nt ();
+ test_split_fields ();
+ test_split_fields_colon ();
+ test_compare_version_strings ();
+ test_format_text ();
+ test_substitute_envvars ();
+
+ xfree (home_buffer);
+ return !!errcount;
+}
diff --git a/common/t-strlist.c b/common/t-strlist.c
new file mode 100644
index 0000000..fdbeb9b
--- /dev/null
+++ b/common/t-strlist.c
@@ -0,0 +1,84 @@
+/* t-strlist.c - Regression tests for strist.c
+ * Copyright (C) 2015 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute and/or modify this
+ * part of GnuPG under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * 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 copies of the GNU General Public License
+ * and the GNU Lesser General Public License along with this program;
+ * if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <string.h>
+
+#include "strlist.h"
+
+#include "t-support.h"
+
+static void
+test_strlist_rev (void)
+{
+ strlist_t s = NULL;
+
+ /* Reversing an empty list should yield the empty list. */
+ if (! (strlist_rev (&s) == NULL))
+ fail (1);
+
+ add_to_strlist (&s, "1");
+ add_to_strlist (&s, "2");
+ add_to_strlist (&s, "3");
+
+ if (strcmp (s->d, "3") != 0)
+ fail (2);
+ if (strcmp (s->next->d, "2") != 0)
+ fail (2);
+ if (strcmp (s->next->next->d, "1") != 0)
+ fail (2);
+ if (s->next->next->next)
+ fail (2);
+
+ strlist_rev (&s);
+
+ if (strcmp (s->d, "1") != 0)
+ fail (2);
+ if (strcmp (s->next->d, "2") != 0)
+ fail (2);
+ if (strcmp (s->next->next->d, "3") != 0)
+ fail (2);
+ if (s->next->next->next)
+ fail (2);
+
+ free_strlist (s);
+}
+
+
+int
+main (int argc, char **argv)
+{
+ (void)argc;
+ (void)argv;
+
+ test_strlist_rev ();
+
+ return 0;
+}
diff --git a/common/t-support.h b/common/t-support.h
new file mode 100644
index 0000000..7aa46c0
--- /dev/null
+++ b/common/t-support.h
@@ -0,0 +1,84 @@
+/* t-support.h - Helper for the regression tests
+ * Copyright (C) 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute and/or modify this
+ * part of GnuPG under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * 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 copies of the GNU General Public License
+ * and the GNU Lesser General Public License along with this program;
+ * if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_COMMON_T_SUPPORT_H
+#define GNUPG_COMMON_T_SUPPORT_H 1
+
+#ifdef GCRYPT_VERSION
+#error The regression tests should not include with gcrypt.h
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <gpg-error.h>
+
+
+#ifndef HAVE_GETENV
+# define getenv(a) (NULL)
+#endif
+
+#ifndef DIM
+# define DIM(v) (sizeof(v)/sizeof((v)[0]))
+# define DIMof(type,member) DIM(((type *)0)->member)
+#endif
+
+
+/* Replacement prototypes. */
+void *gcry_xmalloc (size_t n);
+void *gcry_xcalloc (size_t n, size_t m);
+void *gcry_xrealloc (void *a, size_t n);
+char *gcry_xstrdup (const char * a);
+void gcry_free (void *a);
+
+/* Map the used xmalloc functions to those implemented by t-support.c */
+#define xmalloc(a) gcry_xmalloc ( (a) )
+#define xcalloc(a,b) gcry_xcalloc ( (a), (b) )
+#define xrealloc(a,n) gcry_xrealloc ( (a), (n) )
+#define xstrdup(a) gcry_xstrdup ( (a) )
+#define xfree(a) gcry_free ( (a) )
+
+
+/* Macros to print the result of a test. */
+#define pass() do { ; } while(0)
+#define fail(a) do { fprintf (stderr, "%s:%d: test %d failed\n",\
+ __FILE__,__LINE__, (a)); \
+ errcount++; \
+ if (!no_exit_on_fail) \
+ exit (1); \
+ } while(0)
+
+/* If this flag is set the fail macro does not call exit. */
+static int no_exit_on_fail;
+/* Error counter. */
+static int errcount;
+
+
+#endif /*GNUPG_COMMON_T_SUPPORT_H*/
diff --git a/common/t-sysutils.c b/common/t-sysutils.c
new file mode 100644
index 0000000..79f8385
--- /dev/null
+++ b/common/t-sysutils.c
@@ -0,0 +1,89 @@
+/* t-sysutils.c - Module test for sysutils.c
+ * Copyright (C) 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "util.h"
+#include "sysutils.h"
+
+#ifdef HAVE_W32CE_SYSTEM
+# define rewind(f) do { fseek (f, 0, SEEK_SET); clearerr (f); } while (0)
+#endif
+
+#define pass() do { ; } while(0)
+#define fail(a) do { fprintf (stderr, "%s:%d: test %d failed\n",\
+ __FILE__,__LINE__, (a)); \
+ errcount++; \
+ } while(0)
+
+static int verbose;
+static int errcount;
+
+
+static void
+test_gnupg_tmpfile (void)
+{
+ FILE *fparr[10];
+ int fparridx;
+ int idx;
+ FILE *fp;
+ char buffer[100];
+
+#define ASTRING "fooooooooooooooo\n" /* Needs to be shorter than BUFFER. */
+
+ for (fparridx=0; fparridx < DIM (fparr); fparridx++)
+ {
+ fp = gnupg_tmpfile ();
+ fparr[fparridx] = fp;
+ if (!fp)
+ fail (fparridx);
+ else
+ {
+ fputs ( ASTRING, fp);
+ rewind (fp);
+ if (!fgets (buffer, sizeof (buffer), fp))
+ fail (fparridx);
+ if (strcmp (buffer, ASTRING))
+ fail (fparridx);
+ if (fgets (buffer, sizeof (buffer), fp))
+ fail (fparridx);
+ }
+ }
+ for (idx=0; idx < fparridx; idx++)
+ {
+ if (fparr[idx])
+ fclose (fparr[idx]);
+ }
+}
+
+
+
+int
+main (int argc, char **argv)
+{
+ if (argc > 1 && !strcmp (argv[1], "--verbose"))
+ verbose = 1;
+
+ test_gnupg_tmpfile ();
+ /* Fixme: Add tests for setenv and unsetenv. */
+
+ return !!errcount;
+}
diff --git a/common/t-timestuff.c b/common/t-timestuff.c
new file mode 100644
index 0000000..6a75925
--- /dev/null
+++ b/common/t-timestuff.c
@@ -0,0 +1,175 @@
+/* t-timestuff.c - Regression tests for time functions
+ * Copyright (C) 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute and/or modify this
+ * part of GnuPG under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * 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 copies of the GNU General Public License
+ * and the GNU Lesser General Public License along with this program;
+ * if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+
+#include "mischelp.h"
+
+#include "t-support.h"
+
+
+static int
+cmp_time_s (struct tm *a, struct tm *b)
+{
+ if (a->tm_year != b->tm_year
+ || a->tm_mon != b->tm_mon
+ || a->tm_mday != b->tm_mday
+ || a->tm_hour != b->tm_hour
+ || a->tm_min != b->tm_min
+ || a->tm_sec != b->tm_sec
+ || a->tm_wday != b->tm_wday
+ || a->tm_yday != b->tm_yday
+ || !a->tm_isdst != !b->tm_isdst)
+ return -1;
+ return 0;
+}
+
+
+
+static void
+test_timegm (void)
+{
+ static struct {
+ int year, mon, mday, hour, min, sec;
+ } tvalues[] = {
+ { -1 },
+ { -2, 1 },
+ { -2, 2 },
+ { -2, 86399 },
+ { -2, 86400 },
+ { -2, 0x7ffffffe },
+ { -2, 0x7fffffff },
+ /* Note: Because we use mktime below we can only start with the
+ day after Epoch. */
+ { 1970, 0, 2, 0, 0 , 1},
+ { 1970, 0, 2, 0, 0 , 2},
+ { 1970, 0, 2, 12, 0 , 0},
+ { 1970, 0, 2, 23, 59 , 59},
+ { 1999, 11, 31, 23, 59 , 59},
+ { 2000, 0, 1, 0, 0, 0},
+ { 2000, 0, 1, 0, 0, 1},
+ { 2010, 11, 31, 23, 59 , 59},
+ { 2010, 0, 1, 0, 0, 0},
+ { 2010, 0, 1, 0, 0, 1},
+ /* On GNU based 32 bit systems the end of all ticks will be on
+ 20380119T031408 (unless Uli takes compassion on us and changes
+ time_t to a u64). We check that the previous day is okay. */
+ { 2038, 0, 18, 23, 59, 59}
+
+ };
+ int tidx;
+ time_t now, atime;
+ struct tm tbuf, tbuf2, *tp;
+
+ for (tidx=0; tidx < DIM (tvalues); tidx++)
+ {
+ if (tvalues[tidx].year == -1)
+ {
+ now = time (NULL);
+ }
+ else if (tvalues[tidx].year == -2)
+ {
+ now = tvalues[tidx].mon;
+ }
+ else
+ {
+ memset (&tbuf, 0, sizeof tbuf);
+ tbuf.tm_year = tvalues[tidx].year - 1900;
+ tbuf.tm_mon = tvalues[tidx].mon;
+ tbuf.tm_mday = tvalues[tidx].mday;
+ tbuf.tm_hour = tvalues[tidx].hour;
+ tbuf.tm_min = tvalues[tidx].min;
+ tbuf.tm_sec = tvalues[tidx].sec;
+#ifdef HAVE_TIMEGM
+ now = timegm (&tbuf);
+#else
+ now = mktime (&tbuf);
+#endif
+ }
+ if (now == (time_t)(-1))
+ fail (tidx);
+
+ tp = gmtime (&now);
+ if (!tp)
+ fail (tidx);
+ else
+ {
+ tbuf = *tp;
+ tbuf2 = tbuf;
+#ifdef HAVE_TIMEGM
+ atime = timegm (&tbuf);
+#else
+ atime = mktime (&tbuf);
+#endif
+ if (atime == (time_t)(-1))
+ fail (tidx);
+ else if (atime != now)
+ fail (tidx);
+
+ tp = gmtime (&atime);
+ if (!tp)
+ fail (tidx);
+ else if (cmp_time_s (tp, &tbuf))
+ fail (tidx);
+ else if (cmp_time_s (tp, &tbuf2))
+ fail (tidx);
+ }
+ }
+}
+
+
+
+int
+main (int argc, char **argv)
+{
+ (void)argc;
+ (void)argv;
+
+ /* If we do not have timegm, we use mktime. However, we need to use
+ UTC in this case so that the 20380118T235959 test does not fail
+ for other timezones. */
+#ifndef HAVE_TIMEGM
+# ifdef HAVE_SETENV
+ setenv ("TZ", "UTC", 1);
+#else
+ putenv (xstrdup ("TZ=UTC"));
+#endif
+ tzset ();
+#endif
+
+ test_timegm ();
+
+ return 0;
+}
diff --git a/common/t-w32-cmdline.c b/common/t-w32-cmdline.c
new file mode 100644
index 0000000..a1039d0
--- /dev/null
+++ b/common/t-w32-cmdline.c
@@ -0,0 +1,250 @@
+/* t-w32-cmdline.c - Test the parser for the Windows command line
+ * Copyright (C) 2021 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#ifdef HAVE_W32_SYSTEM
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+#endif
+
+#include "t-support.h"
+#include "utf8conv.h"
+#include "w32help.h"
+
+#define PGM "t-w32-cmdline"
+
+static int verbose;
+static int debug;
+static int errcount;
+
+
+static void
+test_all (void)
+{
+ static struct {
+ const char *cmdline;
+ int argc; /* Expected number of args. */
+ char *argv[10]; /* Expected results. */
+ int use_glob;
+ } tests[] = {
+ /* Examples from "Parsing C++ Command-Line Arguments" dated 11/18/2006.
+ * https://docs.microsoft.com/en-us/previous-versions/17w5ykft(v=vs.85)
+ */
+ { "\"abc\" d e", 3, { "abc", "d", "e" }},
+ { "a\\\\\\b d\"e f\"g h", 3, { "a\\\\\\b", "de fg", "h" }},
+ { "a\\\\\\\"b c d", 3, { "a\\\"b", "c", "d" }},
+ { "a\\\\\\\\\"b c\" d e", 3, { "a\\\\b c", "d", "e" }},
+ /* Examples from "Parsing C Command-Line Arguments" dated 11/09/2020.
+ * https://docs.microsoft.com/en-us/cpp/c-language/\
+ * parsing-c-command-line-arguments?view=msvc-160
+ */
+ { "\"a b c\" d e", 3, { "a b c", "d", "e" }},
+ { "\"ab\\\"c\" \"\\\\\" d", 3, { "ab\"c", "\\", "d" }},
+ { "a\\\\\\b d\"e f\"g h", 3, { "a\\\\\\b", "de fg", "h" }},
+ { "a\\\\\\\"b c d", 3, { "a\\\"b", "c", "d" }},
+ { "a\\\\\\\\\"b c\" d e", 3, { "a\\\\b c", "d", "e" }},
+ { "a\"b\"\" c d", 1, { "ab\" c d" }},
+ /* Some arbitrary tests created using mingw.
+ * But I am not sure whether their parser is fully correct.
+ */
+ { "e:a a b\"c\" ", 3, { "e:a", "a", "bc" }},
+ /* { "e:a a b\"c\"\" d\"\"e \" ", */
+ /* 5, { "e:a", "a", "bc\"", "de", " " }}, */
+ /* { "e:a a b\"c\"\" d\"\"e\" f\\gh ", */
+ /* 4, { "e:a", "a", "bc\"", "de f\\gh "}}, */
+ /* { "e:a a b\"c\"\" d\"\"e\" f\\\"gh \" ", */
+ /* 4, { "e:a", "a", "bc\"", "de f\"gh " }},*/
+
+ { "\"foo bar\"", 1 , { "foo bar" }},
+
+#ifndef HAVE_W32_SYSTEM
+ /* We actually don't use this code on Unix but we provide a way to
+ * test some of the blobing code. */
+ { "foo", 1, { "foo" }, 1 },
+ { "foo*", 2, { "[* follows]", "foo*" }, 1 },
+ { "foo?", 2, { "[? follows]", "foo?" }, 1 },
+ { "? \"*\" *", 5, { "[? follows]", "?", "*", "[* follows]", "*" }, 1 },
+#endif /*!HAVE_W32_SYSTEM*/
+ { "", 1 , { "" }}
+ };
+ int tidx;
+ int i, any, itemsalloced, argc;
+ char *cmdline;
+ char **argv;
+
+ for (tidx = 0; tidx < DIM(tests); tidx++)
+ {
+ cmdline = xstrdup (tests[tidx].cmdline);
+ if (verbose && tidx)
+ putchar ('\n');
+ if (verbose)
+ printf ("test %d: line ->%s<-\n", tidx, cmdline);
+ argv = w32_parse_commandline (cmdline, tests[tidx].use_glob,
+ &argc, &itemsalloced);
+ if (!argv)
+ {
+ fail (tidx);
+ xfree (cmdline);
+ continue;
+ }
+ if (tests[tidx].argc != argc)
+ {
+ fprintf (stderr, PGM": test %d: argc wrong (want %d, got %d)\n",
+ tidx, tests[tidx].argc, argc);
+ any = 1;
+ }
+ else
+ any = 0;
+ for (i=0; i < tests[tidx].argc; i++)
+ {
+ if (verbose)
+ printf ("test %d: argv[%d] ->%s<-\n",
+ tidx, i, tests[tidx].argv[i]);
+ if (i < argc && strcmp (tests[tidx].argv[i], argv[i]))
+ {
+ if (verbose)
+ printf ("test %d: got[%d] ->%s<- ERROR\n",
+ tidx, i, argv[i]);
+ any = 1;
+ }
+ }
+ if (any)
+ {
+ fprintf (stderr, PGM": test %d: error%s\n",
+ tidx, verbose? "":" (use --verbose)");
+ errcount++;
+ }
+
+ if (itemsalloced)
+ {
+ for (i=0; i < argc; i++)
+ xfree (argv[i]);
+ }
+ xfree (argv);
+ xfree (cmdline);
+ }
+}
+
+
+
+int
+main (int argc, char **argv)
+{
+ int last_argc = -1;
+
+ no_exit_on_fail = 1;
+
+ if (argc)
+ { argc--; argv++; }
+ while (argc && last_argc != argc )
+ {
+ last_argc = argc;
+ if (!strcmp (*argv, "--"))
+ {
+ argc--; argv++;
+ break;
+ }
+ else if (!strcmp (*argv, "--help"))
+ {
+ fputs ("usage: " PGM " [test args]\n"
+ "Options:\n"
+ " --verbose Print timings etc.\n"
+ " --debug Flyswatter\n"
+ , stdout);
+ exit (0);
+ }
+ else if (!strcmp (*argv, "--verbose"))
+ {
+ verbose++;
+ argc--; argv++;
+ }
+ else if (!strcmp (*argv, "--debug"))
+ {
+ verbose += 2;
+ debug++;
+ argc--; argv++;
+ }
+ else if (!strncmp (*argv, "--", 2))
+ {
+ fprintf (stderr, PGM ": unknown option '%s'\n", *argv);
+ exit (1);
+ }
+ }
+
+ if (argc)
+ {
+#ifdef HAVE_W32_SYSTEM
+ const wchar_t *wcmdline;
+ char *cmdline;
+ int i, myargc;
+ char **myargv;
+
+ wcmdline = GetCommandLineW ();
+ if (!wcmdline)
+ {
+ fprintf (stderr, PGM ": GetCommandLine failed\n");
+ exit (1);
+ }
+
+ cmdline = wchar_to_utf8 (wcmdline);
+ if (!cmdline)
+ {
+ fprintf (stderr, PGM ": wchar_to_utf8 failed\n");
+ exit (1);
+ }
+
+ printf ("cmdline ->%s<\n", cmdline);
+ myargv = w32_parse_commandline (cmdline, 1, &myargc, NULL);
+ if (!myargv)
+ {
+ fprintf (stderr, PGM ": w32_parse_commandline failed\n");
+ exit (1);
+ }
+
+ for (i=0; i < myargc; i++)
+ printf ("argv[%d] ->%s<-\n", i, myargv[i]);
+ fflush (stdout);
+
+ xfree (myargv);
+ xfree (cmdline);
+#else
+ fprintf (stderr, PGM ": manual test mode not available on Unix\n");
+ errcount++;
+#endif
+ }
+ else
+ test_all ();
+
+ return !!errcount;
+}
diff --git a/common/t-w32-reg.c b/common/t-w32-reg.c
new file mode 100644
index 0000000..1a44e38
--- /dev/null
+++ b/common/t-w32-reg.c
@@ -0,0 +1,87 @@
+/* t-w32-reg.c - Regression tests for W32 registry functions
+ * Copyright (C) 2010 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute and/or modify this
+ * part of GnuPG under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * 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 copies of the GNU General Public License
+ * and the GNU Lesser General Public License along with this program;
+ * if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+
+#include "mischelp.h"
+
+#include "t-support.h"
+#include "w32help.h"
+
+
+static void
+test_read_registry (void)
+{
+ char *string1, *string2;
+
+ string1 = read_w32_registry_string
+ ("HKEY_CURRENT_USER",
+ "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings",
+ "User Agent");
+ if (!string1)
+ fail (0);
+ fprintf (stderr, "User agent: %s\n", string1);
+
+ string2 = read_w32_reg_string
+ ("HKCU\\Software\\Microsoft\\Windows\\CurrentVersion"
+ "\\Internet Settings:User Agent", NULL);
+ if (!string2)
+ fail (1);
+ fprintf (stderr, "User agent: %s\n", string2);
+ if (strcmp (string1, string2))
+ fail (2);
+
+
+ xfree (string1);
+ xfree (string2);
+}
+
+
+
+
+int
+main (int argc, char **argv)
+{
+ if (argc > 1)
+ {
+ char *string = read_w32_reg_string (argv[1], NULL);
+ printf ("%s -> %s\n", argv[1], string? string : "(null)");
+ xfree (string);
+ }
+ else
+ test_read_registry ();
+
+ return 0;
+}
diff --git a/common/t-zb32.c b/common/t-zb32.c
new file mode 100644
index 0000000..956c2f5
--- /dev/null
+++ b/common/t-zb32.c
@@ -0,0 +1,305 @@
+/* t-zb32.c - Module tests for zb32.c
+ * Copyright (C) 2014 Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#ifdef HAVE_DOSISH_SYSTEM
+# include <fcntl.h>
+#endif
+
+#include "zb32.h"
+#include "t-support.h"
+
+#define PGM "t-zb32"
+
+static int verbose;
+static int debug;
+static int errcount;
+
+
+static void
+test_zb32enc (void)
+{
+ static struct {
+ size_t datalen;
+ char *data;
+ const char *expected;
+ } tests[] = {
+ /* From the DESIGN document. */
+ { 1, "\x00", "y" },
+ { 1, "\x80", "o" },
+ { 2, "\x40", "e" },
+ { 2, "\xc0", "a" },
+ { 10, "\x00\x00", "yy" },
+ { 10, "\x80\x80", "on" },
+ { 20, "\x8b\x88\x80", "tqre" },
+ { 24, "\xf0\xbf\xc7", "6n9hq" },
+ { 24, "\xd4\x7a\x04", "4t7ye" },
+ /* The next vector is strange: The DESIGN document from 2007 gives
+ "8ik66o" as result, the revision from 2009 gives "6im5sd". I
+ look at it for quite some time and came to the conclusion that
+ "6im54d" is the right encoding. */
+ { 30, "\xf5\x57\xbd\x0c", "6im54d" },
+ /* From ccrtp's Java code. */
+ { 40, "\x01\x01\x01\x01\x01", "yryonyeb" },
+ { 15, "\x01\x01", "yry" },
+ { 80, "\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01", "yryonyebyryonyeb" },
+ { 15, "\x81\x81", "ogy" },
+ { 16, "\x81\x81", "ogyo" },
+ { 20, "\x81\x81\x81", "ogya" },
+ { 64, "\x81\x81\x81\x81\x81\x81\x81\x81", "ogyadycbogyan" },
+ /* More tests. */
+ { 160, "\x80\x61\x58\x70\xF5\xBA\xD6\x90\x33\x36"
+ /* */"\x86\xD0\xF2\xAD\x85\xAC\x1E\x42\xB3\x67",
+ /* */"oboioh8izmmjyc3so5exfmcfioxrfc58" },
+ { 0, "", "" }
+ };
+ int tidx;
+ char *output;
+
+ for (tidx = 0; tidx < DIM(tests); tidx++)
+ {
+ output = zb32_encode (tests[tidx].data, tests[tidx].datalen);
+ if (!output)
+ {
+ fprintf (stderr, PGM": error encoding test %d: %s\n",
+ tidx, strerror (errno));
+ exit (1);
+ }
+ /* puts (output); */
+ if (strcmp (output, tests[tidx].expected))
+ fail (tidx);
+ xfree (output);
+ }
+}
+
+
+/* Read the file FNAME or stdin if FNAME is NULL and return a malloced
+ buffer with the content. R_LENGTH received the length of the file.
+ Print a diagnostic and returns NULL on error. */
+static char *
+read_file (const char *fname, size_t *r_length)
+{
+ FILE *fp;
+ char *buf;
+ size_t buflen;
+
+ if (!fname)
+ {
+ size_t nread, bufsize = 0;
+
+ fp = stdin;
+#ifdef HAVE_DOSISH_SYSTEM
+ setmode (fileno(fp) , O_BINARY );
+#endif
+ buf = NULL;
+ buflen = 0;
+#define NCHUNK 8192
+ do
+ {
+ bufsize += NCHUNK;
+ if (!buf)
+ buf = xmalloc (bufsize);
+ else
+ buf = xrealloc (buf, bufsize);
+
+ nread = fread (buf+buflen, 1, NCHUNK, fp);
+ if (nread < NCHUNK && ferror (fp))
+ {
+ fprintf (stderr, PGM": error reading '[stdin]': %s\n",
+ strerror (errno));
+ xfree (buf);
+ return NULL;
+ }
+ buflen += nread;
+ }
+ while (nread == NCHUNK);
+#undef NCHUNK
+
+ }
+ else
+ {
+ struct stat st;
+
+ fp = fopen (fname, "rb");
+ if (!fp)
+ {
+ fprintf (stderr, PGM": can't open '%s': %s\n",
+ fname, strerror (errno));
+ return NULL;
+ }
+
+ if (fstat (fileno(fp), &st))
+ {
+ fprintf (stderr, PGM": can't stat '%s': %s\n",
+ fname, strerror (errno));
+ fclose (fp);
+ return NULL;
+ }
+
+ buflen = st.st_size;
+ buf = xmalloc (buflen+1);
+ if (fread (buf, buflen, 1, fp) != 1)
+ {
+ fprintf (stderr, PGM": error reading '%s': %s\n",
+ fname, strerror (errno));
+ fclose (fp);
+ xfree (buf);
+ return NULL;
+ }
+ fclose (fp);
+ }
+
+ *r_length = buflen;
+ return buf;
+}
+
+
+/* Debug helper to encode or decode to/from zb32. */
+static void
+endecode_file (const char *fname, int decode)
+{
+ char *buffer;
+ size_t buflen;
+ char *result;
+
+ if (decode)
+ {
+ fprintf (stderr, PGM": decode mode has not yet been implemented\n");
+ errcount++;
+ return;
+ }
+
+#ifdef HAVE_DOSISH_SYSTEM
+ if (decode)
+ setmode (fileno (stdout), O_BINARY);
+#endif
+
+
+ buffer = read_file (fname, &buflen);
+ if (!buffer)
+ {
+ errcount++;
+ return;
+ }
+
+ result = zb32_encode (buffer, 8 * buflen);
+ if (!result)
+ {
+ fprintf (stderr, PGM": error encoding data: %s\n", strerror (errno));
+ errcount++;
+ xfree (buffer);
+ return;
+ }
+
+ fputs (result, stdout);
+ putchar ('\n');
+
+ xfree (result);
+ xfree (buffer);
+}
+
+
+int
+main (int argc, char **argv)
+{
+ int last_argc = -1;
+ int opt_endecode = 0;
+
+ no_exit_on_fail = 1;
+
+ if (argc)
+ { argc--; argv++; }
+ while (argc && last_argc != argc )
+ {
+ last_argc = argc;
+ if (!strcmp (*argv, "--"))
+ {
+ argc--; argv++;
+ break;
+ }
+ else if (!strcmp (*argv, "--help"))
+ {
+ fputs ("usage: " PGM " [FILE]\n"
+ "Options:\n"
+ " --verbose Print timings etc.\n"
+ " --debug Flyswatter\n"
+ " --encode Encode FILE or stdin\n"
+ " --decode Decode FILE or stdin\n"
+ , stdout);
+ exit (0);
+ }
+ else if (!strcmp (*argv, "--verbose"))
+ {
+ verbose++;
+ argc--; argv++;
+ }
+ else if (!strcmp (*argv, "--debug"))
+ {
+ verbose += 2;
+ debug++;
+ argc--; argv++;
+ }
+ else if (!strcmp (*argv, "--encode"))
+ {
+ opt_endecode = 1;
+ argc--; argv++;
+ }
+ else if (!strcmp (*argv, "--decode"))
+ {
+ opt_endecode = -1;
+ argc--; argv++;
+ }
+ else if (!strncmp (*argv, "--", 2))
+ {
+ fprintf (stderr, PGM ": unknown option '%s'\n", *argv);
+ exit (1);
+ }
+ }
+
+ if (argc > 1)
+ {
+ fprintf (stderr, PGM ": to many arguments given\n");
+ exit (1);
+ }
+
+ if (opt_endecode)
+ {
+ endecode_file (argc? *argv : NULL, (opt_endecode < 0));
+ }
+ else
+ test_zb32enc ();
+
+ return !!errcount;
+}
diff --git a/common/tlv-builder.c b/common/tlv-builder.c
new file mode 100644
index 0000000..59e2691
--- /dev/null
+++ b/common/tlv-builder.c
@@ -0,0 +1,388 @@
+/* tlv-builder.c - Build DER encoded objects
+ * Copyright (C) 2020 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This file 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 Lesser General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <gpg-error.h>
+
+#include "util.h"
+#include "tlv.h"
+
+
+struct item_s
+{
+ int class;
+ int tag;
+ unsigned int is_constructed:1; /* This is a constructed element. */
+ unsigned int is_stop:1; /* This is a STOP item. */
+ const void *value;
+ size_t valuelen;
+ char *buffer; /* Malloced space or NULL. */
+};
+
+
+struct tlv_builder_s
+{
+ gpg_error_t error; /* Last error. */
+ int use_secure; /* Use secure memory for the result. */
+ size_t nallocateditems; /* Number of allocated items. */
+ size_t nitems; /* Number of used items. */
+ struct item_s *items; /* Array of items. */
+ int laststop; /* Used as return value of compute_length. */
+};
+
+
+/* Allocate a new TLV Builder instance. Returns NULL on error. If
+ * SECURE is set the final object is stored in secure memory. */
+tlv_builder_t
+tlv_builder_new (int secure)
+{
+ tlv_builder_t tb;
+
+ tb = xtrycalloc (1, sizeof *tb);
+ if (tb && secure)
+ tb->use_secure = 1;
+ return tb;
+}
+
+
+/* Make sure the array of items is large enough for one new item.
+ * Records any error in TB and returns true in that case. */
+static int
+ensure_space (tlv_builder_t tb)
+{
+ struct item_s *newitems;
+
+ if (!tb || tb->error)
+ return 1;
+
+ if (tb->nitems == tb->nallocateditems)
+ {
+ tb->nallocateditems += 32;
+ newitems = gpgrt_reallocarray (tb->items, tb->nitems,
+ tb->nallocateditems, sizeof *newitems);
+ if (!newitems)
+ tb->error = gpg_error_from_syserror ();
+ else
+ tb->items = newitems;
+ }
+ return !!tb->error;
+}
+
+
+
+/* Add a new primitive element to the builder instance TB. The
+ * element is described by CLASS, TAG, VALUE, and VALUEEN. CLASS and
+ * TAG must describe a primitive element and (VALUE,VALUELEN) specify
+ * its value. The value is a pointer and its object must not be
+ * changed as long as the instance TB exists. For a TAG_NULL no vlaue
+ * is expected. Errors are not returned but recorded for later
+ * retrieval. */
+void
+tlv_builder_add_ptr (tlv_builder_t tb, int class, int tag,
+ void *value, size_t valuelen)
+{
+ if (ensure_space (tb))
+ return;
+ tb->items[tb->nitems].class = class;
+ tb->items[tb->nitems].tag = tag;
+ tb->items[tb->nitems].value = value;
+ tb->items[tb->nitems].valuelen = valuelen;
+ tb->nitems++;
+}
+
+
+/* This is the same as tlv_builder_add_ptr but it takes a copy of the
+ * value and thus the caller does not need to care about it. */
+void
+tlv_builder_add_val (tlv_builder_t tb, int class, int tag,
+ const void *value, size_t valuelen)
+{
+ void *p;
+
+ if (ensure_space (tb))
+ return;
+ if (!value || !valuelen)
+ {
+ tb->error = gpg_error (GPG_ERR_INV_VALUE);
+ return;
+ }
+ p = tb->use_secure? xtrymalloc_secure (valuelen) : xtrymalloc (valuelen);
+ if (!p)
+ {
+ tb->error = gpg_error_from_syserror ();
+ return;
+ }
+ memcpy (p, value, valuelen);
+ tb->items[tb->nitems].buffer = p;
+ tb->items[tb->nitems].class = class;
+ tb->items[tb->nitems].tag = tag;
+ tb->items[tb->nitems].value = p;
+ tb->items[tb->nitems].valuelen = valuelen;
+ tb->nitems++;
+}
+
+
+/* Add a new constructed object to the builder instance TB. The
+ * object is described by CLASS and TAG which must describe a
+ * constructed object. The elements of the constructed objects are
+ * added with more call to the add functions. To close a constructed
+ * element a call to tlv_builer_add_end is required. Errors are not
+ * returned but recorded for later retrieval. */
+void
+tlv_builder_add_tag (tlv_builder_t tb, int class, int tag)
+{
+ if (ensure_space (tb))
+ return;
+ tb->items[tb->nitems].class = class;
+ tb->items[tb->nitems].tag = tag;
+ tb->items[tb->nitems].is_constructed = 1;
+ tb->nitems++;
+}
+
+
+/* A call to this function closes a constructed element. This must be
+ * called even for an empty constructed element. */
+void
+tlv_builder_add_end (tlv_builder_t tb)
+{
+ if (ensure_space (tb))
+ return;
+ tb->items[tb->nitems].is_stop = 1;
+ tb->nitems++;
+}
+
+
+/* Compute and set the length of all constructed elements in the item
+ * array of TB starting at IDX up to the corresponding stop item. On
+ * error tb->error is set. */
+static size_t
+compute_lengths (tlv_builder_t tb, int idx)
+{
+ size_t total = 0;
+
+ if (tb->error)
+ return 0;
+
+ for (; idx < tb->nitems; idx++)
+ {
+ if (tb->items[idx].is_stop)
+ {
+ tb->laststop = idx;
+ break;
+ }
+ if (tb->items[idx].is_constructed)
+ {
+ tb->items[idx].valuelen = compute_lengths (tb, idx+1);
+ if (tb->error)
+ return 0;
+ /* Note: The last processed IDX is stored at tb->LASTSTOP. */
+ }
+ total += get_tlv_length (tb->items[idx].class, tb->items[idx].tag,
+ tb->items[idx].is_constructed,
+ tb->items[idx].valuelen);
+ if (tb->items[idx].is_constructed)
+ idx = tb->laststop;
+ }
+ return total;
+}
+
+
+/* Return the constructed DER encoding and release this instance. On
+ * success the object is stored at R_OBJ and its length at R_OBJLEN.
+ * The caller needs to release that memory. On error NULL is stored
+ * at R_OBJ and an error code is returned. Note than an error may
+ * stem from any of the previous call made to this object or from
+ * constructing the the DER object. */
+gpg_error_t
+tlv_builder_finalize (tlv_builder_t tb, void **r_obj, size_t *r_objlen)
+{
+ gpg_error_t err;
+ membuf_t mb;
+ int mb_initialized = 0;
+ int idx;
+
+ *r_obj = NULL;
+ *r_objlen = 0;
+
+ if (!tb)
+ return gpg_error (GPG_ERR_INTERNAL);
+ if (tb->error)
+ {
+ err = tb->error;
+ goto leave;
+ }
+ if (!tb->nitems || !tb->items[tb->nitems-1].is_stop)
+ {
+ err = gpg_error (GPG_ERR_NO_OBJ);
+ goto leave;
+ }
+
+ compute_lengths (tb, 0);
+ err = tb->error;
+ if (err)
+ goto leave;
+
+ /* for (idx=0; idx < tb->nitems; idx++) */
+ /* log_debug ("TLVB[%2d]: c=%d t=%2d %s p=%p l=%zu\n", */
+ /* idx, */
+ /* tb->items[idx].class, */
+ /* tb->items[idx].tag, */
+ /* tb->items[idx].is_stop? "stop": */
+ /* tb->items[idx].is_constructed? "cons":"prim", */
+ /* tb->items[idx].value, */
+ /* tb->items[idx].valuelen); */
+
+ if (tb->use_secure)
+ init_membuf_secure (&mb, 512);
+ else
+ init_membuf (&mb, 512);
+ mb_initialized = 1;
+
+ for (idx=0; idx < tb->nitems; idx++)
+ {
+ if (tb->items[idx].is_stop)
+ continue;
+ put_tlv_to_membuf (&mb, tb->items[idx].class, tb->items[idx].tag,
+ tb->items[idx].is_constructed,
+ tb->items[idx].valuelen);
+ if (tb->items[idx].value)
+ put_membuf (&mb, tb->items[idx].value, tb->items[idx].valuelen);
+ }
+
+ *r_obj = get_membuf (&mb, r_objlen);
+ if (!*r_obj)
+ err = gpg_error_from_syserror ();
+ mb_initialized = 0;
+
+ leave:
+ if (mb_initialized)
+ xfree (get_membuf (&mb, NULL));
+ for (idx=0; idx < tb->nitems; idx++)
+ xfree (tb->items[idx].buffer);
+ xfree (tb->items);
+ xfree (tb);
+ return err;
+}
+
+
+/* Write TAG of CLASS to MEMBUF. CONSTRUCTED is a flag telling
+ * whether the value is constructed. LENGTH gives the length of the
+ * value, if it is 0 undefinite length is assumed. LENGTH is ignored
+ * for the NULL tag. TAG must be less that 0x1f. */
+void
+put_tlv_to_membuf (membuf_t *membuf, int class, int tag,
+ int constructed, size_t length)
+{
+ unsigned char buf[20];
+ int buflen = 0;
+ int i;
+
+ if (tag < 0x1f)
+ {
+ *buf = (class << 6) | tag;
+ if (constructed)
+ *buf |= 0x20;
+ buflen++;
+ }
+ else
+ BUG ();
+
+ if (!tag && !class)
+ buf[buflen++] = 0; /* end tag */
+ else if (tag == TAG_NULL && !class)
+ buf[buflen++] = 0; /* NULL tag */
+ else if (!length)
+ buf[buflen++] = 0x80; /* indefinite length */
+ else if (length < 128)
+ buf[buflen++] = length;
+ else
+ {
+ /* If we know the sizeof a size_t we could support larger
+ * objects - however this is pretty ridiculous */
+ i = (length <= 0xff ? 1:
+ length <= 0xffff ? 2:
+ length <= 0xffffff ? 3: 4);
+
+ buf[buflen++] = (0x80 | i);
+ if (i > 3)
+ buf[buflen++] = length >> 24;
+ if (i > 2)
+ buf[buflen++] = length >> 16;
+ if (i > 1)
+ buf[buflen++] = length >> 8;
+ buf[buflen++] = length;
+ }
+
+ put_membuf (membuf, buf, buflen);
+}
+
+
+/* Return the length of the to be constructed TLV. CONSTRUCTED is a
+ * flag telling whether the value is constructed. LENGTH gives the
+ * length of the value, if it is 0 undefinite length is assumed.
+ * LENGTH is ignored for the NULL tag. TAG must be less that 0x1f. */
+size_t
+get_tlv_length (int class, int tag, int constructed, size_t length)
+{
+ size_t buflen = 0;
+ int i;
+
+ (void)constructed; /* Not used, but passed for uniformity of such calls. */
+
+ /* coverity[identical_branches] */
+ if (tag < 0x1f)
+ {
+ buflen++;
+ }
+ else
+ {
+ buflen++; /* assume one and let the actual write function bail out */
+ }
+
+ if (!tag && !class)
+ buflen++; /* end tag */
+ else if (tag == TAG_NULL && !class)
+ buflen++; /* NULL tag */
+ else if (!length)
+ buflen++; /* indefinite length */
+ else if (length < 128)
+ buflen++;
+ else
+ {
+ i = (length <= 0xff ? 1:
+ length <= 0xffff ? 2:
+ length <= 0xffffff ? 3: 4);
+
+ buflen++;
+ if (i > 3)
+ buflen++;
+ if (i > 2)
+ buflen++;
+ if (i > 1)
+ buflen++;
+ buflen++;
+ }
+
+ return buflen + length;
+}
diff --git a/common/tlv.c b/common/tlv.c
new file mode 100644
index 0000000..9618d04
--- /dev/null
+++ b/common/tlv.c
@@ -0,0 +1,309 @@
+/* tlv.c - Tag-Length-Value Utilities
+ * Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <gpg-error.h>
+
+
+#include "util.h"
+#include "tlv.h"
+
+
+static const unsigned char *
+do_find_tlv (const unsigned char *buffer, size_t length,
+ int tag, size_t *nbytes, int nestlevel)
+{
+ const unsigned char *s = buffer;
+ size_t n = length;
+ size_t len;
+ int this_tag;
+ int composite;
+
+ for (;;)
+ {
+ if (n < 2)
+ return NULL; /* Buffer definitely too short for tag and length. */
+ if (!*s || *s == 0xff)
+ { /* Skip optional filler between TLV objects. */
+ s++;
+ n--;
+ continue;
+ }
+ composite = !!(*s & 0x20);
+ if ((*s & 0x1f) == 0x1f)
+ { /* more tag bytes to follow */
+ s++;
+ n--;
+ if (n < 2)
+ return NULL; /* buffer definitely too short for tag and length. */
+ if ((*s & 0x1f) == 0x1f)
+ return NULL; /* We support only up to 2 bytes. */
+ this_tag = (s[-1] << 8) | (s[0] & 0x7f);
+ }
+ else
+ this_tag = s[0];
+ len = s[1];
+ s += 2; n -= 2;
+ if (len < 0x80)
+ ;
+ else if (len == 0x81)
+ { /* One byte length follows. */
+ if (!n)
+ return NULL; /* we expected 1 more bytes with the length. */
+ len = s[0];
+ s++; n--;
+ }
+ else if (len == 0x82)
+ { /* Two byte length follows. */
+ if (n < 2)
+ return NULL; /* We expected 2 more bytes with the length. */
+ len = ((size_t)s[0] << 8) | s[1];
+ s += 2; n -= 2;
+ }
+ else
+ return NULL; /* APDU limit is 65535, thus it does not make
+ sense to assume longer length fields. */
+
+ if (composite && nestlevel < 100)
+ { /* Dive into this composite DO after checking for a too deep
+ nesting. */
+ const unsigned char *tmp_s;
+ size_t tmp_len;
+
+ tmp_s = do_find_tlv (s, len, tag, &tmp_len, nestlevel+1);
+ if (tmp_s)
+ {
+ *nbytes = tmp_len;
+ return tmp_s;
+ }
+ }
+
+ if (this_tag == tag)
+ {
+ *nbytes = len;
+ return s;
+ }
+ if (len > n)
+ return NULL; /* Buffer too short to skip to the next tag. */
+ s += len; n -= len;
+ }
+}
+
+
+/* Locate a TLV encoded data object in BUFFER of LENGTH and
+ return a pointer to value as well as its length in NBYTES. Return
+ NULL if it was not found or if the object does not fit into the buffer. */
+const unsigned char *
+find_tlv (const unsigned char *buffer, size_t length,
+ int tag, size_t *nbytes)
+{
+ const unsigned char *p;
+
+ p = do_find_tlv (buffer, length, tag, nbytes, 0);
+ if (p && *nbytes > (length - (p-buffer)))
+ p = NULL; /* Object longer than buffer. */
+ return p;
+}
+
+
+
+/* Locate a TLV encoded data object in BUFFER of LENGTH and
+ return a pointer to value as well as its length in NBYTES. Return
+ NULL if it was not found. Note, that the function does not check
+ whether the value fits into the provided buffer. */
+const unsigned char *
+find_tlv_unchecked (const unsigned char *buffer, size_t length,
+ int tag, size_t *nbytes)
+{
+ return do_find_tlv (buffer, length, tag, nbytes, 0);
+}
+
+
+/* ASN.1 BER parser: Parse BUFFER of length SIZE and return the tag
+ and the length part from the TLV triplet. Update BUFFER and SIZE
+ on success. */
+gpg_error_t
+parse_ber_header (unsigned char const **buffer, size_t *size,
+ int *r_class, int *r_tag,
+ int *r_constructed, int *r_ndef,
+ size_t *r_length, size_t *r_nhdr)
+{
+ int c;
+ unsigned long tag;
+ const unsigned char *buf = *buffer;
+ size_t length = *size;
+
+ *r_ndef = 0;
+ *r_length = 0;
+ *r_nhdr = 0;
+
+ /* Get the tag. */
+ if (!length)
+ return gpg_err_make (default_errsource, GPG_ERR_EOF);
+ c = *buf++; length--; ++*r_nhdr;
+
+ *r_class = (c & 0xc0) >> 6;
+ *r_constructed = !!(c & 0x20);
+ tag = c & 0x1f;
+
+ if (tag == 0x1f)
+ {
+ tag = 0;
+ do
+ {
+ tag <<= 7;
+ if (!length)
+ return gpg_err_make (default_errsource, GPG_ERR_EOF);
+ c = *buf++; length--; ++*r_nhdr;
+ tag |= c & 0x7f;
+
+ }
+ while (c & 0x80);
+ }
+ *r_tag = tag;
+
+ /* Get the length. */
+ if (!length)
+ return gpg_err_make (default_errsource, GPG_ERR_EOF);
+ c = *buf++; length--; ++*r_nhdr;
+
+ if ( !(c & 0x80) )
+ *r_length = c;
+ else if (c == 0x80)
+ *r_ndef = 1;
+ else if (c == 0xff)
+ return gpg_err_make (default_errsource, GPG_ERR_BAD_BER);
+ else
+ {
+ unsigned long len = 0;
+ int count = (c & 0x7f);
+
+ if (count > (sizeof(len)<sizeof(size_t)?sizeof(len):sizeof(size_t)))
+ return gpg_err_make (default_errsource, GPG_ERR_BAD_BER);
+
+ for (; count; count--)
+ {
+ len <<= 8;
+ if (!length)
+ return gpg_err_make (default_errsource, GPG_ERR_EOF);
+ c = *buf++; length--; ++*r_nhdr;
+ len |= c & 0xff;
+ }
+ *r_length = len;
+ }
+
+ if (*r_length > *r_nhdr && (*r_nhdr + *r_length) < *r_length)
+ {
+ return gpg_err_make (default_errsource, GPG_ERR_EOVERFLOW);
+ }
+
+ /* Without this kludge some example certs can't be parsed. */
+ if (*r_class == CLASS_UNIVERSAL && !*r_tag)
+ *r_length = 0;
+
+ *buffer = buf;
+ *size = length;
+ return 0;
+}
+
+
+/* FIXME: The following function should not go into this file but for
+ now it is easier to keep it here. */
+
+/* Return the next token of an canonical encoded S-expression. BUF
+ is the pointer to the S-expression and BUFLEN is a pointer to the
+ length of this S-expression (used to validate the syntax). Both
+ are updated to reflect the new position. The token itself is
+ returned as a pointer into the original buffer at TOK and TOKLEN.
+ If a parentheses is the next token, TOK will be set to NULL.
+ TOKLEN is checked to be within the bounds. On error an error code
+ is returned and pointers are not guaranteed to point to
+ meaningful values. DEPTH should be initialized to 0 and will
+ reflect on return the actual depth of the tree. To detect the end
+ of the S-expression it is advisable to check DEPTH after a
+ successful return.
+
+ depth = 0;
+ while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))
+ && depth)
+ process_token (tok, toklen);
+ if (err)
+ handle_error ();
+ */
+gpg_error_t
+parse_sexp (unsigned char const **buf, size_t *buflen,
+ int *depth, unsigned char const **tok, size_t *toklen)
+{
+ const unsigned char *s;
+ size_t n, vlen;
+
+ s = *buf;
+ n = *buflen;
+ *tok = NULL;
+ *toklen = 0;
+ if (!n)
+ return *depth ? gpg_err_make (default_errsource, GPG_ERR_INV_SEXP) : 0;
+ if (*s == '(')
+ {
+ s++; n--;
+ (*depth)++;
+ *buf = s;
+ *buflen = n;
+ return 0;
+ }
+ if (*s == ')')
+ {
+ if (!*depth)
+ return gpg_err_make (default_errsource, GPG_ERR_INV_SEXP);
+ *toklen = 1;
+ s++; n--;
+ (*depth)--;
+ *buf = s;
+ *buflen = n;
+ return 0;
+ }
+ for (vlen=0; n && *s && *s != ':' && (*s >= '0' && *s <= '9'); s++, n--)
+ vlen = vlen*10 + (*s - '0');
+ if (!n || *s != ':')
+ return gpg_err_make (default_errsource, GPG_ERR_INV_SEXP);
+ s++; n--;
+ if (vlen > n)
+ return gpg_err_make (default_errsource, GPG_ERR_INV_SEXP);
+ *tok = s;
+ *toklen = vlen;
+ s += vlen;
+ n -= vlen;
+ *buf = s;
+ *buflen = n;
+ return 0;
+}
diff --git a/common/tlv.h b/common/tlv.h
new file mode 100644
index 0000000..51a0ef4
--- /dev/null
+++ b/common/tlv.h
@@ -0,0 +1,143 @@
+/* tlv.h - Tag-Length-Value Utilities
+ * Copyright (C) 2004 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef SCD_TLV_H
+#define SCD_TLV_H 1
+
+#include "membuf.h"
+
+
+enum tlv_tag_class {
+ CLASS_UNIVERSAL = 0,
+ CLASS_APPLICATION = 1,
+ CLASS_CONTEXT = 2,
+ CLASS_PRIVATE =3
+};
+
+enum tlv_tag_type {
+ TAG_NONE = 0,
+ TAG_BOOLEAN = 1,
+ TAG_INTEGER = 2,
+ TAG_BIT_STRING = 3,
+ TAG_OCTET_STRING = 4,
+ TAG_NULL = 5,
+ TAG_OBJECT_ID = 6,
+ TAG_OBJECT_DESCRIPTOR = 7,
+ TAG_EXTERNAL = 8,
+ TAG_REAL = 9,
+ TAG_ENUMERATED = 10,
+ TAG_EMBEDDED_PDV = 11,
+ TAG_UTF8_STRING = 12,
+ TAG_REALTIVE_OID = 13,
+ TAG_SEQUENCE = 16,
+ TAG_SET = 17,
+ TAG_NUMERIC_STRING = 18,
+ TAG_PRINTABLE_STRING = 19,
+ TAG_TELETEX_STRING = 20,
+ TAG_VIDEOTEX_STRING = 21,
+ TAG_IA5_STRING = 22,
+ TAG_UTC_TIME = 23,
+ TAG_GENERALIZED_TIME = 24,
+ TAG_GRAPHIC_STRING = 25,
+ TAG_VISIBLE_STRING = 26,
+ TAG_GENERAL_STRING = 27,
+ TAG_UNIVERSAL_STRING = 28,
+ TAG_CHARACTER_STRING = 29,
+ TAG_BMP_STRING = 30
+};
+
+
+struct tlv_builder_s;
+typedef struct tlv_builder_s *tlv_builder_t;
+
+/*-- tlv.c --*/
+
+/* Locate a TLV encoded data object in BUFFER of LENGTH and return a
+ pointer to value as well as its length in NBYTES. Return NULL if
+ it was not found or if the object does not fit into the buffer. */
+const unsigned char *find_tlv (const unsigned char *buffer, size_t length,
+ int tag, size_t *nbytes);
+
+
+/* Locate a TLV encoded data object in BUFFER of LENGTH and return a
+ pointer to value as well as its length in NBYTES. Return NULL if
+ it was not found. Note, that the function does not check whether
+ the value fits into the provided buffer.*/
+const unsigned char *find_tlv_unchecked (const unsigned char *buffer,
+ size_t length,
+ int tag, size_t *nbytes);
+
+/* ASN.1 BER parser: Parse BUFFER of length SIZE and return the tag
+ and the length part from the TLV triplet. Update BUFFER and SIZE
+ on success. */
+gpg_error_t parse_ber_header (unsigned char const **buffer, size_t *size,
+ int *r_class, int *r_tag,
+ int *r_constructed,
+ int *r_ndef, size_t *r_length, size_t *r_nhdr);
+
+
+/* Return the next token of an canonical encoded S-expression. BUF
+ is the pointer to the S-expression and BUFLEN is a pointer to the
+ length of this S-expression (used to validate the syntax). Both
+ are updated to reflect the new position. The token itself is
+ returned as a pointer into the original buffer at TOK and TOKLEN.
+ If a parentheses is the next token, TOK will be set to NULL.
+ TOKLEN is checked to be within the bounds. On error an error code
+ is returned and no pointer is not guaranteed to point to
+ a meaningful value. DEPTH should be initialized to 0 and will
+ reflect on return the actual depth of the tree. To detect the end
+ of the S-expression it is advisable to check DEPTH after a
+ successful return. */
+gpg_error_t parse_sexp (unsigned char const **buf, size_t *buflen,
+ int *depth, unsigned char const **tok, size_t *toklen);
+
+
+/*-- tlv-builder.c --*/
+
+tlv_builder_t tlv_builder_new (int use_secure);
+void tlv_builder_add_ptr (tlv_builder_t tb, int class, int tag,
+ void *value, size_t valuelen);
+void tlv_builder_add_val (tlv_builder_t tb, int class, int tag,
+ const void *value, size_t valuelen);
+void tlv_builder_add_tag (tlv_builder_t tb, int class, int tag);
+void tlv_builder_add_end (tlv_builder_t tb);
+gpg_error_t tlv_builder_finalize (tlv_builder_t tb,
+ void **r_obj, size_t *r_objlen);
+
+/* Wite a TLV header to MEMBUF. */
+void put_tlv_to_membuf (membuf_t *membuf, int class, int tag,
+ int constructed, size_t length);
+
+/* Count the length of a to be constructed TLV. */
+size_t get_tlv_length (int class, int tag, int constructed, size_t length);
+
+
+
+
+#endif /* SCD_TLV_H */
diff --git a/common/ttyio.c b/common/ttyio.c
new file mode 100644
index 0000000..c310817
--- /dev/null
+++ b/common/ttyio.c
@@ -0,0 +1,751 @@
+/* ttyio.c - tty i/O functions
+ * Copyright (C) 1997-2019 Werner Koch
+ * Copyright (C) 1998-2020 Free Software Foundation, Inc.
+ * Copyright (C) 2015-2020 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: (LGPL-3.0-or-later OR GPL-2.0-or-later)
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <unistd.h>
+
+#ifdef HAVE_TCGETATTR
+# include <termios.h>
+#else
+# ifdef HAVE_TERMIO_H
+/* simulate termios with termio */
+# include <termio.h>
+# define termios termio
+# define tcsetattr ioctl
+# define TCSAFLUSH TCSETAF
+# define tcgetattr(A,B) ioctl(A,TCGETA,B)
+# define HAVE_TCGETATTR
+# endif
+#endif
+#ifdef HAVE_W32_SYSTEM
+# ifdef HAVE_WINSOCK2_H
+# include <winsock2.h>
+# endif
+# include <windows.h>
+# ifdef HAVE_TCGETATTR
+# error mingw32 and termios
+# endif
+#endif
+#include <errno.h>
+#include <ctype.h>
+
+#include "util.h"
+#include "ttyio.h"
+#include "i18n.h"
+#include "common-defs.h"
+
+#define CONTROL_D ('D' - 'A' + 1)
+
+
+#ifdef HAVE_W32_SYSTEM
+static struct {
+ HANDLE in, out;
+} con;
+#define DEF_INPMODE (ENABLE_LINE_INPUT|ENABLE_ECHO_INPUT \
+ |ENABLE_PROCESSED_INPUT )
+#define HID_INPMODE (ENABLE_LINE_INPUT|ENABLE_PROCESSED_INPUT )
+#define DEF_OUTMODE (ENABLE_WRAP_AT_EOL_OUTPUT|ENABLE_PROCESSED_OUTPUT)
+
+#else /* Unix */
+static FILE *ttyfp = NULL;
+#endif /* Unix */
+
+static int initialized;
+static int last_prompt_len;
+static int batchmode;
+static int no_terminal;
+
+#ifdef HAVE_TCGETATTR
+ static struct termios termsave;
+ static int restore_termios;
+#endif
+
+/* Hooks set by gpgrlhelp.c if required. */
+static void (*my_rl_set_completer) (rl_completion_func_t *);
+static void (*my_rl_inhibit_completion) (int);
+static void (*my_rl_cleanup_after_signal) (void);
+static void (*my_rl_init_stream) (FILE *);
+static char *(*my_rl_readline) (const char*);
+static void (*my_rl_add_history) (const char*);
+
+
+/* This is a wrapper around ttyname so that we can use it even when
+ the standard streams are redirected. It figures the name out the
+ first time and returns it in a statically allocated buffer. */
+const char *
+tty_get_ttyname (void)
+{
+ static char *name;
+
+ /* On a GNU system ctermid() always return /dev/tty, so this does
+ not make much sense - however if it is ever changed we do the
+ Right Thing now. */
+#ifdef HAVE_CTERMID
+ static int got_name;
+
+ if (!got_name)
+ {
+ const char *s;
+ /* Note that despite our checks for these macros the function is
+ not necessarily thread save. We mainly do this for
+ portability reasons, in case L_ctermid is not defined. */
+# if defined(_POSIX_THREAD_SAFE_FUNCTIONS) || defined(_POSIX_TRHEADS)
+ char buffer[L_ctermid];
+ s = ctermid (buffer);
+# else
+ s = ctermid (NULL);
+# endif
+ if (s)
+ name = strdup (s);
+ got_name = 1;
+ }
+#endif /*HAVE_CTERMID*/
+ /* Assume the standard tty on memory error or when there is no
+ ctermid. */
+ return name? name : "/dev/tty";
+}
+
+
+
+#ifdef HAVE_TCGETATTR
+static void
+cleanup(void)
+{
+ if (restore_termios)
+ {
+ restore_termios = 0; /* do it prior in case it is interrupted again */
+ if (tcsetattr(fileno(ttyfp), TCSAFLUSH, &termsave))
+ log_error ("tcsetattr() failed: %s\n", strerror (errno));
+ }
+}
+#endif /*HAVE_TCGETATTR*/
+
+
+static void
+init_ttyfp(void)
+{
+ if (initialized)
+ return;
+
+#ifdef HAVE_W32_SYSTEM
+ {
+ SECURITY_ATTRIBUTES sa;
+
+ memset (&sa, 0, sizeof(sa));
+ sa.nLength = sizeof(sa);
+ sa.bInheritHandle = TRUE;
+ con.out = CreateFileA ("CONOUT$", GENERIC_READ|GENERIC_WRITE,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ &sa, OPEN_EXISTING, 0, 0 );
+ if (con.out == INVALID_HANDLE_VALUE)
+ log_fatal ("open(CONOUT$) failed: %s\n", w32_strerror (-1));
+
+ memset (&sa, 0, sizeof(sa));
+ sa.nLength = sizeof(sa);
+ sa.bInheritHandle = TRUE;
+ con.in = CreateFileA ("CONIN$", GENERIC_READ|GENERIC_WRITE,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ &sa, OPEN_EXISTING, 0, 0 );
+ if (con.in == INVALID_HANDLE_VALUE)
+ log_fatal ("open(CONIN$) failed: %s\n", w32_strerror (-1));
+ }
+ SetConsoleMode (con.in, DEF_INPMODE);
+ SetConsoleMode (con.out, DEF_OUTMODE);
+
+#else /* Unix */
+ ttyfp = batchmode? stderr : fopen (tty_get_ttyname (), "r+");
+ if (!ttyfp)
+ {
+ log_error ("cannot open '%s': %s\n", tty_get_ttyname (), strerror(errno));
+ exit (2);
+ }
+ if (my_rl_init_stream)
+ my_rl_init_stream (ttyfp);
+#endif /* Unix */
+
+#ifdef HAVE_TCGETATTR
+ atexit (cleanup);
+#endif
+
+ initialized = 1;
+}
+
+
+int
+tty_batchmode( int onoff )
+{
+ int old = batchmode;
+ if (onoff != -1)
+ batchmode = onoff;
+ return old;
+}
+
+int
+tty_no_terminal(int onoff)
+{
+ int old = no_terminal;
+ no_terminal = onoff ? 1 : 0;
+ return old;
+}
+
+
+#ifdef HAVE_W32_SYSTEM
+/* Write the UTF-8 encoded STRING to the console. */
+static void
+w32_write_console (const char *string)
+{
+ wchar_t *wstring;
+ DWORD n, nwritten;
+
+ wstring = utf8_to_wchar (string);
+ if (!wstring)
+ log_fatal ("w32_write_console failed: %s", strerror (errno));
+ n = wcslen (wstring);
+
+ if (!WriteConsoleW (con.out, wstring, n, &nwritten, NULL))
+ {
+ static int shown;
+ if (!shown)
+ {
+ shown = 1;
+ log_info ("WriteConsole failed: %s", w32_strerror (-1));
+ log_info ("Please configure a suitable font for the console\n");
+ }
+ n = strlen (string);
+ if (!WriteConsoleA (con.out, string, n , &nwritten, NULL))
+ log_fatal ("WriteConsole fallback failed: %s", w32_strerror (-1));
+ }
+ else
+ {
+ if (n != nwritten)
+ log_fatal ("WriteConsole failed: %lu != %lu\n",
+ (unsigned long)n, (unsigned long)nwritten);
+ }
+ last_prompt_len += n;
+ xfree (wstring);
+}
+#endif /*HAVE_W32_SYSTEM*/
+
+
+void
+tty_printf (const char *fmt, ... )
+{
+ va_list arg_ptr;
+
+ if (no_terminal)
+ return;
+
+ if (!initialized)
+ init_ttyfp ();
+
+ va_start (arg_ptr, fmt);
+
+#ifdef HAVE_W32_SYSTEM
+ {
+ char *buf = NULL;
+
+ vasprintf(&buf, fmt, arg_ptr);
+ if (!buf)
+ log_bug ("vasprintf() failed\n");
+ w32_write_console (buf);
+ xfree (buf);
+ }
+#else /* Unix */
+ last_prompt_len += vfprintf (ttyfp, fmt, arg_ptr) ;
+ fflush (ttyfp);
+#endif /* Unix */
+ va_end(arg_ptr);
+}
+
+
+/* Same as tty_printf but if FP is not NULL, behave like a regular
+ fprintf. */
+void
+tty_fprintf (estream_t fp, const char *fmt, ... )
+{
+ va_list arg_ptr;
+
+ if (fp)
+ {
+ va_start (arg_ptr, fmt) ;
+ es_vfprintf (fp, fmt, arg_ptr );
+ va_end (arg_ptr);
+ return;
+ }
+
+ if (no_terminal)
+ return;
+
+ if (!initialized)
+ init_ttyfp ();
+
+ va_start (arg_ptr, fmt);
+
+#ifdef HAVE_W32_SYSTEM
+ {
+ char *buf = NULL;
+
+ vasprintf (&buf, fmt, arg_ptr);
+ if (!buf)
+ log_bug ("vasprintf() failed\n");
+ w32_write_console (buf);
+ xfree (buf);
+ }
+#else /* Unix */
+ last_prompt_len += vfprintf(ttyfp,fmt,arg_ptr) ;
+ fflush(ttyfp);
+#endif /* Unix */
+
+ va_end(arg_ptr);
+}
+
+
+/* Print a string, but filter all control characters out. If FP is
+ * not NULL print to that stream instead to the tty. */
+static void
+do_print_string (estream_t fp, const byte *p, size_t n )
+{
+ if (no_terminal && !fp)
+ return;
+
+ if (!initialized && !fp)
+ init_ttyfp();
+
+ if (fp)
+ {
+ print_utf8_buffer (fp, p, n);
+ return;
+ }
+
+#ifdef HAVE_W32_SYSTEM
+ /* Not so effective, change it if you want */
+ for (; n; n--, p++)
+ {
+ if (iscntrl (*p))
+ {
+ if( *p == '\n' )
+ tty_printf ("\\n");
+ else if( !*p )
+ tty_printf ("\\0");
+ else
+ tty_printf ("\\x%02x", *p);
+ }
+ else
+ tty_printf ("%c", *p);
+ }
+#else /* Unix */
+ for (; n; n--, p++)
+ {
+ if (iscntrl (*p))
+ {
+ putc ('\\', ttyfp);
+ if ( *p == '\n' )
+ putc ('n', ttyfp);
+ else if ( !*p )
+ putc ('0', ttyfp);
+ else
+ fprintf (ttyfp, "x%02x", *p );
+ }
+ else
+ putc (*p, ttyfp);
+ }
+#endif /* Unix */
+}
+
+
+void
+tty_print_utf8_string2 (estream_t fp, const byte *p, size_t n, size_t max_n)
+{
+ size_t i;
+ char *buf;
+
+ if (no_terminal && !fp)
+ return;
+
+ /* We can handle plain ascii simpler, so check for it first. */
+ for(i=0; i < n; i++ )
+ {
+ if (p[i] & 0x80)
+ break;
+ }
+ if (i < n)
+ {
+ buf = utf8_to_native ((const char *)p, n, 0);
+ if (max_n && (strlen (buf) > max_n))
+ buf[max_n] = 0;
+ /* (utf8_to_native already did the control character quoting) */
+ tty_fprintf (fp, "%s", buf);
+ xfree (buf);
+ }
+ else
+ {
+ if (max_n && (n > max_n))
+ n = max_n;
+ do_print_string (fp, p, n );
+ }
+}
+
+
+void
+tty_print_utf8_string (const byte *p, size_t n)
+{
+ tty_print_utf8_string2 (NULL, p, n, 0);
+}
+
+
+/* Read a string from the tty using PROMPT. If HIDDEN is set the
+ * input is not echoed. */
+static char *
+do_get (const char *prompt, int hidden)
+{
+ char *buf;
+ int n; /* Allocated size of BUF. */
+ int i; /* Number of bytes in BUF. */
+ int c;
+#ifdef HAVE_W32_SYSTEM
+ char *utf8buf;
+ int errcount = 0;
+#else
+ byte cbuf[1];
+#endif
+
+ if (batchmode)
+ {
+ log_error (_("Sorry, we are in batchmode - can't get input\n"));
+ exit (2);
+ }
+
+ if (no_terminal)
+ {
+ log_error (_("Sorry, no terminal at all requested - can't get input\n"));
+ exit (2);
+ }
+
+ if( !initialized )
+ init_ttyfp();
+
+ last_prompt_len = 0;
+ tty_printf( "%s", prompt );
+ buf = xmalloc((n=50));
+ i = 0;
+
+#ifdef HAVE_W32_SYSTEM
+ if (hidden)
+ SetConsoleMode(con.in, HID_INPMODE );
+
+ utf8buf = NULL;
+ for (;;)
+ {
+ DWORD nread;
+ wchar_t wbuf[2];
+ const unsigned char *s;
+
+ if (!ReadConsoleW (con.in, wbuf, 1, &nread, NULL))
+ log_fatal ("ReadConsole failed: %s", w32_strerror (-1));
+ if (!nread)
+ continue;
+
+ wbuf[1] = 0;
+ xfree (utf8buf);
+ utf8buf = wchar_to_utf8 (wbuf);
+ if (!utf8buf)
+ {
+ log_info ("wchar_to_utf8 failed: %s\n", strerror (errno));
+ if (++errcount > 10)
+ log_fatal (_("too many errors; giving up\n"));
+ continue;
+ }
+ if (*utf8buf == '\n')
+ {
+ if (utf8buf[1])
+ {
+ log_info ("ReadConsole returned more than requested"
+ " (0x0a,0x%02x)\n", utf8buf[1]);
+ if (++errcount > 10)
+ log_fatal (_("too many errors; giving up\n"));
+ }
+ break;
+ }
+ if (!hidden)
+ last_prompt_len++;
+
+ for (s=utf8buf; *s; s++)
+ {
+ c = *s;
+ if (c == '\t')
+ c = ' '; /* Map tab to a space. */
+ else if ((c >= 0 && c <= 0x1f) || c == 0x7f)
+ continue; /* Remove control characters. */
+ if (!(i < n-1))
+ {
+ n += 50;
+ buf = xrealloc (buf, n);
+ }
+ buf[i++] = c;
+ }
+ }
+ xfree (utf8buf);
+
+ if (hidden)
+ SetConsoleMode(con.in, DEF_INPMODE );
+
+#else /* Unix */
+
+ if (hidden)
+ {
+#ifdef HAVE_TCGETATTR
+ struct termios term;
+
+ if (tcgetattr(fileno(ttyfp), &termsave))
+ log_fatal ("tcgetattr() failed: %s\n", strerror(errno));
+ restore_termios = 1;
+ term = termsave;
+ term.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
+ if (tcsetattr( fileno(ttyfp), TCSAFLUSH, &term ) )
+ log_fatal("tcsetattr() failed: %s\n", strerror(errno));
+#endif /*HAVE_TCGETATTR*/
+ }
+
+ /* fixme: How can we avoid that the \n is echoed w/o disabling
+ * canonical mode - w/o this kill_prompt can't work */
+ while (read(fileno(ttyfp), cbuf, 1) == 1 && *cbuf != '\n')
+ {
+ if (!hidden)
+ last_prompt_len++;
+ c = *cbuf;
+ if (c == CONTROL_D)
+ log_info (_("Control-D detected\n"));
+
+ if (c == '\t') /* Map tab to a space. */
+ c = ' ';
+ else if ( (c >= 0 && c <= 0x1f) || c == 0x7f)
+ continue; /* Skip all other ASCII control characters. */
+ if (!(i < n-1))
+ {
+ n += 50;
+ buf = xrealloc (buf, n);
+ }
+ buf[i++] = c;
+ }
+
+ if (*cbuf != '\n')
+ {
+ buf[0] = CONTROL_D;
+ i = 1;
+ }
+
+ if (hidden)
+ {
+#ifdef HAVE_TCGETATTR
+ if (tcsetattr (fileno(ttyfp), TCSAFLUSH, &termsave))
+ log_error ("tcsetattr() failed: %s\n", strerror(errno));
+ restore_termios = 0;
+#endif /*HAVE_TCGETATTR*/
+ }
+#endif /* Unix */
+
+ buf[i] = 0;
+ return buf;
+}
+
+
+char *
+tty_get( const char *prompt )
+{
+ if (!batchmode && !no_terminal && my_rl_readline && my_rl_add_history)
+ {
+ char *line;
+ char *buf;
+
+ if (!initialized)
+ init_ttyfp();
+
+ last_prompt_len = 0;
+
+ line = my_rl_readline (prompt?prompt:"");
+
+ /* We need to copy it to memory controlled by our malloc
+ implementations; further we need to convert an EOF to our
+ convention. */
+ buf = xmalloc(line? strlen(line)+1:2);
+ if (line)
+ {
+ strcpy (buf, line);
+ trim_spaces (buf);
+ if (strlen (buf) > 2 )
+ my_rl_add_history (line); /* Note that we test BUF but add LINE. */
+ free (line);
+ }
+ else
+ {
+ buf[0] = CONTROL_D;
+ buf[1] = 0;
+ }
+ return buf;
+ }
+ else
+ return do_get ( prompt, 0 );
+}
+
+
+/* Variable argument version of tty_get. The prompt is actually a
+ * format string with arguments. */
+char *
+tty_getf (const char *promptfmt, ... )
+{
+ va_list arg_ptr;
+ char *prompt;
+ char *answer;
+
+ va_start (arg_ptr, promptfmt);
+ if (gpgrt_vasprintf (&prompt, promptfmt, arg_ptr) < 0)
+ log_fatal ("estream_vasprintf failed: %s\n", strerror (errno));
+ va_end (arg_ptr);
+ answer = tty_get (prompt);
+ xfree (prompt);
+ return answer;
+}
+
+
+char *
+tty_get_hidden( const char *prompt )
+{
+ return do_get (prompt, 1);
+}
+
+
+void
+tty_kill_prompt (void)
+{
+ if (no_terminal)
+ return;
+
+ if (!initialized)
+ init_ttyfp ();
+
+ if (batchmode)
+ last_prompt_len = 0;
+ if (!last_prompt_len)
+ return;
+#ifdef HAVE_W32_SYSTEM
+ tty_printf ("\r%*s\r", last_prompt_len, "");
+#else /* Unix */
+ {
+ int i;
+ putc ('\r', ttyfp);
+ for (i=0; i < last_prompt_len; i ++ )
+ putc (' ', ttyfp);
+ putc ('\r', ttyfp);
+ fflush (ttyfp);
+ }
+#endif /* Unix */
+ last_prompt_len = 0;
+}
+
+
+int
+tty_get_answer_is_yes( const char *prompt )
+{
+ int yes;
+ char *p;
+
+ p = tty_get (prompt);
+ tty_kill_prompt ();
+ yes = answer_is_yes (p);
+ xfree (p);
+
+ return yes;
+}
+
+
+/* Called by gnupg_rl_initialize to setup the readline support. */
+void
+tty_private_set_rl_hooks (void (*init_stream) (FILE *),
+ void (*set_completer) (rl_completion_func_t*),
+ void (*inhibit_completion) (int),
+ void (*cleanup_after_signal) (void),
+ char *(*readline_fun) (const char*),
+ void (*add_history_fun) (const char*))
+{
+ my_rl_init_stream = init_stream;
+ my_rl_set_completer = set_completer;
+ my_rl_inhibit_completion = inhibit_completion;
+ my_rl_cleanup_after_signal = cleanup_after_signal;
+ my_rl_readline = readline_fun;
+ my_rl_add_history = add_history_fun;
+}
+
+
+#ifdef HAVE_LIBREADLINE
+void
+tty_enable_completion (rl_completion_func_t *completer)
+{
+ if (no_terminal || !my_rl_set_completer )
+ return;
+
+ if (!initialized)
+ init_ttyfp();
+
+ my_rl_set_completer (completer);
+}
+
+void
+tty_disable_completion (void)
+{
+ if (no_terminal || !my_rl_inhibit_completion)
+ return;
+
+ if (!initialized)
+ init_ttyfp();
+
+ my_rl_inhibit_completion (1);
+}
+#endif /* HAVE_LIBREADLINE */
+
+void
+tty_cleanup_after_signal (void)
+{
+#ifdef HAVE_TCGETATTR
+ cleanup ();
+#endif
+}
+
+void
+tty_cleanup_rl_after_signal (void)
+{
+ if (my_rl_cleanup_after_signal)
+ my_rl_cleanup_after_signal ();
+}
diff --git a/common/ttyio.h b/common/ttyio.h
new file mode 100644
index 0000000..5bff82f
--- /dev/null
+++ b/common/ttyio.h
@@ -0,0 +1,73 @@
+/* ttyio.h
+ * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006,
+ * 2009 Free Software Foundation, Inc.
+ *
+ * This file is part of GNUPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+#ifndef GNUPG_COMMON_TTYIO_H
+#define GNUPG_COMMON_TTYIO_H
+
+#include "util.h" /* Make sure our readline typedef is available. */
+
+
+const char *tty_get_ttyname (void);
+int tty_batchmode (int onoff);
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 )
+void tty_printf (const char *fmt, ... )
+ __attribute__ ((format (printf,1,2)));
+void tty_fprintf (estream_t fp, const char *fmt, ... )
+ __attribute__ ((format (printf,2,3)));
+char *tty_getf (const char *promptfmt, ... )
+ __attribute__ ((format (printf,1,2)));
+#else
+void tty_printf (const char *fmt, ... );
+void tty_fprintf (estream_t fp, const char *fmt, ... );
+char *tty_getf (const char *promptfmt, ... );
+#endif
+void tty_print_utf8_string (const unsigned char *p, size_t n);
+void tty_print_utf8_string2 (estream_t fp,
+ const unsigned char *p, size_t n, size_t max_n);
+char *tty_get (const char *prompt);
+char *tty_get_hidden (const char *prompt);
+void tty_kill_prompt (void);
+int tty_get_answer_is_yes (const char *prompt);
+int tty_no_terminal (int onoff);
+
+#ifdef HAVE_LIBREADLINE
+void tty_enable_completion (rl_completion_func_t *completer);
+void tty_disable_completion (void);
+#else
+/* Use a macro to stub out these functions since a macro has no need
+ to typedef a "rl_completion_func_t" which would be undefined
+ without readline. */
+#define tty_enable_completion(x)
+#define tty_disable_completion()
+#endif
+void tty_cleanup_after_signal (void);
+void tty_cleanup_rl_after_signal (void);
+
+
+#endif /*GNUPG_COMMON_TTYIO_H*/
diff --git a/common/types.h b/common/types.h
new file mode 100644
index 0000000..8e551df
--- /dev/null
+++ b/common/types.h
@@ -0,0 +1,116 @@
+/* types.h - define some extra types
+ * Copyright (C) 1999, 2000, 2001, 2006 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute and/or modify this
+ * part of GnuPG under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * 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 copies of the GNU General Public License
+ * and the GNU Lesser General Public License along with this program;
+ * if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_COMMON_TYPES_H
+#define GNUPG_COMMON_TYPES_H
+
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+
+/* The AC_CHECK_SIZEOF() in configure fails for some machines.
+ * we provide some fallback values here */
+#if !SIZEOF_UNSIGNED_SHORT
+# undef SIZEOF_UNSIGNED_SHORT
+# define SIZEOF_UNSIGNED_SHORT 2
+#endif
+#if !SIZEOF_UNSIGNED_INT
+# undef SIZEOF_UNSIGNED_INT
+# define SIZEOF_UNSIGNED_INT 4
+#endif
+#if !SIZEOF_UNSIGNED_LONG
+# undef SIZEOF_UNSIGNED_LONG
+# define SIZEOF_UNSIGNED_LONG 4
+#endif
+
+
+#include <sys/types.h>
+
+
+/* We use byte as an abbreviation for unsigned char. On some
+ platforms this needs special treatment:
+
+ - RISC OS:
+ Norcroft C treats char = unsigned char as legal assignment
+ but char* = unsigned char* as illegal assignment
+ and the same applies to the signed variants as well. Thus we use
+ char which is anyway unsigned.
+
+ - Windows:
+ Windows typedefs byte in the RPC headers but we need to avoid a
+ warning about a double definition.
+ */
+#ifndef HAVE_BYTE_TYPEDEF
+# undef byte /* There might be a macro with this name. */
+# ifdef __riscos__
+ typedef char byte;
+# elif !(defined(_WIN32) && defined(cbNDRContext))
+ typedef unsigned char byte;
+# endif
+# define HAVE_BYTE_TYPEDEF
+#endif /*!HAVE_BYTE_TYPEDEF*/
+
+#ifndef HAVE_USHORT_TYPEDEF
+# undef ushort /* There might be a macro with this name. */
+ typedef unsigned short ushort;
+# define HAVE_USHORT_TYPEDEF
+#endif
+
+#ifndef HAVE_ULONG_TYPEDEF
+# undef ulong /* There might be a macro with this name. */
+ typedef unsigned long ulong;
+# define HAVE_ULONG_TYPEDEF
+#endif
+
+#ifndef HAVE_U16_TYPEDEF
+# undef u16 /* There might be a macro with this name. */
+# if SIZEOF_UNSIGNED_INT == 2
+ typedef unsigned int u16;
+# elif SIZEOF_UNSIGNED_SHORT == 2
+ typedef unsigned short u16;
+# else
+# error no typedef for u16
+# endif
+# define HAVE_U16_TYPEDEF
+#endif
+
+#ifndef HAVE_U32_TYPEDEF
+# undef u32 /* There might be a macro with this name. */
+# if SIZEOF_UNSIGNED_INT == 4
+ typedef unsigned int u32;
+# elif SIZEOF_UNSIGNED_LONG == 4
+ typedef unsigned long u32;
+# else
+# error no typedef for u32
+# endif
+# define HAVE_U32_TYPEDEF
+#endif
+
+#endif /*GNUPG_COMMON_TYPES_H*/
diff --git a/common/userids.c b/common/userids.c
new file mode 100644
index 0000000..00f26b7
--- /dev/null
+++ b/common/userids.c
@@ -0,0 +1,435 @@
+/* userids.c - Utility functions for user ids.
+ * Copyright (C) 2001, 2003, 2004, 2006,
+ * 2009 Free Software Foundation, Inc.
+ * Copyright (C) 2015 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "util.h"
+#include "userids.h"
+
+
+/* Parse the user-id NAME and build a search description for it.
+ * Returns 0 on success or an error code. DESC may be NULL to merely
+ * check the validity of a user-id.
+ *
+ * Some used rules:
+ * - If the username starts with 8,9,16 or 17 hex-digits (the first one
+ * must be in the range 0..9), this is considered a keyid; depending
+ * on the length a short or complete one.
+ * - If the username starts with 32,33,40 or 41 hex-digits (the first one
+ * must be in the range 0..9), this is considered a fingerprint.
+ * - If the username starts with a left angle, we assume it is a complete
+ * email address and look only at this part.
+ * - If the username starts with a colon we assume it is a unified
+ * key specfification.
+ * - If the username starts with a '.', we assume it is the ending
+ * part of an email address
+ * - If the username starts with an '@', we assume it is a part of an
+ * email address
+ * - If the userid start with an '=' an exact compare is done.
+ * - If the userid starts with a '*' a case insensitive substring search is
+ * done (This is the default).
+ * - If the userid starts with a '+' we will compare individual words
+ * and a match requires that all the words are in the userid.
+ * Words are delimited by white space or "()<>[]{}.@-+_,;/&!"
+ * (note that you can't search for these characters). Compare
+ * is not case sensitive.
+ * - If the userid starts with a '&' a 40 hex digits keygrip is expected.
+ */
+
+gpg_error_t
+classify_user_id (const char *name, KEYDB_SEARCH_DESC *desc, int openpgp_hack)
+{
+ const char *s;
+ char *s2 = NULL;
+ int rc = 0;
+ int hexprefix = 0;
+ int hexlength;
+ int mode = 0;
+ KEYDB_SEARCH_DESC dummy_desc;
+
+ if (!desc)
+ desc = &dummy_desc;
+
+ /* Clear the structure so that the mode field is set to zero unless
+ we set it to the correct value right at the end of this
+ function. */
+ memset (desc, 0, sizeof *desc);
+
+ /* Skip leading and trailing spaces. */
+ for(s = name; *s && spacep (s); s++ )
+ ;
+ if (*s && spacep (s + strlen(s) - 1))
+ {
+ s2 = xtrystrdup (s);
+ if (!s2)
+ {
+ rc = gpg_error_from_syserror ();
+ goto out;
+ }
+ trim_trailing_spaces (s2);
+ s = s2;
+ }
+
+ switch (*s)
+ {
+ case 0: /* Empty string is an error. */
+ rc = gpg_error (GPG_ERR_INV_USER_ID);
+ goto out;
+
+ case '.': /* An email address, compare from end. Note that this
+ has not yet been implemented in the search code. */
+ mode = KEYDB_SEARCH_MODE_MAILEND;
+ s++;
+ desc->u.name = s;
+ break;
+
+ case '<': /* An email address. */
+ mode = KEYDB_SEARCH_MODE_MAIL;
+ /* FIXME: The keyring code in g10 assumes that the mail name is
+ prefixed with an '<'. However the keybox code used for sm/
+ assumes it has been removed. For now we use this simple hack
+ to overcome the problem. */
+ if (!openpgp_hack)
+ s++;
+ desc->u.name = s;
+ break;
+
+ case '@': /* Part of an email address. */
+ mode = KEYDB_SEARCH_MODE_MAILSUB;
+ s++;
+ desc->u.name = s;
+ break;
+
+ case '=': /* Exact compare. */
+ mode = KEYDB_SEARCH_MODE_EXACT;
+ s++;
+ desc->u.name = s;
+ break;
+
+ case '*': /* Case insensitive substring search. */
+ mode = KEYDB_SEARCH_MODE_SUBSTR;
+ s++;
+ desc->u.name = s;
+ break;
+
+ case '+': /* Compare individual words. Note that this has not
+ yet been implemented in the search code. */
+ mode = KEYDB_SEARCH_MODE_WORDS;
+ s++;
+ desc->u.name = s;
+ break;
+
+ case '/': /* Subject's DN. */
+ s++;
+ if (!*s || spacep (s)) /* No DN or prefixed with a space. */
+ {
+ rc = gpg_error (GPG_ERR_INV_USER_ID);
+ goto out;
+ }
+ desc->u.name = s;
+ mode = KEYDB_SEARCH_MODE_SUBJECT;
+ break;
+
+ case '#': /* S/N with optional issuer id or just issuer id. */
+ {
+ const char *si;
+
+ s++;
+ if ( *s == '/')
+ { /* "#/" indicates an issuer's DN. */
+ s++;
+ if (!*s || spacep (s)) /* No DN or prefixed with a space. */
+ {
+ rc = gpg_error (GPG_ERR_INV_USER_ID);
+ goto out;
+ }
+ desc->u.name = s;
+ mode = KEYDB_SEARCH_MODE_ISSUER;
+ }
+ else
+ { /* Serialnumber + optional issuer ID. */
+ for (si=s; *si && *si != '/'; si++)
+ {
+ /* Check for an invalid digit in the serial number. */
+ if (!strchr("01234567890abcdefABCDEF", *si))
+ {
+ rc = gpg_error (GPG_ERR_INV_USER_ID);
+ goto out;
+ }
+ }
+ desc->sn = (const unsigned char*)s;
+ desc->snlen = -1;
+ if (!*si)
+ mode = KEYDB_SEARCH_MODE_SN;
+ else
+ {
+ s = si+1;
+ if (!*s || spacep (s)) /* No DN or prefixed with a space. */
+ {
+ rc = gpg_error (GPG_ERR_INV_USER_ID);
+ goto out;
+ }
+ desc->u.name = s;
+ mode = KEYDB_SEARCH_MODE_ISSUER_SN;
+ }
+ }
+ }
+ break;
+
+ case ':': /* Unified fingerprint. */
+ {
+ const char *se, *si;
+ int i;
+
+ se = strchr (++s,':');
+ if (!se)
+ {
+ rc = gpg_error (GPG_ERR_INV_USER_ID);
+ goto out;
+ }
+ for (i=0,si=s; si < se; si++, i++ )
+ {
+ if (!strchr("01234567890abcdefABCDEF", *si))
+ {
+ rc = gpg_error (GPG_ERR_INV_USER_ID); /* Invalid digit. */
+ goto out;
+ }
+ }
+ if (i != 32 && i != 40)
+ {
+ rc = gpg_error (GPG_ERR_INV_USER_ID); /* Invalid length of fpr. */
+ goto out;
+ }
+ for (i=0,si=s; si < se; i++, si +=2)
+ desc->u.fpr[i] = hextobyte(si);
+ for (; i < 20; i++)
+ desc->u.fpr[i]= 0;
+ mode = KEYDB_SEARCH_MODE_FPR;
+ }
+ break;
+
+ case '&': /* Keygrip*/
+ {
+ if (hex2bin (s+1, desc->u.grip, 20) < 0)
+ {
+ rc = gpg_error (GPG_ERR_INV_USER_ID); /* Invalid. */
+ goto out;
+ }
+ mode = KEYDB_SEARCH_MODE_KEYGRIP;
+ }
+ break;
+
+ default:
+ if (s[0] == '0' && s[1] == 'x')
+ {
+ hexprefix = 1;
+ s += 2;
+ }
+
+ hexlength = strspn(s, "0123456789abcdefABCDEF");
+ if (hexlength >= 8 && s[hexlength] =='!')
+ {
+ desc->exact = 1;
+ hexlength++; /* Just for the following check. */
+ }
+
+ /* Check if a hexadecimal number is terminated by EOS or blank. */
+ if (hexlength && s[hexlength] && !spacep (s+hexlength))
+ {
+ if (hexprefix) /* A "0x" prefix without a correct
+ termination is an error. */
+ {
+ rc = gpg_error (GPG_ERR_INV_USER_ID);
+ goto out;
+ }
+ /* The first characters looked like a hex number, but the
+ entire string is not. */
+ hexlength = 0;
+ }
+
+ if (desc->exact)
+ hexlength--; /* Remove the bang. */
+
+ if ((hexlength == 8
+ && (s[hexlength] == 0
+ || (s[hexlength] == '!' && s[hexlength + 1] == 0)))
+ || (!hexprefix && hexlength == 9 && *s == '0'))
+ {
+ /* Short keyid. */
+ if (hexlength == 9)
+ s++;
+ desc->u.kid[1] = strtoul( s, NULL, 16 );
+ mode = KEYDB_SEARCH_MODE_SHORT_KID;
+ }
+ else if ((hexlength == 16
+ && (s[hexlength] == 0
+ || (s[hexlength] == '!' && s[hexlength + 1] == 0)))
+ || (!hexprefix && hexlength == 17 && *s == '0'))
+ {
+ /* Long keyid. */
+ char buf[9];
+ if (hexlength == 17)
+ s++;
+ mem2str (buf, s, 9);
+ desc->u.kid[0] = strtoul (buf, NULL, 16);
+ desc->u.kid[1] = strtoul (s+8, NULL, 16);
+ mode = KEYDB_SEARCH_MODE_LONG_KID;
+ }
+ else if ((hexlength == 32
+ && (s[hexlength] == 0
+ || (s[hexlength] == '!' && s[hexlength + 1] == 0)))
+ || (!hexprefix && hexlength == 33 && *s == '0'))
+ {
+ /* MD5 fingerprint. */
+ int i;
+ if (hexlength == 33)
+ s++;
+ memset (desc->u.fpr+16, 0, 4);
+ for (i=0; i < 16; i++, s+=2)
+ {
+ int c = hextobyte(s);
+ if (c == -1)
+ {
+ rc = gpg_error (GPG_ERR_INV_USER_ID);
+ goto out;
+ }
+ desc->u.fpr[i] = c;
+ }
+ mode = KEYDB_SEARCH_MODE_FPR16;
+ }
+ else if ((hexlength == 40
+ && (s[hexlength] == 0
+ || (s[hexlength] == '!' && s[hexlength + 1] == 0)))
+ || (!hexprefix && hexlength == 41 && *s == '0'))
+ {
+ /* SHA1/RMD160 fingerprint. */
+ int i;
+ if (hexlength == 41)
+ s++;
+ for (i=0; i < 20; i++, s+=2)
+ {
+ int c = hextobyte(s);
+ if (c == -1)
+ {
+ rc = gpg_error (GPG_ERR_INV_USER_ID);
+ goto out;
+ }
+ desc->u.fpr[i] = c;
+ }
+ mode = KEYDB_SEARCH_MODE_FPR20;
+ }
+ else if (!hexprefix)
+ {
+ /* The fingerprint of an X.509 listing is often delimited by
+ * colons, so we try to single this case out. Note that the
+ * OpenPGP bang suffix is not supported here. */
+ desc->exact = 0;
+ mode = 0;
+ hexlength = strspn (s, ":0123456789abcdefABCDEF");
+ if (hexlength == 59 && (!s[hexlength] || spacep (s+hexlength)))
+ {
+ int i;
+
+ for (i=0; i < 20; i++, s += 3)
+ {
+ int c = hextobyte(s);
+ if (c == -1 || (i < 19 && s[2] != ':'))
+ break;
+ desc->u.fpr[i] = c;
+ }
+ if (i == 20)
+ mode = KEYDB_SEARCH_MODE_FPR20;
+ }
+ if (!mode)
+ {
+ /* Still not found. Now check for a space separated
+ OpenPGP v4 fingerprint like:
+ 8061 5870 F5BA D690 3336 86D0 F2AD 85AC 1E42 B367
+ or
+ 8061 5870 F5BA D690 3336 86D0 F2AD 85AC 1E42 B367
+ */
+ hexlength = strspn (s, " 0123456789abcdefABCDEF");
+ if (s[hexlength] && s[hexlength] != ' ')
+ hexlength = 0; /* Followed by non-space. */
+ while (hexlength && s[hexlength-1] == ' ')
+ hexlength--; /* Trim trailing spaces. */
+ if ((hexlength == 49 || hexlength == 50)
+ && (!s[hexlength] || s[hexlength] == ' '))
+ {
+ int i, c;
+
+ for (i=0; i < 20; i++)
+ {
+ if (i && !(i % 2))
+ {
+ if (*s != ' ')
+ break;
+ s++;
+ /* Skip the double space in the middle but
+ don't require it to help copying
+ fingerprints from sources which fold
+ multiple space to one. */
+ if (i == 10 && *s == ' ')
+ s++;
+ }
+
+ c = hextobyte(s);
+ if (c == -1)
+ break;
+ desc->u.fpr[i] = c;
+ s += 2;
+ }
+ if (i == 20)
+ mode = KEYDB_SEARCH_MODE_FPR20;
+ }
+ }
+ if (!mode) /* Default to substring search. */
+ {
+ desc->u.name = s;
+ mode = KEYDB_SEARCH_MODE_SUBSTR;
+ }
+ }
+ else
+ {
+ /* Hex number with a prefix but with a wrong length. */
+ rc = gpg_error (GPG_ERR_INV_USER_ID);
+ goto out;
+ }
+ }
+
+ desc->mode = mode;
+ out:
+ xfree (s2);
+ return rc;
+}
diff --git a/common/userids.h b/common/userids.h
new file mode 100644
index 0000000..c60bc33
--- /dev/null
+++ b/common/userids.h
@@ -0,0 +1,39 @@
+/* userids.h - Utility functions for user ids.
+ * Copyright (C) 2009 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_COMMON_USERIDS_H
+#define GNUPG_COMMON_USERIDS_H
+
+#include "../kbx/keybox-search-desc.h"
+
+gpg_error_t classify_user_id (const char *name, KEYDB_SEARCH_DESC *desc,
+ int openpgp_hack);
+
+
+#endif /*GNUPG_COMMON_USERIDS_H*/
diff --git a/common/utf8conv.c b/common/utf8conv.c
new file mode 100644
index 0000000..bdab225
--- /dev/null
+++ b/common/utf8conv.c
@@ -0,0 +1,857 @@
+/* utf8conf.c - UTF8 character set conversion
+ * Copyright (C) 1994, 1998, 1999, 2000, 2001, 2003, 2006,
+ * 2008, 2010 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute and/or modify this
+ * part of GnuPG under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * 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 copies of the GNU General Public License
+ * and the GNU Lesser General Public License along with this program;
+ * if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <ctype.h>
+#ifdef HAVE_LANGINFO_CODESET
+#include <langinfo.h>
+#endif
+#include <errno.h>
+
+#if HAVE_W32_SYSTEM
+# /* Tell libgpg-error to provide the iconv macros. */
+# define GPGRT_ENABLE_W32_ICONV_MACROS 1
+#elif HAVE_ANDROID_SYSTEM
+# /* No iconv support. */
+#else
+# include <iconv.h>
+#endif
+
+
+#include "util.h"
+#include "common-defs.h"
+#include "i18n.h"
+#include "stringhelp.h"
+#include "utf8conv.h"
+
+#ifndef MB_LEN_MAX
+#define MB_LEN_MAX 16
+#endif
+
+static const char *active_charset_name = "iso-8859-1";
+static int no_translation; /* Set to true if we let simply pass through. */
+static int use_iconv; /* iconv conversion functions required. */
+
+
+#ifdef HAVE_ANDROID_SYSTEM
+/* Fake stuff to get things building. */
+typedef void *iconv_t;
+#define ICONV_CONST
+
+static iconv_t
+iconv_open (const char *tocode, const char *fromcode)
+{
+ (void)tocode;
+ (void)fromcode;
+ return (iconv_t)(-1);
+}
+
+static size_t
+iconv (iconv_t cd, char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ (void)cd;
+ (void)inbuf;
+ (void)inbytesleft;
+ (void)outbuf;
+ (void)outbytesleft;
+ return (size_t)(0);
+}
+
+static int
+iconv_close (iconv_t cd)
+{
+ (void)cd;
+ return 0;
+}
+#endif /*HAVE_ANDROID_SYSTEM*/
+
+
+/* Error handler for iconv failures. This is needed to not clutter the
+ output with repeated diagnostics about a missing conversion. */
+static void
+handle_iconv_error (const char *to, const char *from, int use_fallback)
+{
+ if (errno == EINVAL)
+ {
+ static int shown1, shown2;
+ int x;
+
+ if (to && !strcmp (to, "utf-8"))
+ {
+ x = shown1;
+ shown1 = 1;
+ }
+ else
+ {
+ x = shown2;
+ shown2 = 1;
+ }
+
+ if (!x)
+ log_info (_("conversion from '%s' to '%s' not available\n"),
+ from, to);
+ }
+ else
+ {
+ static int shown;
+
+ if (!shown)
+ log_info (_("iconv_open failed: %s\n"), strerror (errno));
+ shown = 1;
+ }
+
+ if (use_fallback)
+ {
+ /* To avoid further error messages we fallback to UTF-8 for the
+ native encoding. Nowadays this seems to be the best bet in
+ case of errors from iconv or nl_langinfo. */
+ active_charset_name = "utf-8";
+ no_translation = 1;
+ use_iconv = 0;
+ }
+}
+
+
+
+int
+set_native_charset (const char *newset)
+{
+ const char *full_newset;
+
+ if (!newset)
+ {
+#ifdef HAVE_ANDROID_SYSTEM
+ newset = "utf-8";
+#elif defined HAVE_W32_SYSTEM
+ static char codepage[30];
+ unsigned int cpno;
+ const char *aliases;
+
+ /* We are a console program thus we need to use the
+ GetConsoleOutputCP function and not the GetACP which
+ would give the codepage for a GUI program. Note this is not
+ a bulletproof detection because GetConsoleCP might return a
+ different one for console input. Not sure how to cope with
+ that. If the console Code page is not known we fall back to
+ the system code page. */
+#ifndef HAVE_W32CE_SYSTEM
+ cpno = GetConsoleOutputCP ();
+ if (!cpno)
+#endif
+ cpno = GetACP ();
+ sprintf (codepage, "CP%u", cpno );
+ /* Resolve alias. We use a long string string and not the usual
+ array to optimize if the code is taken to a DSO. Taken from
+ libiconv 1.9.2. */
+ newset = codepage;
+ for (aliases = ("CP936" "\0" "GBK" "\0"
+ "CP1361" "\0" "JOHAB" "\0"
+ "CP20127" "\0" "ASCII" "\0"
+ "CP20866" "\0" "KOI8-R" "\0"
+ "CP21866" "\0" "KOI8-RU" "\0"
+ "CP28591" "\0" "ISO-8859-1" "\0"
+ "CP28592" "\0" "ISO-8859-2" "\0"
+ "CP28593" "\0" "ISO-8859-3" "\0"
+ "CP28594" "\0" "ISO-8859-4" "\0"
+ "CP28595" "\0" "ISO-8859-5" "\0"
+ "CP28596" "\0" "ISO-8859-6" "\0"
+ "CP28597" "\0" "ISO-8859-7" "\0"
+ "CP28598" "\0" "ISO-8859-8" "\0"
+ "CP28599" "\0" "ISO-8859-9" "\0"
+ "CP28605" "\0" "ISO-8859-15" "\0"
+ "CP65001" "\0" "UTF-8" "\0");
+ *aliases;
+ aliases += strlen (aliases) + 1, aliases += strlen (aliases) + 1)
+ {
+ if (!strcmp (codepage, aliases) ||(*aliases == '*' && !aliases[1]))
+ {
+ newset = aliases + strlen (aliases) + 1;
+ break;
+ }
+ }
+
+#else /*!HAVE_W32_SYSTEM && !HAVE_ANDROID_SYSTEM*/
+
+#ifdef HAVE_LANGINFO_CODESET
+ newset = nl_langinfo (CODESET);
+#else /*!HAVE_LANGINFO_CODESET*/
+ /* Try to get the used charset from environment variables. */
+ static char codepage[30];
+ const char *lc, *dot, *mod;
+
+ strcpy (codepage, "iso-8859-1");
+ lc = getenv ("LC_ALL");
+ if (!lc || !*lc)
+ {
+ lc = getenv ("LC_CTYPE");
+ if (!lc || !*lc)
+ lc = getenv ("LANG");
+ }
+ if (lc && *lc)
+ {
+ dot = strchr (lc, '.');
+ if (dot)
+ {
+ mod = strchr (++dot, '@');
+ if (!mod)
+ mod = dot + strlen (dot);
+ if (mod - dot < sizeof codepage && dot != mod)
+ {
+ memcpy (codepage, dot, mod - dot);
+ codepage [mod - dot] = 0;
+ }
+ }
+ }
+ newset = codepage;
+#endif /*!HAVE_LANGINFO_CODESET*/
+#endif /*!HAVE_W32_SYSTEM && !HAVE_ANDROID_SYSTEM*/
+ }
+
+ full_newset = newset;
+ if (strlen (newset) > 3 && !ascii_memcasecmp (newset, "iso", 3))
+ {
+ newset += 3;
+ if (*newset == '-' || *newset == '_')
+ newset++;
+ }
+
+ /* Note that we silently assume that plain ASCII is actually meant
+ as Latin-1. This makes sense because many Unix system don't have
+ their locale set up properly and thus would get annoying error
+ messages and we have to handle all the "bug" reports. Latin-1 has
+ traditionally been the character set used for 8 bit characters on
+ Unix systems. */
+ if ( !*newset
+ || !ascii_strcasecmp (newset, "8859-1" )
+ || !ascii_strcasecmp (newset, "646" )
+ || !ascii_strcasecmp (newset, "ASCII" )
+ || !ascii_strcasecmp (newset, "ANSI_X3.4-1968" )
+ )
+ {
+ active_charset_name = "iso-8859-1";
+ no_translation = 0;
+ use_iconv = 0;
+ }
+ else if ( !ascii_strcasecmp (newset, "utf8" )
+ || !ascii_strcasecmp(newset, "utf-8") )
+ {
+ active_charset_name = "utf-8";
+ no_translation = 1;
+ use_iconv = 0;
+ }
+ else
+ {
+ iconv_t cd;
+
+ cd = iconv_open (full_newset, "utf-8");
+ if (cd == (iconv_t)-1)
+ {
+ handle_iconv_error (full_newset, "utf-8", 0);
+ return -1;
+ }
+ iconv_close (cd);
+ cd = iconv_open ("utf-8", full_newset);
+ if (cd == (iconv_t)-1)
+ {
+ handle_iconv_error ("utf-8", full_newset, 0);
+ return -1;
+ }
+ iconv_close (cd);
+ active_charset_name = full_newset;
+ no_translation = 0;
+ use_iconv = 1;
+ }
+ return 0;
+}
+
+const char *
+get_native_charset ()
+{
+ return active_charset_name;
+}
+
+/* Return true if the native charset is utf-8. */
+int
+is_native_utf8 (void)
+{
+ return no_translation;
+}
+
+
+/* Convert string, which is in native encoding to UTF8 and return a
+ new allocated UTF-8 string. This function terminates the process
+ on memory shortage. */
+char *
+native_to_utf8 (const char *orig_string)
+{
+ const unsigned char *string = (const unsigned char *)orig_string;
+ const unsigned char *s;
+ char *buffer;
+ unsigned char *p;
+ size_t length = 0;
+
+ if (no_translation)
+ {
+ /* Already utf-8 encoded. */
+ buffer = xstrdup (orig_string);
+ }
+ else if (!use_iconv)
+ {
+ /* For Latin-1 we can avoid the iconv overhead. */
+ for (s = string; *s; s++)
+ {
+ length++;
+ if (*s & 0x80)
+ length++;
+ }
+ buffer = xmalloc (length + 1);
+ for (p = (unsigned char *)buffer, s = string; *s; s++)
+ {
+ if ( (*s & 0x80 ))
+ {
+ *p++ = 0xc0 | ((*s >> 6) & 3);
+ *p++ = 0x80 | (*s & 0x3f);
+ }
+ else
+ *p++ = *s;
+ }
+ *p = 0;
+ }
+ else
+ {
+ /* Need to use iconv. */
+ iconv_t cd;
+ const char *inptr;
+ char *outptr;
+ size_t inbytes, outbytes;
+
+ cd = iconv_open ("utf-8", active_charset_name);
+ if (cd == (iconv_t)-1)
+ {
+ handle_iconv_error ("utf-8", active_charset_name, 1);
+ return native_to_utf8 (string);
+ }
+
+ for (s=string; *s; s++ )
+ {
+ length++;
+ if ((*s & 0x80))
+ length += 5; /* We may need up to 6 bytes for the utf8 output. */
+ }
+ buffer = xmalloc (length + 1);
+
+ inptr = string;
+ inbytes = strlen (string);
+ outptr = buffer;
+ outbytes = length;
+ if ( iconv (cd, (ICONV_CONST char **)&inptr, &inbytes,
+ &outptr, &outbytes) == (size_t)-1)
+ {
+ static int shown;
+
+ if (!shown)
+ log_info (_("conversion from '%s' to '%s' failed: %s\n"),
+ active_charset_name, "utf-8", strerror (errno));
+ shown = 1;
+ /* We don't do any conversion at all but use the strings as is. */
+ strcpy (buffer, string);
+ }
+ else /* Success. */
+ {
+ *outptr = 0;
+ /* We could realloc the buffer now but I doubt that it makes
+ much sense given that it will get freed anyway soon
+ after. */
+ }
+ iconv_close (cd);
+ }
+ return buffer;
+}
+
+
+
+static char *
+do_utf8_to_native (const char *string, size_t length, int delim,
+ int with_iconv)
+{
+ int nleft;
+ int i;
+ unsigned char encbuf[8];
+ int encidx;
+ const unsigned char *s;
+ size_t n;
+ char *buffer = NULL;
+ char *p = NULL;
+ unsigned long val = 0;
+ size_t slen;
+ int resync = 0;
+
+ /* First pass (p==NULL): count the extended utf-8 characters. */
+ /* Second pass (p!=NULL): create string. */
+ for (;;)
+ {
+ for (slen = length, nleft = encidx = 0, n = 0,
+ s = (const unsigned char *)string;
+ slen;
+ s++, slen--)
+ {
+ if (resync)
+ {
+ if (!(*s < 128 || (*s >= 0xc0 && *s <= 0xfd)))
+ {
+ /* Still invalid. */
+ if (p)
+ {
+ sprintf (p, "\\x%02x", *s);
+ p += 4;
+ }
+ n += 4;
+ continue;
+ }
+ resync = 0;
+ }
+ if (!nleft)
+ {
+ if (!(*s & 0x80))
+ {
+ /* Plain ascii. */
+ if ( delim != -1
+ && (*s < 0x20 || *s == 0x7f || *s == delim
+ || (delim && *s == '\\')))
+ {
+ n++;
+ if (p)
+ *p++ = '\\';
+ switch (*s)
+ {
+ case '\n': n++; if ( p ) *p++ = 'n'; break;
+ case '\r': n++; if ( p ) *p++ = 'r'; break;
+ case '\f': n++; if ( p ) *p++ = 'f'; break;
+ case '\v': n++; if ( p ) *p++ = 'v'; break;
+ case '\b': n++; if ( p ) *p++ = 'b'; break;
+ case 0: n++; if ( p ) *p++ = '0'; break;
+ default:
+ n += 3;
+ if (p)
+ {
+ sprintf (p, "x%02x", *s);
+ p += 3;
+ }
+ break;
+ }
+ }
+ else
+ {
+ if (p)
+ *p++ = *s;
+ n++;
+ }
+ }
+ else if ((*s & 0xe0) == 0xc0) /* 110x xxxx */
+ {
+ val = *s & 0x1f;
+ nleft = 1;
+ encidx = 0;
+ encbuf[encidx++] = *s;
+ }
+ else if ((*s & 0xf0) == 0xe0) /* 1110 xxxx */
+ {
+ val = *s & 0x0f;
+ nleft = 2;
+ encidx = 0;
+ encbuf[encidx++] = *s;
+ }
+ else if ((*s & 0xf8) == 0xf0) /* 1111 0xxx */
+ {
+ val = *s & 0x07;
+ nleft = 3;
+ encidx = 0;
+ encbuf[encidx++] = *s;
+ }
+ else if ((*s & 0xfc) == 0xf8) /* 1111 10xx */
+ {
+ val = *s & 0x03;
+ nleft = 4;
+ encidx = 0;
+ encbuf[encidx++] = *s;
+ }
+ else if ((*s & 0xfe) == 0xfc) /* 1111 110x */
+ {
+ val = *s & 0x01;
+ nleft = 5;
+ encidx = 0;
+ encbuf[encidx++] = *s;
+ }
+ else /* Invalid encoding: print as \xNN. */
+ {
+ if (p)
+ {
+ sprintf (p, "\\x%02x", *s);
+ p += 4;
+ }
+ n += 4;
+ resync = 1;
+ }
+ }
+ else if (*s < 0x80 || *s >= 0xc0) /* Invalid utf-8 */
+ {
+ if (p)
+ {
+ for (i = 0; i < encidx; i++)
+ {
+ sprintf (p, "\\x%02x", encbuf[i]);
+ p += 4;
+ }
+ sprintf (p, "\\x%02x", *s);
+ p += 4;
+ }
+ n += 4 + 4 * encidx;
+ nleft = 0;
+ encidx = 0;
+ resync = 1;
+ }
+ else
+ {
+ encbuf[encidx++] = *s;
+ val <<= 6;
+ val |= *s & 0x3f;
+ if (!--nleft) /* Ready. */
+ {
+ if (no_translation)
+ {
+ if (p)
+ {
+ for (i = 0; i < encidx; i++)
+ *p++ = encbuf[i];
+ }
+ n += encidx;
+ encidx = 0;
+ }
+ else if (with_iconv)
+ {
+ /* Our strategy for using iconv is a bit strange
+ but it better keeps compatibility with
+ previous versions in regard to how invalid
+ encodings are displayed. What we do is to
+ keep the utf-8 as is and have the real
+ translation step then at the end. Yes, I
+ know that this is ugly. However we are short
+ of the 1.4 release and for this branch we
+ should not mess too much around with iconv
+ things. One reason for this is that we don't
+ know enough about non-GNU iconv
+ implementation and want to minimize the risk
+ of breaking the code on too many platforms. */
+ if ( p )
+ {
+ for (i=0; i < encidx; i++ )
+ *p++ = encbuf[i];
+ }
+ n += encidx;
+ encidx = 0;
+ }
+ else /* Latin-1 case. */
+ {
+ if (val >= 0x80 && val < 256)
+ {
+ /* We can simply print this character */
+ n++;
+ if (p)
+ *p++ = val;
+ }
+ else
+ {
+ /* We do not have a translation: print utf8. */
+ if (p)
+ {
+ for (i = 0; i < encidx; i++)
+ {
+ sprintf (p, "\\x%02x", encbuf[i]);
+ p += 4;
+ }
+ }
+ n += encidx * 4;
+ encidx = 0;
+ }
+ }
+ }
+
+ }
+ }
+ if (!buffer)
+ {
+ /* Allocate the buffer after the first pass. */
+ buffer = p = xmalloc (n + 1);
+ }
+ else if (with_iconv)
+ {
+ /* Note: See above for comments. */
+ iconv_t cd;
+ const char *inptr;
+ char *outbuf, *outptr;
+ size_t inbytes, outbytes;
+
+ *p = 0; /* Terminate the buffer. */
+
+ cd = iconv_open (active_charset_name, "utf-8");
+ if (cd == (iconv_t)-1)
+ {
+ handle_iconv_error (active_charset_name, "utf-8", 1);
+ xfree (buffer);
+ return utf8_to_native (string, length, delim);
+ }
+
+ /* Allocate a new buffer large enough to hold all possible
+ encodings. */
+ n = p - buffer + 1;
+ inbytes = n - 1;;
+ inptr = buffer;
+ outbytes = n * MB_LEN_MAX;
+ if (outbytes / MB_LEN_MAX != n)
+ BUG (); /* Actually an overflow. */
+ outbuf = outptr = xmalloc (outbytes);
+ if ( iconv (cd, (ICONV_CONST char **)&inptr, &inbytes,
+ &outptr, &outbytes) == (size_t)-1)
+ {
+ static int shown;
+
+ if (!shown)
+ log_info (_("conversion from '%s' to '%s' failed: %s\n"),
+ "utf-8", active_charset_name, strerror (errno));
+ shown = 1;
+ /* Didn't worked out. Try again but without iconv. */
+ xfree (buffer);
+ buffer = NULL;
+ xfree (outbuf);
+ outbuf = do_utf8_to_native (string, length, delim, 0);
+ }
+ else /* Success. */
+ {
+ *outptr = 0; /* Make sure it is a string. */
+ /* We could realloc the buffer now but I doubt that it
+ makes much sense given that it will get freed
+ anyway soon after. */
+ xfree (buffer);
+ }
+ iconv_close (cd);
+ return outbuf;
+ }
+ else /* Not using iconv. */
+ {
+ *p = 0; /* Make sure it is a string. */
+ return buffer;
+ }
+ }
+}
+
+/* Convert string, which is in UTF-8 to native encoding. Replace
+ illegal encodings by some "\xnn" and quote all control
+ characters. A character with value DELIM will always be quoted, it
+ must be a vanilla ASCII character. A DELIM value of -1 is special:
+ it disables all quoting of control characters. This function
+ terminates the process on memory shortage. */
+char *
+utf8_to_native (const char *string, size_t length, int delim)
+{
+ return do_utf8_to_native (string, length, delim, use_iconv);
+}
+
+
+
+
+/* Wrapper function for iconv_open, required for W32 as we dlopen that
+ library on that system. */
+jnlib_iconv_t
+jnlib_iconv_open (const char *tocode, const char *fromcode)
+{
+ return (jnlib_iconv_t)iconv_open (tocode, fromcode);
+}
+
+
+/* Wrapper function for iconv, required for W32 as we dlopen that
+ library on that system. */
+size_t
+jnlib_iconv (jnlib_iconv_t cd,
+ const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ return iconv ((iconv_t)cd, (ICONV_CONST char**)inbuf, inbytesleft,
+ outbuf, outbytesleft);
+}
+
+/* Wrapper function for iconv_close, required for W32 as we dlopen that
+ library on that system. */
+int
+jnlib_iconv_close (jnlib_iconv_t cd)
+{
+ return iconv_close ((iconv_t)cd);
+}
+
+
+#ifdef HAVE_W32_SYSTEM
+/* Return a malloced string encoded for CODEPAGE from the wide char input
+ string STRING. Caller must free this value. Returns NULL and sets
+ ERRNO on failure. Calling this function with STRING set to NULL is
+ not defined. */
+static char *
+wchar_to_cp (const wchar_t *string, unsigned int codepage)
+{
+ int n;
+ char *result;
+
+ n = WideCharToMultiByte (codepage, 0, string, -1, NULL, 0, NULL, NULL);
+ if (n < 0)
+ {
+ gpg_err_set_errno (EINVAL);
+ return NULL;
+ }
+
+ result = xtrymalloc (n+1);
+ if (!result)
+ return NULL;
+
+ n = WideCharToMultiByte (codepage, 0, string, -1, result, n, NULL, NULL);
+ if (n < 0)
+ {
+ xfree (result);
+ gpg_err_set_errno (EINVAL);
+ result = NULL;
+ }
+ return result;
+}
+
+
+/* Return a malloced wide char string from a CODEPAGE encoded input
+ string STRING. Caller must free this value. Returns NULL and sets
+ ERRNO on failure. Calling this function with STRING set to NULL is
+ not defined. */
+static wchar_t *
+cp_to_wchar (const char *string, unsigned int codepage)
+{
+ int n;
+ size_t nbytes;
+ wchar_t *result;
+
+ n = MultiByteToWideChar (codepage, 0, string, -1, NULL, 0);
+ if (n < 0)
+ {
+ gpg_err_set_errno (EINVAL);
+ return NULL;
+ }
+
+ nbytes = (size_t)(n+1) * sizeof(*result);
+ if (nbytes / sizeof(*result) != (n+1))
+ {
+ gpg_err_set_errno (ENOMEM);
+ return NULL;
+ }
+ result = xtrymalloc (nbytes);
+ if (!result)
+ return NULL;
+
+ n = MultiByteToWideChar (codepage, 0, string, -1, result, n);
+ if (n < 0)
+ {
+ xfree (result);
+ gpg_err_set_errno (EINVAL);
+ result = NULL;
+ }
+ return result;
+}
+
+
+/* Get the current codepage as used by wchar_to_native and
+ * native_to_char. Note that these functions intentionally do not use
+ * iconv based conversion machinery. */
+static unsigned int
+get_w32_codepage (void)
+{
+ static unsigned int cp;
+
+ if (!cp)
+ {
+#ifndef HAVE_W32CE_SYSTEM
+ cp = GetConsoleOutputCP ();
+ if (!cp)
+#endif
+ cp = GetACP ();
+ }
+ return cp;
+}
+
+/* Return a malloced string encoded in the active code page from the
+ * wide char input string STRING. Caller must free this value.
+ * Returns NULL and sets ERRNO on failure. Calling this function with
+ * STRING set to NULL is not defined. */
+char *
+wchar_to_native (const wchar_t *string)
+{
+ return wchar_to_cp (string, get_w32_codepage ());
+}
+
+
+/* Return a malloced wide char string from native encoded input
+ * string STRING. Caller must free this value. Returns NULL and sets
+ * ERRNO on failure. Calling this function with STRING set to NULL is
+ * not defined. */
+wchar_t *
+native_to_wchar (const char *string)
+{
+ return cp_to_wchar (string, get_w32_codepage ());
+}
+
+
+/* Return a malloced string encoded in UTF-8 from the wide char input
+ * string STRING. Caller must free this value. Returns NULL and sets
+ * ERRNO on failure. Calling this function with STRING set to NULL is
+ * not defined. */
+char *
+wchar_to_utf8 (const wchar_t *string)
+{
+ return wchar_to_cp (string, CP_UTF8);
+}
+
+
+/* Return a malloced wide char string from an UTF-8 encoded input
+ * string STRING. Caller must free this value. Returns NULL and sets
+ * ERRNO on failure. Calling this function with STRING set to NULL is
+ * not defined. */
+wchar_t *
+utf8_to_wchar (const char *string)
+{
+ return cp_to_wchar (string, CP_UTF8);
+}
+
+#endif /*HAVE_W32_SYSTEM*/
diff --git a/common/utf8conv.h b/common/utf8conv.h
new file mode 100644
index 0000000..8b76e11
--- /dev/null
+++ b/common/utf8conv.h
@@ -0,0 +1,58 @@
+/* utf8conf.h
+ * Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute and/or modify this
+ * part of GnuPG under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * 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 copies of the GNU General Public License
+ * and the GNU Lesser General Public License along with this program;
+ * if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_COMMON_UTF8CONF_H
+#define GNUPG_COMMON_UTF8CONF_H
+
+int set_native_charset (const char *newset);
+const char *get_native_charset (void);
+int is_native_utf8 (void);
+
+char *native_to_utf8 (const char *string);
+char *utf8_to_native (const char *string, size_t length, int delim);
+
+
+/* Silly wrappers, required for W32 portability. */
+typedef void *jnlib_iconv_t;
+
+jnlib_iconv_t jnlib_iconv_open (const char *tocode, const char *fromcode);
+size_t jnlib_iconv (jnlib_iconv_t cd, const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft);
+int jnlib_iconv_close (jnlib_iconv_t cd);
+
+#ifdef HAVE_W32_SYSTEM
+char *wchar_to_native (const wchar_t *string);
+wchar_t *native_to_wchar (const char *string);
+char *wchar_to_utf8 (const wchar_t *string);
+wchar_t *utf8_to_wchar (const char *string);
+#endif /*HAVE_W32_SYSTEM*/
+
+
+#endif /*GNUPG_COMMON_UTF8CONF_H*/
diff --git a/common/util.h b/common/util.h
new file mode 100644
index 0000000..82b3a34
--- /dev/null
+++ b/common/util.h
@@ -0,0 +1,424 @@
+/* util.h - Utility functions for GnuPG
+ * Copyright (C) 2001, 2002, 2003, 2004, 2009 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute and/or modify this
+ * part of GnuPG under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * 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 copies of the GNU General Public License
+ * and the GNU Lesser General Public License along with this program;
+ * if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_COMMON_UTIL_H
+#define GNUPG_COMMON_UTIL_H
+
+#include <gcrypt.h> /* We need this for the memory function protos. */
+#include <errno.h> /* We need errno. */
+#include <gpg-error.h> /* We need gpg_error_t and estream. */
+
+/* These error codes might be used but not defined in the required
+ * libgpg-error version. Define them here.
+ * Example: (#if GPG_ERROR_VERSION_NUMBER < 0x011500 // 1.21)
+ */
+#if GPG_ERROR_VERSION_NUMBER < 0x012400 /* 1.36 */
+# define GPG_ERR_NO_AUTH 314
+# define GPG_ERR_BAD_AUTH 315
+#endif
+
+#ifndef EXTERN_UNLESS_MAIN_MODULE
+# if !defined (INCLUDED_BY_MAIN_MODULE)
+# define EXTERN_UNLESS_MAIN_MODULE extern
+# else
+# define EXTERN_UNLESS_MAIN_MODULE
+# endif
+#endif
+
+/* Hash function used with libksba. */
+#define HASH_FNC ((void (*)(void *, const void*,size_t))gcry_md_write)
+
+/* The length of the keygrip. This is a SHA-1 hash of the key
+ * parameters as generated by gcry_pk_get_keygrip. */
+#define KEYGRIP_LEN 20
+
+
+/* Get all the stuff from jnlib. */
+#include "../common/logging.h"
+#include "../common/argparse.h"
+#include "../common/stringhelp.h"
+#include "../common/mischelp.h"
+#include "../common/strlist.h"
+#include "../common/dotlock.h"
+#include "../common/utf8conv.h"
+#include "../common/dynload.h"
+#include "../common/fwddecl.h"
+#include "../common/utilproto.h"
+
+#include "gettime.h"
+
+/* Redefine asprintf by our estream version which uses our own memory
+ allocator.. */
+#define asprintf gpgrt_asprintf
+#define vasprintf gpgrt_vasprintf
+
+/* Due to a bug in mingw32's snprintf related to the 'l' modifier and
+ for increased portability we use our snprintf on all systems. */
+#undef snprintf
+#define snprintf gpgrt_snprintf
+
+
+/* Replacements for macros not available with libgpg-error < 1.20. */
+
+/* We need this type even if we are not using libreadline and or we
+ did not include libreadline in the current file. */
+#ifndef GNUPG_LIBREADLINE_H_INCLUDED
+typedef char **rl_completion_func_t (const char *, int, int);
+#endif /*!GNUPG_LIBREADLINE_H_INCLUDED*/
+
+
+/* Handy malloc macros - please use only them. */
+#define xtrymalloc(a) gcry_malloc ((a))
+#define xtrymalloc_secure(a) gcry_malloc_secure ((a))
+#define xtrycalloc(a,b) gcry_calloc ((a),(b))
+#define xtrycalloc_secure(a,b) gcry_calloc_secure ((a),(b))
+#define xtryrealloc(a,b) gcry_realloc ((a),(b))
+#define xtrystrdup(a) gcry_strdup ((a))
+#define xfree(a) gcry_free ((a))
+#define xfree_fnc gcry_free
+
+#define xmalloc(a) gcry_xmalloc ((a))
+#define xmalloc_secure(a) gcry_xmalloc_secure ((a))
+#define xcalloc(a,b) gcry_xcalloc ((a),(b))
+#define xcalloc_secure(a,b) gcry_xcalloc_secure ((a),(b))
+#define xrealloc(a,b) gcry_xrealloc ((a),(b))
+#define xstrdup(a) gcry_xstrdup ((a))
+
+/* For compatibility with gpg 1.4 we also define these: */
+#define xmalloc_clear(a) gcry_xcalloc (1, (a))
+#define xmalloc_secure_clear(a) gcry_xcalloc_secure (1, (a))
+
+/* The default error source of the application. This is different
+ from GPG_ERR_SOURCE_DEFAULT in that it does not depend on the
+ source file and thus is usable in code shared by applications.
+ Defined by init.c. */
+extern gpg_err_source_t default_errsource;
+
+/* Convenience function to return a gpg-error code for memory
+ allocation failures. This function makes sure that an error will
+ be returned even if accidentally ERRNO is not set. */
+static inline gpg_error_t
+out_of_core (void)
+{
+ return gpg_error_from_syserror ();
+}
+
+
+/*-- yesno.c --*/
+int answer_is_yes (const char *s);
+int answer_is_yes_no_default (const char *s, int def_answer);
+int answer_is_yes_no_quit (const char *s);
+int answer_is_okay_cancel (const char *s, int def_answer);
+
+/*-- xreadline.c --*/
+ssize_t read_line (FILE *fp,
+ char **addr_of_buffer, size_t *length_of_buffer,
+ size_t *max_length);
+
+/*-- b64enc.c and b64dec.c --*/
+struct b64state
+{
+ unsigned int flags;
+ int idx;
+ int quad_count;
+ FILE *fp;
+ estream_t stream;
+ char *title;
+ unsigned char radbuf[4];
+ u32 crc;
+ int stop_seen:1;
+ int invalid_encoding:1;
+ gpg_error_t lasterr;
+};
+
+gpg_error_t b64enc_start (struct b64state *state, FILE *fp, const char *title);
+gpg_error_t b64enc_start_es (struct b64state *state, estream_t fp,
+ const char *title);
+gpg_error_t b64enc_write (struct b64state *state,
+ const void *buffer, size_t nbytes);
+gpg_error_t b64enc_finish (struct b64state *state);
+
+gpg_error_t b64dec_start (struct b64state *state, const char *title);
+gpg_error_t b64dec_proc (struct b64state *state, void *buffer, size_t length,
+ size_t *r_nbytes);
+gpg_error_t b64dec_finish (struct b64state *state);
+
+/*-- sexputil.c */
+char *canon_sexp_to_string (const unsigned char *canon, size_t canonlen);
+void log_printcanon (const char *text,
+ const unsigned char *sexp, size_t sexplen);
+void log_printsexp (const char *text, gcry_sexp_t sexp);
+
+gpg_error_t make_canon_sexp (gcry_sexp_t sexp,
+ unsigned char **r_buffer, size_t *r_buflen);
+gpg_error_t make_canon_sexp_pad (gcry_sexp_t sexp, int secure,
+ unsigned char **r_buffer, size_t *r_buflen);
+gpg_error_t keygrip_from_canon_sexp (const unsigned char *key, size_t keylen,
+ unsigned char *grip);
+int cmp_simple_canon_sexp (const unsigned char *a, const unsigned char *b);
+int cmp_canon_sexp (const unsigned char *a, size_t alen,
+ const unsigned char *b, size_t blen,
+ int (*tcmp)(void *ctx, int depth,
+ const unsigned char *aval, size_t avallen,
+ const unsigned char *bval, size_t bvallen),
+ void *tcmpctx);
+unsigned char *make_simple_sexp_from_hexstr (const char *line,
+ size_t *nscanned);
+int hash_algo_from_sigval (const unsigned char *sigval);
+unsigned char *make_canon_sexp_from_rsa_pk (const void *m, size_t mlen,
+ const void *e, size_t elen,
+ size_t *r_len);
+gpg_error_t get_rsa_pk_from_canon_sexp (const unsigned char *keydata,
+ size_t keydatalen,
+ unsigned char const **r_n,
+ size_t *r_nlen,
+ unsigned char const **r_e,
+ size_t *r_elen);
+gpg_error_t get_ecc_q_from_canon_sexp (const unsigned char *keydata,
+ size_t keydatalen,
+ unsigned char const **r_q,
+ size_t *r_qlen);
+gpg_error_t uncompress_ecc_q_in_canon_sexp (const unsigned char *keydata,
+ size_t keydatalen,
+ unsigned char **r_newkeydata,
+ size_t *r_newkeydatalen);
+
+int get_pk_algo_from_key (gcry_sexp_t key);
+int get_pk_algo_from_canon_sexp (const unsigned char *keydata,
+ size_t keydatalen);
+char *pubkey_algo_string (gcry_sexp_t s_pkey, enum gcry_pk_algos *r_algoid);
+const char *pubkey_algo_to_string (int algo);
+const char *hash_algo_to_string (int algo);
+const char *cipher_mode_to_string (int mode);
+
+/*-- convert.c --*/
+int hex2bin (const char *string, void *buffer, size_t length);
+int hexcolon2bin (const char *string, void *buffer, size_t length);
+char *bin2hex (const void *buffer, size_t length, char *stringbuf);
+char *bin2hexcolon (const void *buffer, size_t length, char *stringbuf);
+const char *hex2str (const char *hexstring,
+ char *buffer, size_t bufsize, size_t *buflen);
+char *hex2str_alloc (const char *hexstring, size_t *r_count);
+
+/*-- percent.c --*/
+char *percent_plus_escape (const char *string);
+char *percent_data_escape (int plus_escape, const char *prefix,
+ const void *data, size_t datalen);
+char *percent_plus_unescape (const char *string, int nulrepl);
+char *percent_unescape (const char *string, int nulrepl);
+
+size_t percent_plus_unescape_inplace (char *string, int nulrepl);
+size_t percent_unescape_inplace (char *string, int nulrepl);
+
+/*-- openpgp-oid.c --*/
+gpg_error_t openpgp_oid_from_str (const char *string, gcry_mpi_t *r_mpi);
+char *openpgp_oidbuf_to_str (const unsigned char *buf, size_t len);
+char *openpgp_oid_to_str (gcry_mpi_t a);
+int openpgp_oidbuf_is_ed25519 (const void *buf, size_t len);
+int openpgp_oid_is_ed25519 (gcry_mpi_t a);
+int openpgp_oidbuf_is_cv25519 (const void *buf, size_t len);
+int openpgp_oid_is_cv25519 (gcry_mpi_t a);
+const char *openpgp_curve_to_oid (const char *name,
+ unsigned int *r_nbits, int *r_algo);
+const char *openpgp_oid_to_curve (const char *oid, int canon);
+const char *openpgp_enum_curves (int *idxp);
+const char *openpgp_is_curve_supported (const char *name,
+ int *r_algo, unsigned int *r_nbits);
+
+
+/*-- homedir.c --*/
+const char *standard_homedir (void);
+const char *default_homedir (void);
+void gnupg_set_homedir (const char *newdir);
+void gnupg_maybe_make_homedir (const char *fname, int quiet);
+const char *gnupg_homedir (void);
+int gnupg_default_homedir_p (void);
+const char *gnupg_daemon_rootdir (void);
+const char *gnupg_socketdir (void);
+const char *gnupg_sysconfdir (void);
+const char *gnupg_bindir (void);
+const char *gnupg_libexecdir (void);
+const char *gnupg_libdir (void);
+const char *gnupg_datadir (void);
+const char *gnupg_localedir (void);
+const char *gpg_agent_socket_name (void);
+const char *dirmngr_socket_name (void);
+
+char *_gnupg_socketdir_internal (int skip_checks, unsigned *r_info);
+
+/* All module names. We also include gpg and gpgsm for the sake for
+ gpgconf. */
+#define GNUPG_MODULE_NAME_AGENT 1
+#define GNUPG_MODULE_NAME_PINENTRY 2
+#define GNUPG_MODULE_NAME_SCDAEMON 3
+#define GNUPG_MODULE_NAME_DIRMNGR 4
+#define GNUPG_MODULE_NAME_PROTECT_TOOL 5
+#define GNUPG_MODULE_NAME_CHECK_PATTERN 6
+#define GNUPG_MODULE_NAME_GPGSM 7
+#define GNUPG_MODULE_NAME_GPG 8
+#define GNUPG_MODULE_NAME_CONNECT_AGENT 9
+#define GNUPG_MODULE_NAME_GPGCONF 10
+#define GNUPG_MODULE_NAME_DIRMNGR_LDAP 11
+#define GNUPG_MODULE_NAME_GPGV 12
+const char *gnupg_module_name (int which);
+void gnupg_module_name_flush_some (void);
+void gnupg_set_builddir (const char *newdir);
+
+
+
+/*-- gpgrlhelp.c --*/
+void gnupg_rl_initialize (void);
+
+/*-- helpfile.c --*/
+char *gnupg_get_help_string (const char *key, int only_current_locale);
+
+/*-- localename.c --*/
+const char *gnupg_messages_locale_name (void);
+
+/*-- sysutils.c --*/
+FILE *gnupg_fopen (const char *fname, const char *mode);
+
+/*-- miscellaneous.c --*/
+
+/* This function is called at startup to tell libgcrypt to use our own
+ logging subsystem. */
+void setup_libgcrypt_logging (void);
+
+/* Print an out of core message and die. */
+void xoutofcore (void);
+
+/* Array allocation. */
+void *gnupg_reallocarray (void *a, size_t oldnmemb, size_t nmemb, size_t size);
+void *xreallocarray (void *a, size_t oldnmemb, size_t nmemb, size_t size);
+
+/* Same as estream_asprintf but die on memory failure. */
+char *xasprintf (const char *fmt, ...) GPGRT_ATTR_PRINTF(1,2);
+/* This is now an alias to estream_asprintf. */
+char *xtryasprintf (const char *fmt, ...) GPGRT_ATTR_PRINTF(1,2);
+
+void *xtryreallocarray (void *a, size_t oldnmemb, size_t nmemb, size_t size);
+
+/* Replacement for gcry_cipher_algo_name. */
+const char *gnupg_cipher_algo_name (int algo);
+
+void obsolete_option (const char *configname, unsigned int configlineno,
+ const char *name);
+
+const char *print_fname_stdout (const char *s);
+const char *print_fname_stdin (const char *s);
+void print_utf8_buffer3 (estream_t fp, const void *p, size_t n,
+ const char *delim);
+void print_utf8_buffer2 (estream_t fp, const void *p, size_t n, int delim);
+void print_utf8_buffer (estream_t fp, const void *p, size_t n);
+void print_utf8_string (estream_t stream, const char *p);
+void print_hexstring (FILE *fp, const void *buffer, size_t length,
+ int reserved);
+char *try_make_printable_string (const void *p, size_t n, int delim);
+char *make_printable_string (const void *p, size_t n, int delim);
+char *decode_c_string (const char *src);
+
+int is_file_compressed (const char *s, int *ret_rc);
+
+int match_multistr (const char *multistr,const char *match);
+
+int gnupg_compare_version (const char *a, const char *b);
+
+struct debug_flags_s
+{
+ unsigned int flag;
+ const char *name;
+};
+int parse_debug_flag (const char *string, unsigned int *debugvar,
+ const struct debug_flags_s *flags);
+
+struct compatibility_flags_s
+{
+ unsigned int flag;
+ const char *name;
+ const char *desc;
+};
+int parse_compatibility_flags (const char *string, unsigned int *flagvar,
+ const struct compatibility_flags_s *flags);
+
+
+/*-- Simple replacement functions. */
+
+/* We use the gnupg_ttyname macro to be safe not to run into conflicts
+ which an extisting but broken ttyname. */
+#if !defined(HAVE_TTYNAME) || defined(HAVE_BROKEN_TTYNAME)
+# define gnupg_ttyname(n) _gnupg_ttyname ((n))
+/* Systems without ttyname (W32) will merely return NULL. */
+static inline char *
+_gnupg_ttyname (int fd)
+{
+ (void)fd;
+ return NULL;
+}
+#else /*HAVE_TTYNAME*/
+# define gnupg_ttyname(n) ttyname ((n))
+#endif /*HAVE_TTYNAME */
+
+#ifdef HAVE_W32CE_SYSTEM
+#define getpid() GetCurrentProcessId ()
+char *_gnupg_getenv (const char *name); /* See sysutils.c */
+#define getenv(a) _gnupg_getenv ((a))
+char *_gnupg_setenv (const char *name); /* See sysutils.c */
+#define setenv(a,b,c) _gnupg_setenv ((a),(b),(c))
+int _gnupg_isatty (int fd);
+#define gnupg_isatty(a) _gnupg_isatty ((a))
+#else
+#define gnupg_isatty(a) isatty ((a))
+#endif
+
+
+
+/*-- Macros to replace ctype ones to avoid locale problems. --*/
+#define spacep(p) (*(p) == ' ' || *(p) == '\t')
+#define digitp(p) (*(p) >= '0' && *(p) <= '9')
+#define alphap(p) ((*(p) >= 'A' && *(p) <= 'Z') \
+ || (*(p) >= 'a' && *(p) <= 'z'))
+#define alnump(p) (alphap (p) || digitp (p))
+#define hexdigitp(a) (digitp (a) \
+ || (*(a) >= 'A' && *(a) <= 'F') \
+ || (*(a) >= 'a' && *(a) <= 'f'))
+ /* Note this isn't identical to a C locale isspace() without \f and
+ \v, but works for the purposes used here. */
+#define ascii_isspace(a) ((a)==' ' || (a)=='\n' || (a)=='\r' || (a)=='\t')
+
+/* The atoi macros assume that the buffer has only valid digits. */
+#define atoi_1(p) (*(p) - '0' )
+#define atoi_2(p) ((atoi_1(p) * 10) + atoi_1((p)+1))
+#define atoi_4(p) ((atoi_2(p) * 100) + atoi_2((p)+2))
+#define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
+ *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
+#define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
+#define xtoi_4(p) ((xtoi_2(p) * 256) + xtoi_2((p)+2))
+
+#endif /*GNUPG_COMMON_UTIL_H*/
diff --git a/common/utilproto.h b/common/utilproto.h
new file mode 100644
index 0000000..7467f6b
--- /dev/null
+++ b/common/utilproto.h
@@ -0,0 +1,44 @@
+/* utilproto.h - Some prototypes for inclusion by util.h
+ * Copyright (C) 2016 Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+/* This file is in general included via util.h but sometimes we do not
+ * want all stuff from util.h and instead use this file with its
+ * simple prototypes. */
+
+#ifndef GNUPG_COMMON_UTILPROTO_H
+#define GNUPG_COMMON_UTILPROTO_H
+
+/*-- signal.c --*/
+void gnupg_init_signals (int mode, void (*fast_cleanup)(void));
+void gnupg_block_all_signals (void);
+void gnupg_unblock_all_signals (void);
+
+
+
+#endif /*GNUPG_COMMON_UTILPROTO_H*/
diff --git a/common/w32-cmdline.c b/common/w32-cmdline.c
new file mode 100644
index 0000000..85d5752
--- /dev/null
+++ b/common/w32-cmdline.c
@@ -0,0 +1,450 @@
+/* w32-cmdline.c - Command line helper functions needed in Windows
+ * Copyright (C) 2021 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#ifdef HAVE_W32_SYSTEM
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+#endif /*!HAVE_W32_SYSTEM*/
+
+#include "util.h"
+#include "w32help.h"
+
+
+/* Helper object for add_arg. */
+struct add_arg_s
+{
+ char **argv; /* Calloced array. */
+ int argc; /* Number of items in argc. */
+ int size; /* Allocated size of argv. */
+};
+
+
+/* Add STRING to the argv of PARM. Returns 0 on success; on error
+ * sets ERRNO and returns -1. */
+static int
+add_arg (struct add_arg_s *parm, const char *string)
+{
+ if (parm->argc == parm->size)
+ {
+ char **newargv;
+ int newsize;
+
+ if (parm->size < 256)
+ newsize = ((parm->size + 31) / 32 + 1) * 32;
+ else
+ newsize = ((parm->size + 255) / 256 + 1) * 256;
+ /* We allocate one more item for the trailing NULL. */
+ newargv = xtryreallocarray (parm->argv, parm->size, newsize+1,
+ sizeof *newargv);
+ if (!newargv)
+ return -1;
+ parm->argv = newargv;
+ parm->size = newsize;
+ }
+ parm->argv[parm->argc] = xtrystrdup (string);
+ if (!parm->argv[parm->argc])
+ return -1;
+ parm->argc++;
+ return 0;
+}
+
+
+/* Glob PATTERN and add to the argv of PARM. Returns 0 on success; on
+ * error sets ERRNO and returns -1. */
+static int
+glob_arg (struct add_arg_s *parm, const char *pattern)
+{
+ int rc;
+ const char *s;
+
+#ifdef HAVE_W32_SYSTEM
+ HANDLE hd;
+ WIN32_FIND_DATAW dir;
+ uintptr_t pos; /* Offset to the last slash in pattern/buffer or 0. */
+ char *buffer, *p;
+ int any = 0;
+
+ s = strpbrk (pattern, "*?");
+ if (!s)
+ {
+ /* Called without wildcards. */
+ return add_arg (parm, pattern);
+ }
+ for (; s != pattern && *s != '/' && *s != '\\'; s--)
+ ;
+ pos = s - pattern;
+ if (*s == '/' || *s == L'\\')
+ pos++;
+
+ {
+ wchar_t *wpattern;
+
+ wpattern = utf8_to_wchar (pattern);
+ if (!wpattern)
+ return -1;
+
+ hd = FindFirstFileW (wpattern, &dir);
+ xfree (wpattern);
+ }
+ if (hd == INVALID_HANDLE_VALUE)
+ return add_arg (parm, pattern);
+
+ /* We allocate enough space to hold all kind of UTF-8 strings. */
+ buffer = xtrymalloc (strlen (pattern) + MAX_PATH*6 + 1);
+ if (!buffer)
+ {
+ FindClose (hd);
+ return -1;
+ }
+ mem2str (buffer, pattern, pos+1);
+ for (p=buffer; *p; p++)
+ if (*p == '\\')
+ *p = '/';
+
+ do
+ {
+ if (!(dir.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
+ {
+ char *name;
+
+ name = wchar_to_utf8 (dir.cFileName);
+ if (!name)
+ rc = -1;
+ else
+ {
+ mem2str (buffer + pos, name, MAX_PATH*6);
+ xfree (name);
+ rc = add_arg (parm, buffer);
+ }
+ if (rc)
+ {
+ FindClose (hd);
+ xfree (buffer);
+ return rc;
+ }
+ any = 1;
+ }
+ }
+ while (FindNextFileW (hd, &dir));
+
+ FindClose (hd);
+ xfree (buffer);
+
+ rc = any? 0 : add_arg (parm, pattern);
+
+#else /* Unix */
+
+ /* We use some dummy code here because this is only used in the Unix
+ * test suite. */
+ s = strpbrk (pattern, "*?");
+ if (!s)
+ {
+ /* Called without wildcards. */
+ return add_arg (parm, pattern);
+ }
+
+ if (strchr (pattern, '?'))
+ rc = add_arg (parm, "[? follows]");
+ else if (strchr (pattern, '*'))
+ rc = add_arg (parm, "[* follows]");
+ else
+ rc = add_arg (parm, "[no glob!]"); /* Should not happen. */
+ if (!rc)
+ rc = add_arg (parm, pattern);
+
+#endif /* Unix */
+
+ return rc;
+}
+
+
+/* Return the number of backslashes. */
+static unsigned int
+count_backslashes (const char *s)
+{
+ unsigned int count = 0;
+
+ for ( ;*s == '\\'; s++)
+ count++;
+ return count;
+}
+
+
+static void
+strip_one_arg (char *string, int endquote)
+{
+ char *s, *d;
+ unsigned int n, i;
+
+ for (s=d=string; *s; s++)
+ if (*s == '\\')
+ {
+ n = count_backslashes (s);
+ if (s[n] == '"')
+ {
+ for (i=0; i < n/2; i++)
+ *d++ = '\\';
+ if ((n&1)) /* Odd number of backslashes. */
+ *d++ = '"'; /* Print the quote. */
+ }
+ else if (!s[n] && endquote)
+ {
+ for (i=0; i < n/2; i++)
+ *d++ = '\\';
+ s--;
+ }
+ else /* Print all backslashes. */
+ {
+ for (i=0; i < n; i++)
+ *d++ = '\\';
+ n--; /* Adjust for the increment in the for. */
+ }
+ s += n;
+ }
+ else if (*s == '"' && s[1])
+ *d++ = *++s;
+ else
+ *d++ = *s;
+ *d = 0;
+}
+
+
+/* Helper for parse_w32_commandline. If ARGV and ARGVFLAGS are not
+ * NULL, ARGVFLAGS is expected to be allocated at the same size of
+ * ARGV and zeroed; on return 1 is stored for all arguments which are
+ * quoted (args like (foo"bar"baz") also count as quoted. */
+static int
+parse_cmdstring (char *string, char **argv, unsigned char *argvflags)
+{
+ int argc = 0;
+ int inquote = 0;
+ char *p0, *p;
+ unsigned int n;
+
+ p0 = string;
+ for (p=string; *p; p++)
+ {
+ if (inquote)
+ {
+ if (*p == '\\' && p[1] == '"')
+ p++;
+ else if (*p == '\\' && p[1] == '\\')
+ p++;
+ else if (*p == '"')
+ {
+ if (p[1] == ' ' || p[1] == '\t' || !p[1])
+ {
+ if (argv)
+ {
+ *p = 0;
+ strip_one_arg (p0, 1);
+ argv[argc] = p0;
+ if (argvflags)
+ argvflags[argc] = 1;
+ }
+ argc++;
+ p0 = NULL;
+ }
+ inquote = 0;
+ }
+ }
+ else if (*p == '\\' && (n=count_backslashes (p)))
+ {
+ if (!p0) /* First non-WS; set start. */
+ p0 = p;
+ if (p[n] == '"')
+ {
+ if (!(n&1)) /* Even number. */
+ inquote = 1;
+ p++;
+ }
+ p += n;
+ }
+ else if (*p == '"')
+ {
+ inquote = 1;
+ if (!p0 || p == string) /* First non-WS or first char; set start. */
+ p0 = p + 1;
+ }
+ else if (*p == ' ' || *p == '\t')
+ {
+ if (p0) /* We are in an argument and reached WS. */
+ {
+ if (argv)
+ {
+ *p = 0;
+ strip_one_arg (p0, inquote);
+ argv[argc] = p0;
+ if (argvflags && inquote)
+ argvflags[argc] = 1;
+ }
+ argc++;
+ p0 = NULL;
+ }
+ }
+ else if (!p0) /* First non-WS; set start. */
+ p0 = p;
+ }
+
+ if (inquote || p0)
+ {
+ /* Closing quote missing (we accept this as argument anyway) or
+ * an open argument. */
+ if (argv)
+ {
+ *p = 0;
+ strip_one_arg (p0, inquote);
+ argv[argc] = p0;
+ if (argvflags && inquote)
+ argvflags[argc] = 1;
+ }
+ argc++;
+ }
+
+ return argc;
+}
+
+/* This is a Windows command line parser, returning an array with
+ * strings and its count. The argument CMDLINE is expected to be
+ * utf-8 encoded and may be modified after returning from this
+ * function. The returned array points into CMDLINE, so this should
+ * not be freed. If GLOBING is set to true globing is done for all
+ * items. Returns NULL on error. The number of items in the array is
+ * returned at R_ARGC. If R_ITEMSALLOCED is NOT NULL, it's value is
+ * set to true if the items at R_ALLOC are allocated and not point
+ * into to CMDLINE. */
+char **
+w32_parse_commandline (char *cmdline, int globing, int *r_argc,
+ int *r_itemsalloced)
+{
+ int argc, i;
+ char **argv;
+ char *argvflags;
+
+ if (r_itemsalloced)
+ *r_itemsalloced = 0;
+
+ argc = parse_cmdstring (cmdline, NULL, NULL);
+ if (!argc)
+ {
+ log_error ("%s failed: %s\n", __func__, "internal error");
+ return NULL; /* Ooops. */
+ }
+ argv = xtrycalloc (argc+1, sizeof *argv);
+ if (!argv)
+ {
+ log_error ("%s failed: %s\n", __func__,
+ gpg_strerror (gpg_error_from_syserror ()));
+ return NULL; /* Ooops. */
+ }
+ if (globing)
+ {
+ argvflags = xtrycalloc (argc+1, sizeof *argvflags);
+ if (!argvflags)
+ {
+ log_error ("%s failed: %s\n", __func__,
+ gpg_strerror (gpg_error_from_syserror ()));
+ xfree (argv);
+ return NULL; /* Ooops. */
+ }
+ }
+ else
+ argvflags = NULL;
+
+ i = parse_cmdstring (cmdline, argv, argvflags);
+ if (argc != i)
+ {
+ log_error ("%s failed (argc=%d i=%d)\n", __func__, argc, i);
+ xfree (argv);
+ xfree (argvflags);
+ return NULL; /* Ooops. */
+ }
+
+ if (globing)
+ {
+ for (i=0; i < argc; i++)
+ if (argvflags[i] != 1 && strpbrk (argv[i], "*?"))
+ break;
+ if (i < argc)
+ {
+ /* Indeed some unquoted arguments contain wildcards. We
+ * need to do the globing and thus a dynamically re-allocate
+ * the argv array and strdup all items. */
+ struct add_arg_s parm;
+ int rc;
+
+ if (argc < 32)
+ parm.size = ((argc + 31) / 32 + 1) * 32;
+ else
+ parm.size = ((argc + 255) / 256 + 1) * 256;
+ parm.argc = 0;
+ /* We allocate one more item for the trailing NULL. */
+ parm.argv = xtryreallocarray (NULL, 0, parm.size + 1,
+ sizeof *parm.argv);
+ if (!parm.argv)
+ {
+ log_error ("%s: error allocating array: %s\n", __func__,
+ gpg_strerror (gpg_error_from_syserror ()));
+ xfree (argv);
+ xfree (argvflags);
+ return NULL; /* Ooops. */
+ }
+ rc = 0;
+ for (i=0; i < argc; i++)
+ {
+ if (argvflags[i] != 1)
+ rc = glob_arg (&parm, argv[i]);
+ else
+ rc = add_arg (&parm, argv[i]);
+ if (rc)
+ {
+ log_error ("%s: error adding or blobing: %s\n", __func__,
+ gpg_strerror (gpg_error_from_syserror ()));
+ for (i=0; i < parm.argc; i++)
+ xfree (parm.argv[i]);
+ xfree (parm.argv);
+ xfree (argv);
+ xfree (argvflags);
+ return NULL; /* Ooops. */
+ }
+ }
+ xfree (argv);
+ argv = parm.argv;
+ argc = parm.argc;
+ if (r_itemsalloced)
+ *r_itemsalloced = 1;
+ }
+ }
+
+ xfree (argvflags);
+ *r_argc = argc;
+ return argv;
+}
diff --git a/common/w32-reg.c b/common/w32-reg.c
new file mode 100644
index 0000000..cbaba56
--- /dev/null
+++ b/common/w32-reg.c
@@ -0,0 +1,315 @@
+/* w32-reg.c - MS-Windows Registry access
+ * Copyright (C) 1999, 2002, 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute and/or modify this
+ * part of GnuPG under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * 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 copies of the GNU General Public License
+ * and the GNU Lesser General Public License along with this program;
+ * if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#ifdef HAVE_W32_SYSTEM
+ /* This module is only used in this environment */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#ifdef HAVE_WINSOCK2_H
+# include <winsock2.h>
+#endif
+#include <windows.h>
+
+#include "util.h"
+#include "common-defs.h"
+#include "utf8conv.h"
+#include "w32help.h"
+
+
+static HKEY
+get_root_key(const char *root)
+{
+ HKEY root_key;
+
+ if (!root)
+ root_key = HKEY_CURRENT_USER;
+ else if (!strcmp (root, "HKEY_CLASSES_ROOT") || !strcmp (root, "HKCR"))
+ root_key = HKEY_CLASSES_ROOT;
+ else if (!strcmp (root, "HKEY_CURRENT_USER") || !strcmp (root, "HKCU"))
+ root_key = HKEY_CURRENT_USER;
+ else if (!strcmp (root, "HKEY_LOCAL_MACHINE") || !strcmp (root, "HKLM"))
+ root_key = HKEY_LOCAL_MACHINE;
+ else if (!strcmp (root, "HKEY_USERS") || !strcmp (root, "HKU"))
+ root_key = HKEY_USERS;
+ else if (!strcmp (root, "HKEY_PERFORMANCE_DATA"))
+ root_key = HKEY_PERFORMANCE_DATA;
+ else if (!strcmp (root, "HKEY_CURRENT_CONFIG") || !strcmp (root, "HKCC"))
+ root_key = HKEY_CURRENT_CONFIG;
+ else
+ return NULL;
+
+ return root_key;
+}
+
+
+/* Return a string from the Win32 Registry or NULL in case of error.
+ Caller must release the return value. A NULL for root is an alias
+ for HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE in turn. */
+char *
+read_w32_registry_string (const char *root, const char *dir, const char *name)
+{
+#ifdef HAVE_W32CE_SYSTEM
+ HKEY root_key, key_handle;
+ DWORD n1, nbytes, type;
+ char *result = NULL;
+ wchar_t *wdir, *wname;
+
+ if ( !(root_key = get_root_key(root) ) )
+ return NULL;
+
+ wdir = utf8_to_wchar (dir);
+ if (!wdir)
+ return NULL;
+
+ if (RegOpenKeyEx (root_key, wdir, 0, KEY_READ, &key_handle) )
+ {
+ if (root)
+ {
+ xfree (wdir);
+ return NULL; /* No need for a RegClose, so return immediately. */
+ }
+ /* It seems to be common practise to fall back to HKLM. */
+ if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, wdir, 0, KEY_READ, &key_handle) )
+ {
+ xfree (wdir);
+ return NULL; /* Still no need for a RegClose. */
+ }
+ }
+ xfree (wdir);
+
+ if (name)
+ {
+ wname = utf8_to_wchar (name);
+ if (!wname)
+ goto leave;
+ }
+ else
+ wname = NULL;
+
+ nbytes = 2;
+ if (RegQueryValueEx (key_handle, wname, 0, NULL, NULL, &nbytes))
+ goto leave;
+ result = xtrymalloc ((n1=nbytes+2));
+ if (!result)
+ goto leave;
+ if (RegQueryValueEx (key_handle, wname, 0, &type, result, &n1))
+ {
+ xfree (result);
+ result = NULL;
+ goto leave;
+ }
+ result[nbytes] = 0; /* Make sure it is a string. */
+ result[nbytes+1] = 0;
+ if (type == REG_SZ || type == REG_EXPAND_SZ)
+ {
+ wchar_t *tmp = (void*)result;
+ result = wchar_to_utf8 (tmp);
+ xfree (tmp);
+ }
+
+ leave:
+ xfree (wname);
+ RegCloseKey (key_handle);
+ return result;
+#else /*!HAVE_W32CE_SYSTEM*/
+ HKEY root_key, key_handle;
+ DWORD n1, nbytes, type;
+ char *result = NULL;
+
+ if ( !(root_key = get_root_key(root) ) )
+ return NULL;
+
+ if (RegOpenKeyEx (root_key, dir, 0, KEY_READ, &key_handle) )
+ {
+ if (root)
+ return NULL; /* No need for a RegClose, so return immediately. */
+ /* It seems to be common practise to fall back to HKLM. */
+ if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle) )
+ return NULL; /* Still no need for a RegClose. */
+ }
+
+ nbytes = 1;
+ if (RegQueryValueEx (key_handle, name, 0, NULL, NULL, &nbytes))
+ {
+ if (root)
+ goto leave;
+ /* Try to fallback to HKLM also for a missing value. */
+ RegCloseKey (key_handle);
+ if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle))
+ return NULL; /* Nope. */
+ if (RegQueryValueEx (key_handle, name, 0, NULL, NULL, &nbytes))
+ goto leave;
+ }
+
+ result = xtrymalloc ((n1=nbytes+1));
+ if (!result)
+ goto leave;
+ if (RegQueryValueEx( key_handle, name, 0, &type, result, &n1 ))
+ {
+ xfree (result);
+ result = NULL;
+ goto leave;
+ }
+ result[nbytes] = 0; /* Make sure it is a string. */
+ if (type == REG_EXPAND_SZ && strchr (result, '%'))
+ {
+ char *tmp;
+
+ n1 += 1000;
+ tmp = xtrymalloc (n1+1);
+ if (!tmp)
+ goto leave;
+ nbytes = ExpandEnvironmentStrings (result, tmp, n1);
+ if (nbytes && nbytes > n1)
+ {
+ xfree (tmp);
+ n1 = nbytes;
+ tmp = xtrymalloc (n1 + 1);
+ if (!tmp)
+ goto leave;
+ nbytes = ExpandEnvironmentStrings (result, tmp, n1);
+ if (nbytes && nbytes > n1)
+ {
+ /* Oops - truncated, better don't expand at all. */
+ xfree (tmp);
+ goto leave;
+ }
+ tmp[nbytes] = 0;
+ xfree (result);
+ result = tmp;
+ }
+ else if (nbytes)
+ {
+ /* Okay, reduce the length. */
+ tmp[nbytes] = 0;
+ xfree (result);
+ result = xtrymalloc (strlen (tmp)+1);
+ if (!result)
+ result = tmp;
+ else
+ {
+ strcpy (result, tmp);
+ xfree (tmp);
+ }
+ }
+ else
+ {
+ /* Error - don't expand. */
+ xfree (tmp);
+ }
+ }
+ else if (type == REG_DWORD && nbytes == sizeof (DWORD))
+ {
+ char *tmp;
+ DWORD dummy;
+
+ memcpy (&dummy, result, nbytes);
+ tmp = xtryasprintf ("%u", (unsigned int)dummy);
+ if (tmp)
+ {
+ xfree (result);
+ result = tmp;
+ }
+ }
+
+ leave:
+ RegCloseKey (key_handle);
+ return result;
+#endif /*!HAVE_W32CE_SYSTEM*/
+}
+
+/* Compact version of read_w32_registry_string. This version expects
+ * a single string as key described here using an example:
+ *
+ * HKCU\Software\GNU\GnuPG:HomeDir
+ *
+ * HKCU := the class, other supported classes are HKLM, HKCR, HKU, and
+ * HKCC. If no class is given and the string thus starts with
+ * a backslash HKCU with a fallback to HKLM is used.
+ * Software\GNU\GnuPG := The actual key.
+ * HomeDir := the name of the item. The name is optional to use the default
+ * value.
+ *
+ * Note that the first backslash and the first colon act as delimiters.
+ *
+ * Returns a malloced string or NULL if not found. If R_HKLM_FALLBACK
+ * is not NULL, no class was given, and the result came from HKLM,
+ * true is stored there.
+ */
+char *
+read_w32_reg_string (const char *key_arg, int *r_hklm_fallback)
+{
+ char *key;
+ char *p1, *p2;
+ char *result, *result2;
+
+ if (r_hklm_fallback)
+ *r_hklm_fallback = 0;
+
+ if (!key_arg)
+ return NULL;
+ key = xtrystrdup (key_arg);
+ if (!key)
+ {
+ log_info ("warning: malloc failed while reading registry key\n");
+ return NULL;
+ }
+
+ p1 = strchr (key, '\\');
+ if (!p1)
+ {
+ xfree (key);
+ return NULL;
+ }
+ *p1++ = 0;
+ p2 = strchr (p1, ':');
+ if (p2)
+ *p2++ = 0;
+
+ result = read_w32_registry_string (*key? key : NULL, p1, p2);
+ if (result && !*key && r_hklm_fallback)
+ {
+ /* No key given - see whether the result came from HKCU or HKLM. */
+ result2 = read_w32_registry_string ("HKCU", p1, p2);
+ if (result2)
+ xfree (result2);
+ else
+ *r_hklm_fallback = 1;
+ }
+ xfree (key);
+ return result;
+}
+
+
+#endif /*HAVE_W32_SYSTEM*/
diff --git a/common/w32help.h b/common/w32help.h
new file mode 100644
index 0000000..54e9267
--- /dev/null
+++ b/common/w32help.h
@@ -0,0 +1,66 @@
+/* w32help.h - W32 speicif functions
+ * Copyright (C) 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute and/or modify this
+ * part of GnuPG under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * 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 copies of the GNU General Public License
+ * and the GNU Lesser General Public License along with this program;
+ * if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_COMMON_W32HELP_H
+#define GNUPG_COMMON_W32HELP_H
+
+/*-- w32-cmdline.c --*/
+
+/* This module is also part of the Unix tests. */
+char **w32_parse_commandline (char *cmdline, int globing, int *r_argv,
+ int *r_itemsalloced);
+
+
+
+#ifdef HAVE_W32_SYSTEM
+
+/*-- w32-reg.c --*/
+char *read_w32_registry_string (const char *root,
+ const char *dir, const char *name );
+char *read_w32_reg_string (const char *key, int *r_hklm_fallback);
+
+/* Other stuff. */
+#ifdef HAVE_W32CE_SYSTEM
+/* Setmode is missing in cegcc but available since CE 5.0. */
+int _setmode (int handle, int mode);
+# define setmode(a,b) _setmode ((a),(b))
+
+static inline int
+umask (int a)
+{
+ (void)a;
+ return 0;
+}
+
+
+#endif /*HAVE_W32CE_SYSTEM*/
+
+#endif /*HAVE_W32_SYSTEM*/
+#endif /*GNUPG_COMMON_MISCHELP_H*/
diff --git a/common/w32info-rc.h.in b/common/w32info-rc.h.in
new file mode 100644
index 0000000..4c0e034
--- /dev/null
+++ b/common/w32info-rc.h.in
@@ -0,0 +1,32 @@
+/* w32info-rc.h.in - Common defs for VERSIONINFO resources.
+ * Copyright (C) 2013 g10 Code GmbH
+ *
+ * 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 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.
+ */
+
+/* This file is processed by configure to create w32info-rc.h . */
+
+#define W32INFO_COMMENTS "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 3 of the License, or (at your option) any later version.\0"
+
+#define W32INFO_COMPANYNAME "g10 Code GmbH\0"
+
+#define W32INFO_VI_FILEVERSION @BUILD_FILEVERSION@
+#define W32INFO_VI_PRODUCTVERSION @BUILD_FILEVERSION@
+
+#define W32INFO_FILEVERSION "@VERSION@ (@BUILD_REVISION@) \
+built on @BUILD_HOSTNAME@ at @BUILD_TIMESTAMP@\0"
+
+#define W32INFO_PRODUCTNAME "GNU Privacy Guard (GnuPG)\0"
+#define W32INFO_PRODUCTVERSION "@VERSION@\0"
+
+#define W32INFO_LEGALCOPYRIGHT "Copyright \xa9 \
+2022 g10 Code GmbH\0"
diff --git a/common/xasprintf.c b/common/xasprintf.c
new file mode 100644
index 0000000..7e37e5b
--- /dev/null
+++ b/common/xasprintf.c
@@ -0,0 +1,123 @@
+/* xasprintf.c
+ * Copyright (C) 2003, 2005 Free Software Foundation, Inc.
+ * Copyright (C) 2020 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "util.h"
+
+/* Same as asprintf but return an allocated buffer suitable to be
+ freed using xfree. This function simply dies on memory failure,
+ thus no extra check is required.
+
+ FIXME: We should remove these functions in favor of gpgrt_bsprintf
+ and a xgpgrt_bsprintf or rename them to xbsprintf and
+ xtrybsprintf. */
+char *
+xasprintf (const char *fmt, ...)
+{
+ va_list ap;
+ char *buf;
+
+ va_start (ap, fmt);
+ if (gpgrt_vasprintf (&buf, fmt, ap) < 0)
+ log_fatal ("estream_asprintf failed: %s\n", strerror (errno));
+ va_end (ap);
+ return buf;
+}
+
+/* Same as above but return NULL on memory failure. */
+char *
+xtryasprintf (const char *fmt, ...)
+{
+ int rc;
+ va_list ap;
+ char *buf;
+
+ va_start (ap, fmt);
+ rc = gpgrt_vasprintf (&buf, fmt, ap);
+ va_end (ap);
+ if (rc < 0)
+ return NULL;
+ return buf;
+}
+
+
+/* This is safe version of realloc useful for reallocing a calloced
+ * array. There are two ways to call it: The first example
+ * reallocates the array A to N elements each of SIZE but does not
+ * clear the newly allocated elements:
+ *
+ * p = xtryreallocarray (a, n, n, nsize);
+ *
+ * Note that when NOLD is larger than N no cleaning is needed anyway.
+ * The second example reallocates an array of size NOLD to N elements
+ * each of SIZE but clear the newly allocated elements:
+ *
+ * p = xtryreallocarray (a, nold, n, nsize);
+ *
+ * Note that xtryreallocarray (NULL, 0, n, nsize) is equivalent to
+ * xtrycalloc (n, nsize).
+ *
+ * The same function under the name gpgrt_reallocarray exists in
+ * libgpg-error but only since version 1.38 and thus we use a copy
+ * here.
+ */
+void *
+xtryreallocarray (void *a, size_t oldnmemb, size_t nmemb, size_t size)
+{
+ size_t oldbytes, bytes;
+ char *p;
+
+ bytes = nmemb * size; /* size_t is unsigned so the behavior on overflow
+ * is defined. */
+ if (size && bytes / size != nmemb)
+ {
+ gpg_err_set_errno (ENOMEM);
+ return NULL;
+ }
+
+ p = xtryrealloc (a, bytes);
+ if (p && oldnmemb < nmemb)
+ {
+ /* OLDNMEMBS is lower than NMEMB thus the user asked for a
+ calloc. Clear all newly allocated members. */
+ oldbytes = oldnmemb * size;
+ if (size && oldbytes / size != oldnmemb)
+ {
+ xfree (p);
+ gpg_err_set_errno (ENOMEM);
+ return NULL;
+ }
+ memset (p + oldbytes, 0, bytes - oldbytes);
+ }
+ return p;
+}
diff --git a/common/xreadline.c b/common/xreadline.c
new file mode 100644
index 0000000..b17579f
--- /dev/null
+++ b/common/xreadline.c
@@ -0,0 +1,127 @@
+/* xreadline.c - fgets replacement function
+ * Copyright (C) 1999, 2004 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "util.h"
+
+
+/* Same as fgets() but if the provided buffer is too short a larger
+ one will be allocated. This is similar to getline. A line is
+ considered a byte stream ending in a LF.
+
+ If MAX_LENGTH is not NULL, it shall point to a value with the
+ maximum allowed allocation.
+
+ Returns the length of the line. EOF is indicated by a line of
+ length zero. A truncated line is indicated by setting the value at
+ MAX_LENGTH to 0. If the returned value is less then 0 not enough
+ memory was enable and ERRNO is set accordingly.
+
+ If a line has been truncated, the file pointer is moved forward to
+ the end of the line so that the next read starts with the next
+ line. Note that MAX_LENGTH must be re-initialzied in this case.
+
+ Note: The returned buffer is allocated with enough extra space to
+ append a CR,LF,Nul
+ */
+ssize_t
+read_line (FILE *fp,
+ char **addr_of_buffer, size_t *length_of_buffer,
+ size_t *max_length)
+{
+ int c;
+ char *buffer = *addr_of_buffer;
+ size_t length = *length_of_buffer;
+ size_t nbytes = 0;
+ size_t maxlen = max_length? *max_length : 0;
+ char *p;
+
+ if (!buffer)
+ { /* No buffer given - allocate a new one. */
+ length = 256;
+ buffer = xtrymalloc (length);
+ *addr_of_buffer = buffer;
+ if (!buffer)
+ {
+ *length_of_buffer = 0;
+ if (max_length)
+ *max_length = 0;
+ return -1;
+ }
+ *length_of_buffer = length;
+ }
+
+ length -= 3; /* Reserve 3 bytes for CR,LF,EOL. */
+ p = buffer;
+ while ((c = getc (fp)) != EOF)
+ {
+ if (nbytes == length)
+ { /* Enlarge the buffer. */
+ if (maxlen && length > maxlen) /* But not beyond our limit. */
+ {
+ /* Skip the rest of the line. */
+ while (c != '\n' && (c=getc (fp)) != EOF)
+ ;
+ *p++ = '\n'; /* Always append a LF (we reserved some space). */
+ nbytes++;
+ if (max_length)
+ *max_length = 0; /* Indicate truncation. */
+ break; /* the while loop. */
+ }
+ length += 3; /* Adjust for the reserved bytes. */
+ length += length < 1024? 256 : 1024;
+ *addr_of_buffer = xtryrealloc (buffer, length);
+ if (!*addr_of_buffer)
+ {
+ int save_errno = errno;
+ xfree (buffer);
+ *length_of_buffer = 0;
+ if (max_length)
+ *max_length = 0;
+ gpg_err_set_errno (save_errno);
+ return -1;
+ }
+ buffer = *addr_of_buffer;
+ *length_of_buffer = length;
+ length -= 3;
+ p = buffer + nbytes;
+ }
+ *p++ = c;
+ nbytes++;
+ if (c == '\n')
+ break;
+ }
+ *p = 0; /* Make sure the line is a string. */
+
+ return nbytes;
+}
diff --git a/common/yesno.c b/common/yesno.c
new file mode 100644
index 0000000..ebe8d82
--- /dev/null
+++ b/common/yesno.c
@@ -0,0 +1,150 @@
+/* yesno.c - Yes/No questions
+ * Copyright (C) 1998, 1999, 2000, 2001, 2003 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "i18n.h"
+#include "util.h"
+
+
+/* Check the string S for a YES or NO answer and take care of
+ localization. If no valid string is given the value of DEF_ANSWER
+ is returned. Returns 1 for yes and 0 for no. */
+int
+answer_is_yes_no_default (const char *s, int def_answer)
+{
+ /* TRANSLATORS: See doc/TRANSLATE about this string. */
+ const char *long_yes = _("yes");
+ const char *short_yes = _("yY");
+ /* TRANSLATORS: See doc/TRANSLATE about this string. */
+ const char *long_no = _("no");
+ const char *short_no = _("nN");
+
+ /* Note: we have to use the local dependent compare here. */
+ if ( match_multistr(long_yes,s) )
+ return 1;
+ if ( *s && strchr( short_yes, *s ) && !s[1] )
+ return 1;
+ /* Test for "no" strings to catch ambiguities for the next test. */
+ if ( match_multistr(long_no,s) )
+ return 0;
+ if ( *s && strchr( short_no, *s ) && !s[1] )
+ return 0;
+ /* Test for the english version (for those who are used to type yes). */
+ if ( !ascii_strcasecmp(s, "yes" ) )
+ return 1;
+ if ( *s && strchr( "yY", *s ) && !s[1] )
+ return 1;
+ return def_answer;
+}
+
+int
+answer_is_yes ( const char *s )
+{
+ return answer_is_yes_no_default(s,0);
+}
+
+/****************
+ * Return 1 for yes, -1 for quit, or 0 for no
+ */
+int
+answer_is_yes_no_quit ( const char *s )
+{
+ /* TRANSLATORS: See doc/TRANSLATE about this string. */
+ const char *long_yes = _("yes");
+ /* TRANSLATORS: See doc/TRANSLATE about this string. */
+ const char *long_no = _("no");
+ /* TRANSLATORS: See doc/TRANSLATE about this string. */
+ const char *long_quit = _("quit");
+ const char *short_yes = _("yY");
+ const char *short_no = _("nN");
+ const char *short_quit = _("qQ");
+
+ /* Note: we have to use a local dependent compare here. */
+ if ( match_multistr(long_no,s) )
+ return 0;
+ if ( match_multistr(long_yes,s) )
+ return 1;
+ if ( match_multistr(long_quit,s) )
+ return -1;
+ if ( *s && strchr( short_no, *s ) && !s[1] )
+ return 0;
+ if ( *s && strchr( short_yes, *s ) && !s[1] )
+ return 1;
+ if ( *s && strchr( short_quit, *s ) && !s[1] )
+ return -1;
+ /* but not here. */
+ if ( !ascii_strcasecmp(s, "yes" ) )
+ return 1;
+ if ( !ascii_strcasecmp(s, "quit" ) )
+ return -1;
+ if ( *s && strchr( "yY", *s ) && !s[1] )
+ return 1;
+ if ( *s && strchr( "qQ", *s ) && !s[1] )
+ return -1;
+ return 0;
+}
+
+/*
+ Return 1 for okay, 0 for cancel or DEF_ANSWER for default.
+ */
+int
+answer_is_okay_cancel (const char *s, int def_answer)
+{
+ /* TRANSLATORS: See doc/TRANSLATE about this string. */
+ const char *long_okay = _("okay|okay");
+ /* TRANSLATORS: See doc/TRANSLATE about this string. */
+ const char *long_cancel = _("cancel|cancel");
+ const char *short_okay = _("oO");
+ const char *short_cancel = _("cC");
+
+ /* Note: We have to use the locale dependent compare. */
+ if ( match_multistr(long_okay,s) )
+ return 1;
+ if ( match_multistr(long_cancel,s) )
+ return 0;
+ if ( *s && strchr( short_okay, *s ) && !s[1] )
+ return 1;
+ if ( *s && strchr( short_cancel, *s ) && !s[1] )
+ return 0;
+ /* Always test for the English values (not locale here). */
+ if ( !ascii_strcasecmp(s, "okay" ) )
+ return 1;
+ if ( !ascii_strcasecmp(s, "ok" ) )
+ return 1;
+ if ( !ascii_strcasecmp(s, "cancel" ) )
+ return 0;
+ if ( *s && strchr( "oO", *s ) && !s[1] )
+ return 1;
+ if ( *s && strchr( "cC", *s ) && !s[1] )
+ return 0;
+ return def_answer;
+}
diff --git a/common/zb32.c b/common/zb32.c
new file mode 100644
index 0000000..517321e
--- /dev/null
+++ b/common/zb32.c
@@ -0,0 +1,120 @@
+/* zb32.c - z-base-32 functions
+ * Copyright (C) 2014 Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "util.h"
+#include "zb32.h"
+
+/* Zooko's base32 variant. See RFC-6189 and
+ http://philzimmermann.com/docs/human-oriented-base-32-encoding.txt
+ Caller must xfree the returned string. Returns NULL and sets ERRNO
+ on error. To avoid integer overflow DATALEN is limited to 2^16
+ bytes. Note, that DATABITS is measured in bits!. */
+char *
+zb32_encode (const void *data, unsigned int databits)
+{
+ static char const zb32asc[32] = {'y','b','n','d','r','f','g','8',
+ 'e','j','k','m','c','p','q','x',
+ 'o','t','1','u','w','i','s','z',
+ 'a','3','4','5','h','7','6','9' };
+ const unsigned char *s;
+ char *output, *d;
+ size_t datalen;
+
+ datalen = (databits + 7) / 8;
+ if (datalen > (1 << 16))
+ {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ d = output = xtrymalloc (8 * (datalen / 5)
+ + 2 * (datalen % 5)
+ - ((datalen%5)>2)
+ + 1);
+ if (!output)
+ return NULL;
+
+ /* I use straightforward code. The compiler should be able to do a
+ better job on optimization than me and it is easier to read. */
+ for (s = data; datalen >= 5; s += 5, datalen -= 5)
+ {
+ *d++ = zb32asc[((s[0] ) >> 3) ];
+ *d++ = zb32asc[((s[0] & 7) << 2) | (s[1] >> 6) ];
+ *d++ = zb32asc[((s[1] & 63) >> 1) ];
+ *d++ = zb32asc[((s[1] & 1) << 4) | (s[2] >> 4) ];
+ *d++ = zb32asc[((s[2] & 15) << 1) | (s[3] >> 7) ];
+ *d++ = zb32asc[((s[3] & 127) >> 2) ];
+ *d++ = zb32asc[((s[3] & 3) << 3) | (s[4] >> 5) ];
+ *d++ = zb32asc[((s[4] & 31) ) ];
+ }
+
+ switch (datalen)
+ {
+ case 4:
+ *d++ = zb32asc[((s[0] ) >> 3) ];
+ *d++ = zb32asc[((s[0] & 7) << 2) | (s[1] >> 6) ];
+ *d++ = zb32asc[((s[1] & 63) >> 1) ];
+ *d++ = zb32asc[((s[1] & 1) << 4) | (s[2] >> 4) ];
+ *d++ = zb32asc[((s[2] & 15) << 1) | (s[3] >> 7) ];
+ *d++ = zb32asc[((s[3] & 127) >> 2) ];
+ *d++ = zb32asc[((s[3] & 3) << 3) ];
+ break;
+ case 3:
+ *d++ = zb32asc[((s[0] ) >> 3) ];
+ *d++ = zb32asc[((s[0] & 7) << 2) | (s[1] >> 6) ];
+ *d++ = zb32asc[((s[1] & 63) >> 1) ];
+ *d++ = zb32asc[((s[1] & 1) << 4) | (s[2] >> 4) ];
+ *d++ = zb32asc[((s[2] & 15) << 1) ];
+ break;
+ case 2:
+ *d++ = zb32asc[((s[0] ) >> 3) ];
+ *d++ = zb32asc[((s[0] & 7) << 2) | (s[1] >> 6) ];
+ *d++ = zb32asc[((s[1] & 63) >> 1) ];
+ *d++ = zb32asc[((s[1] & 1) << 4) ];
+ break;
+ case 1:
+ *d++ = zb32asc[((s[0] ) >> 3) ];
+ *d++ = zb32asc[((s[0] & 7) << 2) ];
+ break;
+ default:
+ break;
+ }
+ *d = 0;
+
+ /* Need to strip some bytes if not a multiple of 40. */
+ output[(databits + 5 - 1) / 5] = 0;
+ return output;
+}
diff --git a/common/zb32.h b/common/zb32.h
new file mode 100644
index 0000000..47bb1f8
--- /dev/null
+++ b/common/zb32.h
@@ -0,0 +1,38 @@
+/* zb32.h - z-base-32 functions
+ * Copyright (C) 2014 Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - 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.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_COMMON_ZB32_H
+#define GNUPG_COMMON_ZB32_H
+
+/* Encode DATA which has a length of DATABITS (bits!) using the
+ zbase32 encoder and return a malloced string. Returns NULL on
+ error and sets ERRNO. */
+char *zb32_encode (const void *data, unsigned int databits);
+
+#endif /*GNUPG_COMMON_ZB32_H*/