diff --git a/Makefile.am b/Makefile.am
index 11e4696..0da00ea 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,76 +1,76 @@
# Assuan top level Makefile
# Copyright (C) 2001, 2002, 2003, 2007, 2011 Free Software Foundation, Inc.
#
# This file is part of Assuan.
#
# Assuan 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.
#
# Assuan 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
# Lesser 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 .
# SPDX-License-Identifier: LGPL-2.1+
## Process this file with automake to produce Makefile.in
ACLOCAL_AMFLAGS = -I m4
DISTCHECK_CONFIGURE_FLAGS = --enable-doc
# (A suitable gitlog-to-changelog script can be found in GnuPG master.)
GITLOG_TO_CHANGELOG=gitlog-to-changelog
EXTRA_DIST = autogen.sh autogen.rc README.GIT VERSION \
ChangeLog-2011 doc/ChangeLog-2011 src/ChangeLog-2011 \
- tests/ChangeLog-2011 contrib/ChangeLog-2011 \
+ tests/ChangeLog-2011 \
build-aux/git-log-footer build-aux/git-log-fix
if BUILD_DOC
doc = doc
else
doc =
endif
SUBDIRS = m4 src $(doc) tests
dist-hook: gen-ChangeLog
distcheck-hook:
set -e; ( \
pref="#+macro: $$(echo $(PACKAGE_NAME)|tr '-' '_')_" ;\
reldate="$$(date -u +%Y-%m-%d)" ;\
echo "$${pref}ver $(PACKAGE_VERSION)" ;\
echo "$${pref}date $${reldate}" ;\
list='$(DIST_ARCHIVES)'; for i in $$list; do \
case "$$i" in *.tar.bz2) \
echo "$${pref}size $$(wc -c <$$i|awk '{print int($$1/1024)}')k" ;\
echo "$${pref}sha1 $$(sha1sum <$$i|cut -d' ' -f1)" ;\
echo "$${pref}sha2 $$(sha256sum <$$i|cut -d' ' -f1)" ;;\
esac;\
done ) | tee $(distdir).swdb
gen_start_date = 2011-12-01T00:00:00
.PHONY: gen-ChangeLog
gen-ChangeLog:
set -e; \
if test -d $(top_srcdir)/.git; then \
(cd $(top_srcdir) && \
$(GITLOG_TO_CHANGELOG) --append-dot --tear-off \
--amend=build-aux/git-log-fix --tear-off \
--since=$(gen_start_date) ) > $(distdir)/cl-t; \
cat $(top_srcdir)/build-aux/git-log-footer >> $(distdir)/cl-t;\
rm -f $(distdir)/ChangeLog; \
mv $(distdir)/cl-t $(distdir)/ChangeLog; \
fi
stowinstall:
$(MAKE) $(AM_MAKEFLAGS) install prefix=/usr/local/stow/libassuan
diff --git a/NEWS b/NEWS
index 0ed6e87..dc04e8f 100644
--- a/NEWS
+++ b/NEWS
@@ -1,586 +1,588 @@
Noteworthy changes in version 2.5.6 (unreleased) [C8/A8/R_]
------------------------------------------------
* Use of ASSUAN_SYSTEM_NPTH is deprecated. Instead, please use
the gpgrt_set_syscall_clamp function from gpgrt library.
+ * No support for WindowsCE, any more.
+
Noteworthy changes in version 2.5.5 (2021-03-22) [C8/A8/R5]
------------------------------------------------
* Allows starting servers with Unicode names on Windows. [#4398]
* Fix a crash in the logging code. [0dd8ffbd32]
* Upgrade autoconf stuff.
Release-info: https://dev.gnupg.org/T5354
Noteworthy changes in version 2.5.4 (2020-10-23) [C8/A8/R4]
------------------------------------------------
* Support Unicode socket names on Windows.
* Fix some minor build annoyances.
Release-info: https://dev.gnupg.org/T5112
Noteworthy changes in version 2.5.3 (2019-02-11) [C8/A8/R3]
------------------------------------------------
* Add a timeout for writing to a SOCKS5 proxy. This helps if another
service is running on the standard tor socket (e.g. Windows 10).
[#3381]
* Add workaround for a problem with LD_LIBRARY_PATH on newer systems.
[#4298]
Release-info: https://dev.gnupg.org/T4361
Noteworthy changes in version 2.5.2 (2018-12-13) [C8/A8/R2]
------------------------------------------------
* Better credential support for BSDs.
* Fix some compiler warnings.
* Update the build system.
Noteworthy changes in version 2.5.1 (2017-12-07) [C8/A8/R1]
------------------------------------------------
* Fix c+p error in the previous usleep fix.
Noteworthy changes in version 2.5.0 (2017-12-07) [C8/A8/R0]
------------------------------------------------
* New function to change the system hooks for the socket
interface. [#3378]
* Fix the use of the internal usleep in the nPth implementation.
* Interface changes relative to the 2.4.0 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
assuan_sock_set_system_hooks NEW.
Noteworthy changes in version 2.4.5 (2017-12-01) [C7/A7/R5]
------------------------------------------------
* Avoid a blocking close on Windows with nPth. [#3378]
Noteworthy changes in version 2.4.4 (2017-11-16) [C7/A7/R4]
------------------------------------------------
* New configure option --disable-doc.
* Fix the use of nanosleep.
* Portability fixes for OpenBSD and macOS. [#2910]
* Portability fix for systems not defining INADDR_LOOPBACK. [#2447]
* Improve descriptor passing test to fix a Cygwin build
problem. [#3384]
Noteworthy changes in version 2.4.3 (2016-07-14) [C7/A7/R3]
------------------------------------------------
* Allow socket redirection with assuan_socket_connect.
* Speedup spawning programs on Linux
* Fix minor memory leaks
* Portability fixes for Solaris and AIX.
Noteworthy changes in version 2.4.2 (2015-12-02) [C7/A7/R2]
------------------------------------------------
* The nPth version of the connect system hook does now wrap the call
with npth_unprotec/npth_protect to avoid blocking during a connect.
* Add feature to assuan_sock_connect_byname to test for SOCKS5
availability.
Noteworthy changes in version 2.4.1 (2015-11-23) [C7/A7/R1]
------------------------------------------------
* In Tor mode fallback to port 9150 if 9050 is not listening.
* Allow building with older mingw-w64 versions.
Noteworthy changes in version 2.4.0 (2015-11-03) [C7/A7/R0]
------------------------------------------------
* New flags "socks" and "tor-mode" for assuan_sock_{set,get}_flag.
* New function assuan_sock_connect_byname.
* Require at least libgpg-error 1.17.
* Interface changes relative to the 2.3.0 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
assuan_sock_connect_byname NEW.
ASSUAN_SOCK_TOR NEW.
ASSUAN_SOCK_SOCKS NEW.
assuan_sock_set_flag EXTENDED.
assuan_sock_get_flag EXTENDED.
Noteworthy changes in version 2.3.0 (2015-08-28) [C6/A6/R0]
------------------------------------------------
* Now wipes out the memory of the context structure before freeing.
The context may have stored sensitive data in its line buffers.
* Fixed a problem with the data length limit in assuan_inquire.
* Returns GPG_ERR_SOURCE_ASSUAN with errors from functions w/o a
context.
* Two new functions to tweak the behaviour of the socket wrappers.
* Experimental code to support Cygwin's local sockets.
* By default build without a build timestamp.
* Interface changes relative to the 2.2.1 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
assuan_sock_set_flag NEW.
assuan_sock_get_flag NEW.
Noteworthy changes in version 2.2.1 (2015-05-12) [C5/A5/R1]
------------------------------------------------
* Documentation updates.
* Fixed building for Windows with newer versions of Mingw.
Noteworthy changes in version 2.2.0 (2014-12-11) [C5/A5/R0]
------------------------------------------------
* Added support for socket redirection.
* Interface changes relative to the 2.1.3 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
assuan_sock_set_sockaddr_un NEW.
Noteworthy changes in version 2.1.3 (2014-11-07) [C4/A4/R3]
------------------------------------------------
* Performance fix for Windows.
Noteworthy changes in version 2.1.2 (2014-08-17) [C4/A4/R2]
------------------------------------------------
* Fixed portability bugs for Solaris and AIX.
* Added support for ppc64le.
Noteworthy changes in version 2.1.1 (2013-06-24) [C4/A4/R1]
------------------------------------------------
* Limited support for 64 bit Windows. This is sufficient for use by
GpgEX.
Noteworthy changes in version 2.1.0 (2013-02-22)
------------------------------------------------
* Support for the nPth library.
* Add assuan_check_version and two version macros.
* Interface changes relative to the 2.0.3 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ASSUAN_SYSTEM_NPTH_IMPL NEW macro.
ASSUAN_SYSTEM_NPTH NEW macro.
__assuan_read NEW (private).
__assuan_write NEW (private).
__assuan_recvmsg NEW (private).
__assuan_sendmsg NEW (private).
__assuan_waitpid NEW (private).
ASSUAN_VERSION NEW macro.
ASSUAN_VERSION_NUMBER NEW macro.
assuan_check_version NEW.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Noteworthy changes in version 2.0.3 (2011-12-20)
------------------------------------------------
* Make assuan_get_pid work correctly for pipe server.
* Interface changes relative to the 2.0.2 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ASSUAN_FORCE_CLOSE NEW.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Noteworthy changes in version 2.0.2 (2011-06-16)
------------------------------------------------
* A new flag may now be used to convey comments via assuan_transact.
* A new flag value may now be used to disable logging.
* The gpgcedev.c driver now provides a log device.
* It is now possible to overwrite socket and connect functions in
struct assuan_system_hooks.
* Interface changes relative to the 2.0.1 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ASSUAN_CONVEY_COMMENTS NEW.
ASSUAN_NO_LOGGING NEW.
assuan_system_hooks_t CHANGED: Added socket and connect members.
ASSUAN_SYSTEM_HOOKS_VERSION CHANGED: Bumped to 2.
assuan_register_pre_cmd_notify NEW.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Noteworthy changes in version 2.0.1 (2010-08-09)
------------------------------------------------
* Support for WindowsCE.
* Input and output notification handler can now really access the
parsed fd as stated in the manual.
* Cleaned up the logging.
* Interface changes relative to the 2.0.0 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
assuan_free NEW.
_assuan_w32ce_create_pipe NEW.
ASSUAN_LOG_CONTROL NEW.
ASSUAN_NO_LOGGING NEW.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Noteworthy changes in version 2.0.0 (2010-01-08)
------------------------------------------------
* Now using libtool and builds a DSO.
* Lots of interface cleanups. See below for details of the most
important changes. Here is a quick note on how to upgrade:
For each invocation of the connect or server functions, allocate a
context with assuan_new and use that. Instead of assuan_disconnect
or assuan_deinit_server, call assuan_release. Use
assuan_set_gpg_err_source instead of assuan_set_assuan_err_source.
If you use assuan_pipe_connect with NAME of NULL, you have to
provide a non-NULL ARGV argument and check that against "server" or
"client" to determine which end you got after fork(). If you use
the assuan sock interface, you must call assuan_sock_init after
setting global context defaults. Add a NULL as the last arg to
assuan_register_command.
* Pth support has changed. This now follows the same style as
libgcrypt by setting system hook callbacks.
* Interface changes relative to the 1.0.5 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
_ASSUAN_ONLY_GPG_ERRORS REMOVED
assuan_set_assuan_err_source REMOVED: Use assuan_set_gpg_err_source.
assuan_set_gpg_err_source NEW
assuan_get_gpg_err_source NEW
assuan_strerror REMOVED
ASSUAN_* Error values removed.
assuan_error_t REMOVED
AssuanError REMOVED
assuan_init_connected_socket_server REMOVED
assuan_pipe_connect2 REMOVED
AssuanCommand REMOVED
assuan_flag_t CHANGED: From enum to unsigned int.
ASSUAN_CONTENT REMOVED
assuan_disconnect REMOVED: Use assuan_release.
assuan_deinit_server REMOVED: Use assuan_release.
assuan_get_malloc_hooks NEW
assuan_set_log_cb NEW
assuan_get_log_cb NEW
assuan_new_ext NEW
assuan_new NEW
assuan_release NEW
assuan_init_socket_server CHANGED: Take ctx arg instead of pointer to ctx.
CHANGED: As assuan_init_socket_server_ext was.
assuan_init_socket_server_ext REMOVED
assuan_socket_connect CHANGED: Take ctx arg instead of pointer to ctx.
CHANGED: Is what assuan_socket_connect_ext was.
assuan_socket_connect_ext REMOVED
assuan_pipe_connect CHANGED: Take ctx arg instead of pointer to ctx.
If NAME is NULL, ARGV will contain fork result.
CHANGED: Is now what assuan_pipe_connect_ext was.
CHANGED: Child fds are now assuan_fd_t.
assuan_pipe_connect_ext REMOVED
assuan_init_pipe_server CHANGED: Take ctx arg instead of pointer to ctx.
CHANGED: Swallows fds (are closed at end).
CHANGED: Take assuan_fd_t.
assuan_fdopen NEW
assuan_set_io_hooks REMOVED: Use assuan_system_hooks interface.
assuan_io_hooks_t REMOVED: Use assuan_system_hooks interface.
assuan_io_monitor_t CHANGED: Add a hook data argument.
assuan_get_command_name NEW
assuan_msghdr_t NEW
ASSUAN_INVALID_PID NEW
ASSUAN_NO_FIXSIGNALS NEW
ASSUAN_SYSTEM_HOOKS_VERSION NEW
assuan_system_hooks_t NEW
assuan_set_system_hooks NEW
assuan_ctx_set_system_hooks NEW
ASSUAN_SYSTEM_PTH_IMPL NEW
ASSUAN_SYSTEM_PTH_DECL NEW
ASSUAN_SYSTEM_PTH NEW
assuan_sock_init NEW
assuan_sock_deinit NEW
assuan_handler_t NEW
assuan_register_command CHANGED: Add arg HELP_STRING.
assuan_register_bye_notify CHANGED: Handler gets line and returns err now.
assuan_register_reset_notify CHANGED: Handler gets line and returns err now.
assuan_register_cancel_notify CHANGED: Handler gets line and returns err now.
assuan_register_input_notify CHANGED: Handler returns error now.
assuan_register_output_notify CHANGED: Handler returns error now.
assuan_process_next CHANGED: New DONE argument instead EOF return.
ASSUAN_PIPE_CONNECT_FDPASSING NEW
ASSUAN_PIPE_CONNECT_DETACHED NEW
ASSUAN_SOCKET_SERVER_FDPASSING NEW
ASSUAN_SOCKET_SERVER_ACCEPTED NEW
ASSUAN_SOCKET_CONNECT_FDPASSING NEW
assuan_peercred_t NEW
assuan_get_peercred CHANGED: Return assuan_peercred_t.
assuan_client_read_response NEW
assuan_client_parse_response NEW
assuan_fd_from_posix_fd NEW
ASSUAN_SPAWN_DETACHED NEW
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Noteworthy changes in version 1.0.5 (2008-05-25)
------------------------------------------------
* Minor fixes.
* Build library for GNU/Linux as PIC.
Noteworthy changes in version 1.0.4 (2007-12-12)
------------------------------------------------
* New socket wrapper functions to support Unix domain sockets under
Windows.
* New hook feature to enhance the internal I/O functions.
Noteworthy changes in version 1.0.3 (2007-08-24)
------------------------------------------------
* New type assuan_fd_t and constant ASSUAN_INVALID_FD for better W32
support. It does not change the semantics under Unix. Under W32
all file descriptors are now guaranteed to be system handles.
* New functions assuan_process_done and assuan_inquire_ext to support
external event loops.
* Changed the license of the library code back to LGPLv2.1 to support
a bunch of GPLv2(only) software which does not allow the use of
LGPLv3. Note that this is only a temporary change and authors of
GPLv2(only) software are asked to switch to GPLv3 or to add an
exception which allow the use of LPGLv3 software.
Noteworthy changes in version 1.0.2 (2007-07-05)
------------------------------------------------
* Changed license to LGPLv3.
* New flag ASSUAN_CONFIDENTIAL to return the state of
confidential logging.
* Better support for W32.
* Assorted bug fixed and code cleanups.
Noteworthy changes in version 1.0.1 (2006-11-22)
------------------------------------------------
* New function: assuan_set_io_monitor.
* New function: assuan_register_post_cmd_notify.
* Fixed a memory leak.
Noteworthy changes in version 1.0.0 (2006-10-31)
------------------------------------------------
* Finished the manual.
Noteworthy changes in version 0.9.3 (2006-10-10)
------------------------------------------------
* Portability fixes.
* Pth is not anymore linked by means of weak symbol tricks. It is
now required to link to the pth version of libassuan. New autoconf
macros are provided to to check for this. The pth version is only
build if Pth is available.
* configure does now check that descripotor passing is available. A
way to check at runtime for this is also provided
Noteworthy changes in version 0.9.2 (2006-10-04)
------------------------------------------------
* A fix to make CANCEL work again in Pinentries.
Noteworthy changes in version 0.9.1 (2006-10-04)
------------------------------------------------
* Minor bug fixes
* Portability fixes.
Noteworthy changes in version 0.9.0 (2006-09-14)
------------------------------------------------
* Internal cleanups to make inclusion of the code into libraries
easier.
* Made clear that the software is under the LGPL.
* New function assuan_set_assuan_err_source. All gpg-error enabled
software should call this right at startup to switch libassuan into
the gpg-error style mode. All error codes are then returned as
gpg-error style codes (GPG_ERR_ASS_* as well as others).
If the new macro _ASSUAN_ONLY_GPG_ERRORS is defned all old
definitions are excluded from assuan.h.
* Logging of hex strings is now limited to 16 bytes. To enable
printing of the full data, a new environment variable
ASSUAN_FULL_LOGGING may be set to any value.
* Removed the assuan_domain_* functions.
* New functions assuan_pipe_connect_ext and assuan_socket_connect_ext
to allow connections on a socketpair and to pass descriptors.
* New function assuan_get_peercred.
Noteworthy changes in version 0.6.10 (2005-06-20)
-------------------------------------------------
* New functions assuan_get_flag and assuan_set_flag.
* Add flag ASSUAN_NO_WAITPID.
Noteworthy changes in version 0.6.9 (2004-12-22)
------------------------------------------------
* Ported to W32 based systems.
Noteworthy changes in version 0.6.8 (2004-11-25)
------------------------------------------------
* assuan_write_status does now return an error code.
* Fixes for C89 compatibility and some first takes on a W32 port.
Noteworthy changes in version 0.6.7 (2004-09-27)
------------------------------------------------
* Minor build fixes.
Noteworthy changes in version 0.6.6 (2004-06-08)
------------------------------------------------
* assuan_set_hello_line may now take a multi line argument where the
first lines are send as comment lines and the last one as a OK
line.
Noteworthy changes in version 0.6.5 (2004-04-29)
------------------------------------------------
* Pass the client's pid to a pipe server.
Noteworthy changes in version 0.6.4 (2004-02-20)
------------------------------------------------
* Will now also build on systems not providing funopen or
fopencookie.
* Some smaller build fixes.
Noteworthy changes in version 0.6.3 (2004-01-29)
------------------------------------------------
* Fixed a data corruption bug in assuan_get_data_fp.
* New function assuan_pipe_connect2.
Noteworthy changes in version 0.6.2 (2003-12-18)
------------------------------------------------
* New function assuan_set_assuan_log_prefix to store a log prefix to
be used when no context is available. The existing function
assuan_get_assuan_log_context is not anymore declared as user
overridable.
* Documentation cleanups.
Noteworthy changes in version 0.6.1 (2003-11-17)
------------------------------------------------
* Fixed a bug in assuan_inquire which led to an Invalid_Value error
for large inquiry parameters.
* Fixed a bug in the client socket connect code.
Noteworthy changes in version 0.6.0 (2003-08-06)
------------------------------------------------
* Initial release as a standalone library.
Copyright 2003, 2004, 2006, 2007, 2011,
2013 Free Software Foundation, Inc.
This file is free software; as a special exception the author gives
unlimited permission to copy and/or distribute it, with or without
modifications, as long as this notice is preserved.
This file is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/configure.ac b/configure.ac
index 29c66dd..b5c2cc7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,473 +1,456 @@
# configure.ac - for libassuan
# Copyright (C) 2001, 2002, 2003, 2006, 2007, 2009,
# 2011, 2012, 2013 Free Software Foundation, Inc.
# Copyright (C) 2013, 2014, 2015 g10 Code GmbH
#
# This file is part of Assuan.
#
# Assuan 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.
#
# Assuan 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
# Lesser 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 .
# SPDX-License-Identifier: LGPL-2.1+
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.69])
min_automake_version="1.14"
# To build a release you need to create a tag with the version number
# (git tag -s libassuan-n.m.k) and run "./autogen.sh --force". Please
# bump the version number immediately after the release and do another
# commit and push so that the git magic is able to work. See below
# for the LT versions.
m4_define([mym4_package],[libassuan])
m4_define([mym4_major], [2])
m4_define([mym4_minor], [5])
m4_define([mym4_micro], [6])
# To start a new development series, i.e a new major or minor number
# you need to mark an arbitrary commit before the first beta release
# with an annotated tag. For example a 2.1 branch starts off with
# the tag "foo-2.1-base". This is used as the base for counting
# beta numbers before the first release of a series.
# Below is m4 magic to extract and compute the git revision number,
# the decimalized short revision number, a beta version string and a
# flag indicating a development version (mym4_isbeta). Note that the
# m4 processing is done by autoconf and not during the configure run.
m4_define([mym4_verslist], m4_split(m4_esyscmd([./autogen.sh --find-version] \
mym4_package mym4_major mym4_minor mym4_micro),[:]))
m4_define([mym4_isbeta], m4_argn(2, mym4_verslist))
m4_define([mym4_version], m4_argn(4, mym4_verslist))
m4_define([mym4_revision], m4_argn(7, mym4_verslist))
m4_define([mym4_revision_dec], m4_argn(8, mym4_verslist))
m4_esyscmd([echo ]mym4_version[>VERSION])
AC_INIT([mym4_package],[mym4_version],[https://bugs.gnupg.org])
# LT Version numbers, remember to change them just *before* a release.
# (Code changed: REVISION++)
# (Interfaces added/removed/changed: CURRENT++, REVISION=0)
# (Interfaces added: AGE++)
# (Interfaces removed/changed: AGE=0)
#
LIBASSUAN_LT_CURRENT=8
LIBASSUAN_LT_AGE=8
LIBASSUAN_LT_REVISION=5
# If the API is changed in an incompatible way: increment the next counter.
LIBASSUAN_CONFIG_API_VERSION=2
##############################################
AC_SUBST(LIBASSUAN_LT_CURRENT)
AC_SUBST(LIBASSUAN_LT_AGE)
AC_SUBST(LIBASSUAN_LT_REVISION)
AC_CONFIG_AUX_DIR([build-aux])
AM_INIT_AUTOMAKE([serial-tests dist-bzip2 no-dist-gzip])
AM_MAINTAINER_MODE
AC_CONFIG_SRCDIR(src/assuan.h.in)
AC_CONFIG_MACRO_DIR(m4)
AC_CONFIG_HEADERS([config.h])
AC_CANONICAL_HOST
AM_SILENT_RULES
AB_INIT
AC_USE_SYSTEM_EXTENSIONS
# Taken from mpfr-4.0.1, then modified for LDADD_FOR_TESTS_KLUDGE
dnl Under Linux, make sure that the old dtags are used if LD_LIBRARY_PATH
dnl is defined. The issue is that with the new dtags, LD_LIBRARY_PATH has
dnl the precedence over the run path, so that if a compatible MPFR library
dnl is installed in some directory from $LD_LIBRARY_PATH, then the tested
dnl MPFR library will be this library instead of the MPFR library from the
dnl build tree. Other OS with the same issue might be added later.
dnl
dnl References:
dnl https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=859732
dnl http://lists.gnu.org/archive/html/libtool/2017-05/msg00000.html
dnl
dnl We need to check whether --disable-new-dtags is supported as alternate
dnl linkers may be used (e.g., with tcc: CC=tcc LD=tcc).
dnl
case $host in
*-*-linux*)
if test -n "$LD_LIBRARY_PATH"; then
saved_LDFLAGS="$LDFLAGS"
LDADD_FOR_TESTS_KLUDGE="-Wl,--disable-new-dtags"
LDFLAGS="$LDFLAGS $LDADD_FOR_TESTS_KLUDGE"
AC_MSG_CHECKING(whether --disable-new-dtags is supported by the linker)
AC_LINK_IFELSE([AC_LANG_SOURCE([[
int main (void) { return 0; }
]])],
[AC_MSG_RESULT(yes (use it since LD_LIBRARY_PATH is set))],
[AC_MSG_RESULT(no)
LDADD_FOR_TESTS_KLUDGE=""
])
LDFLAGS="$saved_LDFLAGS"
fi
;;
esac
AC_SUBST([LDADD_FOR_TESTS_KLUDGE])
VERSION_NUMBER=m4_esyscmd(printf "0x%02x%02x%02x" mym4_major \
mym4_minor mym4_micro)
AC_SUBST(VERSION_NUMBER)
# Don't default to build static libs.
LT_PREREQ([2.2.6])
LT_INIT([win32-dll disable-static])
LT_LANG([Windows Resource])
# For now we hardcode the use of version scripts. It would be better
# to write a test for this or even implement this within libtool.
have_ld_version_script=no
check_descriptor_passing=yes
case "${host}" in
*-*-cygwin*)
check_descriptor_passing=no
;;
*-*-linux*)
have_ld_version_script=yes
;;
*-*-gnu*)
have_ld_version_script=yes
;;
*-apple-darwin*)
AC_DEFINE(_XOPEN_SOURCE, 500, Activate POSIX interface on MacOS X)
AC_DEFINE(_DARWIN_C_SOURCE, 1,
Expose all libc features (__DARWIN_C_FULL))
;;
esac
AM_CONDITIONAL(HAVE_LD_VERSION_SCRIPT, test "$have_ld_version_script" = "yes")
AH_TOP([
#ifndef _ASSUAN_CONFIG_H_INCLUDED
#define _ASSUAN_CONFIG_H_INCLUDED
-/* Enable gpg-error's strerror macro under W32CE. */
-#define GPG_ERR_ENABLE_ERRNO_MACROS 1
-
/* Provide the es_ macro for estream. */
#define GPGRT_ENABLE_ES_MACROS 1
])
AH_BOTTOM([
#endif /*_ASSUAN_CONFIG_H_INCLUDED*/
])
# Checks for programs.
missing_dir=`cd $ac_aux_dir && pwd`
AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir)
AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir)
AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir)
AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir)
AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir)
AC_PROG_AWK
AC_PROG_CC
AC_PROG_CPP
AM_PROG_CC_C_O
if test "x$ac_cv_prog_cc_c89" = "xno" ; then
AC_MSG_ERROR([[No C-89 compiler found]])
fi
AC_PROG_INSTALL
AC_PROG_LN_S
AC_PROG_MAKE_SET
#AC_ARG_PROGRAM
# We need to compile and run a program on the build machine.
AX_CC_FOR_BUILD
if test "$GCC" = yes; then
CFLAGS="$CFLAGS -Wall -Wcast-align -Wshadow -Wstrict-prototypes"
AC_MSG_CHECKING([if gcc supports -Wpointer-arith])
_gcc_cflags_save=$CFLAGS
CFLAGS="-Wpointer-arith"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])],_gcc_wopt=yes,_gcc_wopt=no)
AC_MSG_RESULT($_gcc_wopt)
CFLAGS=$_gcc_cflags_save;
if test x"$_gcc_wopt" = xyes ; then
CFLAGS="$CFLAGS -Wpointer-arith"
fi
fi
#
# Options depending on the host OS.
#
have_dosish_system=no
have_w32_system=no
have_w64_system=no
-have_w32ce_system=no
case "${host}" in
*-linux*)
if test "$GCC" = yes; then
CFLAGS="$CFLAGS -fPIC -DPIC"
fi
;;
x86_64-*mingw32*)
have_dosish_system=yes
have_w32_system=yes
have_w64_system=yes
;;
- *-mingw32ce*)
- have_dosish_system=yes
- have_w32_system=yes
- have_w32ce_system=yes
- ;;
*-mingw32*)
have_dosish_system=yes
have_w32_system=yes
;;
*-solaris*)
AC_DEFINE(_XOPEN_SOURCE, 500, Activate extensions on Solaris)
AC_DEFINE(_XOPEN_SOURCE_EXTENDED, 1, Activate extensions on Solaris)
AC_DEFINE(__EXTENSIONS__, 1, Activate extensions on Solaris)
;;
esac
if test "$have_dosish_system" = yes; then
AC_DEFINE(HAVE_DOSISH_SYSTEM,1,
[Defined if we run on some of the PCDOS like systems
(DOS, Windoze. OS/2) with special properties like
no file modes])
fi
if test "$have_w32_system" = yes; then
AC_DEFINE(HAVE_W32_SYSTEM,1,[Defined if we run on a W32 API based system])
if test "$have_w64_system" = yes; then
AC_DEFINE(HAVE_W64_SYSTEM,1,
[Defined if we run on a 64 bit W32 API based system])
fi
- if test "$have_w32ce_system" = yes; then
- AC_DEFINE(HAVE_W32CE_SYSTEM,1,[Defined if we run on WindowsCE])
- fi
AC_CHECK_HEADERS([winsock2.h])
fi
AM_CONDITIONAL(HAVE_W32_SYSTEM, test "$have_w32_system" = yes)
-AM_CONDITIONAL(HAVE_W32CE_SYSTEM, test "$have_w32ce_system" = yes)
AM_CONDITIONAL(HAVE_W64_SYSTEM, test "$have_w64_system" = yes)
#
# Provide information about the build.
#
BUILD_REVISION="mym4_revision"
AC_SUBST(BUILD_REVISION)
AC_DEFINE_UNQUOTED(BUILD_REVISION, "$BUILD_REVISION",
[GIT commit id revision used to build this package])
changequote(,)dnl
BUILD_FILEVERSION=`echo "$VERSION" | sed 's/\([0-9.]*\).*/\1./;s/\./,/g'`
changequote([,])dnl
BUILD_FILEVERSION="${BUILD_FILEVERSION}mym4_revision_dec"
AC_SUBST(BUILD_FILEVERSION)
AC_ARG_ENABLE([build-timestamp],
AS_HELP_STRING([--enable-build-timestamp],
[set an explicit build timestamp for reproducibility.
(default is the current time in ISO-8601 format)]),
[if test "$enableval" = "yes"; then
BUILD_TIMESTAMP=`date -u +%Y-%m-%dT%H:%M+0000 2>/dev/null || date`
else
BUILD_TIMESTAMP="$enableval"
fi],
[BUILD_TIMESTAMP=""])
AC_SUBST(BUILD_TIMESTAMP)
AC_DEFINE_UNQUOTED(BUILD_TIMESTAMP, "$BUILD_TIMESTAMP",
[The time this package was configured for a build])
#
# Check for network libraries. They are needed for tests.
#
AC_CHECK_FUNC(setsockopt, , AC_CHECK_LIB(socket, setsockopt,
[NETLIBS="-lsocket $NETLIBS"]))
AC_SUBST(NETLIBS)
if test "$have_w32_system" = yes; then
- if test "$have_w32ce_system" = yes; then
- NETLIBS="-lws2 $NETLIBS"
- else
- # FIXME: Check why we need to use ws2_32 and document that.
- NETLIBS="-lws2_32 $NETLIBS"
- fi
+ # FIXME: Check why we need to use ws2_32 and document that.
+ NETLIBS="-lws2_32 $NETLIBS"
fi
#
# Provide info for src/libassuan-config.in
#
LIBASSUAN_CONFIG_LIBS="-lassuan"
LIBASSUAN_CONFIG_CFLAGS=""
LIBASSUAN_CONFIG_HOST="$host"
AC_SUBST(LIBASSUAN_CONFIG_LIBS)
AC_SUBST(LIBASSUAN_CONFIG_CFLAGS)
AC_SUBST(LIBASSUAN_CONFIG_HOST)
AC_SUBST(LIBASSUAN_CONFIG_API_VERSION)
#
# Checks for header files.
#
AC_CHECK_HEADERS([locale.h sys/uio.h stdint.h inttypes.h \
sys/types.h sys/stat.h unistd.h sys/time.h fcntl.h \
sys/select.h ucred.h sys/ucred.h])
AC_TYPE_UINTPTR_T
AC_TYPE_UINT16_T
#
# Checks for typedefs, structures, and compiler characteristics.
#
AC_C_CONST
AC_C_INLINE
AC_TYPE_SIZE_T
gl_TYPE_SOCKLEN_T
if test $check_descriptor_passing != yes; then
use_descriptor_passing=no
else
AC_CHECK_MEMBER(struct cmsghdr.cmsg_len,
[use_descriptor_passing=yes],
[use_descriptor_passing=no
AC_MSG_WARN([
***
*** Data structure for sending ancillary data missing.
*** Descriptor passing won't work.
***])],[
#include
#include
#include
#include
#include
#include
#if HAVE_SYS_UIO_H
#include
#endif
#include
])
fi
if test "$use_descriptor_passing" = "yes"; then
AC_DEFINE(USE_DESCRIPTOR_PASSING, 1,
[Defined if descriptor passing is supported])
fi
AM_CONDITIONAL(USE_DESCRIPTOR_PASSING, test "$use_descriptor_passing" = "yes")
# Checking for libgpg-error.
AM_PATH_GPG_ERROR(1.17,, AC_MSG_ERROR([libgpg-error was not found]))
AM_CONDITIONAL(USE_GPGRT_CONFIG, [test -n "$GPGRT_CONFIG" \
-a "$ac_cv_path_GPG_ERROR_CONFIG" = no])
#
# Checks for library functions.
#
AC_CHECK_FUNCS([flockfile funlockfile inet_pton stat getaddrinfo \
getrlimit ])
# If we didn't find inet_pton, it might be in -lsocket (which might
# require -lnsl)
if test X"$ac_cv_func_inet_pton" != X"yes" ; then
AC_SEARCH_LIBS([inet_pton],[socket],[],[],[-lnsl])
if test X"$ac_cv_search_inet_pton" != X"no" ; then
AC_DEFINE([HAVE_INET_PTON],1,[Define to 1 if you have `inet_pton'.])
fi
fi
# On some systems (e.g. Solaris) nanosleep requires linking to librl.
# Given that we use nanosleep only as an optimization over a select
# based wait function we want it only if it is available in libc.
_save_libs="$LIBS"
AC_SEARCH_LIBS([nanosleep], [],
[AC_DEFINE(HAVE_NANOSLEEP,1,
[Define to 1 if you have the `nanosleep' function in libc.])])
LIBS="$_save_libs"
# Check for funopen
AC_CHECK_FUNCS(funopen)
if test $ac_cv_func_funopen != yes; then
# No funopen but we can implement that in terms of fopencookie.
AC_CHECK_FUNCS(fopencookie)
if test $ac_cv_func_fopencookie = yes; then
AC_LIBOBJ([funopen])
else
AC_MSG_WARN([
***
*** No implementation of fopencookie or funopen available.
*** The assuan_get_data_fp function won't work; see the
*** manual for details. GnuPG does not require this feature.
***])
fi
fi
AC_REPLACE_FUNCS(isascii)
AC_REPLACE_FUNCS(memrchr)
AC_REPLACE_FUNCS(stpcpy)
AC_CHECK_HEADERS(unistd.h)
AC_REPLACE_FUNCS(setenv)
#
# Check for the getsockopt SO_PEERCRED, etc.
#
AC_CHECK_MEMBER(struct sockpeercred.pid,
[AC_DEFINE(HAVE_STRUCT_SOCKPEERCRED_PID, 1,
Define if struct sockpeercred contains the pid member.)],
[], [#include
#include ])
# (Open)Solaris
AC_CHECK_FUNCS([getpeerucred])
# FreeBSD
AC_CHECK_FUNCS([getpeereid])
#
# Extra features
#
build_doc=yes
AC_ARG_ENABLE([doc], AS_HELP_STRING([--disable-doc],
[do not build the documentation]),
build_doc=$enableval, build_doc=yes)
AM_CONDITIONAL([BUILD_DOC], [test "x$build_doc" != xno])
#
# Create the config files.
#
AC_CONFIG_FILES([Makefile])
AC_CONFIG_FILES([m4/Makefile])
AC_CONFIG_FILES([src/Makefile])
AC_CONFIG_FILES([doc/Makefile])
AC_CONFIG_FILES([tests/Makefile])
AC_CONFIG_FILES([src/libassuan-config], [chmod +x src/libassuan-config])
AC_CONFIG_FILES([src/versioninfo.rc])
AC_CONFIG_FILES([src/libassuan.pc])
AC_OUTPUT
echo "
Libassuan v${VERSION} has been configured as follows:
Revision: mym4_revision (mym4_revision_dec)
Platform: $host
"
diff --git a/contrib/ChangeLog-2011 b/contrib/ChangeLog-2011
deleted file mode 100644
index 65306e3..0000000
--- a/contrib/ChangeLog-2011
+++ /dev/null
@@ -1,29 +0,0 @@
-2011-12-01 Werner Koch
-
- 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.
-
-2010-11-15 Marcus Brinkmann
-
- * conf-w32ce-msc/stdint.h: New file.
- * conf-w32ce-msc/build.mk (conf_sources): Add stdint.h.
- (copy-static-source): Revert last change.
-
-2010-11-15 Werner Koch
-
- * conf-w32ce-msc/config.h (strdup, strcasecmp): Add macros.
-
- * conf-w32ce-msc/build.mk (copy-static-source): Create stdint.h.
- (all): Add ws2.lib
- (clean): New.
-
-2010-11-02 Werner Koch
-
- * conf-w32ce-msc/build.mk: Change directory layout.
-
-2010-11-01 Werner Koch
-
- * conf-w32ce-msc/build.mk: New.
- * conf-w32ce-msc/config.h: New.
diff --git a/contrib/conf-w32ce-msc/build.mk b/contrib/conf-w32ce-msc/build.mk
deleted file mode 100755
index 70b9634..0000000
--- a/contrib/conf-w32ce-msc/build.mk
+++ /dev/null
@@ -1,169 +0,0 @@
-# build.mk - Makefile to build libgpg-error using Visual-C
-# Copyright 2010 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 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.
-
-# This is a helper make script to build libgpg-error for WindowsCE
-# using the Microsoft Visual C compiler.
-
-# The target build directory where we run the Visual C compiler/ This
-# needs to be an absolute directory name. Further we expect this
-# structure of the tree:
-#
-# TARGET/src - Source directories: One directory for each project
-# /bin - Installed DLLs
-# /lib - Installed import libs.
-# /include - Instaled header files.
-
-targetdir = /home/smb/xppro-gnu
-targetsrc = $(targetdir)/src
-
-# Install directories (relative)
-bindir = ../../../bin
-libdir = ../../../lib
-incdir = ../../../include
-
-help:
- @echo "Run "
- @echo " make -f ../contrib/conf-w32ce-msc/build.mk copy-source"
- @echo "on the POSIX system and then"
- @echo " nmake -f build.mk all"
- @echo " nmake -f build.mk install"
- @echo "on the Windows system"
-
-ce_defines = -DWINCE -D_WIN32_WCE=0x502 -DUNDER_CE \
- -DWIN32_PLATFORM_PSPC -D_UNICODE -DUNICODE \
- -D_CONSOLE -DARM -D_ARM_
-#-D_DEBUG -DDEBUG
-
-# See libgpg-error's build-mk for a list of compiler options.
-CFLAGS = -nologo -W3 -fp:fast -Os $(ce_defines) \
- -DHAVE_CONFIG_H -DDLL_EXPORT -D_CRT_SECURE_NO_WARNINGS \
- -I. -I$(incdir) -I$(incdir)/gpg-extra
-
-LDFLAGS =
-
-# Standard source files
-sources = \
- assuan.c \
- context.c \
- system.c \
- debug.c \
- conversion.c \
- sysutils.c \
- client.c \
- server.c \
- assuan-error.c \
- assuan-buffer.c \
- assuan-handler.c \
- assuan-inquire.c \
- assuan-listen.c \
- assuan-pipe-server.c \
- assuan-socket-server.c \
- assuan-pipe-connect.c \
- assuan-socket-connect.c \
- assuan-uds.c \
- assuan-logging.c \
- assuan-socket.c \
- system-w32ce.c \
- assuan-io.c \
- putc_unlocked.c \
- memrchr.c \
- stpcpy.c \
- setenv.c \
- vasprintf.c \
- assuan-defs.h \
- debug.h \
- libassuan.def
-
-# The object files we need to create from sources.
-objs = \
- assuan.obj \
- context.obj \
- system.obj \
- debug.obj \
- conversion.obj \
- sysutils.obj \
- client.obj \
- server.obj \
- assuan-error.obj \
- assuan-buffer.obj \
- assuan-handler.obj \
- assuan-inquire.obj \
- assuan-listen.obj \
- assuan-pipe-server.obj \
- assuan-socket-server.obj \
- assuan-pipe-connect.obj \
- assuan-socket-connect.obj \
- assuan-uds.obj \
- assuan-logging.obj \
- assuan-socket.obj \
- system-w32ce.obj \
- assuan-io.obj \
- putc_unlocked.obj \
- memrchr.obj \
- stpcpy.obj \
- setenv.obj \
- vasprintf.obj
-
-
-# Sources files in this directory inclduing this Makefile
-conf_sources = \
- build.mk \
- config.h \
- stdint.h
-
-# Source files built by running the standard build system.
-built_sources = \
- assuan.h
-
-
-copy-static-source:
- @if [ ! -f ./assuan-defs.h ]; then \
- echo "Please cd to the src/ directory first"; \
- exit 1; \
- fi
- cp -t $(targetsrc)/libassuan/src $(sources);
- cd ../contrib/conf-w32ce-msc ; \
- cp -t $(targetsrc)/libassuan/src $(conf_sources)
-
-
-copy-built-source:
- @if [ ! -f ./assuan.h ]; then \
- echo "Please build using ./autogen.sh --build-w32ce first"; \
- exit 1; \
- fi
- cp -t $(targetsrc)/libassuan/src $(built_sources)
-
-copy-source: copy-static-source copy-built-source
-
-
-.c.obj:
- $(CC) $(CFLAGS) -c $<
-
-all: $(sources) $(conf_sources) $(built_sources) $(objs)
- link /DLL /IMPLIB:libassuan-0-msc.lib \
- /OUT:libassuan-0-msc.dll \
- /DEF:libassuan.def /NOLOGO /MANIFEST:NO \
- /NODEFAULTLIB:"oldnames.lib" /DYNAMICBASE:NO \
- $(objs) $(libdir)/libgpg-error-0-msc.lib \
- coredll.lib corelibc.lib ole32.lib oleaut32.lib uuid.lib \
- commctrl.lib ws2.lib /subsystem:windowsce,5.02
-
-# Note that we don't need to create the install directories because
-# libgpg-error must have been build and installed prior to this
-# package.
-install: all
- copy /y libassuan-0-msc.dll $(bindir:/=\)
- copy /y libassuan-0-msc.lib $(libdir:/=\)
- copy /y assuan.h $(incdir:/=\)
-
-clean:
- del *.obj libassuan-0-msc.lib libassuan-0-msc.dll libassuan-0-msc.exp
-
diff --git a/contrib/conf-w32ce-msc/config.h b/contrib/conf-w32ce-msc/config.h
deleted file mode 100644
index c247377..0000000
--- a/contrib/conf-w32ce-msc/config.h
+++ /dev/null
@@ -1,188 +0,0 @@
-/* config.h for building with Visual-C for WindowsCE.
- * Copyright 2010 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 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.
- */
-
-/* This file was originally created by running
- * ./autogen.sh --build-w32ce
- * on svn revision 389 (libassuan 2.0.2-svn389) and then adjusted to work
- * with Visual-C.
- */
-
-#ifndef _ASSUAN_CONFIG_H_INCLUDED
-#define _ASSUAN_CONFIG_H_INCLUDED
-
-/* Define to the version of this package. */
-#define PACKAGE_VERSION "2.0.2-svn389-msc1"
-
-/* Define to the full name and version of this package. */
-#define PACKAGE_STRING "libassuan " PACKAGE_VERSION
-
-/* Name of this package */
-#define PACKAGE "libassuan"
-
-/* Bug report address */
-#define PACKAGE_BUGREPORT "bug-libassuan@gnupg.org"
-
-/* Define to the full name of this package. */
-#define PACKAGE_NAME "libassuan"
-
-
-/* Define to the one symbol short name of this package. */
-#define PACKAGE_TARNAME "libassuan"
-
-/* Define to the home page for this package. */
-#define PACKAGE_URL ""
-
-/* Version of this package */
-#define VERSION PACKAGE_VERSION
-
-
-/* Enable gpg-error's strerror macro under W32CE. */
-#define GPG_ERR_ENABLE_ERRNO_MACROS 1
-
-
-/* Define to 1 if you have the declaration of `sys_siglist', and to 0 if you
- don't. */
-#define HAVE_DECL_SYS_SIGLIST 0
-
-/* Define to 1 if you have the header file. */
-/* #undef HAVE_DLFCN_H */
-
-/* Defined if we run on some of the PCDOS like systems (DOS, Windoze. OS/2)
- with special properties like no file modes */
-#define HAVE_DOSISH_SYSTEM 1
-
-/* Define to 1 if you have the `flockfile' function. */
-/* #undef HAVE_FLOCKFILE */
-
-/* Define to 1 if you have the `fopencookie' function. */
-/* #undef HAVE_FOPENCOOKIE */
-
-/* Define to 1 if you have the `funlockfile' function. */
-/* #undef HAVE_FUNLOCKFILE */
-
-/* Define to 1 if you have the `funopen' function. */
-/* #undef HAVE_FUNOPEN */
-
-/* Define to 1 if you have the `inet_pton' function. */
-/* #undef HAVE_INET_PTON */
-
-/* Define to 1 if you have the header file. */
-/* #undef HAVE_INTTYPES_H */
-
-/* Define to 1 if you have the `isascii' function. */
-#define HAVE_ISASCII 1
-
-/* Define to 1 if you have the header file. */
-/* #undef HAVE_LOCALE_H */
-
-/* Define to 1 if you have the header file. */
-#define HAVE_MEMORY_H 1
-
-/* Define to 1 if you have the `memrchr' function. */
-/* #undef HAVE_MEMRCHR */
-
-/* Define to 1 if you have the `nanosleep' function in libc. */
-/* #undef HAVE_NANOSLEEP */
-
-/* Define to 1 if you have the `putc_unlocked' function. */
-/* #undef HAVE_PUTC_UNLOCKED */
-
-/* Define to 1 if you have the `setenv' function. */
-/* #undef HAVE_SETENV */
-
-/* Defined if SO_PEERCRED is supported (Linux specific) */
-/* #undef HAVE_SO_PEERCRED */
-
-/* Define to 1 if you have the header file. */
-#define HAVE_STDINT_H 1
-
-/* Define to 1 if you have the header file. */
-#define HAVE_STDLIB_H 1
-
-/* Define to 1 if you have the `stpcpy' function. */
-/* #undef HAVE_STPCPY */
-
-/* Define to 1 if you have the header file. */
-/* #undef HAVE_STRINGS_H */
-
-/* Define to 1 if you have the header file. */
-#define HAVE_STRING_H 1
-
-/* Define to 1 if you have the header file. */
-/* #undef HAVE_SYS_SOCKET_H */
-
-/* Define to 1 if you have the header file. */
-/* #undef HAVE_SYS_STAT_H */
-
-/* Define to 1 if you have the header file. */
-/* #undef HAVE_SYS_TYPES_H */
-
-/* Define to 1 if you have the header file. */
-/* #undef HAVE_SYS_UIO_H */
-
-/* Define to 1 if the system has the type `uintptr_t'. */
-#define HAVE_UINTPTR_T 1
-
-/* Define to 1 if you have the header file. */
-/* #undef HAVE_UNISTD_H */
-
-/* Define to 1 if you have the `vasprintf' function. */
-/* #undef HAVE_VASPRINTF */
-
-/* Defined if we run on WindowsCE */
-#define HAVE_W32CE_SYSTEM 1
-
-/* Defined if we run on a W32 API based system */
-#define HAVE_W32_SYSTEM 1
-
-/* Define to 1 if you have the header file. */
-#define HAVE_WINSOCK2_H 1
-
-/* Define to 1 if you have the header file. */
-#define HAVE_WS2TCPIP_H 1
-
-/* Define to 1 if your C compiler doesn't accept -c and -o together. */
-/* #undef NO_MINUS_C_MINUS_O */
-
-/* Define as the return type of signal handlers (`int' or `void'). */
-#define RETSIGTYPE void
-
-/* Define to 1 if you have the ANSI C header files. */
-#define STDC_HEADERS 1
-
-/* Defined if descriptor passing is supported */
-/* #undef USE_DESCRIPTOR_PASSING */
-
-/* Enable extensions on AIX 3, Interix. */
-#ifndef _ALL_SOURCE
-# define _ALL_SOURCE 1
-#endif
-/* Enable GNU extensions on systems that have them. */
-#ifndef _GNU_SOURCE
-# define _GNU_SOURCE 1
-#endif
-/* Enable threading extensions on Solaris. */
-#ifndef _POSIX_PTHREAD_SEMANTICS
-# define _POSIX_PTHREAD_SEMANTICS 1
-#endif
-
-
-/* snprintf is not part of oldnames.lib thus we redefine it here. */
-#define snprintf _snprintf
-
-/* We also need to define these functions. */
-#define strdup _strdup
-#define strcasecmp _stricmp
-
-
-#endif /*_ASSUAN_CONFIG_H_INCLUDED*/
-
diff --git a/contrib/conf-w32ce-msc/stdint.h b/contrib/conf-w32ce-msc/stdint.h
deleted file mode 100755
index 0a821b7..0000000
--- a/contrib/conf-w32ce-msc/stdint.h
+++ /dev/null
@@ -1,9 +0,0 @@
-typedef unsigned long long uint64_t;
-typedef long long int64_t;
-typedef unsigned int uint32_t;
-typedef int int32_t;
-typedef unsigned short uint16_t;
-typedef short int16_t;
-typedef unsigned int uintptr_t;
-typedef int intptr_t;
-
diff --git a/src/Makefile.am b/src/Makefile.am
index 321aea3..f3a3aac 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,160 +1,139 @@
# Assuan Makefile
# Copyright (C) 2001, 2002, 2003, 2009, 2010 Free Software Foundation, Inc.
#
# This file is part of Assuan.
#
# Assuan 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.
#
# Assuan 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
# Lesser 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 .
#
# SPDX-License-Identifier: LGPL-2.1+
## Process this file with automake to produce Makefile.in
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libassuan.pc
EXTRA_DIST = libassuan-config.in libassuan.m4 libassuan.vers \
- versioninfo.rc.in libassuan.def mkheader.c gpgcedev.def \
+ versioninfo.rc.in libassuan.def mkheader.c \
libassuan.pc.in
AM_CPPFLAGS = -I..
if USE_GPGRT_CONFIG
noinst_SCRIPTS = libassuan-config
else
bin_SCRIPTS = libassuan-config
endif
m4datadir = $(datadir)/aclocal
m4data_DATA = libassuan.m4
lib_LTLIBRARIES = libassuan.la
-if HAVE_W32CE_SYSTEM
-lib_LTLIBRARIES += libgpgcedev.la
-bin_PROGRAMS = gpgcemgr
-endif
nodist_include_HEADERS = assuan.h
if HAVE_LD_VERSION_SCRIPT
libassuan_version_script_cmd = -Wl,--version-script=$(srcdir)/libassuan.vers
else
libassuan_version_script_cmd =
endif
CLEANFILES = mkheader assuan.h
BUILT_SOURCES = assuan.h
parts_of_assuan_h = \
- posix-includes.inc.h w32-includes.inc.h \
+ posix-includes.inc.h \
posix-types.inc.h w32-types.inc.h \
- posix-fd-t.inc.h w32-fd-t.inc.h w32ce-fd-t.inc.h \
- posix-sock-nonce.inc.h w32-sock-nonce.inc.h \
- w32ce-add.h
+ posix-fd-t.inc.h w32-fd-t.inc.h \
+ posix-sock-nonce.inc.h w32-sock-nonce.inc.h
common_sources = \
assuan.h.in $(parts_of_assuan_h) \
assuan-defs.h \
assuan.c context.c system.c \
debug.c debug.h conversion.c sysutils.c \
client.c server.c \
assuan-error.c \
assuan-buffer.c \
assuan-handler.c \
assuan-inquire.c \
assuan-listen.c \
assuan-pipe-server.c \
assuan-socket-server.c \
assuan-pipe-connect.c \
assuan-socket-connect.c \
assuan-uds.c \
assuan-logging.c \
assuan-socket.c
if HAVE_W32_SYSTEM
-if HAVE_W32CE_SYSTEM
-common_sources += system-w32ce.c
-else
common_sources += system-w32.c
-endif
else
common_sources += system-posix.c
endif
if HAVE_W32_SYSTEM
LTRCCOMPILE = $(LIBTOOL) --mode=compile $(RC) \
`echo $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) | \
sed -e 's/-I/--include-dir /g;s/-D/--define /g'`
SUFFIXES: .rc .lo
.rc.lo:
$(LTRCCOMPILE) -i $< -o $@
libassuan_res = versioninfo.lo
libassuan_res_ldflag = -Wl,.libs/versioninfo.o
no_undefined = -no-undefined
export_symbols = -export-symbols $(srcdir)/libassuan.def
extra_ltoptions = -XCClinker -static-libgcc
install-def-file:
$(INSTALL) $(srcdir)/libassuan.def $(DESTDIR)$(libdir)/libassuan.def
uninstall-def-file:
-rm $(DESTDIR)$(libdir)/libassuan.def
libassuan_deps = $(libassuan_res) libassuan.def
else
libassuan_res =
libassuan_res_ldflag =
no_undefined =
export_symbols =
extra_ltoptions =
install-def-file:
uninstall-def-file:
libassuan_deps =
endif
libassuan_la_SOURCES = $(common_sources) assuan-io.c
nodist_libassuan_la_SOURCES = assuan.h
libassuan_la_CPPFLAGS = $(AM_CPPFLAGS) @GPG_ERROR_CFLAGS@
libassuan_la_LDFLAGS = $(libassuan_res_ldflag) $(no_undefined) \
$(extra_ltoptions) \
$(export_symbols) $(libassuan_version_script_cmd) -version-info \
@LIBASSUAN_LT_CURRENT@:@LIBASSUAN_LT_REVISION@:@LIBASSUAN_LT_AGE@
libassuan_la_DEPENDENCIES = @LTLIBOBJS@ \
$(srcdir)/libassuan.vers $(libassuan_deps)
libassuan_la_LIBADD = @LTLIBOBJS@ @NETLIBS@ @GPG_ERROR_LIBS@
-if HAVE_W32CE_SYSTEM
-libgpgcedev_la_SOURCES = gpgcedev.c
-libgpgcedev_la_CPPFLAGS = $(AM_CPPFLAGS)
-libgpgcedev_la_LDFLAGS = $(no_undefined) -export-symbols $(srcdir)/gpgcedev.def
-libgpgcedev_la_DEPENDENCIES = gpgcedev.def
-gpgcemgr_SOURCES = gpgcemgr.c
-gpgcemgr_CPPFLAGS = $(AM_CPPFLAGS)
-install-exec-hook:
- mv -f $(DESTDIR)$(bindir)/libgpgcedev-0.dll \
- $(DESTDIR)$(bindir)/gpgcedev.dll
-endif
-
mkheader$(EXEEXT_FOR_BUILD): mkheader.c Makefile
$(CC_FOR_BUILD) $(CFLAGS_FOR_BUILD) $(CPPFLAGS_FOR_BUILD) \
$(LDFLAGS_FOR_BUILD) -I. -I$(srcdir) -o $@ $(srcdir)/mkheader.c
assuan.h: assuan.h.in mkheader$(EXEEXT_FOR_BUILD) $(parts_of_assuan_h)
./mkheader$(EXEEXT_FOR_BUILD) $(host_os) $(srcdir)/assuan.h.in \
$(PACKAGE_VERSION) $(VERSION_NUMBER) >$@
diff --git a/src/assuan-buffer.c b/src/assuan-buffer.c
index 7cb3032..895eb93 100644
--- a/src/assuan-buffer.c
+++ b/src/assuan-buffer.c
@@ -1,552 +1,550 @@
/* assuan-buffer.c - read and send data
* Copyright (C) 2001-2004, 2006, 2009, 2010 Free Software Foundation, Inc.
*
* This file is part of Assuan.
*
* Assuan 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.
*
* Assuan 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
* Lesser 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 .
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#include
#include
#include
#include
#include
#ifdef HAVE_UNISTD_H
# include
#endif
#include
#ifdef HAVE_W32_SYSTEM
-#ifndef HAVE_W32CE_SYSTEM
# include
#endif
-#endif
#include "assuan-defs.h"
/* Extended version of write(2) to guarantee that all bytes are
written. Returns 0 on success or -1 and ERRNO on failure. NOTE:
This function does not return the number of bytes written, so any
error must be treated as fatal for this connection as the state of
the receiver is unknown. This works best if blocking is allowed
(so EAGAIN cannot occur). */
static int
writen (assuan_context_t ctx, const char *buffer, size_t length)
{
while (length)
{
ssize_t nwritten = ctx->engine.writefnc (ctx, buffer, length);
if (nwritten < 0)
{
if (errno == EINTR)
continue;
return -1; /* write error */
}
length -= nwritten;
buffer += nwritten;
}
return 0; /* okay */
}
/* Read an entire line. Returns 0 on success or -1 and ERRNO on
failure. EOF is indictated by setting the integer at address
R_EOF. Note: BUF, R_NREAD and R_EOF contain a valid result even if
an error is returned. */
static int
readline (assuan_context_t ctx, char *buf, size_t buflen,
int *r_nread, int *r_eof)
{
size_t nleft = buflen;
char *p;
*r_eof = 0;
*r_nread = 0;
while (nleft > 0)
{
ssize_t n = ctx->engine.readfnc (ctx, buf, nleft);
if (n < 0)
{
if (errno == EINTR)
continue;
#ifdef HAVE_W32_SYSTEM
if (errno == EPIPE)
{
/* Under Windows we get EPIPE (actually ECONNRESET)
after termination of the client. Assume an EOF. */
*r_eof = 1;
break; /* allow incomplete lines */
}
#endif /*HAVE_W32_SYSTEM*/
return -1; /* read error */
}
else if (!n)
{
*r_eof = 1;
break; /* allow incomplete lines */
}
p = buf;
nleft -= n;
buf += n;
*r_nread += n;
p = memrchr (p, '\n', n);
if (p)
break; /* at least one full line available - that's enough for now */
}
return 0;
}
/* Read a line with buffering of partial lines. Function returns an
Assuan error. */
gpg_error_t
_assuan_read_line (assuan_context_t ctx)
{
gpg_error_t rc = 0;
char *line = ctx->inbound.line;
int nread, atticlen;
char *endp = 0;
if (ctx->inbound.eof)
return _assuan_error (ctx, GPG_ERR_EOF);
atticlen = ctx->inbound.attic.linelen;
if (atticlen)
{
memcpy (line, ctx->inbound.attic.line, atticlen);
ctx->inbound.attic.linelen = 0;
endp = memchr (line, '\n', atticlen);
if (endp)
{
/* Found another line in the attic. */
nread = atticlen;
atticlen = 0;
}
else
{
/* There is pending data but not a full line. */
assert (atticlen < LINELENGTH);
rc = readline (ctx, line + atticlen,
LINELENGTH - atticlen, &nread, &ctx->inbound.eof);
}
}
else
/* No pending data. */
rc = readline (ctx, line, LINELENGTH,
&nread, &ctx->inbound.eof);
if (rc)
{
int saved_errno = errno;
char buf[100];
snprintf (buf, sizeof buf, "error: %s", strerror (errno));
_assuan_log_control_channel (ctx, 0, buf, NULL, 0, NULL, 0);
if (saved_errno == EAGAIN)
{
/* We have to save a partial line. Due to readline's
behaviour, we know that this is not a complete line yet
(no newline). So we don't set PENDING to true. */
memcpy (ctx->inbound.attic.line, line, atticlen + nread);
ctx->inbound.attic.pending = 0;
ctx->inbound.attic.linelen = atticlen + nread;
}
gpg_err_set_errno (saved_errno);
return _assuan_error (ctx, gpg_err_code_from_syserror ());
}
if (!nread)
{
assert (ctx->inbound.eof);
_assuan_log_control_channel (ctx, 0, "eof", NULL, 0, NULL, 0);
return _assuan_error (ctx, GPG_ERR_EOF);
}
ctx->inbound.attic.pending = 0;
nread += atticlen;
if (! endp)
endp = memchr (line, '\n', nread);
if (endp)
{
unsigned monitor_result;
int n = endp - line + 1;
if (n < nread)
/* LINE contains more than one line. We copy it to the attic
now as handlers are allowed to modify the passed
buffer. */
{
int len = nread - n;
memcpy (ctx->inbound.attic.line, endp + 1, len);
ctx->inbound.attic.pending = memrchr (endp + 1, '\n', len) ? 1 : 0;
ctx->inbound.attic.linelen = len;
}
if (endp != line && endp[-1] == '\r')
endp --;
*endp = 0;
ctx->inbound.linelen = endp - line;
monitor_result = 0;
if (ctx->io_monitor)
monitor_result = ctx->io_monitor (ctx, ctx->io_monitor_data, 0,
ctx->inbound.line,
ctx->inbound.linelen);
if (monitor_result & ASSUAN_IO_MONITOR_IGNORE)
ctx->inbound.linelen = 0;
if ( !(monitor_result & ASSUAN_IO_MONITOR_NOLOG))
_assuan_log_control_channel (ctx, 0, NULL,
ctx->inbound.line, ctx->inbound.linelen,
NULL, 0);
return 0;
}
else
{
_assuan_log_control_channel (ctx, 0, "invalid line",
NULL, 0, NULL, 0);
*line = 0;
ctx->inbound.linelen = 0;
return _assuan_error (ctx, ctx->inbound.eof
? GPG_ERR_ASS_INCOMPLETE_LINE
: GPG_ERR_ASS_LINE_TOO_LONG);
}
}
/* Read the next line from the client or server and return a pointer
in *LINE to a buffer holding the line. LINELEN is the length of
*LINE. The buffer is valid until the next read operation on it.
The caller may modify the buffer. The buffer is invalid (i.e. must
not be used) if an error is returned.
Returns 0 on success or an assuan error code.
See also: assuan_pending_line().
*/
gpg_error_t
assuan_read_line (assuan_context_t ctx, char **line, size_t *linelen)
{
gpg_error_t err;
if (!ctx)
return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
do
{
err = _assuan_read_line (ctx);
}
while (_assuan_error_is_eagain (ctx, err));
*line = ctx->inbound.line;
*linelen = ctx->inbound.linelen;
return err;
}
/* Return true if a full line is buffered (i.e. an entire line may be
read without any I/O). */
int
assuan_pending_line (assuan_context_t ctx)
{
return ctx && ctx->inbound.attic.pending;
}
gpg_error_t
_assuan_write_line (assuan_context_t ctx, const char *prefix,
const char *line, size_t len)
{
gpg_error_t rc = 0;
size_t prefixlen = prefix? strlen (prefix):0;
unsigned int monitor_result;
/* Make sure that the line is short enough. */
if (len + prefixlen + 2 > ASSUAN_LINELENGTH)
{
_assuan_log_control_channel (ctx, 1,
"supplied line too long - truncated",
NULL, 0, NULL, 0);
if (prefixlen > 5)
prefixlen = 5;
if (len > ASSUAN_LINELENGTH - prefixlen - 2)
len = ASSUAN_LINELENGTH - prefixlen - 2 - 1;
}
monitor_result = 0;
if (ctx->io_monitor)
monitor_result = ctx->io_monitor (ctx, ctx->io_monitor_data, 1, line, len);
/* Fixme: we should do some kind of line buffering. */
if (!(monitor_result & ASSUAN_IO_MONITOR_NOLOG))
_assuan_log_control_channel (ctx, 1, NULL,
prefixlen? prefix:NULL, prefixlen,
line, len);
if (prefixlen && !(monitor_result & ASSUAN_IO_MONITOR_IGNORE))
{
rc = writen (ctx, prefix, prefixlen);
if (rc)
rc = _assuan_error (ctx, gpg_err_code_from_syserror ());
}
if (!rc && !(monitor_result & ASSUAN_IO_MONITOR_IGNORE))
{
rc = writen (ctx, line, len);
if (rc)
rc = _assuan_error (ctx, gpg_err_code_from_syserror ());
if (!rc)
{
rc = writen (ctx, "\n", 1);
if (rc)
rc = _assuan_error (ctx, gpg_err_code_from_syserror ());
}
}
return rc;
}
gpg_error_t
assuan_write_line (assuan_context_t ctx, const char *line)
{
size_t len;
const char *str;
if (! ctx)
return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
/* Make sure that we never take a LF from the user - this might
violate the protocol. */
str = strchr (line, '\n');
len = str ? (str - line) : strlen (line);
if (str)
_assuan_log_control_channel (ctx, 1,
"supplied line with LF - truncated",
NULL, 0, NULL, 0);
return _assuan_write_line (ctx, NULL, line, len);
}
/* Write out the data in buffer as datalines with line wrapping and
percent escaping. This function is used for GNU's custom streams. */
int
_assuan_cookie_write_data (void *cookie, const char *buffer, size_t orig_size)
{
assuan_context_t ctx = cookie;
size_t size = orig_size;
char *line;
size_t linelen;
if (ctx->outbound.data.error)
return 0;
line = ctx->outbound.data.line;
linelen = ctx->outbound.data.linelen;
line += linelen;
while (size)
{
unsigned int monitor_result;
/* Insert data line header. */
if (!linelen)
{
*line++ = 'D';
*line++ = ' ';
linelen += 2;
}
/* Copy data, keep space for the CRLF and to escape one character. */
while (size && linelen < LINELENGTH-2-2)
{
if (*buffer == '%' || *buffer == '\r' || *buffer == '\n')
{
sprintf (line, "%%%02X", *(unsigned char*)buffer);
line += 3;
linelen += 3;
buffer++;
}
else
{
*line++ = *buffer++;
linelen++;
}
size--;
}
monitor_result = 0;
if (ctx->io_monitor)
monitor_result = ctx->io_monitor (ctx, ctx->io_monitor_data, 1,
ctx->outbound.data.line, linelen);
if (linelen >= LINELENGTH-2-2)
{
if (!(monitor_result & ASSUAN_IO_MONITOR_NOLOG))
_assuan_log_control_channel (ctx, 1, NULL,
ctx->outbound.data.line, linelen,
NULL, 0);
*line++ = '\n';
linelen++;
if ( !(monitor_result & ASSUAN_IO_MONITOR_IGNORE)
&& writen (ctx, ctx->outbound.data.line, linelen))
{
ctx->outbound.data.error = gpg_err_code_from_syserror ();
return 0;
}
line = ctx->outbound.data.line;
linelen = 0;
}
}
ctx->outbound.data.linelen = linelen;
return (int) orig_size;
}
/* Write out any buffered data
This function is used for GNU's custom streams */
int
_assuan_cookie_write_flush (void *cookie)
{
assuan_context_t ctx = cookie;
char *line;
size_t linelen;
unsigned int monitor_result;
if (ctx->outbound.data.error)
return 0;
line = ctx->outbound.data.line;
linelen = ctx->outbound.data.linelen;
line += linelen;
monitor_result = 0;
if (ctx->io_monitor)
monitor_result = ctx->io_monitor (ctx, ctx->io_monitor_data, 1,
ctx->outbound.data.line, linelen);
if (linelen)
{
if (!(monitor_result & ASSUAN_IO_MONITOR_NOLOG))
_assuan_log_control_channel (ctx, 1, NULL,
ctx->outbound.data.line, linelen,
NULL, 0);
*line++ = '\n';
linelen++;
if (! (monitor_result & ASSUAN_IO_MONITOR_IGNORE)
&& writen (ctx, ctx->outbound.data.line, linelen))
{
ctx->outbound.data.error = gpg_err_code_from_syserror ();
return 0;
}
ctx->outbound.data.linelen = 0;
}
return 0;
}
/**
* assuan_send_data:
* @ctx: An assuan context
* @buffer: Data to send or NULL to flush
* @length: length of the data to send/
*
* This function may be used by the server or the client to send data
* lines. The data will be escaped as required by the Assuan protocol
* and may get buffered until a line is full. To force sending the
* data out @buffer may be passed as NULL (in which case @length must
* also be 0); however when used by a client this flush operation does
* also send the terminating "END" command to terminate the response on
* a INQUIRE response. However, when assuan_transact() is used, this
* function takes care of sending END itself.
*
* If BUFFER is NULL and LENGTH is 1 and we are a client, a "CAN" is
* send instead of an "END".
*
* Return value: 0 on success or an error code
**/
gpg_error_t
assuan_send_data (assuan_context_t ctx, const void *buffer, size_t length)
{
if (!ctx)
return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
if (!buffer && length > 1)
return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
if (!buffer)
{ /* flush what we have */
_assuan_cookie_write_flush (ctx);
if (ctx->flags.confidential)
wipememory (ctx->outbound.data.line, LINELENGTH);
if (ctx->outbound.data.error)
return ctx->outbound.data.error;
if (!ctx->flags.is_server)
return assuan_write_line (ctx, length == 1? "CAN":"END");
}
else
{
_assuan_cookie_write_data (ctx, buffer, length);
if (ctx->outbound.data.error)
return ctx->outbound.data.error;
}
return 0;
}
gpg_error_t
assuan_sendfd (assuan_context_t ctx, assuan_fd_t fd)
{
/* It is explicitly allowed to use (NULL, -1) as a runtime test to
check whether descriptor passing is available. */
if (!ctx && fd == ASSUAN_INVALID_FD)
#ifdef USE_DESCRIPTOR_PASSING
return 0;
#else
return _assuan_error (ctx, GPG_ERR_NOT_IMPLEMENTED);
#endif
if (!ctx)
return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
if (! ctx->engine.sendfd)
return set_error (ctx, GPG_ERR_NOT_IMPLEMENTED,
"server does not support sending and receiving "
"of file descriptors");
return ctx->engine.sendfd (ctx, fd);
}
gpg_error_t
assuan_receivefd (assuan_context_t ctx, assuan_fd_t *fd)
{
if (!ctx)
return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
if (! ctx->engine.receivefd)
return set_error (ctx, GPG_ERR_NOT_IMPLEMENTED,
"server does not support sending and receiving "
"of file descriptors");
return ctx->engine.receivefd (ctx, fd);
}
diff --git a/src/assuan-defs.h b/src/assuan-defs.h
index 37a50af..47ff4ef 100644
--- a/src/assuan-defs.h
+++ b/src/assuan-defs.h
@@ -1,442 +1,433 @@
/* assuan-defs.h - Internal definitions to Assuan
* Copyright (C) 2001, 2002, 2004, 2005, 2007, 2008,
* 2009, 2010 Free Software Foundation, Inc.
*
* This file is part of Assuan.
*
* Assuan 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.
*
* Assuan 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
* Lesser 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 .
* SPDX-License-Identifier: LGPL-2.1+
*/
#ifndef ASSUAN_DEFS_H
#define ASSUAN_DEFS_H
#ifdef HAVE_SYS_TYPES_H
# include
#endif
#ifndef HAVE_W32_SYSTEM
# include
# include
#else
# ifdef HAVE_WINSOCK2_H
# /* Avoid inclusion of winsock.h via windows.h. */
# include
# endif
# include
#endif
#ifdef HAVE_UNISTD_H
# include
#endif
#include "assuan.h"
#if __GNUC__ > 2
# define ASSUAN_GCC_A_PURE __attribute__ ((__pure__))
#else
# define ASSUAN_GCC_A_PURE
#endif
#ifndef HAVE_W32_SYSTEM
#define DIRSEP_C '/'
#else
#define DIRSEP_C '\\'
#endif
#define LINELENGTH ASSUAN_LINELENGTH
struct cmdtbl_s
{
const char *name;
assuan_handler_t handler;
const char *helpstr;
};
/* The context we use with most functions. */
struct assuan_context_s
{
/* Members managed by the generic routines in assuan.c. */
/* The error source for errors generated from this context. */
gpg_err_source_t err_source;
#ifdef HAVE_W32_SYSTEM
/* The per-context w32 error string. */
char w32_strerror[256];
#endif
/* The allocation hooks. */
struct assuan_malloc_hooks malloc_hooks;
/* Logging callback handler. */
assuan_log_cb_t log_cb;
void *log_cb_data;
void *user_pointer;
/* Context specific flags (cf. assuan_flag_t). */
struct
{
unsigned int no_waitpid : 1;
unsigned int confidential : 1;
unsigned int no_fixsignals : 1;
unsigned int convey_comments : 1;
unsigned int no_logging : 1;
unsigned int force_close : 1;
/* From here, we have internal flags, not defined by assuan_flag_t. */
unsigned int is_socket : 1;
unsigned int is_server : 1; /* Set if this is context belongs to a server */
unsigned int in_inquire : 1; /* Server: inside assuan_inquire */
unsigned int in_process_next : 1;
unsigned int process_complete : 1;
unsigned int in_command : 1;
unsigned int in_inq_cb : 1; /* Client: inquire callback is active */
unsigned int confidential_inquiry : 1; /* Client: inquiry is confidential */
} flags;
/* If set, this is called right before logging an I/O line. */
assuan_io_monitor_t io_monitor;
void *io_monitor_data;
/* Callback handlers replacing system I/O functions. */
struct assuan_system_hooks system;
int peercred_valid; /* Whether this structure has valid information. */
struct _assuan_peercred peercred;
/* Now come the members specific to subsystems or engines. FIXME:
This is not developed yet. See below for the legacy members. */
struct
{
void (*release) (assuan_context_t ctx);
/* Routine to read from input_fd. Sets errno on failure. */
ssize_t (*readfnc) (assuan_context_t, void *, size_t);
/* Routine to write to output_fd. Sets errno on failure. */
ssize_t (*writefnc) (assuan_context_t, const void *, size_t);
/* Send a file descriptor. */
gpg_error_t (*sendfd) (assuan_context_t, assuan_fd_t);
/* Receive a file descriptor. */
gpg_error_t (*receivefd) (assuan_context_t, assuan_fd_t *);
} engine;
/* Engine specific or other subsystem members. */
/* assuan-logging.c. Does not require deallocation from us. */
FILE *log_fp;
/* assuan-util.c */
gpg_error_t err_no;
const char *err_str;
/* The following members are used by assuan_inquire_ext. */
gpg_error_t (*inquire_cb) (void *cb_data, gpg_error_t rc,
unsigned char *buf, size_t len);
void *inquire_cb_data;
void *inquire_membuf;
char *hello_line;
char *okay_line; /* See assuan_set_okay_line() */
struct {
assuan_fd_t fd;
int eof;
char line[LINELENGTH];
int linelen; /* w/o CR, LF - might not be the same as
strlen(line) due to embedded nuls. However a nul
is always written at this pos. */
struct {
char line[LINELENGTH];
int linelen ;
int pending; /* i.e. at least one line is available in the attic */
} attic;
} inbound;
struct {
assuan_fd_t fd;
struct {
FILE *fp;
char line[LINELENGTH];
int linelen;
int error;
} data;
} outbound;
int max_accepts; /* If we can not handle more than one connection,
set this to 1, otherwise to -1. */
pid_t pid; /* The pid of the peer. */
assuan_fd_t listen_fd; /* The fd we are listening on (used by
socket servers) */
assuan_sock_nonce_t listen_nonce; /* Used with LISTEN_FD. */
assuan_fd_t connected_fd; /* helper */
/* Used for Unix domain sockets. */
struct sockaddr_un myaddr;
struct sockaddr_un serveraddr;
/* Structure used for unix domain sockets. */
struct {
assuan_fd_t pendingfds[5]; /* Array to save received descriptors. */
int pendingfdscount; /* Number of received descriptors. */
} uds;
gpg_error_t (*accept_handler)(assuan_context_t);
void (*finish_handler)(assuan_context_t);
struct cmdtbl_s *cmdtbl;
size_t cmdtbl_used; /* used entries */
size_t cmdtbl_size; /* allocated size of table */
/* The name of the command currently processed by a command handler.
This is a pointer into CMDTBL. NULL if not in a command
handler. */
const char *current_cmd_name;
assuan_handler_t bye_notify_fnc;
assuan_handler_t reset_notify_fnc;
assuan_handler_t cancel_notify_fnc;
gpg_error_t (*option_handler_fnc)(assuan_context_t,const char*, const char*);
assuan_handler_t input_notify_fnc;
assuan_handler_t output_notify_fnc;
/* This function is called right before a command handler is called. */
gpg_error_t (*pre_cmd_notify_fnc)(assuan_context_t, const char *cmd);
/* This function is called right after a command has been processed.
It may be used to command related cleanup. */
void (*post_cmd_notify_fnc)(assuan_context_t, gpg_error_t);
assuan_fd_t input_fd; /* Set by the INPUT command. */
assuan_fd_t output_fd; /* Set by the OUTPUT command. */
};
/* Generate an error code specific to a context. */
static GPG_ERR_INLINE gpg_error_t
_assuan_error (assuan_context_t ctx, gpg_err_code_t errcode)
{
return gpg_err_make (ctx?ctx->err_source: GPG_ERR_SOURCE_ASSUAN, errcode);
}
/* Release all resources associated with an engine operation. */
void _assuan_reset (assuan_context_t ctx);
/* Default log handler. */
int _assuan_log_handler (assuan_context_t ctx, void *hook,
unsigned int cat, const char *msg);
/* Manage memory specific to a context. */
void *_assuan_malloc (assuan_context_t ctx, size_t cnt);
void *_assuan_realloc (assuan_context_t ctx, void *ptr, size_t cnt);
void *_assuan_calloc (assuan_context_t ctx, size_t cnt, size_t elsize);
void _assuan_free (assuan_context_t ctx, void *ptr);
/* System hooks. */
void _assuan_usleep (assuan_context_t ctx, unsigned int usec);
int _assuan_pipe (assuan_context_t ctx, assuan_fd_t fd[2], int inherit_idx);
int _assuan_close (assuan_context_t ctx, assuan_fd_t fd);
int _assuan_close_inheritable (assuan_context_t ctx, assuan_fd_t fd);
ssize_t _assuan_read (assuan_context_t ctx, assuan_fd_t fd, void *buffer,
size_t size);
ssize_t _assuan_write (assuan_context_t ctx, assuan_fd_t fd, const void *buffer,
size_t size);
int _assuan_recvmsg (assuan_context_t ctx, assuan_fd_t fd,
assuan_msghdr_t msg, int flags);
int _assuan_sendmsg (assuan_context_t ctx, assuan_fd_t fd,
assuan_msghdr_t msg, int flags);
int _assuan_spawn (assuan_context_t ctx, pid_t *r_pid, const char *name,
const char *argv[],
assuan_fd_t fd_in, assuan_fd_t fd_out,
assuan_fd_t *fd_child_list,
void (*atfork) (void *opaque, int reserved),
void *atforkvalue, unsigned int flags);
pid_t _assuan_waitpid (assuan_context_t ctx, pid_t pid, int nowait,
int *status, int options);
int _assuan_socketpair (assuan_context_t ctx, int namespace, int style,
int protocol, assuan_fd_t filedes[2]);
assuan_fd_t _assuan_socket (assuan_context_t ctx, int namespace,
int style, int protocol);
int _assuan_connect (assuan_context_t ctx, assuan_fd_t sock,
struct sockaddr *addr, socklen_t length);
extern struct assuan_system_hooks _assuan_system_hooks;
/* Copy the system hooks struct, paying attention to version
differences. SRC is usually from the user, DST MUST be from the
library. */
void
_assuan_system_hooks_copy (assuan_system_hooks_t dst,
assuan_system_hooks_t src);
/*-- assuan-pipe-server.c --*/
void _assuan_release_context (assuan_context_t ctx);
/*-- assuan-uds.c --*/
void _assuan_uds_close_fds (assuan_context_t ctx);
void _assuan_uds_deinit (assuan_context_t ctx);
void _assuan_init_uds_io (assuan_context_t ctx);
/*-- assuan-handler.c --*/
gpg_error_t _assuan_register_std_commands (assuan_context_t ctx);
/*-- assuan-buffer.c --*/
gpg_error_t _assuan_read_line (assuan_context_t ctx);
int _assuan_cookie_write_data (void *cookie, const char *buffer, size_t size);
int _assuan_cookie_write_flush (void *cookie);
gpg_error_t _assuan_write_line (assuan_context_t ctx, const char *prefix,
const char *line, size_t len);
/*-- client.c --*/
gpg_error_t _assuan_read_from_server (assuan_context_t ctx,
assuan_response_t *okay, int *off,
int convey_comments);
/*-- assuan-error.c --*/
/*-- assuan-inquire.c --*/
gpg_error_t _assuan_inquire_ext_cb (assuan_context_t ctx);
void _assuan_inquire_release (assuan_context_t ctx);
/* Check if ERR means EAGAIN. */
int _assuan_error_is_eagain (assuan_context_t ctx, gpg_error_t err);
#define set_error(c,e,t) \
assuan_set_error ((c), _assuan_error (c,e), (t))
#ifdef HAVE_W32_SYSTEM
char *_assuan_w32_strerror (assuan_context_t ctx, int ec);
#endif /*HAVE_W32_SYSTEM*/
/*-- assuan-logging.c --*/
void _assuan_init_log_envvars (void);
void _assuan_log_control_channel (assuan_context_t ctx, int outbound,
const char *string,
const void *buffer1, size_t length1,
const void *buffer2, size_t length2);
/*-- assuan-io.c --*/
ssize_t _assuan_simple_read (assuan_context_t ctx, void *buffer, size_t size);
ssize_t _assuan_simple_write (assuan_context_t ctx, const void *buffer,
size_t size);
/*-- assuan-socket.c --*/
assuan_fd_t _assuan_sock_new (assuan_context_t ctx, int domain, int type,
int proto);
int _assuan_sock_connect (assuan_context_t ctx, assuan_fd_t sockfd,
struct sockaddr *addr, int addrlen);
int _assuan_sock_bind (assuan_context_t ctx, assuan_fd_t sockfd,
struct sockaddr *addr, int addrlen);
int _assuan_sock_set_sockaddr_un (const char *fname, struct sockaddr *addr,
int *r_redirected);
int _assuan_sock_get_nonce (assuan_context_t ctx, struct sockaddr *addr,
int addrlen, assuan_sock_nonce_t *nonce);
int _assuan_sock_check_nonce (assuan_context_t ctx, assuan_fd_t fd,
assuan_sock_nonce_t *nonce);
#ifdef HAVE_W32_SYSTEM
wchar_t *_assuan_utf8_to_wchar (const char *string);
int _assuan_sock_wsa2errno (int err);
#endif
#ifdef HAVE_FOPENCOOKIE
/* We have to implement funopen in terms of glibc's fopencookie. */
FILE *_assuan_funopen(void *cookie,
cookie_read_function_t *readfn,
cookie_write_function_t *writefn,
cookie_seek_function_t *seekfn,
cookie_close_function_t *closefn);
#define funopen(a,r,w,s,c) _assuan_funopen ((a), (r), (w), (s), (c))
#endif /*HAVE_FOPENCOOKIE*/
/*-- sysutils.c --*/
const char *_assuan_sysutils_blurb (void);
-#ifdef HAVE_W32CE_SYSTEM
-
-#define getpid() GetCurrentProcessId ()
-char *_assuan_getenv (const char *name);
-#define getenv(a) _assuan_getenv ((a))
-
-#endif /*HAVE_W32CE_SYSTEM*/
-
-
/* Prototypes for replacement functions. */
#ifndef HAVE_MEMRCHR
void *memrchr (const void *block, int c, size_t size);
#endif
#ifndef HAVE_STPCPY
char *stpcpy (char *dest, const char *src);
#endif
#ifndef HAVE_SETENV
#define setenv _assuan_setenv
#define unsetenv _assuan_unsetenv
#define clearenv _assuan_clearenv
int setenv (const char *name, const char *value, int replace);
#endif
#ifndef HAVE_PUTC_UNLOCKED
int putc_unlocked (int c, FILE *stream);
#endif
#define DIM(v) (sizeof(v)/sizeof((v)[0]))
/* To avoid that a compiler optimizes memset calls away, these macros
can be used. */
#define wipememory2(_ptr,_set,_len) do { \
volatile char *_vptr=(volatile char *)(_ptr); \
size_t _vlen=(_len); \
while(_vlen) { *_vptr=(_set); _vptr++; _vlen--; } \
} while(0)
#define wipememory(_ptr,_len) wipememory2(_ptr,0,_len)
#if HAVE_W64_SYSTEM
# define SOCKET2HANDLE(s) ((void *)(s))
# define HANDLE2SOCKET(h) ((uintptr_t)(h))
#elif HAVE_W32_SYSTEM
# define SOCKET2HANDLE(s) ((void *)(s))
# define HANDLE2SOCKET(h) ((unsigned int)(h))
#else
# define SOCKET2HANDLE(s) (s)
# define HANDLE2SOCKET(h) (h)
#endif
void _assuan_client_finish (assuan_context_t ctx);
void _assuan_client_release (assuan_context_t ctx);
void _assuan_server_finish (assuan_context_t ctx);
void _assuan_server_release (assuan_context_t ctx);
/* Encode the C formatted string SRC and return the malloc'ed result. */
char *_assuan_encode_c_string (assuan_context_t ctx, const char *src);
void _assuan_pre_syscall (void);
void _assuan_post_syscall (void);
#endif /*ASSUAN_DEFS_H*/
diff --git a/src/assuan-error.c b/src/assuan-error.c
index 8799203..57fb740 100644
--- a/src/assuan-error.c
+++ b/src/assuan-error.c
@@ -1,68 +1,63 @@
/* assuan-error.c
* Copyright (C) 2009 Free Software Foundation, Inc.
*
* This file is part of Assuan.
*
* Assuan 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.
*
* Assuan 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
* Lesser 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 .
* SPDX-License-Identifier: LGPL-2.1+
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include
#include
#undef _ASSUAN_IN_LIBASSUAN /* undef to get all error codes. */
#include "assuan.h"
#include "assuan-defs.h"
/* A small helper function to treat EAGAIN transparently to the
caller. */
int
_assuan_error_is_eagain (assuan_context_t ctx, gpg_error_t err)
{
if (gpg_err_code (err) == GPG_ERR_EAGAIN)
{
/* Avoid spinning by sleeping for one tenth of a second. */
_assuan_usleep (ctx, 100000);
return 1;
}
else
return 0;
}
#ifdef HAVE_W32_SYSTEM
char *
_assuan_w32_strerror (assuan_context_t ctx, int ec)
{
if (ec == -1)
ec = (int)GetLastError ();
-#ifdef HAVE_W32CE_SYSTEM
- snprintf (ctx->w32_strerror, sizeof (ctx->w32_strerror) - 1,
- "ec=%d", (int)GetLastError ());
-#else
FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, ec,
MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
ctx->w32_strerror, sizeof (ctx->w32_strerror) - 1, NULL);
-#endif
return ctx->w32_strerror;
}
#endif
diff --git a/src/assuan-handler.c b/src/assuan-handler.c
index a572b62..126eccb 100644
--- a/src/assuan-handler.c
+++ b/src/assuan-handler.c
@@ -1,1069 +1,1047 @@
/* assuan-handler.c - dispatch commands
* Copyright (C) 2001, 2002, 2003, 2007, 2009,
* 2011 Free Software Foundation, Inc.
*
* This file is part of Assuan.
*
* Assuan 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.
*
* Assuan 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
* Lesser 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 .
* SPDX-License-Identifier: LGPL-2.1+
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include
#include
#include
#include "assuan-defs.h"
#include "debug.h"
#define spacep(p) (*(p) == ' ' || *(p) == '\t')
#define digitp(a) ((a) >= '0' && (a) <= '9')
static int my_strcasecmp (const char *a, const char *b);
#define PROCESS_DONE(ctx, rc) \
((ctx)->flags.in_process_next ? assuan_process_done ((ctx), (rc)) : (rc))
static gpg_error_t
dummy_handler (assuan_context_t ctx, char *line)
{
return
PROCESS_DONE (ctx, set_error (ctx, GPG_ERR_ASSUAN_SERVER_FAULT,
"no handler registered"));
}
static const char std_help_nop[] =
"NOP\n"
"\n"
"No operation. Returns OK without any action.";
static gpg_error_t
std_handler_nop (assuan_context_t ctx, char *line)
{
return PROCESS_DONE (ctx, 0); /* okay */
}
static const char std_help_cancel[] =
"CANCEL\n"
"\n"
"Run the server's cancel handler if one has been registered.";
static gpg_error_t
std_handler_cancel (assuan_context_t ctx, char *line)
{
if (ctx->cancel_notify_fnc)
/* Return value ignored. */
ctx->cancel_notify_fnc (ctx, line);
return PROCESS_DONE (ctx, set_error (ctx, GPG_ERR_NOT_IMPLEMENTED, NULL));
}
static const char std_help_option[] =
"OPTION [ [=] ]\n"
"\n"
"Set option to configure server operation. Leading and\n"
"trailing spaces around and are allowed but should be\n"
"ignored. For compatibility reasons, may be prefixed with two\n"
"dashes. The use of the equal sign is optional but suggested if\n"
" is given.";
static gpg_error_t
std_handler_option (assuan_context_t ctx, char *line)
{
char *key, *value, *p;
for (key=line; spacep (key); key++)
;
if (!*key)
return
PROCESS_DONE (ctx, set_error (ctx, GPG_ERR_ASS_SYNTAX, "argument required"));
if (*key == '=')
return
PROCESS_DONE (ctx, set_error (ctx, GPG_ERR_ASS_SYNTAX,
"no option name given"));
for (value=key; *value && !spacep (value) && *value != '='; value++)
;
if (*value)
{
if (spacep (value))
*value++ = 0; /* terminate key */
for (; spacep (value); value++)
;
if (*value == '=')
{
*value++ = 0; /* terminate key */
for (; spacep (value); value++)
;
if (!*value)
return
PROCESS_DONE (ctx, set_error (ctx, GPG_ERR_ASS_SYNTAX,
"option argument expected"));
}
if (*value)
{
for (p = value + strlen(value) - 1; p > value && spacep (p); p--)
;
if (p > value)
*++p = 0; /* strip trailing spaces */
}
}
if (*key == '-' && key[1] == '-' && key[2])
key += 2; /* the double dashes are optional */
if (*key == '-')
return PROCESS_DONE (ctx,
set_error (ctx, GPG_ERR_ASS_SYNTAX,
"option should not begin with one dash"));
if (ctx->option_handler_fnc)
return PROCESS_DONE (ctx, ctx->option_handler_fnc (ctx, key, value));
return PROCESS_DONE (ctx, 0);
}
static const char std_help_bye[] =
"BYE\n"
"\n"
"Close the connection. The server will reply with OK.";
static gpg_error_t
std_handler_bye (assuan_context_t ctx, char *line)
{
if (ctx->bye_notify_fnc)
/* Return value ignored. */
ctx->bye_notify_fnc (ctx, line);
assuan_close_input_fd (ctx);
assuan_close_output_fd (ctx);
/* pretty simple :-) */
ctx->flags.process_complete = 1;
return PROCESS_DONE (ctx, 0);
}
static const char std_help_auth[] =
"AUTH\n"
"\n"
"Reserved for future extensions.";
static gpg_error_t
std_handler_auth (assuan_context_t ctx, char *line)
{
return PROCESS_DONE (ctx, set_error (ctx, GPG_ERR_NOT_IMPLEMENTED, NULL));
}
static const char std_help_reset[] =
"RESET\n"
"\n"
"Reset the connection but not any existing authentication. The server\n"
"should release all resources associated with the connection.";
static gpg_error_t
std_handler_reset (assuan_context_t ctx, char *line)
{
gpg_error_t err = 0;
if (ctx->reset_notify_fnc)
err = ctx->reset_notify_fnc (ctx, line);
if (! err)
{
assuan_close_input_fd (ctx);
assuan_close_output_fd (ctx);
_assuan_uds_close_fds (ctx);
}
return PROCESS_DONE (ctx, err);
}
static const char std_help_help[] =
"HELP []\n"
"\n"
"Lists all commands that the server understands as comment lines on\n"
"the status channel. If is given, list detailed help for\n"
"that command.";
static gpg_error_t
std_handler_help (assuan_context_t ctx, char *line)
{
unsigned int i;
char buf[ASSUAN_LINELENGTH];
const char *helpstr;
size_t n;
n = strcspn (line, " \t\n");
if (!n)
{
/* Print all commands. If a help string is available and that
starts with the command name, print the first line of the
help string. */
for (i = 0; i < ctx->cmdtbl_used; i++)
{
n = strlen (ctx->cmdtbl[i].name);
helpstr = ctx->cmdtbl[i].helpstr;
if (helpstr
&& !strncmp (ctx->cmdtbl[i].name, helpstr, n)
&& (!helpstr[n] || helpstr[n] == '\n' || helpstr[n] == ' ')
&& (n = strcspn (helpstr, "\n")) )
snprintf (buf, sizeof (buf), "# %.*s", (int)n, helpstr);
else
snprintf (buf, sizeof (buf), "# %s", ctx->cmdtbl[i].name);
buf[ASSUAN_LINELENGTH - 1] = '\0';
assuan_write_line (ctx, buf);
}
}
else
{
/* Print the help for the given command. */
int c = line[n];
line[n] = 0;
for (i=0; ctx->cmdtbl[i].name; i++)
if (!my_strcasecmp (line, ctx->cmdtbl[i].name))
break;
line[n] = c;
if (!ctx->cmdtbl[i].name)
return PROCESS_DONE (ctx, set_error (ctx,GPG_ERR_UNKNOWN_COMMAND,NULL));
helpstr = ctx->cmdtbl[i].helpstr;
if (!helpstr)
return PROCESS_DONE (ctx, set_error (ctx, GPG_ERR_NOT_FOUND, NULL));
do
{
n = strcspn (helpstr, "\n");
snprintf (buf, sizeof (buf), "# %.*s", (int)n, helpstr);
helpstr += n;
if (*helpstr == '\n')
helpstr++;
buf[ASSUAN_LINELENGTH - 1] = '\0';
assuan_write_line (ctx, buf);
}
while (*helpstr);
}
return PROCESS_DONE (ctx, 0);
}
static const char std_help_end[] =
"END\n"
"\n"
"Used by a client to mark the end of raw data.";
static gpg_error_t
std_handler_end (assuan_context_t ctx, char *line)
{
return PROCESS_DONE (ctx, set_error (ctx, GPG_ERR_NOT_IMPLEMENTED, NULL));
}
gpg_error_t
assuan_command_parse_fd (assuan_context_t ctx, char *line, assuan_fd_t *rfd)
{
char *endp;
if ((strncmp (line, "FD", 2) && strncmp (line, "fd", 2))
|| (line[2] != '=' && line[2] != '\0' && !spacep(&line[2])))
return set_error (ctx, GPG_ERR_ASS_SYNTAX, "FD[=] expected");
line += 2;
if (*line == '=')
{
line ++;
if (!digitp (*line))
return set_error (ctx, GPG_ERR_ASS_SYNTAX, "number required");
#if HAVE_W64_SYSTEM
*rfd = (void*)strtoull (line, &endp, 10);
#elif HAVE_W32_SYSTEM
*rfd = (void*)strtoul (line, &endp, 10);
#else
*rfd = strtoul (line, &endp, 10);
#endif
/* Remove that argument so that a notify handler won't see it. */
memset (line, ' ', endp? (endp-line):strlen(line));
if (*rfd == ctx->inbound.fd)
return set_error (ctx, GPG_ERR_ASS_PARAMETER, "fd same as inbound fd");
if (*rfd == ctx->outbound.fd)
return set_error (ctx, GPG_ERR_ASS_PARAMETER, "fd same as outbound fd");
return 0;
}
else
/* Our peer has sent the file descriptor. */
return assuan_receivefd (ctx, rfd);
}
static const char std_help_input[] =
"INPUT FD[=]\n"
"\n"
"Used by a client to pass an input file descriptor to the server.\n"
"The server opens as a local file descriptor. Without , the\n"
"server opens the file descriptor just sent by the client using\n"
"assuan_sendfd.";
static gpg_error_t
std_handler_input (assuan_context_t ctx, char *line)
{
gpg_error_t rc;
assuan_fd_t fd, oldfd;
rc = assuan_command_parse_fd (ctx, line, &fd);
if (rc)
return PROCESS_DONE (ctx, rc);
-#ifdef HAVE_W32CE_SYSTEM
- oldfd = fd;
- fd = _assuan_w32ce_finish_pipe ((int)fd, 0);
- if (fd == INVALID_HANDLE_VALUE)
- return PROCESS_DONE (ctx, set_error (ctx, GPG_ERR_ASS_PARAMETER,
- "rvid conversion failed"));
- TRACE2 (ctx, ASSUAN_LOG_SYSIO, "std_handler_input", ctx,
- "turned RVID 0x%x into handle 0x%x", oldfd, fd);
-#endif
-
if (ctx->input_notify_fnc)
{
oldfd = ctx->input_fd;
ctx->input_fd = fd;
rc = ctx->input_notify_fnc (ctx, line);
if (rc)
ctx->input_fd = oldfd;
}
else if (!rc)
ctx->input_fd = fd;
return PROCESS_DONE (ctx, rc);
}
static const char std_help_output[] =
"OUTPUT FD[=]\n"
"\n"
"Used by a client to pass an output file descriptor to the server.\n"
"The server opens as a local file descriptor. Without , the\n"
"server opens the file descriptor just sent by the client using\n"
"assuan_sendfd.";
static gpg_error_t
std_handler_output (assuan_context_t ctx, char *line)
{
gpg_error_t rc;
assuan_fd_t fd, oldfd;
rc = assuan_command_parse_fd (ctx, line, &fd);
if (rc)
return PROCESS_DONE (ctx, rc);
-#ifdef HAVE_W32CE_SYSTEM
- oldfd = fd;
- fd = _assuan_w32ce_finish_pipe ((int)fd, 1);
- if (fd == INVALID_HANDLE_VALUE)
- return PROCESS_DONE (ctx, set_error (ctx, gpg_err_code_from_syserror (),
- "rvid conversion failed"));
- TRACE2 (ctx, ASSUAN_LOG_SYSIO, "std_handler_output", ctx,
- "turned RVID 0x%x into handle 0x%x", oldfd, fd);
-#endif
-
if (ctx->output_notify_fnc)
{
oldfd = ctx->output_fd;
ctx->output_fd = fd;
rc = ctx->output_notify_fnc (ctx, line);
if (rc)
ctx->output_fd = oldfd;
}
else if (!rc)
ctx->output_fd = fd;
return PROCESS_DONE (ctx, rc);
}
/* This is a table with the standard commands and handler for them.
The table is used to initialize a new context and associate strings
with default handlers */
static struct {
const char *name;
gpg_error_t (*handler)(assuan_context_t, char *line);
const char *help;
int always; /* always initialize this command */
} std_cmd_table[] = {
{ "NOP", std_handler_nop, std_help_nop, 1 },
{ "CANCEL", std_handler_cancel, std_help_cancel, 1 },
{ "OPTION", std_handler_option, std_help_option, 1 },
{ "BYE", std_handler_bye, std_help_bye, 1 },
{ "AUTH", std_handler_auth, std_help_auth, 1 },
{ "RESET", std_handler_reset, std_help_reset, 1 },
{ "END", std_handler_end, std_help_end, 1 },
{ "HELP", std_handler_help, std_help_help, 1 },
{ "INPUT", std_handler_input, std_help_input, 0 },
{ "OUTPUT", std_handler_output, std_help_output, 0 },
{ } };
/**
* assuan_register_command:
* @ctx: the server context
* @cmd_name: A string with the command name
* @handler: The handler function to be called or NULL to use a default
* handler.
* HELPSTRING
*
* Register a handler to be used for a given command. Note that
* several default handlers are already registered with a new context.
* This function however allows to override them.
*
* Return value: 0 on success or an error code
**/
gpg_error_t
assuan_register_command (assuan_context_t ctx, const char *cmd_name,
assuan_handler_t handler, const char *help_string)
{
int i, cmd_index = -1;
const char *s;
if (cmd_name && !*cmd_name)
cmd_name = NULL;
if (!cmd_name)
return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
if (!handler)
{ /* find a default handler. */
for (i=0; (s=std_cmd_table[i].name) && strcmp (cmd_name, s); i++)
;
if (!s)
{ /* Try again but case insensitive. */
for (i=0; (s=std_cmd_table[i].name)
&& my_strcasecmp (cmd_name, s); i++)
;
}
if (s)
handler = std_cmd_table[i].handler;
if (!handler)
handler = dummy_handler; /* Last resort is the dummy handler. */
}
if (!ctx->cmdtbl)
{
ctx->cmdtbl_size = 50;
ctx->cmdtbl = _assuan_calloc (ctx, ctx->cmdtbl_size, sizeof *ctx->cmdtbl);
if (!ctx->cmdtbl)
return _assuan_error (ctx, gpg_err_code_from_syserror ());
ctx->cmdtbl_used = 0;
}
else if (ctx->cmdtbl_used >= ctx->cmdtbl_size)
{
struct cmdtbl_s *x;
x = _assuan_realloc (ctx, ctx->cmdtbl, (ctx->cmdtbl_size+10) * sizeof *x);
if (!x)
return _assuan_error (ctx, gpg_err_code_from_syserror ());
ctx->cmdtbl = x;
ctx->cmdtbl_size += 50;
}
for (i=0; icmdtbl_used; i++)
{
if (!my_strcasecmp (cmd_name, ctx->cmdtbl[i].name))
{
cmd_index = i;
break;
}
}
if (cmd_index == -1)
cmd_index = ctx->cmdtbl_used++;
ctx->cmdtbl[cmd_index].name = cmd_name;
ctx->cmdtbl[cmd_index].handler = handler;
ctx->cmdtbl[cmd_index].helpstr = help_string;
return 0;
}
/* Return the name of the command currently processed by a handler.
The string returned is valid until the next call to an assuan
function on the same context. Returns NULL if no handler is
executed or the command is not known. */
const char *
assuan_get_command_name (assuan_context_t ctx)
{
return ctx? ctx->current_cmd_name : NULL;
}
gpg_error_t
assuan_register_pre_cmd_notify (assuan_context_t ctx,
gpg_error_t (*fnc)(assuan_context_t,
const char *cmd))
{
if (!ctx)
return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
ctx->pre_cmd_notify_fnc = fnc;
return 0;
}
gpg_error_t
assuan_register_post_cmd_notify (assuan_context_t ctx,
void (*fnc)(assuan_context_t, gpg_error_t))
{
if (!ctx)
return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
ctx->post_cmd_notify_fnc = fnc;
return 0;
}
gpg_error_t
assuan_register_bye_notify (assuan_context_t ctx, assuan_handler_t fnc)
{
if (!ctx)
return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
ctx->bye_notify_fnc = fnc;
return 0;
}
gpg_error_t
assuan_register_reset_notify (assuan_context_t ctx, assuan_handler_t fnc)
{
if (!ctx)
return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
ctx->reset_notify_fnc = fnc;
return 0;
}
gpg_error_t
assuan_register_cancel_notify (assuan_context_t ctx, assuan_handler_t fnc)
{
if (!ctx)
return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
ctx->cancel_notify_fnc = fnc;
return 0;
}
gpg_error_t
assuan_register_option_handler (assuan_context_t ctx,
gpg_error_t (*fnc)(assuan_context_t,
const char*, const char*))
{
if (!ctx)
return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
ctx->option_handler_fnc = fnc;
return 0;
}
gpg_error_t
assuan_register_input_notify (assuan_context_t ctx, assuan_handler_t fnc)
{
if (!ctx)
return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
ctx->input_notify_fnc = fnc;
return 0;
}
gpg_error_t
assuan_register_output_notify (assuan_context_t ctx, assuan_handler_t fnc)
{
if (!ctx)
return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
ctx->output_notify_fnc = fnc;
return 0;
}
/* Helper to register the standards commands */
gpg_error_t
_assuan_register_std_commands (assuan_context_t ctx)
{
gpg_error_t rc;
int i;
for (i = 0; std_cmd_table[i].name; i++)
{
if (std_cmd_table[i].always)
{
rc = assuan_register_command (ctx, std_cmd_table[i].name, NULL, NULL);
if (rc)
return rc;
}
}
return 0;
}
/* Process the special data lines. The "D " has already been removed
from the line. As all handlers this function may modify the line. */
static gpg_error_t
handle_data_line (assuan_context_t ctx, char *line, int linelen)
{
return set_error (ctx, GPG_ERR_NOT_IMPLEMENTED, NULL);
}
/* like ascii_strcasecmp but assume that B is already uppercase */
static int
my_strcasecmp (const char *a, const char *b)
{
if (a == b)
return 0;
for (; *a && *b; a++, b++)
{
if (((*a >= 'a' && *a <= 'z')? (*a&~0x20):*a) != *b)
break;
}
return *a == *b? 0 : (((*a >= 'a' && *a <= 'z')? (*a&~0x20):*a) - *b);
}
/* Parse the line, break out the command, find it in the command
table, remove leading and white spaces from the arguments, call the
handler with the argument line and return the error. */
static gpg_error_t
dispatch_command (assuan_context_t ctx, char *line, int linelen)
{
gpg_error_t err;
char *p;
const char *s;
int shift, i;
/* Note that as this function is invoked by assuan_process_next as
well, we need to hide non-critical errors with PROCESS_DONE. */
if (*line == 'D' && line[1] == ' ') /* divert to special handler */
/* FIXME: Depending on the final implementation of
handle_data_line, this may be wrong here. For example, if a
user callback is invoked, and that callback is responsible for
calling assuan_process_done, then this is wrong. */
return PROCESS_DONE (ctx, handle_data_line (ctx, line+2, linelen-2));
for (p=line; *p && *p != ' ' && *p != '\t'; p++)
;
if (p==line)
return PROCESS_DONE
(ctx, set_error (ctx, GPG_ERR_ASS_SYNTAX, "leading white-space"));
if (*p)
{ /* Skip over leading WS after the keyword */
*p++ = 0;
while ( *p == ' ' || *p == '\t')
p++;
}
shift = p - line;
for (i=0; (s=ctx->cmdtbl[i].name); i++)
{
if (!strcmp (line, s))
break;
}
if (!s)
{ /* and try case insensitive */
for (i=0; (s=ctx->cmdtbl[i].name); i++)
{
if (!my_strcasecmp (line, s))
break;
}
}
if (!s)
return PROCESS_DONE (ctx, set_error (ctx, GPG_ERR_ASS_UNKNOWN_CMD, NULL));
line += shift;
/* linelen -= shift; -- not needed. */
if (ctx->pre_cmd_notify_fnc) {
err = ctx->pre_cmd_notify_fnc(ctx, ctx->cmdtbl[i].name);
if (err)
return PROCESS_DONE(ctx, err);
}
/* fprintf (stderr, "DBG-assuan: processing %s `%s'\n", s, line); */
ctx->current_cmd_name = ctx->cmdtbl[i].name;
err = ctx->cmdtbl[i].handler (ctx, line);
ctx->current_cmd_name = NULL;
return err;
}
/* Call this to acknowledge the current command. */
gpg_error_t
assuan_process_done (assuan_context_t ctx, gpg_error_t rc)
{
if (!ctx->flags.in_command)
return _assuan_error (ctx, GPG_ERR_ASS_GENERAL);
if (ctx->flags.force_close)
ctx->flags.process_complete = 1;
ctx->flags.in_command = 0;
/* Check for data write errors. */
if (ctx->outbound.data.fp)
{
/* Flush the data lines. */
fclose (ctx->outbound.data.fp);
ctx->outbound.data.fp = NULL;
if (!rc && ctx->outbound.data.error)
rc = ctx->outbound.data.error;
}
else
{
/* Flush any data send without using the data FP. */
assuan_send_data (ctx, NULL, 0);
if (!rc && ctx->outbound.data.error)
rc = ctx->outbound.data.error;
}
/* Error handling. */
if (!rc)
{
if (ctx->flags.process_complete)
{
/* No error checking because the peer may have already
disconnect. */
assuan_write_line (ctx, "OK closing connection");
ctx->finish_handler (ctx);
}
else
rc = assuan_write_line (ctx, ctx->okay_line ? ctx->okay_line : "OK");
}
else
{
char errline[300];
const char *text = ctx->err_no == rc ? ctx->err_str : NULL;
char ebuf[50];
if (ctx->flags.force_close)
text = "[closing connection]";
gpg_strerror_r (rc, ebuf, sizeof (ebuf));
snprintf (errline, sizeof errline, "ERR %d %.50s <%.30s>%s%.100s",
rc, ebuf, gpg_strsource (rc),
text? " - ":"", text?text:"");
rc = assuan_write_line (ctx, errline);
if (ctx->flags.force_close)
ctx->finish_handler (ctx);
}
if (ctx->post_cmd_notify_fnc)
ctx->post_cmd_notify_fnc (ctx, rc);
ctx->flags.confidential = 0;
if (ctx->okay_line)
{
_assuan_free (ctx, ctx->okay_line);
ctx->okay_line = NULL;
}
return rc;
}
static gpg_error_t
process_next (assuan_context_t ctx)
{
gpg_error_t rc;
/* What the next thing to do is depends on the current state.
However, we will always first read the next line. The client is
required to write full lines without blocking long after starting
a partial line. */
rc = _assuan_read_line (ctx);
if (_assuan_error_is_eagain (ctx, rc))
return 0;
if (gpg_err_code (rc) == GPG_ERR_EOF)
{
ctx->flags.process_complete = 1;
return 0;
}
if (rc)
return rc;
if (*ctx->inbound.line == '#' || !ctx->inbound.linelen)
/* Comment lines are ignored. */
return 0;
/* Now we have a line that really means something. It could be one
of the following things: First, if we are not in a command
already, it is the next command to dispatch. Second, if we are
in a command, it can only be the response to an INQUIRE
reply. */
if (!ctx->flags.in_command)
{
ctx->flags.in_command = 1;
ctx->outbound.data.error = 0;
ctx->outbound.data.linelen = 0;
/* Dispatch command and return reply. */
ctx->flags.in_process_next = 1;
rc = dispatch_command (ctx, ctx->inbound.line, ctx->inbound.linelen);
ctx->flags.in_process_next = 0;
}
else if (ctx->flags.in_inquire)
{
/* FIXME: Pick up the continuation. */
rc = _assuan_inquire_ext_cb (ctx);
}
else
{
/* Should not happen. The client is sending data while we are
in a command and not waiting for an inquire. We log an error
and discard it. */
TRACE0 (ctx, ASSUAN_LOG_DATA, "process_next", ctx,
"unexpected client data");
rc = 0;
}
return rc;
}
/* This function should be invoked when the assuan connected FD is
ready for reading. If the equivalent to EWOULDBLOCK is returned
(this should be done by the command handler), assuan_process_next
should be invoked the next time the connected FD is readable.
Eventually, the caller will finish by invoking assuan_process_done.
DONE is set to 1 if the connection has ended. */
gpg_error_t
assuan_process_next (assuan_context_t ctx, int *done)
{
gpg_error_t rc;
if (done)
*done = 0;
ctx->flags.process_complete = 0;
do
{
rc = process_next (ctx);
}
while (!rc && !ctx->flags.process_complete && assuan_pending_line (ctx));
if (done)
*done = !!ctx->flags.process_complete;
return rc;
}
static gpg_error_t
process_request (assuan_context_t ctx)
{
gpg_error_t rc;
if (ctx->flags.in_inquire)
return _assuan_error (ctx, GPG_ERR_ASS_NESTED_COMMANDS);
do
{
rc = _assuan_read_line (ctx);
}
while (_assuan_error_is_eagain (ctx, rc));
if (gpg_err_code (rc) == GPG_ERR_EOF)
{
ctx->flags.process_complete = 1;
return 0;
}
if (rc)
return rc;
if (*ctx->inbound.line == '#' || !ctx->inbound.linelen)
return 0; /* comment line - ignore */
ctx->flags.in_command = 1;
ctx->outbound.data.error = 0;
ctx->outbound.data.linelen = 0;
/* dispatch command and return reply */
rc = dispatch_command (ctx, ctx->inbound.line, ctx->inbound.linelen);
return assuan_process_done (ctx, rc);
}
/**
* assuan_process:
* @ctx: assuan context
*
* This function is used to handle the assuan protocol after a
* connection has been established using assuan_accept(). This is the
* main protocol handler.
*
* Return value: 0 on success or an error code if the assuan operation
* failed. Note, that no error is returned for operational errors.
**/
gpg_error_t
assuan_process (assuan_context_t ctx)
{
gpg_error_t rc;
ctx->flags.process_complete = 0;
do {
rc = process_request (ctx);
} while (!rc && !ctx->flags.process_complete);
return rc;
}
/**
* assuan_get_active_fds:
* @ctx: Assuan context
* @what: 0 for read fds, 1 for write fds
* @fdarray: Caller supplied array to store the FDs
* @fdarraysize: size of that array
*
* Return all active filedescriptors for the given context. This
* function can be used to select on the fds and call
* assuan_process_next() if there is an active one. The first fd in
* the array is the one used for the command connection.
*
* Note, that write FDs are not yet supported.
*
* Return value: number of FDs active and put into @fdarray or -1 on
* error which is most likely a too small fdarray.
**/
int
assuan_get_active_fds (assuan_context_t ctx, int what,
assuan_fd_t *fdarray, int fdarraysize)
{
int n = 0;
if (!ctx || fdarraysize < 2 || what < 0 || what > 1)
return -1;
if (!what)
{
if (ctx->inbound.fd != ASSUAN_INVALID_FD)
fdarray[n++] = ctx->inbound.fd;
}
else
{
if (ctx->outbound.fd != ASSUAN_INVALID_FD)
fdarray[n++] = ctx->outbound.fd;
if (ctx->outbound.data.fp)
-#if defined(HAVE_W32CE_SYSTEM)
- fdarray[n++] = (void*)fileno (ctx->outbound.data.fp);
-#elif defined(HAVE_W32_SYSTEM)
+#if defined(HAVE_W32_SYSTEM)
fdarray[n++] = (void*)_get_osfhandle (fileno (ctx->outbound.data.fp));
#else
fdarray[n++] = fileno (ctx->outbound.data.fp);
#endif
}
return n;
}
/* Two simple wrappers to make the expected function types match. */
#ifdef HAVE_FUNOPEN
static int
fun1_cookie_write (void *cookie, const char *buffer, int orig_size)
{
return _assuan_cookie_write_data (cookie, buffer, orig_size);
}
#endif /*HAVE_FUNOPEN*/
#ifdef HAVE_FOPENCOOKIE
static ssize_t
fun2_cookie_write (void *cookie, const char *buffer, size_t orig_size)
{
return _assuan_cookie_write_data (cookie, buffer, orig_size);
}
#endif /*HAVE_FOPENCOOKIE*/
/* Return a FP to be used for data output. The FILE pointer is valid
until the end of a handler. So a close is not needed. Assuan does
all the buffering needed to insert the status line as well as the
required line wappping and quoting for data lines.
We use GNU's custom streams here. There should be an alternative
implementaion for systems w/o a glibc, a simple implementation
could use a child process */
FILE *
assuan_get_data_fp (assuan_context_t ctx)
{
#if defined (HAVE_FOPENCOOKIE) || defined (HAVE_FUNOPEN)
if (ctx->outbound.data.fp)
return ctx->outbound.data.fp;
#ifdef HAVE_FUNOPEN
ctx->outbound.data.fp = funopen (ctx, 0, fun1_cookie_write,
0, _assuan_cookie_write_flush);
#else
ctx->outbound.data.fp = funopen (ctx, 0, fun2_cookie_write,
0, _assuan_cookie_write_flush);
#endif
ctx->outbound.data.error = 0;
return ctx->outbound.data.fp;
#else
gpg_err_set_errno (ENOSYS);
return NULL;
#endif
}
/* Set the text used for the next OK response. This string is
automatically reset to NULL after the next command. */
gpg_error_t
assuan_set_okay_line (assuan_context_t ctx, const char *line)
{
if (!ctx)
return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
if (!line)
{
_assuan_free (ctx, ctx->okay_line);
ctx->okay_line = NULL;
}
else
{
/* FIXME: we need to use gcry_is_secure() to test whether
we should allocate the entire line in secure memory */
char *buf = _assuan_malloc (ctx, 3 + strlen(line) + 1);
if (!buf)
return _assuan_error (ctx, gpg_err_code_from_syserror ());
strcpy (buf, "OK ");
strcpy (buf+3, line);
_assuan_free (ctx, ctx->okay_line);
ctx->okay_line = buf;
}
return 0;
}
gpg_error_t
assuan_write_status (assuan_context_t ctx,
const char *keyword, const char *text)
{
char buffer[256];
char *helpbuf;
size_t n;
gpg_error_t ae;
if ( !ctx || !keyword)
return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
if (!text)
text = "";
n = 2 + strlen (keyword) + 1 + strlen (text) + 1;
if (n < sizeof (buffer))
{
strcpy (buffer, "S ");
strcat (buffer, keyword);
if (*text)
{
strcat (buffer, " ");
strcat (buffer, text);
}
ae = assuan_write_line (ctx, buffer);
}
else if ( (helpbuf = _assuan_malloc (ctx, n)) )
{
strcpy (helpbuf, "S ");
strcat (helpbuf, keyword);
if (*text)
{
strcat (helpbuf, " ");
strcat (helpbuf, text);
}
ae = assuan_write_line (ctx, helpbuf);
_assuan_free (ctx, helpbuf);
}
else
ae = 0;
return ae;
}
diff --git a/src/assuan-socket.c b/src/assuan-socket.c
index 0588dc2..bb5ccfd 100644
--- a/src/assuan-socket.c
+++ b/src/assuan-socket.c
@@ -1,1557 +1,1555 @@
/* assuan-socket.c - Socket wrapper
* Copyright (C) 2004, 2005, 2009 Free Software Foundation, Inc.
* Copyright (C) 2001-2015 g10 Code GmbH
*
* This file is part of Assuan.
*
* Assuan 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.
*
* Assuan 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
* Lesser 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 .
* SPDX-License-Identifier: LGPL-2.1+
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include
#ifdef HAVE_W32_SYSTEM
# define WIN32_LEAN_AND_MEAN
# include
# include
-#ifndef HAVE_W32CE_SYSTEM
# include
-#endif
#else
# include
# include
# include
# include
#endif
#include
#ifdef HAVE_SYS_STAT_H
# include
#endif
#ifdef HAVE_FCNTL_H
#include
#endif
#include
#include "assuan-defs.h"
#include "debug.h"
/* Hacks for Slowaris. */
#ifndef PF_LOCAL
# ifdef PF_UNIX
# define PF_LOCAL PF_UNIX
# else
# define PF_LOCAL AF_UNIX
# endif
#endif
#ifndef AF_LOCAL
# define AF_LOCAL AF_UNIX
#endif
#ifdef HAVE_W32_SYSTEM
#ifndef S_IRUSR
# define S_IRUSR 0
# define S_IWUSR 0
#endif
#ifndef S_IRGRP
# define S_IRGRP 0
# define S_IWGRP 0
#endif
#ifndef ENOTSUP
#define ENOTSUP 129
#endif
#ifndef EPROTO
#define EPROTO 134
#endif
#ifndef EPROTONOSUPPORT
#define EPROTONOSUPPORT 135
#endif
#ifndef ENETDOWN
#define ENETDOWN 116
#endif
#ifndef ENETUNREACH
#define ENETUNREACH 118
#endif
#ifndef EHOSTUNREACH
#define EHOSTUNREACH 110
#endif
#ifndef ECONNREFUSED
#define ECONNREFUSED 107
#endif
#ifndef ETIMEDOUT
#define ETIMEDOUT 138
#endif
#endif
#ifndef ENAMETOOLONG
# define ENAMETOOLONG EINVAL
#endif
#ifndef SUN_LEN
# define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) \
+ strlen ((ptr)->sun_path))
#endif
#ifndef INADDR_LOOPBACK
# define INADDR_LOOPBACK ((in_addr_t) 0x7f000001) /* 127.0.0.1. */
#endif
/* The standard SOCKS and TOR port. */
#define SOCKS_PORT 1080
#define TOR_PORT 9050
#define TOR_PORT2 9150 /* The Tor browser is listening there. */
/* In the future, we can allow access to sock_ctx, if that context's
hook functions need to be overridden. There can only be one global
assuan_sock_* user (one library or one application) with this
convenience interface, if non-standard hook functions are
needed. */
static assuan_context_t sock_ctx;
/* This global flag can be set using assuan_sock_set_flag to enable
TOR or SOCKS mode for all sockets. It may not be reset. The value
is the port to be used. */
static unsigned short tor_mode;
#ifdef HAVE_W32_SYSTEM
/* A table of active Cygwin connections. This is only used for
listening socket which should be only a few. We do not enter
sockets after a connect into this table. */
static assuan_fd_t cygwin_fdtable[16];
/* A critical section to guard access to the table of Cygwin
connections. */
static CRITICAL_SECTION cygwin_fdtable_cs;
/* Return true if SOCKFD is listed as Cygwin socket. */
static int
is_cygwin_fd (assuan_fd_t sockfd)
{
int ret = 0;
int i;
EnterCriticalSection (&cygwin_fdtable_cs);
for (i=0; i < DIM(cygwin_fdtable); i++)
{
if (cygwin_fdtable[i] == sockfd)
{
ret = 1;
break;
}
}
LeaveCriticalSection (&cygwin_fdtable_cs);
return ret;
}
/* Insert SOCKFD into the table of Cygwin sockets. Return 0 on
success or -1 on error. */
static int
insert_cygwin_fd (assuan_fd_t sockfd)
{
int ret = 0;
int mark = -1;
int i;
EnterCriticalSection (&cygwin_fdtable_cs);
for (i=0; i < DIM(cygwin_fdtable); i++)
{
if (cygwin_fdtable[i] == sockfd)
goto leave; /* Already in table. */
else if (cygwin_fdtable[i] == ASSUAN_INVALID_FD)
mark = i;
}
if (mark == -1)
{
gpg_err_set_errno (EMFILE);
ret = -1;
}
else
cygwin_fdtable[mark] = sockfd;
leave:
LeaveCriticalSection (&cygwin_fdtable_cs);
return ret;
}
/* Delete SOCKFD from the table of Cygwin sockets. */
static void
delete_cygwin_fd (assuan_fd_t sockfd)
{
int i;
EnterCriticalSection (&cygwin_fdtable_cs);
for (i=0; i < DIM(cygwin_fdtable); i++)
{
if (cygwin_fdtable[i] == sockfd)
{
cygwin_fdtable[i] = ASSUAN_INVALID_FD;
break;
}
}
LeaveCriticalSection (&cygwin_fdtable_cs);
return;
}
wchar_t *
_assuan_utf8_to_wchar (const char *string)
{
int n;
size_t nbytes;
wchar_t *result;
if (!string)
return NULL;
n = MultiByteToWideChar (CP_UTF8, 0, string, -1, NULL, 0);
if (n < 0)
return NULL;
nbytes = (size_t)(n+1) * sizeof(*result);
if (nbytes / sizeof(*result) != (n+1))
{
SetLastError (ERROR_INVALID_PARAMETER);
return NULL;
}
result = malloc (nbytes);
if (!result)
return NULL;
n = MultiByteToWideChar (CP_UTF8, 0, string, -1, result, n);
if (n < 0)
{
n = GetLastError ();
free (result);
result = NULL;
SetLastError (n);
}
return result;
}
static HANDLE
MyCreateFile (LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwSharedMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile)
{
wchar_t *filename;
HANDLE result;
int err;
filename = _assuan_utf8_to_wchar (lpFileName);
if (!filename)
return INVALID_HANDLE_VALUE;
result = CreateFileW (filename, dwDesiredAccess, dwSharedMode,
lpSecurityAttributes, dwCreationDisposition,
dwFlagsAndAttributes, hTemplateFile);
err = GetLastError ();
free (filename);
SetLastError (err);
return result;
}
static int
MyDeleteFile (LPCSTR lpFileName)
{
wchar_t *filename;
int result, err;
filename = _assuan_utf8_to_wchar (lpFileName);
if (!filename)
return 0;
result = DeleteFileW (filename);
err = GetLastError ();
free (filename);
SetLastError (err);
return result;
}
int
_assuan_sock_wsa2errno (int err)
{
switch (err)
{
case WSAENOTSOCK:
return EINVAL;
case WSAEWOULDBLOCK:
return EAGAIN;
case ERROR_BROKEN_PIPE:
return EPIPE;
case WSANOTINITIALISED:
return ENOSYS;
case WSAECONNREFUSED:
return ECONNREFUSED;
default:
return EIO;
}
}
/* W32: Fill BUFFER with LENGTH bytes of random. Returns -1 on
failure, 0 on success. Sets errno on failure. */
static int
get_nonce (char *buffer, size_t nbytes)
{
HCRYPTPROV prov;
int ret = -1;
if (!CryptAcquireContext (&prov, NULL, NULL, PROV_RSA_FULL,
(CRYPT_VERIFYCONTEXT|CRYPT_SILENT)) )
gpg_err_set_errno (ENODEV);
else
{
if (!CryptGenRandom (prov, nbytes, (unsigned char *) buffer))
gpg_err_set_errno (ENODEV);
else
ret = 0;
CryptReleaseContext (prov, 0);
}
return ret;
}
/* W32: The buffer for NONCE needs to be at least 16 bytes. Returns 0
on success and sets errno on failure. If FNAME has a Cygwin socket
descriptor True is stored at CYGWIN. */
static int
read_port_and_nonce (const char *fname, unsigned short *port, char *nonce,
int *cygwin)
{
estream_t fp;
char buffer[50], *p;
size_t nread;
int aval;
*cygwin = 0;
fp = gpgrt_fopen (fname, "rb");
if (!fp)
return -1;
nread = gpgrt_fread (buffer, 1, sizeof buffer - 1, fp);
gpgrt_fclose (fp);
if (!nread)
{
gpg_err_set_errno (ENOENT);
return -1;
}
buffer[nread] = 0;
if (!strncmp (buffer, "!", 10))
{
/* This is the Cygwin compatible socket emulation. The format
* of the file is:
*
* "!%u %c %08x-%08x-%08x-%08x\x00"
*
* %d for port number, %c for kind of socket (s for STREAM), and
* we have 16-byte random bytes for nonce. We only support
* stream mode.
*/
unsigned int u0;
int narr[4];
if (sscanf (buffer+10, "%u s %08x-%08x-%08x-%08x",
&u0, narr+0, narr+1, narr+2, narr+3) != 5
|| u0 < 1 || u0 > 65535)
{
gpg_err_set_errno (EINVAL);
return -1;
}
*port = u0;
memcpy (nonce, narr, 16);
*cygwin = 1;
}
else
{
/* This is our own socket emulation. */
aval = atoi (buffer);
if (aval < 1 || aval > 65535)
{
gpg_err_set_errno (EINVAL);
return -1;
}
*port = (unsigned int)aval;
for (p=buffer; nread && *p != '\n'; p++, nread--)
;
if (*p != '\n' || nread != 17)
{
gpg_err_set_errno (EINVAL);
return -1;
}
p++; nread--;
memcpy (nonce, p, 16);
}
return 0;
}
#endif /*HAVE_W32_SYSTEM*/
#ifndef HAVE_W32_SYSTEM
/* Find a redirected socket name for fname and return a malloced setup
filled sockaddr. If this does not work out NULL is returned and
ERRNO is set. If the file seems to be a redirect True is stored at
R_REDIRECT. Note that this function uses the standard malloc and
not the assuan wrapped one. The format of the file is:
%Assuan%
socket=NAME
where NAME is the actual socket to use. No white spaces are
allowed, both lines must be terminated by a single LF, extra lines
are not allowed. Environment variables are interpreted in NAME if
given in "${VAR} notation; no escape characters are defined, if
"${" shall be used verbatim, you need to use an environment
variable with that content.
The use of an absolute NAME is strongly suggested. The length of
the file is limited to 511 bytes which is more than sufficient for
that common value of 107 for sun_path. */
static struct sockaddr_un *
eval_redirection (const char *fname, int *r_redirect)
{
FILE *fp;
char buffer[512], *name;
size_t n;
struct sockaddr_un *addr;
char *p, *pend;
const char *s;
*r_redirect = 0;
fp = fopen (fname, "rb");
if (!fp)
return NULL;
n = fread (buffer, 1, sizeof buffer - 1, fp);
fclose (fp);
if (!n)
{
gpg_err_set_errno (ENOENT);
return NULL;
}
buffer[n] = 0;
/* Check that it is a redirection file. We also check that the
first byte of the name is not a LF because that would lead to an
zero length name. */
if (n < 17 || buffer[n-1] != '\n'
|| memcmp (buffer, "%Assuan%\nsocket=", 16)
|| buffer[16] == '\n')
{
gpg_err_set_errno (EINVAL);
return NULL;
}
buffer[n-1] = 0;
name = buffer + 16;
*r_redirect = 1;
addr = calloc (1, sizeof *addr);
if (!addr)
return NULL;
addr->sun_family = AF_LOCAL;
n = 0;
for (p=name; *p; p++)
{
if (*p == '$' && p[1] == '{')
{
p += 2;
pend = strchr (p, '}');
if (!pend)
{
free (addr);
gpg_err_set_errno (EINVAL);
return NULL;
}
*pend = 0;
if (*p && (s = getenv (p)))
{
for (; *s; s++)
{
if (n < sizeof addr->sun_path - 1)
addr->sun_path[n++] = *s;
else
{
free (addr);
gpg_err_set_errno (ENAMETOOLONG);
return NULL;
}
}
}
p = pend;
}
else if (*p == '\n')
break; /* Be nice and stop at the first LF. */
else if (n < sizeof addr->sun_path - 1)
addr->sun_path[n++] = *p;
else
{
free (addr);
gpg_err_set_errno (ENAMETOOLONG);
return NULL;
}
}
return addr;
}
#endif /*!HAVE_W32_SYSTEM*/
/* Return a new socket. Note that under W32 we consider a socket the
same as an System Handle; all functions using such a handle know
about this dual use and act accordingly. */
assuan_fd_t
_assuan_sock_new (assuan_context_t ctx, int domain, int type, int proto)
{
#ifdef HAVE_W32_SYSTEM
assuan_fd_t res;
if (domain == AF_UNIX || domain == AF_LOCAL)
domain = AF_INET;
res = _assuan_socket (ctx, domain, type, proto);
return res;
#else
return _assuan_socket (ctx, domain, type, proto);
#endif
}
int
_assuan_sock_set_flag (assuan_context_t ctx, assuan_fd_t sockfd,
const char *name, int value)
{
(void)ctx;
if (!strcmp (name, "cygwin"))
{
#ifdef HAVE_W32_SYSTEM
if (!value)
delete_cygwin_fd (sockfd);
else if (insert_cygwin_fd (sockfd))
return -1;
#else
/* Setting the Cygwin flag on non-Windows is ignored. */
#endif
}
else if (!strcmp (name, "tor-mode") || !strcmp (name, "socks"))
{
/* If SOCKFD is ASSUAN_INVALID_FD this controls global flag to
switch AF_INET and AF_INET6 into TOR mode by using a SOCKS5
proxy on localhost:9050. It may only be switched on and this
needs to be done before any new threads are started. Once
TOR mode has been enabled, TOR mode can be disabled for a
specific socket by using SOCKFD with a VALUE of 0. */
if (sockfd == ASSUAN_INVALID_FD)
{
if (tor_mode && !value)
{
gpg_err_set_errno (EPERM);
return -1; /* Clearing the global flag is not allowed. */
}
else if (value)
{
if (*name == 's')
tor_mode = SOCKS_PORT;
else
tor_mode = TOR_PORT;
}
}
else if (tor_mode && sockfd != ASSUAN_INVALID_FD)
{
/* Fixme: Disable/enable tormode for the given context. */
}
else
{
gpg_err_set_errno (EINVAL);
return -1;
}
}
else
{
gpg_err_set_errno (EINVAL);
return -1;
}
return 0;
}
int
_assuan_sock_get_flag (assuan_context_t ctx, assuan_fd_t sockfd,
const char *name, int *r_value)
{
(void)ctx;
if (!strcmp (name, "cygwin"))
{
#ifdef HAVE_W32_SYSTEM
*r_value = is_cygwin_fd (sockfd);
#else
*r_value = 0;
#endif
}
else if (!strcmp (name, "tor-mode"))
{
/* FIXME: Find tor-mode for the given socket. */
*r_value = tor_mode == TOR_PORT;
}
else if (!strcmp (name, "socks"))
{
*r_value = tor_mode == SOCKS_PORT;
}
else
{
gpg_err_set_errno (EINVAL);
return -1;
}
return 0;
}
/* Read NBYTES from SOCKFD into BUFFER. Return 0 on success. Handle
EAGAIN and EINTR. */
static int
do_readn (assuan_context_t ctx, assuan_fd_t sockfd,
void *buffer, size_t nbytes)
{
char *p = buffer;
ssize_t n;
while (nbytes)
{
n = _assuan_read (ctx, sockfd, p, nbytes);
if (n < 0 && errno == EINTR)
;
else if (n < 0 && errno == EAGAIN)
_assuan_usleep (ctx, 100000); /* 100ms */
else if (n < 0)
return -1;
else if (!n)
{
gpg_err_set_errno (EIO);
return -1;
}
else
{
p += n;
nbytes -= n;
}
}
return 0;
}
/* Write NBYTES from BUFFER to SOCKFD. Return 0 on success; on error
return -1 and set ERRNO. */
static int
do_writen (assuan_context_t ctx, assuan_fd_t sockfd,
const void *buffer, size_t nbytes)
{
int ret;
ret = _assuan_write (ctx, sockfd, buffer, nbytes);
if (ret >= 0 && ret != nbytes)
{
gpg_err_set_errno (EIO);
ret = -1;
}
else if (ret >= 0)
ret = 0;
return ret;
}
#define TIMEOUT_NOT_WAITING_SOCKS5_FOREVER 1 /* in second(s) */
/* Connect using the SOCKS5 protocol. */
static int
socks5_connect (assuan_context_t ctx, assuan_fd_t sock,
unsigned short socksport,
const char *credentials,
const char *hostname, unsigned short hostport,
struct sockaddr *addr, socklen_t length)
{
int ret;
/* struct sockaddr_in6 proxyaddr_in6; */
struct sockaddr_in proxyaddr_in;
struct sockaddr *proxyaddr;
size_t proxyaddrlen;
union {
struct sockaddr *addr;
struct sockaddr_in *addr_in;
struct sockaddr_in6 *addr_in6;
} addru;
unsigned char buffer[22+512]; /* The extra 512 gives enough space
for username/password or the
hostname. */
size_t buflen, hostnamelen;
int method;
fd_set fds;
struct timeval tv = { TIMEOUT_NOT_WAITING_SOCKS5_FOREVER, 0 };
addru.addr = addr;
FD_ZERO (&fds);
FD_SET (HANDLE2SOCKET (sock), &fds);
/* memset (&proxyaddr_in6, 0, sizeof proxyaddr_in6); */
memset (&proxyaddr_in, 0, sizeof proxyaddr_in);
/* Either HOSTNAME or ADDR may be given. */
if (hostname && addr)
{
gpg_err_set_errno (EINVAL);
return -1;
}
/* If a hostname is given it must fit into our buffer and it must be
less than 256 so that its length can be encoded in one byte. */
hostnamelen = hostname? strlen (hostname) : 0;
if (hostnamelen > 255)
{
gpg_err_set_errno (ENAMETOOLONG);
return -1;
}
/* Connect to local host. */
/* Fixme: First try to use IPv6 but note that
_assuan_sock_connect_byname created the socket with AF_INET. */
proxyaddr_in.sin_family = AF_INET;
proxyaddr_in.sin_port = htons (socksport);
proxyaddr_in.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
proxyaddr = (struct sockaddr *)&proxyaddr_in;
proxyaddrlen = sizeof proxyaddr_in;
ret = _assuan_connect (ctx, sock, proxyaddr, proxyaddrlen);
if (ret && socksport == TOR_PORT && errno == ECONNREFUSED)
{
/* Standard Tor port failed - try the Tor browser port. */
proxyaddr_in.sin_port = htons (TOR_PORT2);
ret = _assuan_connect (ctx, sock, proxyaddr, proxyaddrlen);
}
/* If we get an EINPROGRESS here the caller is trying to do a
* non-blocking connect (e.g. for custom time out handling) which
* fails here. The easiest fix would be to allow the client to tell
* us the timeout value and we do the timeout handling later on in the
* Socks protocol. */
if (ret)
return ret;
buffer[0] = 5; /* RFC-1928 VER field. */
buffer[1] = 1; /* NMETHODS */
if (credentials)
method = 2; /* Method: username/password authentication. */
else
method = 0; /* Method: No authentication required. */
buffer[2] = method;
/* Negotiate method. */
ret = do_writen (ctx, sock, buffer, 3);
if (ret)
return ret;
/* There may be a different service at the port, which doesn't
respond. Not to be bothred by such a service. */
/* FIXME: Since the process may block on select, it should be
npth_select to release thread scheduling if nPth is enabled.
Ideally, select is better to be in the system hooks. However, it
is considered OK to use select directly; Normal use case is three
steps: detect SOCKS5 service before nPth use, configure nPth
system hooks, and then use socks5_connect. For the first call,
select indeed blocks, but it's only single thread. For
succeeding calls, this select should soon return successfully.
*/
ret = select (HANDLE2SOCKET (sock)+1, &fds, NULL, NULL, &tv);
if (!ret)
{
gpg_err_set_errno (ETIMEDOUT);
return -1;
}
ret = do_readn (ctx, sock, buffer, 2);
if (ret)
return ret;
if (buffer[0] != 5 || buffer[1] != method )
{
/* Socks server returned wrong version or does not support our
requested method. */
gpg_err_set_errno (ENOTSUP); /* Fixme: Is there a better errno? */
return -1;
}
if (credentials)
{
const char *password;
int ulen, plen;
password = strchr (credentials, ':');
if (!password)
{
gpg_err_set_errno (EINVAL); /* No password given. */
return -1;
}
ulen = password - credentials;
password++;
plen = strlen (password);
if (!ulen || ulen > 255 || !plen || plen > 255)
{
gpg_err_set_errno (EINVAL);
return -1;
}
buffer[0] = 1; /* VER of the sub-negotiation. */
buffer[1] = ulen;
buflen = 2;
memcpy (buffer+buflen, credentials, ulen);
buflen += ulen;
buffer[buflen++] = plen;
memcpy (buffer+buflen, password, plen);
buflen += plen;
ret = do_writen (ctx, sock, buffer, buflen);
wipememory (buffer, buflen);
if (ret)
return ret;
ret = do_readn (ctx, sock, buffer, 2);
if (ret)
return ret;
if (buffer[0] != 1)
{
/* SOCKS server returned wrong version. */
gpg_err_set_errno (EPROTONOSUPPORT);
return -1;
}
if (buffer[1])
{
/* SOCKS server denied access. */
gpg_err_set_errno (EACCES);
return -1;
}
}
if (hostname && !*hostname && !hostport)
{
/* Empty hostname given. Stop right here to allow the caller to
do the actual proxy request. */
return 0;
}
/* Send request details (rfc-1928, 4). */
buffer[0] = 5; /* VER */
buffer[1] = 1; /* CMD = CONNECT */
buffer[2] = 0; /* RSV */
if (hostname)
{
buffer[3] = 3; /* ATYP = DOMAINNAME */
buflen = 4;
buffer[buflen++] = hostnamelen;
memcpy (buffer+buflen, hostname, hostnamelen);
buflen += hostnamelen;
buffer[buflen++] = (hostport >> 8); /* DST.PORT */
buffer[buflen++] = hostport;
}
else if (addr->sa_family == AF_INET6)
{
buffer[3] = 4; /* ATYP = IPv6 */
memcpy (buffer+ 4, &addru.addr_in6->sin6_addr.s6_addr, 16); /* DST.ADDR */
memcpy (buffer+20, &addru.addr_in6->sin6_port, 2); /* DST.PORT */
buflen = 22;
}
else
{
buffer[3] = 1; /* ATYP = IPv4 */
memcpy (buffer+4, &addru.addr_in->sin_addr.s_addr, 4); /* DST.ADDR */
memcpy (buffer+8, &addru.addr_in->sin_port, 2); /* DST.PORT */
buflen = 10;
}
ret = do_writen (ctx, sock, buffer, buflen);
if (ret)
return ret;
ret = do_readn (ctx, sock, buffer, 10 /* Length for IPv4 */);
if (ret)
return ret;
if (buffer[0] != 5 || buffer[2] != 0 )
{
/* Socks server returned wrong version or the reserved field is
not zero. */
gpg_err_set_errno (EPROTONOSUPPORT);
return -1;
}
if (buffer[1])
{
switch (buffer[1])
{
case 0x01: /* General SOCKS server failure. */
gpg_err_set_errno (ENETDOWN);
break;
case 0x02: /* Connection not allowed by ruleset. */
gpg_err_set_errno (EACCES);
break;
case 0x03: /* Network unreachable */
gpg_err_set_errno (ENETUNREACH);
break;
case 0x04: /* Host unreachable */
gpg_err_set_errno (EHOSTUNREACH);
break;
case 0x05: /* Connection refused */
gpg_err_set_errno (ECONNREFUSED);
break;
case 0x06: /* TTL expired */
gpg_err_set_errno (ETIMEDOUT);
break;
case 0x08: /* Address type not supported */
gpg_err_set_errno (EPROTONOSUPPORT);
break;
case 0x07: /* Command not supported */
default:
gpg_err_set_errno (ENOTSUP); /* Fixme: Is there a better errno? */
}
return -1;
}
if (buffer[3] == 4)
{
/* ATYP indicates a v6 address. We need to read the remaining
12 bytes. */
ret = do_readn (ctx, sock, buffer+10, 12);
if (ret)
return ret;
}
/* FIXME: We have not way to store the actual address used by the
server. */
return 0;
}
/* Return true if SOCKS shall be used. This is the case if tor_mode
is enabled and the desired address is not the loopback
address. */
static int
use_socks (struct sockaddr *addr)
{
union {
struct sockaddr *addr;
struct sockaddr_in *addr_in;
struct sockaddr_in6 *addr_in6;
} addru;
addru.addr = addr;
if (!tor_mode)
return 0;
else if (addr->sa_family == AF_INET6)
{
const unsigned char *s;
int i;
s = (unsigned char *)&addru.addr_in6->sin6_addr.s6_addr;
if (s[15] != 1)
return 1; /* Last octet is not 1 - not the loopback address. */
for (i=0; i < 15; i++, s++)
if (*s)
return 1; /* Non-zero octet found - not the loopback address. */
return 0; /* This is the loopback address. */
}
else if (addr->sa_family == AF_INET)
{
if (*(unsigned char*)&addru.addr_in->sin_addr.s_addr == 127)
return 0; /* Loopback (127.0.0.0/8) */
return 1;
}
else
return 0;
}
static assuan_fd_t
_assuan_sock_accept (assuan_context_t ctx, assuan_fd_t sockfd,
struct sockaddr *addr, socklen_t *p_addrlen)
{
(void)ctx;
#ifdef HAVE_W32_SYSTEM
assuan_fd_t res;
res = SOCKET2HANDLE (accept (HANDLE2SOCKET (sockfd), addr, p_addrlen));
if (res == SOCKET2HANDLE (INVALID_SOCKET))
gpg_err_set_errno (_assuan_sock_wsa2errno (WSAGetLastError ()));
return res;
#else
return accept (sockfd, addr, p_addrlen);
#endif
}
int
_assuan_sock_connect (assuan_context_t ctx, assuan_fd_t sockfd,
struct sockaddr *addr, int addrlen)
{
#ifdef HAVE_W32_SYSTEM
if (addr->sa_family == AF_LOCAL || addr->sa_family == AF_UNIX)
{
struct sockaddr_in myaddr;
struct sockaddr_un *unaddr;
unsigned short port;
char nonce[16];
int cygwin;
int ret;
unaddr = (struct sockaddr_un *)addr;
if (read_port_and_nonce (unaddr->sun_path, &port, nonce, &cygwin))
return -1;
myaddr.sin_family = AF_INET;
myaddr.sin_port = htons (port);
myaddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
/* Set return values. */
unaddr->sun_family = myaddr.sin_family;
unaddr->sun_port = myaddr.sin_port;
unaddr->sun_addr.s_addr = myaddr.sin_addr.s_addr;
ret = _assuan_connect (ctx, sockfd,
(struct sockaddr *)&myaddr, sizeof myaddr);
if (!ret)
{
/* Send the nonce. */
ret = do_writen (ctx, sockfd, nonce, 16);
if (!ret && cygwin)
{
char buffer[16];
/* The client sends the nonce back - not useful. We do
a dummy read. */
ret = do_readn (ctx, sockfd, buffer, 16);
if (!ret)
{
/* Send our credentials. */
int n = getpid ();
memcpy (buffer, &n, 4);
memset (buffer+4, 0, 4); /* uid = gid = 0 */
ret = do_writen (ctx, sockfd, buffer, 8);
if (!ret)
{
/* Receive credentials. We don't need them. */
ret = do_readn (ctx, sockfd, buffer, 8);
}
}
}
}
return ret;
}
else if (use_socks (addr))
{
return socks5_connect (ctx, sockfd, tor_mode,
NULL, NULL, 0, addr, addrlen);
}
else
{
return _assuan_connect (ctx, sockfd, addr, addrlen);
}
#else
# if HAVE_STAT
if (addr->sa_family == AF_LOCAL || addr->sa_family == AF_UNIX)
{
struct sockaddr_un *unaddr;
struct stat statbuf;
int redirect, res;
unaddr = (struct sockaddr_un *)addr;
if (!stat (unaddr->sun_path, &statbuf)
&& !S_ISSOCK (statbuf.st_mode)
&& S_ISREG (statbuf.st_mode))
{
/* The given socket file is not a socket but a regular file.
We use the content of that file to redirect to another
socket file. This can be used to use sockets on file
systems which do not support sockets or if for example a
home directory is shared by several machines. */
unaddr = eval_redirection (unaddr->sun_path, &redirect);
if (unaddr)
{
res = _assuan_connect (ctx, sockfd, (struct sockaddr *)unaddr,
SUN_LEN (unaddr));
free (unaddr);
return res;
}
if (redirect)
return -1;
/* Continue using the standard connect. */
}
}
# endif /*HAVE_STAT*/
if (use_socks (addr))
{
return socks5_connect (ctx, sockfd, tor_mode,
NULL, NULL, 0, addr, addrlen);
}
else
{
return _assuan_connect (ctx, sockfd, addr, addrlen);
}
#endif
}
/* Connect to HOST specified as host name on PORT. The current
implementation requires that either the flags ASSUAN_SOCK_SOCKS or
ASSUAN_SOCK_TOR are given in FLAGS. On success a new socket is
returned; on error ASSUAN_INVALID_FD is returned and ERRNO set. If
CREDENTIALS is not NULL, it is a string used for password based
authentication. Username and password are separated by a colon.
RESERVED must be 0. By passing HOST and PORT as 0 the function can
be used to check for proxy availability: If the proxy is available
a socket will be returned which the caller should then close. */
assuan_fd_t
_assuan_sock_connect_byname (assuan_context_t ctx, const char *host,
unsigned short port, int reserved,
const char *credentials, unsigned int flags)
{
assuan_fd_t fd;
unsigned short socksport;
if ((flags & ASSUAN_SOCK_TOR))
socksport = TOR_PORT;
else if ((flags & ASSUAN_SOCK_SOCKS))
socksport = SOCKS_PORT;
else
{
gpg_err_set_errno (ENOTSUP);
return ASSUAN_INVALID_FD;
}
if (host && !*host)
{
/* Error out early on an empty host name. See below. */
gpg_err_set_errno (EINVAL);
return ASSUAN_INVALID_FD;
}
fd = _assuan_sock_new (ctx, AF_INET, SOCK_STREAM, 0);
if (fd == ASSUAN_INVALID_FD)
return fd;
/* For HOST being NULL we pass an empty string which indicates to
socks5_connect to stop midway during the proxy negotiation. Note
that we can't pass NULL directly as this indicates IP address
mode to the called function. */
if (socks5_connect (ctx, fd, socksport,
credentials, host? host:"", port, NULL, 0))
{
int save_errno = errno;
assuan_sock_close (fd);
gpg_err_set_errno (save_errno);
return ASSUAN_INVALID_FD;
}
return fd;
}
int
_assuan_sock_bind (assuan_context_t ctx, assuan_fd_t sockfd,
struct sockaddr *addr, int addrlen)
{
#ifdef HAVE_W32_SYSTEM
if (addr->sa_family == AF_LOCAL || addr->sa_family == AF_UNIX)
{
struct sockaddr_in myaddr;
struct sockaddr_un *unaddr;
HANDLE filehd;
int len = sizeof myaddr;
int rc;
union {
char data[16];
int aint[4];
} nonce;
char tmpbuf[50+16];
DWORD nwritten;
if (get_nonce (nonce.data, 16))
return -1;
unaddr = (struct sockaddr_un *)addr;
myaddr.sin_port = 0;
myaddr.sin_family = AF_INET;
myaddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
filehd = MyCreateFile (unaddr->sun_path,
GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
CREATE_NEW,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (filehd == INVALID_HANDLE_VALUE)
{
if (GetLastError () == ERROR_FILE_EXISTS)
gpg_err_set_errno (EADDRINUSE);
return -1;
}
rc = bind (HANDLE2SOCKET (sockfd), (struct sockaddr *)&myaddr, len);
if (!rc)
rc = getsockname (HANDLE2SOCKET (sockfd),
(struct sockaddr *)&myaddr, &len);
if (rc)
{
int save_e = errno;
CloseHandle (filehd);
MyDeleteFile (unaddr->sun_path);
gpg_err_set_errno (save_e);
return rc;
}
if (is_cygwin_fd (sockfd))
{
snprintf (tmpbuf, sizeof tmpbuf,
"!%d s %08x-%08x-%08x-%08x",
ntohs (myaddr.sin_port),
nonce.aint[0], nonce.aint[1], nonce.aint[2], nonce.aint[3]);
len = strlen (tmpbuf) + 1;
}
else
{
snprintf (tmpbuf, sizeof tmpbuf-16, "%d\n", ntohs (myaddr.sin_port));
len = strlen (tmpbuf);
memcpy (tmpbuf+len, nonce.data,16);
len += 16;
}
if (!WriteFile (filehd, tmpbuf, len, &nwritten, NULL))
{
CloseHandle (filehd);
MyDeleteFile (unaddr->sun_path);
gpg_err_set_errno (EIO);
return -1;
}
CloseHandle (filehd);
return 0;
}
else
{
int res = bind (HANDLE2SOCKET(sockfd), addr, addrlen);
if (res < 0)
gpg_err_set_errno ( _assuan_sock_wsa2errno (WSAGetLastError ()));
return res;
}
#else
return bind (sockfd, addr, addrlen);
#endif
}
/* Setup the ADDR structure for a Unix domain socket with the socket
name FNAME. If this is a redirected socket and R_REDIRECTED is not
NULL, it will be setup for the real socket. Returns 0 on success
and stores 1 at R_REDIRECTED if it is a redirected socket. On
error -1 is returned and ERRNO will be set. */
int
_assuan_sock_set_sockaddr_un (const char *fname, struct sockaddr *addr,
int *r_redirected)
{
struct sockaddr_un *unaddr = (struct sockaddr_un *)addr;
#if !defined(HAVE_W32_SYSTEM) && defined(HAVE_STAT)
struct stat statbuf;
#endif
if (r_redirected)
*r_redirected = 0;
#if !defined(HAVE_W32_SYSTEM) && defined(HAVE_STAT)
if (r_redirected
&& !stat (fname, &statbuf)
&& !S_ISSOCK (statbuf.st_mode)
&& S_ISREG (statbuf.st_mode))
{
/* The given socket file is not a socket but a regular file. We
use the content of that file to redirect to another socket
file. This can be used to use sockets on file systems which
do not support sockets or if for example a home directory is
shared by several machines. */
struct sockaddr_un *unaddr_new;
int redirect;
unaddr_new = eval_redirection (fname, &redirect);
if (unaddr_new)
{
memcpy (unaddr, unaddr_new, sizeof *unaddr);
free (unaddr_new);
*r_redirected = 1;
return 0;
}
if (redirect)
{
*r_redirected = 1;
return -1; /* Error. */
}
/* Fallback to standard setup. */
}
#endif /*!HAVE_W32_SYSTEM && HAVE_STAT*/
if (strlen (fname)+1 >= sizeof unaddr->sun_path)
{
gpg_err_set_errno (ENAMETOOLONG);
return -1;
}
memset (unaddr, 0, sizeof *unaddr);
unaddr->sun_family = AF_LOCAL;
strncpy (unaddr->sun_path, fname, sizeof unaddr->sun_path - 1);
unaddr->sun_path[sizeof unaddr->sun_path - 1] = 0;
return 0;
}
int
_assuan_sock_get_nonce (assuan_context_t ctx, struct sockaddr *addr,
int addrlen, assuan_sock_nonce_t *nonce)
{
#ifdef HAVE_W32_SYSTEM
if (addr->sa_family == AF_LOCAL || addr->sa_family == AF_UNIX)
{
struct sockaddr_un *unaddr;
unsigned short port;
int dummy;
if (sizeof nonce->nonce != 16)
{
gpg_err_set_errno (EINVAL);
return -1;
}
nonce->length = 16;
unaddr = (struct sockaddr_un *)addr;
if (read_port_and_nonce (unaddr->sun_path, &port, nonce->nonce, &dummy))
return -1;
}
else
{
nonce->length = 42; /* Arbitrary value to detect unitialized nonce. */
nonce->nonce[0] = 42;
}
#else
(void)addr;
(void)addrlen;
nonce->length = 0;
#endif
return 0;
}
int
_assuan_sock_check_nonce (assuan_context_t ctx, assuan_fd_t fd,
assuan_sock_nonce_t *nonce)
{
#ifdef HAVE_W32_SYSTEM
char buffer[16];
int n;
if (sizeof nonce->nonce != 16)
{
gpg_err_set_errno (EINVAL);
return -1;
}
if (nonce->length == 42 && nonce->nonce[0] == 42)
return 0; /* Not a Unix domain socket. */
if (nonce->length != 16)
{
gpg_err_set_errno (EINVAL);
return -1;
}
if (do_readn (ctx, fd, buffer, 16))
return -1;
if (memcmp (buffer, nonce->nonce, 16))
{
gpg_err_set_errno (EACCES);
return -1;
}
if (is_cygwin_fd (fd))
{
/* Send the nonce back to the client. */
if (do_writen (ctx, fd, buffer, 16))
return -1;
/* Read the credentials. Cygwin uses the
struct ucred { pid_t pid; uid_t uid; gid_t gid; };
with pid_t being an int (4 bytes) and uid_t and gid_t being
shorts (2 bytes). Thus we need to read 8 bytes. However we
we ignore the values because they are not kernel controlled. */
if (do_readn (ctx, fd, buffer, 8))
return -1;
/* Send our credentials: We use the uid and gid we received but
our own pid. */
n = getpid ();
memcpy (buffer, &n, 4);
if (do_writen (ctx, fd, buffer, 8))
return -1;
}
#else
(void)fd;
(void)nonce;
#endif
return 0;
}
/* Public API. */
gpg_error_t
assuan_sock_init ()
{
gpg_error_t err;
#ifdef HAVE_W32_SYSTEM
WSADATA wsadat;
#endif
if (sock_ctx != NULL)
return 0;
#ifdef HAVE_W32_SYSTEM
InitializeCriticalSection (&cygwin_fdtable_cs);
#endif
err = assuan_new (&sock_ctx);
sock_ctx->flags.is_socket = 1;
#ifdef HAVE_W32_SYSTEM
if (! err)
WSAStartup (0x202, &wsadat);
#endif
return err;
}
void
assuan_sock_deinit ()
{
if (sock_ctx == NULL)
return;
#ifdef HAVE_W32_SYSTEM
WSACleanup ();
#endif
assuan_release (sock_ctx);
sock_ctx = NULL;
#ifdef HAVE_W32_SYSTEM
DeleteCriticalSection (&cygwin_fdtable_cs);
#endif
}
int
assuan_sock_close (assuan_fd_t fd)
{
#ifdef HAVE_W32_SYSTEM
if (fd != ASSUAN_INVALID_FD)
delete_cygwin_fd (fd);
#endif
return _assuan_close (sock_ctx, fd);
}
assuan_fd_t
assuan_sock_new (int domain, int type, int proto)
{
return _assuan_sock_new (sock_ctx, domain, type, proto);
}
int
assuan_sock_set_flag (assuan_fd_t sockfd, const char *name, int value)
{
return _assuan_sock_set_flag (sock_ctx, sockfd, name, value);
}
int
assuan_sock_get_flag (assuan_fd_t sockfd, const char *name, int *r_value)
{
return _assuan_sock_get_flag (sock_ctx, sockfd, name, r_value);
}
assuan_fd_t
assuan_sock_accept (assuan_fd_t sockfd, struct sockaddr *addr,
socklen_t *p_addrlen)
{
return _assuan_sock_accept (sock_ctx, sockfd, addr, p_addrlen);
}
int
assuan_sock_connect (assuan_fd_t sockfd, struct sockaddr *addr, int addrlen)
{
return _assuan_sock_connect (sock_ctx, sockfd, addr, addrlen);
}
assuan_fd_t
assuan_sock_connect_byname (const char *host, unsigned short port,
int reserved, const char *credentials,
unsigned int flags)
{
return _assuan_sock_connect_byname (sock_ctx,
host, port, reserved, credentials, flags);
}
int
assuan_sock_bind (assuan_fd_t sockfd, struct sockaddr *addr, int addrlen)
{
return _assuan_sock_bind (sock_ctx, sockfd, addr, addrlen);
}
int
assuan_sock_set_sockaddr_un (const char *fname, struct sockaddr *addr,
int *r_redirected)
{
return _assuan_sock_set_sockaddr_un (fname, addr, r_redirected);
}
int
assuan_sock_get_nonce (struct sockaddr *addr, int addrlen,
assuan_sock_nonce_t *nonce)
{
return _assuan_sock_get_nonce (sock_ctx, addr, addrlen, nonce);
}
int
assuan_sock_check_nonce (assuan_fd_t fd, assuan_sock_nonce_t *nonce)
{
return _assuan_sock_check_nonce (sock_ctx, fd, nonce);
}
void
assuan_sock_set_system_hooks (assuan_system_hooks_t system_hooks)
{
if (sock_ctx)
_assuan_system_hooks_copy (&sock_ctx->system, system_hooks);
}
diff --git a/src/gpgcedev.c b/src/gpgcedev.c
deleted file mode 100644
index c841ec2..0000000
--- a/src/gpgcedev.c
+++ /dev/null
@@ -1,1640 +0,0 @@
-/* gpgcedrv.c - WindowsCE device driver to implement pipe and syslog.
- * Copyright (C) 2010 Free Software Foundation, Inc.
- *
- * This file is part of Assuan.
- *
- * Assuan 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 3 of
- * the License, or (at your option) any later version.
- *
- * Assuan 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
- * Lesser 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 .
- * SPDX-License-Identifier: LGPL-3.0+
- */
-
-#include
-#include
-#include
-#include
-#include
-#include
-
-/* FIXME Cancel not handled. */
-
-#define DBGFILENAME "\\gpgcedev.dbg"
-#define LOGFILENAME L"\\gpgcedev.log"
-#define GPGCEDEV_KEY_NAME L"Drivers\\GnuPG_Device"
-#define GPGCEDEV_KEY_NAME2 L"Drivers\\GnuPG_Log"
-
-
-/* Missing IOCTLs in the current mingw32ce. */
-#ifndef IOCTL_PSL_NOTIFY
-# define FILE_DEVICE_PSL 259
-# define IOCTL_PSL_NOTIFY \
- CTL_CODE (259, 255, METHOD_NEITHER, FILE_ANY_ACCESS)
-#endif /*IOCTL_PSL_NOTIFY*/
-
-
-/* The IOCTL to return the rendezvous id of the handle.
-
- The required outbuf parameter is the address of a variable to store
- the rendezvous ID, which is a LONG value. */
-#define GPGCEDEV_IOCTL_GET_RVID \
- CTL_CODE (FILE_DEVICE_STREAMS, 2048, METHOD_BUFFERED, FILE_ANY_ACCESS)
-
-/* The IOCTL used to create the pipe.
-
- The caller sends this IOCTL to the read or the write handle. The
- required inbuf parameter is address of a variable holding the
- rendezvous id of the pipe's other end. There is one possible
- problem with the code: If a pipe is kept in non-rendezvous state
- until after the rendezvous ids overflow, it is possible that the
- wrong end will be used. However this is not a realistic scenario. */
-#define GPGCEDEV_IOCTL_MAKE_PIPE \
- CTL_CODE (FILE_DEVICE_STREAMS, 2049, METHOD_BUFFERED, FILE_ANY_ACCESS)
-
-/* The IOCTL used to unblock a blocking thread.
-
- The caller sends this IOCTL to the read or the write handle. No
- parameter is required. The effect is that a reader or writer
- blocked on the same handle is unblocked (and will return
- ERROR_BUSY). Note that the operation can be repeated, if so
- desired. The state of the pipe itself will not be affected in any
- way. */
-#define GPGCEDEV_IOCTL_UNBLOCK \
- CTL_CODE (FILE_DEVICE_STREAMS, 2050, METHOD_BUFFERED, FILE_ANY_ACCESS)
-
-/* The IOCTL to assign a rendezvous id to a process.
-
- The required inbuf parameters are the rendezvous ID to assign and
- the process ID of the process receiving the RVID. The handle on
- which this is called is not really used at all! */
-#define GPGCEDEV_IOCTL_ASSIGN_RVID \
- CTL_CODE (FILE_DEVICE_STREAMS, 2051, METHOD_BUFFERED, FILE_ANY_ACCESS)
-
-
-/* An object to describe a pipe. */
-struct pipeimpl_s
-{
- CRITICAL_SECTION critsect; /* Lock for all members. */
-
- int refcnt;
- char *buffer;
- size_t buffer_size;
- size_t buffer_len; /* The valid length of the bufer. */
- size_t buffer_pos; /* The actual read position. */
-
-#define PIPE_FLAG_NO_READER 1
-#define PIPE_FLAG_NO_WRITER 2
-#define PIPE_FLAG_UNBLOCK_READER 4
-#define PIPE_FLAG_UNBLOCK_WRITER 8
-#define PIPE_FLAG_HALT_MONITOR 16
- int flags;
-
- HANDLE space_available; /* Set if space is available. */
- HANDLE data_available; /* Set if data is available. */
-
- /* For the monitor thread started by ASSIGN_RVID. */
- HANDLE monitor_proc;
- int monitor_access;
- LONG monitor_rvid;
-};
-typedef struct pipeimpl_s *pipeimpl_t;
-
-
-/* An object to describe a logging context. We can't write directly
- to the log stream because we want to do line buffering and thus we
- need to store data until we see LF. */
-struct logimpl_s;
-typedef struct logimpl_s *logimpl_t;
-struct logimpl_s
-{
- unsigned long logid; /* An identifier for a log source. */
- unsigned long dsec; /* Tenth of a second since system start. */
- char *line; /* Malloced line buffer. */
- size_t linesize; /* Allocated size of LINE. */
- size_t linelen; /* Used length of the line. */
- int truncated; /* Indicates a truncated log line. */
-};
-
-
-
-/* An object to store information pertaining to an open-context. */
-struct opnctx_s;
-typedef struct opnctx_s *opnctx_t;
-struct opnctx_s
-{
- int inuse; /* True if this object has valid data. */
- int is_log; /* True if this describes a log device. */
- LONG rvid; /* The unique rendezvous identifier. */
- DWORD access_code;/* Value from OpenFile. */
- DWORD share_mode; /* Value from OpenFile. */
-
- /* The state shared by all pipe users. Only used if IS_LOG is false. */
- pipeimpl_t pipeimpl;
-
- /* The state used to implement a log stream. Only used if IS_LOG is true. */
- logimpl_t logimpl;
-};
-
-/* A malloced table of open-context and the number of allocated slots. */
-static opnctx_t opnctx_table;
-static size_t opnctx_table_size;
-/* The macros make sure that 0 is never a valid openctx_arg. */
-#define OPNCTX_TO_IDX(ctx_arg) (((ctx_arg) - opnctx_table) + 1)
-#define OPNCTX_FROM_IDX(idx) (&opnctx_table[(idx) - 1])
-#define OPNCTX_VALID_IDX_P(idx) ((idx) > 0 && (idx) <= opnctx_table_size)
-
-typedef struct monitor_s *monitor_t;
-struct monitor_s
-{
- int inuse; /* True if this object has valid data. */
- pipeimpl_t pipeimpl;
-};
-static monitor_t monitor_table;
-static size_t monitor_table_size;
-
-/* A criticial section object used to protect the OPNCTX_TABLE and
- MONITOR_TABLE. */
-static CRITICAL_SECTION opnctx_table_cs;
-
-
-
-/* A global object to control the logging. */
-struct {
- CRITICAL_SECTION lock; /* Lock for this structure. */
- HANDLE filehd; /* Handle of the log output file. */
- int references; /* Number of objects references this one. */
-} logcontrol;
-
-
-/* We don't need a device context for the pipe thus we use the address
- of the critical section object for it. */
-#define PIPECTX_VALUE ((DWORD)(&opnctx_table_cs))
-
-/* The device context for the log device is the address of our
- control structure. */
-#define LOGCTX_VALUE ((DWORD)(&logcontrol))
-
-
-/* True if we have enabled debugging. */
-static int enable_debug;
-
-/* True if logging has been enabled. */
-static int enable_logging;
-
-
-
-static void
-log_debug (const char *fmt, ...)
-{
- if (enable_debug)
- {
- va_list arg_ptr;
- FILE *fp;
-
- fp = fopen (DBGFILENAME, "a+");
- if (!fp)
- return;
- va_start (arg_ptr, fmt);
- vfprintf (fp, fmt, arg_ptr);
- va_end (arg_ptr);
- fclose (fp);
- }
-}
-
-
-/* Return a new rendezvous id. We will never return an RVID of 0. */
-static LONG
-create_rendezvous_id (void)
-{
- static LONG rendezvous_id;
- LONG rvid;
-
- while (!(rvid = InterlockedIncrement (&rendezvous_id)))
- ;
- return rvid;
-}
-
-/* Return a new log id. These log ids are used to identify log lines
- send to the same device; ie. for each CreateFile("GPG2:") a new log
- id is assigned. We will ever return a log id of 0. */
-static LONG
-create_log_id (void)
-{
- static LONG log_id;
- LONG lid;
-
- while (!(lid = InterlockedIncrement (&log_id)))
- ;
- return lid;
-}
-
-
-
-pipeimpl_t
-pipeimpl_new (void)
-{
- pipeimpl_t pimpl;
-
- pimpl = malloc (sizeof (*pimpl));
- if (!pimpl)
- return NULL;
-
- InitializeCriticalSection (&pimpl->critsect);
- pimpl->refcnt = 1;
- pimpl->buffer_size = 512;
- pimpl->buffer = malloc (pimpl->buffer_size);
- if (!pimpl->buffer)
- {
- DeleteCriticalSection (&pimpl->critsect);
- free (pimpl);
- return NULL;
- }
- pimpl->buffer_len = 0;
- pimpl->buffer_pos = 0;
- pimpl->flags = 0;
- pimpl->space_available = CreateEvent (NULL, FALSE, FALSE, NULL);
- if (!pimpl->space_available)
- {
- free (pimpl->buffer);
- DeleteCriticalSection (&pimpl->critsect);
- free (pimpl);
- return NULL;
- }
- pimpl->data_available = CreateEvent (NULL, FALSE, FALSE, NULL);
- if (!pimpl->data_available)
- {
- CloseHandle (pimpl->space_available);
- free (pimpl->buffer);
- DeleteCriticalSection (&pimpl->critsect);
- free (pimpl);
- return NULL;
- }
- pimpl->monitor_proc = INVALID_HANDLE_VALUE;
- pimpl->monitor_access = 0;
- pimpl->monitor_rvid = 0;
- return pimpl;
-}
-
-
-/* PIMPL must be locked. It is unlocked at exit. */
-void
-pipeimpl_unref (pipeimpl_t pimpl)
-{
- int release = 0;
-
- if (!pimpl)
- return;
-
- log_debug ("pipeimpl_unref (%p): dereference\n", pimpl);
-
- if (--pimpl->refcnt == 0)
- release = 1;
- LeaveCriticalSection (&pimpl->critsect);
-
- if (! release)
- return;
-
- log_debug ("pipeimpl_unref (%p): release\n", pimpl);
-
- DeleteCriticalSection (&pimpl->critsect);
- if (pimpl->buffer)
- {
- free (pimpl->buffer);
- pimpl->buffer = NULL;
- pimpl->buffer_size = 0;
- }
- if (pimpl->space_available != INVALID_HANDLE_VALUE)
- {
- CloseHandle (pimpl->space_available);
- pimpl->space_available = INVALID_HANDLE_VALUE;
- }
- if (pimpl->data_available != INVALID_HANDLE_VALUE)
- {
- CloseHandle (pimpl->data_available);
- pimpl->data_available = INVALID_HANDLE_VALUE;
- }
-}
-
-
-
-/* Allocate a new log structure. */
-logimpl_t
-logimpl_new (void)
-{
- logimpl_t limpl;
-
- limpl = calloc (1, sizeof *limpl);
- if (!limpl)
- return NULL;
- limpl->logid = create_log_id ();
- limpl->linesize = 256;
- limpl->line = malloc (limpl->linesize);
- if (!limpl->line)
- {
- free (limpl);
- return NULL;
- }
-
- return limpl;
-}
-
-
-/* There is no need to lock LIMPL, thus is a dummy function. */
-void
-logimpl_unref (logimpl_t limpl)
-{
- (void)limpl;
-}
-
-
-/* Flush a pending log line. */
-static void
-logimpl_flush (logimpl_t limpl)
-{
- if (!limpl->linelen || !enable_logging)
- return;
-
- EnterCriticalSection (&logcontrol.lock);
- if (logcontrol.filehd == INVALID_HANDLE_VALUE)
- logcontrol.filehd = CreateFile (LOGFILENAME, GENERIC_WRITE,
- FILE_SHARE_READ,
- NULL, OPEN_ALWAYS,
- FILE_ATTRIBUTE_NORMAL, NULL);
- if (!logcontrol.filehd)
- log_debug ("can't open log file: rc=%d\n", (int)GetLastError ());
- else
- {
- char buf[50];
- DWORD nwritten;
-
- snprintf (buf, sizeof buf,
- "%06lu/%lu//", limpl->dsec % 1000000, limpl->logid);
- if (!WriteFile (logcontrol.filehd, buf, strlen (buf), &nwritten, NULL))
- log_debug ("error writing log file: rc=%d\n", (int)GetLastError ());
- else if (!WriteFile (logcontrol.filehd,
- limpl->line, limpl->linelen, &nwritten, NULL))
- log_debug ("error writing log file: rc=%d\n", (int)GetLastError ());
-
- snprintf (buf, sizeof buf, "%s\n", limpl->truncated? "[...]":"");
- if (!WriteFile (logcontrol.filehd, buf, strlen (buf), &nwritten, NULL))
- log_debug ("error writing log file: rc=%d\n", (int)GetLastError ());
- }
-
- LeaveCriticalSection (&logcontrol.lock);
- limpl->linelen = 0;
- limpl->truncated = 0;
-}
-
-
-/* Return a new opnctx handle and mark it as used. Returns NULL and
- sets LastError on memory failure etc. opnctx_table_cs must be
- locked on entry and is locked on exit. Note that the returned
- pointer is only valid as long as opnctx_table_cs stays locked, as
- it is not stable under table reallocation. */
-static opnctx_t
-allocate_opnctx (int is_log)
-{
- opnctx_t opnctx = NULL;
- int idx;
-
- for (idx = 0; idx < opnctx_table_size; idx++)
- if (! opnctx_table[idx].inuse)
- break;
- if (idx == opnctx_table_size)
- {
- /* We need to increase the size of the table. The approach we
- take is straightforward to minimize the risk of bugs. */
- opnctx_t newtbl;
- size_t newsize = opnctx_table_size + 64;
-
- newtbl = calloc (newsize, sizeof *newtbl);
- if (!newtbl)
- goto leave;
- memcpy (newtbl, opnctx_table, opnctx_table_size * sizeof (*newtbl));
- free (opnctx_table);
- opnctx_table = newtbl;
- idx = opnctx_table_size;
- opnctx_table_size = newsize;
- }
- opnctx = &opnctx_table[idx];
- opnctx->inuse = 1;
- opnctx->is_log = is_log;
- opnctx->rvid = 0;
- opnctx->access_code = 0;
- opnctx->share_mode = 0;
- opnctx->pipeimpl = 0;
- opnctx->logimpl = 0;
-
- leave:
- return opnctx;
-}
-
-
-/* Verify context CTX, returns NULL if not valid and the pointer to
- the context if valid. opnctx_table_cs must be locked on entry and
- is locked on exit. Note that the returned pointer is only valid as
- long as opnctx_table_cs remains locked. */
-opnctx_t
-verify_opnctx (DWORD ctx_arg)
-{
- opnctx_t ctx;
-
- if (! OPNCTX_VALID_IDX_P (ctx_arg))
- {
- SetLastError (ERROR_INVALID_HANDLE);
- return NULL;
- }
- ctx = OPNCTX_FROM_IDX (ctx_arg);
-
- if (! ctx->inuse)
- {
- SetLastError (ERROR_INVALID_HANDLE);
- return NULL;
- }
- return ctx;
-}
-
-
-/* Return a new monitor handle and mark it as used. Returns NULL and
- sets LastError on memory failure etc. opnctx_table_cs must be
- locked on entry and is locked on exit. Note that the returned
- pointer is only valid as long as opnctx_table_cs stays locked, as
- it is not stable under table reallocation. */
-static monitor_t
-allocate_monitor (void)
-{
- monitor_t monitor = NULL;
- int idx;
-
- for (idx = 0; idx < monitor_table_size; idx++)
- if (! monitor_table[idx].inuse)
- break;
- if (idx == monitor_table_size)
- {
- /* We need to increase the size of the table. The approach we
- take is straightforward to minimize the risk of bugs. */
- monitor_t newtbl;
- size_t newsize = monitor_table_size + 16;
-
- newtbl = calloc (newsize, sizeof *newtbl);
- if (!newtbl)
- goto leave;
- memcpy (newtbl, monitor_table, monitor_table_size * sizeof (*newtbl));
- free (monitor_table);
- monitor_table = newtbl;
- idx = monitor_table_size;
- monitor_table_size = newsize;
- }
- monitor = &monitor_table[idx];
- monitor->inuse = 1;
- monitor->pipeimpl = 0;
-
- leave:
- return monitor;
-}
-
-
-static pipeimpl_t
-assert_pipeimpl (opnctx_t ctx)
-{
- DWORD ctx_arg = OPNCTX_TO_IDX (ctx);
-
- if (ctx->is_log)
- {
- log_debug (" assert_pipeimpl (ctx=%i): "
- "error: not valid for a log device\n", ctx_arg);
- return NULL;
- }
- if (! ctx->pipeimpl)
- {
- ctx->pipeimpl = pipeimpl_new ();
- if (! ctx->pipeimpl)
- {
- log_debug (" assert_pipeimpl (ctx=%i): error: can't create pipe\n",
- ctx_arg);
- return NULL;
- }
- log_debug (" assert_pipeimpl (ctx=%i): created pipe 0x%p\n",
- ctx_arg, ctx->pipeimpl);
- }
- return ctx->pipeimpl;
-}
-
-
-static logimpl_t
-assert_logimpl (opnctx_t ctx)
-{
- DWORD ctx_arg = OPNCTX_TO_IDX (ctx);
-
- if (!ctx->is_log)
- {
- log_debug (" assert_logimpl (ctx=%i): "
- "error: not valid for a pipe device\n", ctx_arg);
- return NULL;
- }
- if (!ctx->logimpl)
- {
- ctx->logimpl = logimpl_new ();
- if (!ctx->logimpl)
- {
- log_debug (" assert_logimpl (ctx=%i): error: can't create log\n",
- ctx_arg);
- return NULL;
- }
- log_debug (" assert_logimpl (ctx=%i): created log 0x%p\n",
- ctx_arg, ctx->logimpl);
- }
- return ctx->logimpl;
-}
-
-
-/* Verify access CODE for context CTX_ARG, returning a reference to
- the locked pipe or the locked log implementation. opnctx_table_cs
- must be unlocked on entry and is unlocked on exit. */
-int
-access_opnctx (DWORD ctx_arg, DWORD code, pipeimpl_t *r_pipe, logimpl_t *r_log)
-{
- opnctx_t ctx;
-
- *r_pipe = NULL;
- *r_log = NULL;
-
- EnterCriticalSection (&opnctx_table_cs);
- ctx = verify_opnctx (ctx_arg);
- if (! ctx)
- {
- /* Error is set by verify_opnctx. */
- LeaveCriticalSection (&opnctx_table_cs);
- return -1;
- }
-
- if (! (ctx->access_code & code))
- {
- SetLastError (ERROR_INVALID_ACCESS);
- LeaveCriticalSection (&opnctx_table_cs);
- return -1;
- }
-
- if (ctx->is_log)
- {
- logimpl_t limpl;
-
- limpl = assert_logimpl (ctx);
- if (!limpl)
- {
- LeaveCriticalSection (&opnctx_table_cs);
- return -1;
- }
- *r_log = limpl;
- }
- else
- {
- pipeimpl_t pimpl;
-
- pimpl = assert_pipeimpl (ctx);
- if (! pimpl)
- {
- LeaveCriticalSection (&opnctx_table_cs);
- return -1;
- }
- EnterCriticalSection (&pimpl->critsect);
- pimpl->refcnt++;
- *r_pipe = pimpl;
- }
-
- LeaveCriticalSection (&opnctx_table_cs);
- return 0;
-}
-
-
-
-static char *
-wchar_to_utf8 (const wchar_t *string)
-{
- int n;
- size_t length = wcslen (string);
- char *result;
-
- n = WideCharToMultiByte (CP_UTF8, 0, string, length, NULL, 0, NULL, NULL);
- if (n < 0 || (n+1) <= 0)
- abort ();
-
- result = malloc (n+1);
- if (!result)
- abort ();
- n = WideCharToMultiByte (CP_ACP, 0, string, length, result, n, NULL, NULL);
- if (n < 0)
- abort ();
-
- result[n] = 0;
- return result;
-}
-
-
-/* Initialize the device and return a device specific context. */
-DWORD
-GPG_Init (LPCTSTR active_key, DWORD bus_context)
-{
- static int firsttimedone;
- HKEY handle;
- wchar_t buffer[25];
- DWORD buflen;
- DWORD result;
-
- (void)bus_context;
-
- EnterCriticalSection (&logcontrol.lock);
- if (!firsttimedone)
- {
- firsttimedone++;
- if (!RegOpenKeyEx (HKEY_LOCAL_MACHINE, GPGCEDEV_KEY_NAME,
- 0, KEY_READ, &handle))
- {
- buflen = sizeof buffer;
- if (!RegQueryValueEx (handle, L"debugDriver", 0, NULL,
- (PBYTE)buffer, &buflen)
- && wcstol (buffer, NULL, 10) > 0)
- enable_debug = 1;
- RegCloseKey (handle);
- }
- if (!RegOpenKeyEx (HKEY_LOCAL_MACHINE, GPGCEDEV_KEY_NAME2,
- 0, KEY_READ, &handle))
- {
- buflen = sizeof buffer;
- if (!RegQueryValueEx (handle, L"enableLog", 0, NULL,
- (PBYTE)buffer, &buflen)
- && wcstol (buffer, NULL, 10) > 0)
- enable_logging = 1;
- RegCloseKey (handle);
- }
- }
- LeaveCriticalSection (&logcontrol.lock);
-
- if (enable_debug)
- {
- char *tmpbuf;
- tmpbuf = wchar_to_utf8 (active_key);
- log_debug ("GPG_Init (%s)\n", tmpbuf);
- free (tmpbuf);
- }
-
- if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, active_key, 0, KEY_READ, &handle))
- {
- log_debug ("GPG_Init: error reading registry: rc=%d\n",
- (int)GetLastError ());
- return 0;
- }
-
- buflen = sizeof buffer;
- if (RegQueryValueEx (handle, L"Name", 0, NULL, (PBYTE)buffer, &buflen))
- {
- log_debug ("GPG_Init: error reading registry value 'Name': rc=%d\n",
- (int)GetLastError ());
- result = 0;
- }
- else if (!wcscmp (buffer, L"GPG1:"))
- {
- /* This is the pipe device: We don't need any global data.
- However, we need to return something. */
- log_debug ("GPG_Init: created pipe device (devctx=%p)\n", PIPECTX_VALUE);
- result = PIPECTX_VALUE;
- }
- else if (!wcscmp (buffer, L"GPG2:"))
- {
- /* This is the log device. Clear the object and return something. */
- logcontrol.filehd = INVALID_HANDLE_VALUE;
- log_debug ("GPG_Init: created log device (devctx=%p)\n", 0);
- result = LOGCTX_VALUE;
- }
- else
- {
- if (enable_debug)
- {
- char *tmpbuf;
- tmpbuf = wchar_to_utf8 (buffer);
- log_debug ("GPG_Init: device '%s' is not supported\n", tmpbuf);
- free (tmpbuf);
- }
- SetLastError (ERROR_DEV_NOT_EXIST);
- result = 0;
- }
-
- RegCloseKey (handle);
- return result;
-}
-
-
-
-/* Deinitialize this device driver. */
-BOOL
-GPG_Deinit (DWORD devctx)
-{
- log_debug ("GPG_Deinit (devctx=0x%p)\n", (void*)devctx);
- if (devctx == PIPECTX_VALUE)
- {
- /* No need to release resources. */
- }
- else if (devctx == LOGCTX_VALUE)
- {
- EnterCriticalSection (&logcontrol.lock);
- if (logcontrol.filehd != INVALID_HANDLE_VALUE)
- {
- CloseHandle (logcontrol.filehd);
- logcontrol.filehd = INVALID_HANDLE_VALUE;
- }
- LeaveCriticalSection (&logcontrol.lock);
- }
- else
- {
- SetLastError (ERROR_INVALID_PARAMETER);
- return FALSE; /* Error. */
- }
-
- return TRUE; /* Success. */
-}
-
-
-
-/* Create a new open context. This function is called due to a
- CreateFile from the application. */
-DWORD
-GPG_Open (DWORD devctx, DWORD access_code, DWORD share_mode)
-{
- opnctx_t opnctx;
- DWORD ctx_arg = 0;
- int is_log;
-
- log_debug ("GPG_Open (devctx=%p)\n", (void*)devctx);
- if (devctx == PIPECTX_VALUE)
- is_log = 0;
- else if (devctx == LOGCTX_VALUE)
- is_log = 1;
- else
- {
- log_debug ("GPG_Open (devctx=%p): error: wrong devctx (expected 0x%p)\n",
- (void*) devctx);
- SetLastError (ERROR_INVALID_PARAMETER);
- return 0; /* Error. */
- }
-
- EnterCriticalSection (&opnctx_table_cs);
- opnctx = allocate_opnctx (is_log);
- if (!opnctx)
- {
- log_debug ("GPG_Open (devctx=%p): error: could not allocate context\n",
- (void*) devctx);
- goto leave;
- }
-
- opnctx->access_code = access_code;
- opnctx->share_mode = share_mode;
-
- ctx_arg = OPNCTX_TO_IDX (opnctx);
-
- log_debug ("GPG_Open (devctx=%p, is_log=%d): success: created context %i\n",
- (void*) devctx, is_log, ctx_arg);
- if (is_log)
- {
- EnterCriticalSection (&logcontrol.lock);
- logcontrol.references++;
- LeaveCriticalSection (&logcontrol.lock);
- }
-
- leave:
- LeaveCriticalSection (&opnctx_table_cs);
- return ctx_arg;
-}
-
-
-
-BOOL
-GPG_Close (DWORD opnctx_arg)
-{
- opnctx_t opnctx;
- BOOL result = FALSE;
-
- log_debug ("GPG_Close (ctx=%i)\n", opnctx_arg);
-
- EnterCriticalSection (&opnctx_table_cs);
- opnctx = verify_opnctx (opnctx_arg);
- if (!opnctx)
- {
- log_debug ("GPG_Close (ctx=%i): could not find context\n", opnctx_arg);
- goto leave;
- }
-
- if (opnctx->pipeimpl)
- {
- pipeimpl_t pimpl = opnctx->pipeimpl;
- EnterCriticalSection (&pimpl->critsect);
- /* This needs to be adjusted if there can be multiple
- reader/writers. */
- if (opnctx->access_code & GENERIC_READ)
- {
- pimpl->flags |= PIPE_FLAG_NO_READER;
- SetEvent (pimpl->space_available);
- }
- else if (opnctx->access_code & GENERIC_WRITE)
- {
- pimpl->flags |= PIPE_FLAG_NO_WRITER;
- SetEvent (pimpl->data_available);
- }
- pipeimpl_unref (pimpl);
- opnctx->pipeimpl = 0;
- }
- if (opnctx->logimpl)
- {
- logimpl_t limpl = opnctx->logimpl;
-
- logimpl_flush (limpl);
- logimpl_unref (limpl);
- free (limpl->line);
- free (limpl);
- opnctx->logimpl = 0;
- EnterCriticalSection (&logcontrol.lock);
- logcontrol.references--;
- if (!logcontrol.references && logcontrol.filehd)
- {
- CloseHandle (logcontrol.filehd);
- logcontrol.filehd = INVALID_HANDLE_VALUE;
- }
- LeaveCriticalSection (&logcontrol.lock);
- }
- opnctx->access_code = 0;
- opnctx->share_mode = 0;
- opnctx->rvid = 0;
- opnctx->inuse = 0;
- result = TRUE;
- log_debug ("GPG_Close (ctx=%i): success\n", opnctx_arg);
-
- leave:
- LeaveCriticalSection (&opnctx_table_cs);
- return result;
-}
-
-
-
-DWORD
-GPG_Read (DWORD opnctx_arg, void *buffer, DWORD count)
-{
- pipeimpl_t pimpl;
- logimpl_t limpl;
- const char *src;
- char *dst;
- int result = -1;
-
- log_debug ("GPG_Read (ctx=%i, buffer=0x%p, count=%d)\n",
- opnctx_arg, buffer, count);
-
- if (access_opnctx (opnctx_arg, GENERIC_READ, &pimpl, &limpl))
- {
- log_debug ("GPG_Read (ctx=%i): error: could not access context\n",
- opnctx_arg);
- return -1;
- }
-
- if (limpl)
- {
- /* Reading from a log stream does not make sense. Return EOF. */
- result = 0;
- goto leave;
- }
-
- retry:
- if (pimpl->buffer_pos == pimpl->buffer_len)
- {
- HANDLE data_available = pimpl->data_available;
-
- /* Check for end of file. */
- if (pimpl->flags & PIPE_FLAG_NO_WRITER)
- {
- log_debug ("GPG_Read (ctx=%i): success: EOF\n", opnctx_arg);
- result = 0;
- goto leave;
- }
-
- /* Check for request to unblock once. */
- if (pimpl->flags & PIPE_FLAG_UNBLOCK_READER)
- {
- log_debug ("GPG_Read (ctx=%i): success: EBUSY (due to unblock)\n",
- opnctx_arg);
- pimpl->flags &= ~PIPE_FLAG_UNBLOCK_READER;
- SetLastError (ERROR_BUSY);
- result = -1;
- goto leave;
- }
-
- LeaveCriticalSection (&pimpl->critsect);
- log_debug ("GPG_Read (ctx=%i): waiting: data_available\n", opnctx_arg);
- WaitForSingleObject (data_available, INFINITE);
- log_debug ("GPG_Read (ctx=%i): resuming: data_available\n", opnctx_arg);
- EnterCriticalSection (&pimpl->critsect);
- goto retry;
- }
-
- dst = buffer;
- src = pimpl->buffer + pimpl->buffer_pos;
- while (count > 0 && pimpl->buffer_pos < pimpl->buffer_len)
- {
- *dst++ = *src++;
- count--;
- pimpl->buffer_pos++;
- }
- result = (dst - (char*)buffer);
- if (pimpl->buffer_pos == pimpl->buffer_len)
- pimpl->buffer_pos = pimpl->buffer_len = 0;
-
- /* Now there should be some space available. Signal the write end.
- Even if COUNT was passed as NULL and no space is available,
- signaling must be done. */
- if (!SetEvent (pimpl->space_available))
- log_debug ("GPG_Read (ctx=%i): warning: SetEvent(space_available) "
- "failed: rc=%d\n", opnctx_arg, (int)GetLastError ());
-
- log_debug ("GPG_Read (ctx=%i): success: result=%d\n", opnctx_arg, result);
-
- leave:
- pipeimpl_unref (pimpl);
- logimpl_unref (limpl);
- return result;
-}
-
-
-
-DWORD
-GPG_Write (DWORD opnctx_arg, const void *buffer, DWORD count)
-{
- pipeimpl_t pimpl;
- logimpl_t limpl;
- int result = -1;
- const char *src;
- char *dst;
- size_t nwritten = 0;
-
- log_debug ("GPG_Write (ctx=%i, buffer=0x%p, count=%d)\n", opnctx_arg,
- buffer, count);
-
- if (access_opnctx (opnctx_arg, GENERIC_WRITE, &pimpl, &limpl))
- {
- log_debug ("GPG_Write (ctx=%i): error: could not access context\n",
- opnctx_arg);
- return -1;
- }
-
- if (!count)
- {
- log_debug ("GPG_Write (ctx=%i): success\n", opnctx_arg);
- result = 0;
- goto leave;
- }
-
- retry:
- if (limpl)
- {
- /* Store it in our buffer up to a LF and print complete lines. */
- result = count;
- if (!limpl->linelen)
- limpl->dsec = GetTickCount () / 100;
- dst = limpl->line + limpl->linelen;
- for (src = buffer; count; count--, src++)
- {
- if (*src == '\n')
- {
- logimpl_flush (limpl);
- dst = limpl->line + limpl->linelen;
- }
- else if (limpl->linelen >= limpl->linesize)
- limpl->truncated = 1;
- else
- {
- *dst++ = *src;
- limpl->linelen++;
- }
- }
- }
- else /* pimpl */
- {
- /* Check for broken pipe. */
- if (pimpl->flags & PIPE_FLAG_NO_READER)
- {
- log_debug ("GPG_Write (ctx=%i): error: broken pipe\n", opnctx_arg);
- SetLastError (ERROR_BROKEN_PIPE);
- goto leave;
- }
-
- /* Check for request to unblock once. */
- if (pimpl->flags & PIPE_FLAG_UNBLOCK_WRITER)
- {
- log_debug ("GPG_Write (ctx=%i): success: EBUSY (due to unblock)\n",
- opnctx_arg);
- pimpl->flags &= ~PIPE_FLAG_UNBLOCK_WRITER;
- SetLastError (ERROR_BUSY);
- result = -1;
- goto leave;
- }
-
- /* Write to our buffer. */
- if (pimpl->buffer_len == pimpl->buffer_size)
- {
- /* Buffer is full. */
- HANDLE space_available = pimpl->space_available;
- LeaveCriticalSection (&pimpl->critsect);
- log_debug ("GPG_Write (ctx=%i): waiting: space_available\n",
- opnctx_arg);
- WaitForSingleObject (space_available, INFINITE);
- log_debug ("GPG_Write (ctx=%i): resuming: space_available\n",
- opnctx_arg);
- EnterCriticalSection (&pimpl->critsect);
- goto retry;
- }
-
- src = buffer;
- dst = pimpl->buffer + pimpl->buffer_len;
- while (count > 0 && pimpl->buffer_len < pimpl->buffer_size)
- {
- *dst++ = *src++;
- count--;
- pimpl->buffer_len++;
- nwritten++;
- }
- result = nwritten;
-
- if (!SetEvent (pimpl->data_available))
- log_debug ("GPG_Write (ctx=%i): warning: SetEvent(data_available) "
- "failed: rc=%d\n", opnctx_arg, (int)GetLastError ());
- }
-
- log_debug ("GPG_Write (ctx=%i): success: result=%d\n", opnctx_arg, result);
-
- leave:
- pipeimpl_unref (pimpl);
- logimpl_unref (limpl);
- return result;
-}
-
-
-
-DWORD
-GPG_Seek (DWORD opnctx_arg, long amount, WORD type)
-{
- SetLastError (ERROR_SEEK_ON_DEVICE);
- return -1; /* Error. */
-}
-
-
-
-/* opnctx_table_s is locked on entering and on exit. */
-static BOOL
-make_pipe (opnctx_t ctx, LONG rvid)
-{
- DWORD ctx_arg = OPNCTX_TO_IDX (ctx);
- opnctx_t peerctx = NULL;
- int idx;
- pipeimpl_t pimpl;
-
- log_debug (" make_pipe (ctx=%i, rvid=%08lx)\n", ctx_arg, rvid);
-
- if (ctx->pipeimpl)
- {
- log_debug (" make_pipe (ctx=%i): error: already assigned\n", ctx_arg);
- SetLastError (ERROR_ALREADY_ASSIGNED);
- return FALSE;
- }
-
- /* GnuPG and other programs don't use the safe ASSIGN_RVID call
- because they guarantee that the context exists during the whole
- time the child process runs. GPGME is more asynchronous and
- relies on ASSIGN_RVID monitors. So, first check for open
- contexts, then check for monitors. */
-
- for (idx = 0; idx < opnctx_table_size; idx++)
- if (opnctx_table[idx].inuse && opnctx_table[idx].rvid == rvid)
- {
- peerctx = &opnctx_table[idx];
- break;
- }
- if (peerctx)
- {
- /* This is the GnuPG etc case, where the context is still open.
- It may also cover the GPGME case if GPGME is still using its
- own end of the pipe at the time of this call. */
- if (peerctx == ctx)
- {
- log_debug (" make_pipe (ctx=%i): error: target and source identical\n",
- ctx_arg);
- SetLastError (ERROR_INVALID_TARGET_HANDLE);
- return FALSE;
- }
-
- if ((ctx->access_code & GENERIC_READ))
- {
- /* Check that the peer is a write end. */
- if (!(peerctx->access_code & GENERIC_WRITE))
- {
- log_debug (" make_pipe (ctx=%i): error: peer is not writer\n",
- ctx_arg);
- SetLastError (ERROR_INVALID_ACCESS);
- return FALSE;
- }
- }
- else if ((ctx->access_code & GENERIC_WRITE))
- {
- /* Check that the peer is a read end. */
- if (!(peerctx->access_code & GENERIC_READ))
- {
- log_debug (" make_pipe (ctx=%i): error: peer is not reader\n",
- ctx_arg);
- SetLastError (ERROR_INVALID_ACCESS);
- return FALSE;
- }
- }
- else
- {
- log_debug (" make_pipe (ctx=%i): error: invalid access\n", ctx_arg);
- SetLastError (ERROR_INVALID_ACCESS);
- return FALSE;
- }
-
- /* Make sure the peer has a pipe implementation to be shared. If
- not yet, create one. */
- pimpl = assert_pipeimpl (peerctx);
- if (! pimpl)
- return FALSE;
- }
- else
- {
- /* This is the case where ASSIGN_RVID was called to create a
- monitor, and the pipe is already closed at the parent side.
- For example GPGME verify detached plain text, where GPG calls
- MAKE_PIPE very late. */
-
- for (idx = 0; idx < monitor_table_size; idx++)
- if (monitor_table[idx].inuse
- && monitor_table[idx].pipeimpl->monitor_rvid == rvid)
- {
- pimpl = monitor_table[idx].pipeimpl;
- break;
- }
- if (idx == monitor_table_size)
- {
- log_debug (" make_pipe (ctx=%i): error: not found\n", ctx_arg);
- SetLastError (ERROR_NOT_FOUND);
- return FALSE;
- }
-
- if (ctx->access_code & GENERIC_READ)
- {
- /* Check that the peer is a write end. */
- if (!(pimpl->monitor_access & GENERIC_READ))
- {
- log_debug (" make_pipe (ctx=%i): error: monitor is not reader\n",
- ctx_arg);
- SetLastError (ERROR_INVALID_ACCESS);
- return FALSE;
- }
- }
- else if ((ctx->access_code & GENERIC_WRITE))
- {
- /* Check that the peer is a read end. */
- if (!(pimpl->monitor_access & GENERIC_WRITE))
- {
- log_debug (" make_pipe (ctx=%i): error: monitor is not writer\n",
- ctx_arg);
- SetLastError (ERROR_INVALID_ACCESS);
- return FALSE;
- }
- }
- else
- {
- log_debug (" make_pipe (ctx=%i): error: invalid access\n", ctx_arg);
- SetLastError (ERROR_INVALID_ACCESS);
- return FALSE;
- }
- }
-
- EnterCriticalSection (&pimpl->critsect);
- pimpl->refcnt++;
- if (pimpl->monitor_proc != INVALID_HANDLE_VALUE)
- {
- /* If there is a monitor to the pipe, then it's now about time
- to ask it to go away. */
- log_debug (" make_pipe (ctx=%i): waking up monitor for pipe 0x%p\n",
- ctx_arg, pimpl);
- pimpl->flags |= PIPE_FLAG_HALT_MONITOR;
- if (pimpl->monitor_access & GENERIC_READ)
- SetEvent (pimpl->data_available);
- else
- SetEvent (pimpl->space_available);
- }
- LeaveCriticalSection (&pimpl->critsect);
-
- ctx->pipeimpl = pimpl;
-
- if (peerctx)
- {
- log_debug (" make_pipe (ctx=%i): success: combined with peer ctx=%i "
- "(pipe 0x%p)\n", ctx_arg, OPNCTX_TO_IDX (peerctx), pimpl);
- }
- else
- {
- log_debug (" make_pipe (ctx=%i): success: combined with "
- "pipe 0x%p\n", ctx_arg, OPNCTX_TO_IDX (peerctx), pimpl);
- }
-
- return TRUE;
-}
-
-
-/* opnctx_table_s is locked on entering and on exit. */
-static BOOL
-unblock_call (opnctx_t ctx)
-{
- /* If there is no pipe object, no thread can be blocked. */
- if (!ctx->pipeimpl)
- return TRUE;
-
- EnterCriticalSection (&ctx->pipeimpl->critsect);
- if (ctx->access_code & GENERIC_READ)
- {
- ctx->pipeimpl->flags |= PIPE_FLAG_UNBLOCK_READER;
- SetEvent (ctx->pipeimpl->data_available);
- }
- else if (ctx->access_code & GENERIC_WRITE)
- {
- ctx->pipeimpl->flags |= PIPE_FLAG_UNBLOCK_WRITER;
- SetEvent (ctx->pipeimpl->space_available);
- }
- LeaveCriticalSection (&ctx->pipeimpl->critsect);
-
- return TRUE;
-}
-
-
-static DWORD CALLBACK
-monitor_main (void *arg)
-{
- pipeimpl_t pimpl = (pipeimpl_t) arg;
- HANDLE handles[2];
- int idx;
-
- log_debug ("starting monitor (pimpl=0x%p)\n", pimpl);
-
- EnterCriticalSection (&pimpl->critsect);
- /* Putting proc first in the array is convenient, as this is a hard
- break-out condition (and thus takes precedence in WFMO). The
- reader/writer event is a soft condition, which also requires a
- flag to be set. */
- handles[0] = pimpl->monitor_proc;
- if (pimpl->monitor_access & GENERIC_READ)
- handles[1] = pimpl->data_available;
- else
- handles[1] = pimpl->space_available;
-
- retry:
- /* First check if the peer has not gone away. If it has, we are done. */
- if (pimpl->flags & PIPE_FLAG_HALT_MONITOR)
- {
- log_debug ("monitor (pimpl=0x%p): done: monitored process taking over\n",
- pimpl);
- }
- else
- {
- DWORD res;
-
- LeaveCriticalSection (&pimpl->critsect);
- log_debug ("monitor (pimpl=0x%p): waiting\n", pimpl);
- res = WaitForMultipleObjects (2, handles, FALSE, INFINITE);
- log_debug ("monitor (pimpl=0x%p): resuming\n", pimpl);
- EnterCriticalSection (&pimpl->critsect);
-
- if (res == WAIT_FAILED)
- {
- log_debug ("monitor (pimpl=0x%p): WFMO failed: %i\n",
- pimpl, GetLastError ());
- }
- else if (res == WAIT_OBJECT_0)
- {
- log_debug ("monitor (pimpl=0x%p): done: monitored process died\n",
- pimpl);
- }
- else if (res == WAIT_OBJECT_0 + 1)
- goto retry;
- else
- {
- log_debug ("monitor (pimpl=0x%p): unexpected result of WFMO: %i\n",
- pimpl, res);
- }
- }
-
- log_debug ("ending monitor (pimpl=0x%p)\n", pimpl);
-
- /* Remove the monitor from the monitor table. */
- LeaveCriticalSection (&pimpl->critsect);
- EnterCriticalSection (&opnctx_table_cs);
- for (idx = 0; idx < monitor_table_size; idx++)
- if (monitor_table[idx].inuse
- && monitor_table[idx].pipeimpl == pimpl)
- {
- monitor_table[idx].pipeimpl = NULL;
- monitor_table[idx].inuse = 0;
- break;
- }
- if (idx == monitor_table_size)
- log_debug ("can not find monitor in table (pimpl=0x%p)\n", pimpl);
- LeaveCriticalSection (&opnctx_table_cs);
- EnterCriticalSection (&pimpl->critsect);
-
- /* Now do the rest of the cleanup. */
- CloseHandle (pimpl->monitor_proc);
- pimpl->monitor_proc = INVALID_HANDLE_VALUE;
- pimpl->monitor_access = 0;
- pimpl->monitor_rvid = 0;
- pimpl->flags &= ~PIPE_FLAG_HALT_MONITOR;
- pipeimpl_unref (pimpl);
-
- return 0;
-}
-
-
-/* opnctx_table_s is locked on entering and on exit. */
-static BOOL
-assign_rvid (opnctx_t ctx, DWORD rvid, DWORD pid)
-{
- DWORD ctx_arg = OPNCTX_TO_IDX (ctx);
- int idx;
- opnctx_t peerctx;
- HANDLE monitor_hnd;
- HANDLE proc;
- pipeimpl_t pimpl;
- monitor_t monitor;
-
- log_debug (" assign_rvid (ctx=%i, rvid=%08lx, pid=%08lx)\n",
- ctx_arg, rvid, pid);
-
- for (idx = 0; idx < opnctx_table_size; idx++)
- if (opnctx_table[idx].inuse && opnctx_table[idx].rvid == rvid)
- {
- peerctx = &opnctx_table[idx];
- break;
- }
- if (! peerctx)
- {
- log_debug (" assign_rvid (ctx=%i): error: not found\n", ctx_arg);
- SetLastError (ERROR_NOT_FOUND);
- return FALSE;
- }
-
- if (peerctx->pipeimpl
- && peerctx->pipeimpl->monitor_proc != INVALID_HANDLE_VALUE)
- {
- log_debug (" assign_rvid (ctx=%i): error: rvid already assigned\n",
- ctx_arg);
- SetLastError (ERROR_ALREADY_ASSIGNED);
- return FALSE;
- }
-
- proc = OpenProcess (0, FALSE, pid);
- if (proc == NULL)
- {
- log_debug (" assign_rvid (ctx=%i): error: process not found\n",
- ctx_arg);
- return FALSE;
- }
-
- /* Acquire a reference to the pipe. We don't want accesss to be
- checked. */
- pimpl = assert_pipeimpl (peerctx);
- if (! pimpl)
- {
- CloseHandle (proc);
- return FALSE;
- }
-
- monitor = allocate_monitor ();
- if (!monitor)
- {
- log_debug (" assign_rvid (ctx=%i): error: could not allocate monitor\n",
- ctx_arg);
- CloseHandle (proc);
- return FALSE;
- }
- monitor->pipeimpl = pimpl;
-
- EnterCriticalSection (&pimpl->critsect);
- pimpl->refcnt++;
-
- /* The monitor shadows the peer, so it takes its access. Our access
- is the opposite of that of the peer. */
- pimpl->monitor_proc = proc;
- if (peerctx->access_code == GENERIC_READ)
- pimpl->monitor_access = GENERIC_WRITE;
- else
- pimpl->monitor_access = GENERIC_READ;
- pimpl->monitor_rvid = rvid;
-
- monitor_hnd = CreateThread (NULL, 0, monitor_main, pimpl, 0, NULL);
- if (monitor_hnd == INVALID_HANDLE_VALUE)
- {
- pimpl->monitor_access = 0;
- pimpl->monitor_proc = INVALID_HANDLE_VALUE;
- LeaveCriticalSection (&pimpl->critsect);
-
- monitor->pipeimpl = NULL;
- monitor->inuse = 0;
-
- CloseHandle (proc);
- log_debug (" assign_rvid (ctx=%i): error: can not create monitor\n",
- ctx_arg);
- return FALSE;
- }
- CloseHandle (monitor_hnd);
-
- /* Consume the pimpl reference. */
- LeaveCriticalSection (&pimpl->critsect);
-
- return TRUE;
-}
-
-
-BOOL
-GPG_IOControl (DWORD opnctx_arg, DWORD code, void *inbuf, DWORD inbuflen,
- void *outbuf, DWORD outbuflen, DWORD *actualoutlen)
-{
- opnctx_t opnctx;
- BOOL result = FALSE;
- LONG rvid;
- LONG pid;
-
- log_debug ("GPG_IOControl (ctx=%i, %08x)\n", opnctx_arg, code);
-
- EnterCriticalSection (&opnctx_table_cs);
- opnctx = verify_opnctx (opnctx_arg);
- if (!opnctx)
- {
- log_debug ("GPG_IOControl (ctx=%i): error: could not access context\n",
- opnctx_arg);
- goto leave;
- }
- if (opnctx->is_log)
- {
- log_debug ("GPG_IOControl (ctx=%i): error: invalid code %u"
- " for log device\n", opnctx_arg, (unsigned int)code);
- SetLastError (ERROR_INVALID_PARAMETER);
- goto leave;
- }
-
- switch (code)
- {
- case GPGCEDEV_IOCTL_GET_RVID:
- log_debug ("GPG_IOControl (ctx=%i): code: GET_RVID\n", opnctx_arg);
- if (inbuf || inbuflen || !outbuf || outbuflen < sizeof (LONG))
- {
- log_debug ("GPG_IOControl (ctx=%i): error: invalid parameter\n",
- opnctx_arg);
- SetLastError (ERROR_INVALID_PARAMETER);
- goto leave;
- }
-
- if (! opnctx->rvid)
- opnctx->rvid = create_rendezvous_id ();
- log_debug ("GPG_IOControl (ctx=%i): returning rvid: %08lx\n",
- opnctx_arg, opnctx->rvid);
-
- memcpy (outbuf, &opnctx->rvid, sizeof (LONG));
- if (actualoutlen)
- *actualoutlen = sizeof (LONG);
- result = TRUE;
- break;
-
- case GPGCEDEV_IOCTL_MAKE_PIPE:
- log_debug ("GPG_IOControl (ctx=%i): code: MAKE_PIPE\n", opnctx_arg);
- if (!inbuf || inbuflen < sizeof (LONG)
- || outbuf || outbuflen || actualoutlen)
- {
- log_debug ("GPG_IOControl (ctx=%i): error: invalid parameter\n",
- opnctx_arg);
- SetLastError (ERROR_INVALID_PARAMETER);
- goto leave;
- }
- memcpy (&rvid, inbuf, sizeof (LONG));
- log_debug ("GPG_IOControl (ctx=%i): make pipe for rvid: %08lx\n",
- opnctx_arg, rvid);
- if (make_pipe (opnctx, rvid))
- result = TRUE;
- break;
-
- case GPGCEDEV_IOCTL_UNBLOCK:
- log_debug ("GPG_IOControl (ctx=%i): code: UNBLOCK\n", opnctx_arg);
- if (inbuf || inbuflen || outbuf || outbuflen || actualoutlen)
- {
- log_debug ("GPG_IOControl (ctx=%i): error: invalid parameter\n",
- opnctx_arg);
- SetLastError (ERROR_INVALID_PARAMETER);
- goto leave;
- }
-
- if (unblock_call (opnctx))
- result = TRUE;
- break;
-
- case GPGCEDEV_IOCTL_ASSIGN_RVID:
- log_debug ("GPG_IOControl (ctx=%i): code: ASSIGN_RVID\n", opnctx_arg);
- if (!inbuf || inbuflen < 2 * sizeof (DWORD)
- || outbuf || outbuflen || actualoutlen)
- {
- log_debug ("GPG_IOControl (ctx=%i): error: invalid parameter\n",
- opnctx_arg);
- SetLastError (ERROR_INVALID_PARAMETER);
- goto leave;
- }
- memcpy (&rvid, inbuf, sizeof (DWORD));
- memcpy (&pid, ((char *) inbuf) + sizeof (DWORD), sizeof (DWORD));
- log_debug ("GPG_IOControl (ctx=%i): assign rvid %08lx to pid %08lx\n",
- opnctx_arg, rvid, pid);
- if (assign_rvid (opnctx, rvid, pid))
- result = TRUE;
- break;
-
- case IOCTL_PSL_NOTIFY:
- /* This notification is received if the application's main
- thread exits and the application has other threads running
- and the application has open handles for this device. What
- we do is to unblock them all simialr to an explicit unblock
- call. */
- log_debug ("GPG_IOControl (ctx=%i): code: NOTIFY\n", opnctx_arg);
-
- if (unblock_call (opnctx))
- result = TRUE;
- break;
-
- default:
- log_debug ("GPG_IOControl (ctx=%i): code: (unknown)\n", opnctx_arg);
- SetLastError (ERROR_INVALID_PARAMETER);
- break;
- }
-
- log_debug ("GPG_IOControl (ctx=%i): success: result=%d\n", opnctx_arg,
- result);
-
- leave:
- LeaveCriticalSection (&opnctx_table_cs);
- return result;
-}
-
-
-
-void
-GPG_PowerUp (DWORD devctx)
-{
- log_debug ("GPG_PowerUp (devctx=%i)\n", devctx);
-}
-
-
-
-void
-GPG_PowerDown (DWORD devctx)
-{
- log_debug ("GPG_PowerDown (devctx=%i)\n", devctx);
-}
-
-
-
-
-
-/* Entry point called by the DLL loader. */
-int WINAPI
-DllMain (HINSTANCE hinst, DWORD reason, LPVOID reserved)
-{
- (void)reserved;
-
- switch (reason)
- {
- case DLL_PROCESS_ATTACH:
- InitializeCriticalSection (&opnctx_table_cs);
- InitializeCriticalSection (&logcontrol.lock);
- break;
-
- case DLL_THREAD_ATTACH:
- break;
-
- case DLL_THREAD_DETACH:
- break;
-
- case DLL_PROCESS_DETACH:
- DeleteCriticalSection (&opnctx_table_cs);
- break;
-
- default:
- break;
- }
-
- return TRUE;
-}
diff --git a/src/gpgcedev.def b/src/gpgcedev.def
deleted file mode 100644
index bc52d3a..0000000
--- a/src/gpgcedev.def
+++ /dev/null
@@ -1,34 +0,0 @@
-; gpgcedev.def - List of symbols to export for gpgcedev.
-; Copyright (C) 2010 Free Software Foundation, Inc.
-;
-; This file is part of Assuan.
-;
-; Assuan 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 3 of
-; the License, or (at your option) any later version.
-;
-; Assuan 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
-; Lesser 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 .
-; SPDX-License-Identifier: LGPL-3.0+
-
-
-EXPORTS
- GPG_Init
- GPG_Deinit
- GPG_Open
- GPG_Close
- GPG_Read
- GPG_Write
- GPG_Seek
- GPG_IOControl
- GPG_PowerUp
- GPG_PowerDown
-
-; END
-
diff --git a/src/gpgcemgr.c b/src/gpgcemgr.c
deleted file mode 100644
index 5b4f56e..0000000
--- a/src/gpgcemgr.c
+++ /dev/null
@@ -1,608 +0,0 @@
-/* gpgcempr.c - Manager for GPG CE devices
- * Copyright (C) 2010 Free Software Foundation, Inc.
- *
- * This file is part of Assuan.
- *
- * Assuan 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 3 of
- * the License, or (at your option) any later version.
- *
- * Assuan 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
- * Lesser 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 .
- * SPDX-License-Identifier: LGPL-3.0+
- */
-
-#define _WIN32_WCE 0x0500
-
-#include
-#include
-
-#define PGM "gpgcemgr"
-
-#define GPGCEDEV_KEY_NAME L"Drivers\\GnuPG_Device"
-#define GPGCEDEV_KEY_NAME2 L"Drivers\\GnuPG_Log"
-#define GPGCEDEV_DLL_NAME L"gpgcedev.dll"
-#define GPGCEDEV_PREFIX L"GPG"
-
-
-static char *
-wchar_to_utf8 (const wchar_t *string)
-{
- int n;
- size_t length = wcslen (string);
- char *result;
-
- n = WideCharToMultiByte (CP_UTF8, 0, string, length, NULL, 0, NULL, NULL);
- if (n < 0 || (n+1) <= 0)
- abort ();
-
- result = malloc (n+1);
- if (!result)
- abort ();
- n = WideCharToMultiByte (CP_ACP, 0, string, length, result, n, NULL, NULL);
- if (n < 0)
- abort ();
-
- result[n] = 0;
- return result;
-}
-
-
-static wchar_t *
-utf8_to_wchar (const char *string)
-{
- int n;
- size_t nbytes;
- wchar_t *result;
-
- if (!string)
- abort ();
-
- n = MultiByteToWideChar (CP_UTF8, 0, string, -1, NULL, 0);
- if (n < 0)
- abort ();
- nbytes = (size_t)(n+1) * sizeof(*result);
- if (nbytes / sizeof(*result) != (n+1))
- abort ();
- result = malloc (nbytes);
- if (!result)
- abort ();
-
- n = MultiByteToWideChar (CP_UTF8, 0, string, -1, result, n);
- if (n < 0)
- abort ();
- return result;
-}
-
-
-static int
-install (void)
-{
- HKEY handle;
- DWORD disp, dw;
- int rc;
-
- if ((rc=RegCreateKeyEx (HKEY_LOCAL_MACHINE, GPGCEDEV_KEY_NAME, 0, NULL, 0,
- KEY_WRITE, NULL, &handle, &disp)))
- {
- fprintf (stderr, PGM": error creating registry key 1: rc=%d\n", rc);
- return 1;
- }
-
- RegSetValueEx (handle, L"dll", 0, REG_SZ,
- (void*)GPGCEDEV_DLL_NAME, sizeof (GPGCEDEV_DLL_NAME));
- RegSetValueEx (handle, L"prefix", 0, REG_SZ,
- (void*)GPGCEDEV_PREFIX, sizeof (GPGCEDEV_PREFIX));
-
- dw = 1;
- RegSetValueEx (handle, L"Index", 0, REG_DWORD, (void*)&dw, sizeof dw);
-
- RegCloseKey (handle);
-
- fprintf (stderr, PGM": registry key 1 created\n");
-
- if ((rc=RegCreateKeyEx (HKEY_LOCAL_MACHINE, GPGCEDEV_KEY_NAME2, 0, NULL, 0,
- KEY_WRITE, NULL, &handle, &disp)))
- {
- fprintf (stderr, PGM": error creating registry key 2: rc=%d\n", rc);
- return 1;
- }
-
- RegSetValueEx (handle, L"dll", 0, REG_SZ,
- (void*)GPGCEDEV_DLL_NAME, sizeof (GPGCEDEV_DLL_NAME));
- RegSetValueEx (handle, L"prefix", 0, REG_SZ,
- (void*)GPGCEDEV_PREFIX, sizeof (GPGCEDEV_PREFIX));
-
- dw = 2;
- RegSetValueEx (handle, L"Index", 0, REG_DWORD, (void*)&dw, sizeof dw);
-
- RegCloseKey (handle);
-
- fprintf (stderr, PGM": registry key 2 created\n");
-
-
- return 0;
-}
-
-
-static int
-deinstall (wchar_t *name)
-{
- int result = 0;
- HANDLE shd;
- DEVMGR_DEVICE_INFORMATION dinfo;
-
- memset (&dinfo, 0, sizeof dinfo);
- dinfo.dwSize = sizeof dinfo;
- shd = FindFirstDevice (DeviceSearchByLegacyName, name, &dinfo);
- if (shd == INVALID_HANDLE_VALUE)
- {
- if (GetLastError () == 18)
- fprintf (stderr, PGM": device not found\n");
- else
- {
- fprintf (stderr, PGM": FindFirstDevice failed: rc=%d\n",
- (int)GetLastError ());
- result = 1;
- }
- }
- else
- {
- fprintf (stderr, PGM": ActivateDevice handle is %p\n", dinfo.hDevice);
- if (dinfo.hDevice && dinfo.hDevice != INVALID_HANDLE_VALUE)
- {
- if (!DeactivateDevice (dinfo.hDevice))
- {
- fprintf (stderr, PGM": DeactivateDevice failed: rc=%d\n",
- (int)GetLastError ());
- result = 1;
- }
- else
- fprintf (stderr, PGM": DeactivateDevice succeeded\n");
- }
- FindClose (shd);
- }
-
- return result;
-}
-
-
-static int
-enable_debug (int yes)
-{
- HKEY handle;
- DWORD disp;
- int rc;
-
- if ((rc=RegCreateKeyEx (HKEY_LOCAL_MACHINE, GPGCEDEV_KEY_NAME, 0, NULL, 0,
- KEY_WRITE, NULL, &handle, &disp)))
- {
- fprintf (stderr, PGM": error creating debug registry key: rc=%d\n", rc);
- return 1;
- }
-
- RegSetValueEx (handle, L"debugDriver", 0, REG_SZ,
- (void*)(yes? L"1":L"0"), sizeof L"0");
- RegCloseKey (handle);
- return 0;
-}
-
-
-static int
-enable_log (int yes)
-{
- HKEY handle;
- DWORD disp;
- int rc;
-
- if ((rc=RegCreateKeyEx (HKEY_LOCAL_MACHINE, GPGCEDEV_KEY_NAME2, 0, NULL, 0,
- KEY_WRITE, NULL, &handle, &disp)))
- {
- fprintf (stderr, PGM": error creating debug registry key: rc=%d\n", rc);
- return 1;
- }
-
- RegSetValueEx (handle, L"enableLog", 0, REG_SZ,
- (void*)(yes? L"1":L"0"), sizeof L"0");
- RegCloseKey (handle);
- return 0;
-}
-
-
-
-/* Kudos to Scott Seligman for his work
- on the reverse engineering. */
-struct htc_sensor_s
-{
- SHORT tilt_x; // From -1000 to 1000 (about), 0 is flat
- SHORT tilt_y; // From -1000 to 1000 (about), 0 is flat
- SHORT tilt_z; // From -1000 to 1000 (about)
- DWORD angle_x; // 0 .. 359
- DWORD angle_y; // From 0 to 359
- DWORD orientation; // 0.. 5?
- DWORD unknown; // Handle?
-};
-typedef struct htc_sensor_s *htc_sensor_t;
-
-static HANDLE (WINAPI *HTCSensorOpen) (DWORD);
-static void (WINAPI *HTCSensorClose) (HANDLE);
-static DWORD (WINAPI *HTCSensorGetDataOutput) (HANDLE, htc_sensor_t);
-
-static int
-load_sensor_api (void)
-{
- static HMODULE dll_hd;
-
- if (dll_hd)
- return 0;
-
- dll_hd = LoadLibrary (L"HTCSensorSDK.dll");
- if (!dll_hd)
- {
- fprintf (stderr, PGM": error loading sensor DLL: rc=%d\n",
- (int)GetLastError ());
- return 1;
- }
-
- HTCSensorOpen = (void*)GetProcAddress (dll_hd, L"HTCSensorOpen");
- if (HTCSensorOpen)
- HTCSensorClose = (void*)GetProcAddress (dll_hd, L"HTCSensorClose");
- if (HTCSensorClose)
- HTCSensorGetDataOutput = (void*)
- GetProcAddress (dll_hd, L"HTCSensorGetDataOutput");
- if (!HTCSensorGetDataOutput)
- {
- fprintf (stderr, PGM": error loading function from sensor DLL: rc=%d\n",
- (int)GetLastError ());
- CloseHandle (dll_hd);
- return 1;
- }
- return 0;
-}
-
-
-static int
-gravity (void)
-{
- int rc;
- HANDLE sensor;
- struct htc_sensor_s lastdata;
- struct htc_sensor_s data;
-
- rc = load_sensor_api ();
- if (rc)
- return rc;
-
- sensor = HTCSensorOpen (1 /* tilt sensor */);
- if (!sensor || sensor == INVALID_HANDLE_VALUE)
- {
- fprintf (stderr, PGM": error opening gravity sensor: rc=%d\n",
- (int)GetLastError ());
- HTCSensorClose (sensor);
- return 1;
- }
-
- memset (&lastdata, 0, sizeof lastdata);
- while (HTCSensorGetDataOutput (sensor, &data))
- {
- if (lastdata.tilt_x/10 != data.tilt_x/10
- || lastdata.tilt_y/10 != data.tilt_y/10
- || lastdata.tilt_z/10 != data.tilt_z/10
- || lastdata.angle_x/5 != data.angle_x/5
- || lastdata.angle_y/5 != data.angle_y/5
- || lastdata.orientation != data.orientation)
- {
- lastdata = data;
- printf ("tilt: x=%-5d y=%-5d z=%-5d "
- "angle: x=%-3d y=%-3d "
- "ori: %d\n",
- (int)data.tilt_x, (int)data.tilt_y, (int)data.tilt_z,
- (int)data.angle_x, (int)data.angle_y,
- (int)data.orientation);
- }
- Sleep (200);
- }
- fprintf (stderr, PGM": reading sensor data failed: rc=%d\n",
- (int)GetLastError ());
- HTCSensorClose (sensor);
- return 0;
-}
-
-
-
-/* No GPD1 device on the HTC Touch Pro 2. */
-# if 0
-static int
-gps_raw (void)
-{
- HANDLE hd;
- char buffer[1000];
- unsigned long nread;
- int count;
-
- hd = CreateFile (L"GPD1:", GENERIC_READ, FILE_SHARE_READ,
- NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
- if (hd == INVALID_HANDLE_VALUE)
- {
- fprintf (stderr, PGM": can't open `GPD1': rc=%d\n",
- (int)GetLastError ());
- return 1;
- }
- fprintf (stderr, PGM": GPS device successfully opened\n");
-
- for (count=0; count < 100; count++)
- {
- if (!ReadFile (hd, buffer, sizeof buffer-1, &nread, NULL))
- {
- fprintf (stderr, PGM": error reading `GPD1': rc=%d\n",
- (int)GetLastError ());
- CloseHandle (hd);
- return 1;
- }
- buffer[nread-1] = 0;
- fputs (buffer, stdout);
- }
-
- CloseHandle (hd);
- return 0;
-}
-#endif
-
-/* Untested samples for CE6. */
-#if 0
-static int
-gps (void)
-{
- HANDLE hd;
- GPS_POSITION pos;
-
- hd = GPSOpenDevice (NULL, NULL, NULL, 0);
- if (hd == INVALID_HANDLE_VALUE)
- {
- fprintf (stderr, PGM": GPSOpenDevice failed: rc=%d\n",
- (int)GetLastError ());
- return 1;
- }
- fprintf (stderr, PGM": GPS device successfully opened\n");
-
- if (GPSGetPosition (hd, &pos, 2000, 0))
- {
- fprintf (stderr, PGM": GPSGetPosition failed: rc=%d\n",
- (int)GetLastError ());
- GPSCloseDevice (hd);
- return 1;
- }
-
-
- GPSCloseDevice (hd);
- return 0;
-}
-#endif
-
-
-static void
-set_show_registry (const wchar_t *key, const wchar_t *name, const char *value)
-{
- HKEY handle;
- DWORD disp, nbytes, n1, type;
- int rc;
-
- if ((rc=RegCreateKeyEx (HKEY_LOCAL_MACHINE, key, 0, NULL, 0,
- KEY_WRITE, NULL, &handle, &disp)))
- {
- fprintf (stderr, PGM": error creating registry key: rc=%d\n", rc);
- return;
- }
-
- if (value && !stricmp (value, "none"))
- {
- if ((rc=RegDeleteValue (handle, name)))
- fprintf (stderr, PGM": error deleting registry value: rc=%d\n", rc);
- }
- else if (value)
- {
- wchar_t *tmp = utf8_to_wchar (value);
- if ((rc=RegSetValueEx (handle, name, 0, REG_SZ,
- (void*)tmp, wcslen (tmp)*sizeof(wchar_t))))
- fprintf (stderr, PGM": error setting registry value: rc=%d\n", rc);
- free (tmp);
- }
- else
- {
- nbytes = 2;
- if ((rc=RegQueryValueEx (handle, name, 0, NULL, NULL, &nbytes)))
- {
- if (rc == ERROR_FILE_NOT_FOUND)
- fprintf (stderr, PGM": registry value not set\n");
- else
- fprintf (stderr, PGM": error reading registry value: rc=%d\n", rc);
- }
- else
- {
- char *result = malloc ((n1=nbytes+2));
- if (!result)
- fprintf (stderr, PGM": malloc failed: rc=%d\n",
- (int)GetLastError ());
- else if ((rc=RegQueryValueEx (handle, name, 0, &type,
- (void*)result, &n1)))
- {
- fprintf (stderr, PGM": error reading registry value (2): "
- "rc=%d\n", rc);
- free (result);
- }
- else
- {
- result[nbytes] = 0; /* Make sure it is a string. */
- result[nbytes+1] = 0;
- if (type == REG_SZ)
- {
- wchar_t *tmp = (void*)result;
- result = wchar_to_utf8 (tmp);
- free (tmp);
- printf ("%s\n", result);
- }
- else
- fprintf (stderr, PGM": registry value is not a string\n");
- free (result);
- }
- }
- }
-
- RegCloseKey (handle);
-}
-
-
-
-int
-main (int argc, char **argv)
-{
- int result = 0;
-
- if (argc > 1 && !strcmp (argv[1], "--register"))
- result = install ();
- else if (argc > 1 && !strcmp (argv[1], "--deactivate"))
- {
- if (deinstall (L"GPG1:"))
- result = 1;
- if (deinstall (L"GPG2:"))
- result = 1;
- }
- else if (argc > 1 && !strcmp (argv[1], "--activate"))
- {
- HANDLE hd;
-
- /* This is mainly for testing. The activation is usually done
- right before the device is opened. */
- if (ActivateDevice (GPGCEDEV_KEY_NAME, 0) == INVALID_HANDLE_VALUE)
- {
- fprintf (stderr, PGM": ActivateDevice 1 failed: rc=%d\n",
- (int)GetLastError ());
- result = 1;
- }
- else if (ActivateDevice (GPGCEDEV_KEY_NAME2, 0) == INVALID_HANDLE_VALUE)
- {
- fprintf (stderr, PGM": ActivateDevice 2 failed: rc=%d\n",
- (int)GetLastError ());
- result = 1;
- }
- else
- {
- fprintf (stderr, PGM": devices activated\n");
- hd = CreateFile (L"GPG1:", GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
- if (hd == INVALID_HANDLE_VALUE)
- {
- fprintf (stderr, PGM": opening `GPG1:' failed: rc=%d\n",
- (int)GetLastError ());
- result = 1;
- }
- else
- {
- fprintf (stderr, PGM": device `GPG1:' seems to work\n");
- CloseHandle (hd);
- }
-
- hd = CreateFile (L"GPG2:", GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
- if (hd == INVALID_HANDLE_VALUE)
- {
- fprintf (stderr, PGM": opening `GPG2:' failed: rc=%d\n",
- (int)GetLastError ());
- result = 1;
- }
- else
- {
- fprintf (stderr, PGM": device `GPG2:' seems to work\n");
- CloseHandle (hd);
- }
-
- }
- }
- else if (argc > 1 && !strcmp (argv[1], "--gravity"))
- result = gravity ();
- /* else if (argc > 1 && !strcmp (argv[1], "--gps")) */
- /* result = gps (); */
- else if (argc > 1 && !strcmp (argv[1], "--log"))
- {
- HANDLE hd;
-
- hd = CreateFile (L"GPG2:", GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
- if (hd == INVALID_HANDLE_VALUE)
- {
- fprintf (stderr, PGM": opening `GPG2:' failed: rc=%d\n",
- (int)GetLastError ());
- result = 1;
- }
- else
- {
- char marktwain[] = "I have never let my schooling interfere"
- " with my education.\n";
- DWORD nwritten;
- int i;
-
- for (i=0; i < 3; i++)
- {
- if (!WriteFile (hd, marktwain, strlen (marktwain),
- &nwritten, NULL))
- {
- fprintf (stderr, PGM": writing `GPG2:' failed: rc=%d\n",
- (int)GetLastError ());
- result = 1;
- }
- Sleep (200);
- }
- CloseHandle (hd);
- }
- }
- else if (argc > 1 && !strcmp (argv[1], "--enable-debug"))
- result = enable_debug (1);
- else if (argc > 1 && !strcmp (argv[1], "--disable-debug"))
- result = enable_debug (0);
- else if (argc > 1 && !strcmp (argv[1], "--enable-log"))
- result = enable_log (1);
- else if (argc > 1 && !strcmp (argv[1], "--disable-log"))
- result = enable_log (0);
- else if (argc > 1 && !strcmp (argv[1], "--gpgme-log"))
- set_show_registry (L"Software\\GNU\\gpgme", L"debug",
- argc > 2? argv[2] : NULL);
- else if (argc > 1 && !strcmp (argv[1], "--gnupg-log"))
- set_show_registry (L"Software\\GNU\\GnuPG", L"DefaultLogFile",
- argc > 2? argv[2] : NULL);
- else
- {
- fprintf (stderr,
- "usage: " PGM " COMMAND\n"
- "Commands are:\n"
- " --register Register the GPGCEDEV device\n"
- " --deactivate Deactivate the GPGCEDEV device\n"
- " --activate Activate the GPGCEDEV devive\n"
- " --enable-debug Enable debugging of GPGCEDEV device\n"
- " --disable-debug Disable debugging of GPGCEDEV device\n"
- " --gravity Show output of the gravity sensor\n"
- " --enable-log Enable logging via \"GPG2:\"\n"
- " --disable-log Disable logging via \"GPG2:\"\n"
- " --log Write a test string to \"GPG2:\"\n"
- " --gpgme-log [ARG] Show or set GPGME log output\n"
- " --gnupg-log [ARG] Show or set GnuPG default log file\n"
- " (No ARG shows, \"none\" disables)\n"
- );
- result = 1;
- }
-
- fflush (stdout);
- fflush (stderr);
- Sleep (1000);
- return result;
-}
-
-
diff --git a/src/setenv.c b/src/setenv.c
index 3410b30..487de4e 100644
--- a/src/setenv.c
+++ b/src/setenv.c
@@ -1,358 +1,354 @@
/* Copyright (C) 1992,1995-2001,2004 Free Software Foundation, Inc.
* This file is part of the GNU C Library.
*
* The GNU C Library 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.
*
* The GNU C Library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the GNU C Library; if not,
* see .
* SPDX-License-Identifier: LGPL-2.1+
*/
#if HAVE_CONFIG_H
# include
#endif
-#ifndef HAVE_W32CE_SYSTEM
-
#define setenv _assuan_setenv
#define unsetenv _assuan_unsetenv
#define clearenv _assuan_clearenv
#define __builtin_expect(cond,val) (cond)
#include
#if !_LIBC
# if !defined errno && !defined HAVE_ERRNO_DECL
extern int errno;
# endif
# define __set_errno(ev) ((errno) = (ev))
#endif
#if _LIBC || HAVE_STDLIB_H
# include
#endif
#if _LIBC || HAVE_STRING_H
# include
#endif
#if _LIBC || HAVE_UNISTD_H
# include
#endif
#if !_LIBC
# define __environ environ
# ifndef HAVE_ENVIRON_DECL
extern char **environ;
# endif
#endif
#if _LIBC
/* This lock protects against simultaneous modifications of `environ'. */
# include
__libc_lock_define_initialized (static, envlock)
# define LOCK __libc_lock_lock (envlock)
# define UNLOCK __libc_lock_unlock (envlock)
#else
# define LOCK
# define UNLOCK
#endif
/* In the GNU C library we must keep the namespace clean. */
#ifdef _LIBC
# define setenv __setenv
# define unsetenv __unsetenv
# define clearenv __clearenv
# define tfind __tfind
# define tsearch __tsearch
#endif
/* In the GNU C library implementation we try to be more clever and
allow arbitrarily many changes of the environment given that the used
values are from a small set. Outside glibc this will eat up all
memory after a while. */
#if defined _LIBC || (defined HAVE_SEARCH_H && defined HAVE_TSEARCH \
&& defined __GNUC__)
# define USE_TSEARCH 1
# include
/* This is a pointer to the root of the search tree with the known
values. */
static void *known_values;
# define KNOWN_VALUE(Str) \
({ \
void *value = tfind (Str, &known_values, (__compar_fn_t) strcmp); \
value != NULL ? *(char **) value : NULL; \
})
# define STORE_VALUE(Str) \
tsearch (Str, &known_values, (__compar_fn_t) strcmp)
#else
# undef USE_TSEARCH
# define KNOWN_VALUE(Str) NULL
# define STORE_VALUE(Str) do { } while (0)
#endif
/* If this variable is not a null pointer we allocated the current
environment. */
static char **last_environ;
/* This function is used by `setenv' and `putenv'. The difference between
the two functions is that for the former must create a new string which
is then placed in the environment, while the argument of `putenv'
must be used directly. This is all complicated by the fact that we try
to reuse values once generated for a `setenv' call since we can never
free the strings. */
static int
__add_to_environ (const char *name, const char *value, const char *combined,
int replace)
{
register char **ep;
register size_t size;
const size_t namelen = strlen (name);
const size_t vallen = value != NULL ? strlen (value) + 1 : 0;
LOCK;
/* We have to get the pointer now that we have the lock and not earlier
since another thread might have created a new environment. */
ep = __environ;
size = 0;
if (ep != NULL)
{
for (; *ep != NULL; ++ep)
if (!strncmp (*ep, name, namelen) && (*ep)[namelen] == '=')
break;
else
++size;
}
if (ep == NULL || __builtin_expect (*ep == NULL, 1))
{
char **new_environ;
/* We allocated this space; we can extend it. */
new_environ = (char **) realloc (last_environ,
(size + 2) * sizeof (char *));
if (new_environ == NULL)
{
UNLOCK;
return -1;
}
/* If the whole entry is given add it. */
if (combined != NULL)
/* We must not add the string to the search tree since it belongs
to the user. */
new_environ[size] = (char *) combined;
else
{
/* See whether the value is already known. */
#ifdef USE_TSEARCH
# ifdef __GNUC__
char new_value[namelen + 1 + vallen];
# else
char *new_value = (char *) alloca (namelen + 1 + vallen);
# endif
# ifdef _LIBC
__mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1),
value, vallen);
# else
memcpy (new_value, name, namelen);
new_value[namelen] = '=';
memcpy (&new_value[namelen + 1], value, vallen);
# endif
new_environ[size] = KNOWN_VALUE (new_value);
if (__builtin_expect (new_environ[size] == NULL, 1))
#endif
{
new_environ[size] = (char *) malloc (namelen + 1 + vallen);
if (__builtin_expect (new_environ[size] == NULL, 0))
{
__set_errno (ENOMEM);
UNLOCK;
return -1;
}
#ifdef USE_TSEARCH
memcpy (new_environ[size], new_value, namelen + 1 + vallen);
#else
memcpy (new_environ[size], name, namelen);
new_environ[size][namelen] = '=';
memcpy (&new_environ[size][namelen + 1], value, vallen);
#endif
/* And save the value now. We cannot do this when we remove
the string since then we cannot decide whether it is a
user string or not. */
STORE_VALUE (new_environ[size]);
}
}
if (__environ != last_environ)
memcpy ((char *) new_environ, (char *) __environ,
size * sizeof (char *));
new_environ[size + 1] = NULL;
last_environ = __environ = new_environ;
}
else if (replace)
{
char *np;
/* Use the user string if given. */
if (combined != NULL)
np = (char *) combined;
else
{
#ifdef USE_TSEARCH
# ifdef __GNUC__
char new_value[namelen + 1 + vallen];
# else
char *new_value = (char *) alloca (namelen + 1 + vallen);
# endif
# ifdef _LIBC
__mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1),
value, vallen);
# else
memcpy (new_value, name, namelen);
new_value[namelen] = '=';
memcpy (&new_value[namelen + 1], value, vallen);
# endif
np = KNOWN_VALUE (new_value);
if (__builtin_expect (np == NULL, 1))
#endif
{
np = malloc (namelen + 1 + vallen);
if (__builtin_expect (np == NULL, 0))
{
UNLOCK;
return -1;
}
#ifdef USE_TSEARCH
memcpy (np, new_value, namelen + 1 + vallen);
#else
memcpy (np, name, namelen);
np[namelen] = '=';
memcpy (&np[namelen + 1], value, vallen);
#endif
/* And remember the value. */
STORE_VALUE (np);
}
}
*ep = np;
}
UNLOCK;
return 0;
}
int
setenv (const char *name, const char *value, int replace)
{
if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
{
__set_errno (EINVAL);
return -1;
}
return __add_to_environ (name, value, NULL, replace);
}
int
unsetenv (const char *name)
{
size_t len;
char **ep;
if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
{
__set_errno (EINVAL);
return -1;
}
len = strlen (name);
LOCK;
ep = __environ;
while (*ep != NULL)
if (!strncmp (*ep, name, len) && (*ep)[len] == '=')
{
/* Found it. Remove this pointer by moving later ones back. */
char **dp = ep;
do
dp[0] = dp[1];
while (*dp++);
/* Continue the loop in case NAME appears again. */
}
else
++ep;
UNLOCK;
return 0;
}
/* The `clearenv' was planned to be added to POSIX.1 but probably
never made it. Nevertheless the POSIX.9 standard (POSIX bindings
for Fortran 77) requires this function. */
int
clearenv (void)
{
LOCK;
if (__environ == last_environ && __environ != NULL)
{
/* We allocated this environment so we can free it. */
free (__environ);
last_environ = NULL;
}
/* Clear the environment pointer removes the whole environment. */
__environ = NULL;
UNLOCK;
return 0;
}
#ifdef _LIBC
libc_freeres_fn (free_mem)
{
/* Remove all traces. */
clearenv ();
/* Now remove the search tree. */
__tdestroy (known_values, free);
known_values = NULL;
}
# undef setenv
# undef unsetenv
# undef clearenv
weak_alias (__setenv, setenv)
weak_alias (__unsetenv, unsetenv)
weak_alias (__clearenv, clearenv)
#endif
-
-#endif /*!HAVE_W32CE_SYSTEM*/
diff --git a/src/system-w32ce.c b/src/system-w32ce.c
deleted file mode 100644
index da5dcf2..0000000
--- a/src/system-w32ce.c
+++ /dev/null
@@ -1,706 +0,0 @@
-/* system-w32ce.c - System support functions for WindowsCE.
- * Copyright (C) 2010 Free Software Foundation, Inc.
- *
- * This file is part of Assuan.
- *
- * Assuan 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.
- *
- * Assuan 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
- * Lesser 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 .
- * SPDX-License-Identifier: LGPL-2.1+
- */
-
-
-#ifdef HAVE_CONFIG_H
-#include
-#endif
-
-#include
-#include
-#include
-# ifdef HAVE_WINSOCK2_H
-# include
-# endif
-#include
-#include
-#include
-
-#include "assuan-defs.h"
-#include "debug.h"
-
-
-#define GPGCEDEV_IOCTL_GET_RVID \
- CTL_CODE (FILE_DEVICE_STREAMS, 2048, METHOD_BUFFERED, FILE_ANY_ACCESS)
-#define GPGCEDEV_IOCTL_MAKE_PIPE \
- CTL_CODE (FILE_DEVICE_STREAMS, 2049, METHOD_BUFFERED, FILE_ANY_ACCESS)
-
-
-
-
-static wchar_t *
-utf8_to_wchar (const char *string)
-{
- int n;
- size_t nbytes;
- wchar_t *result;
-
- if (!string)
- return NULL;
-
- n = MultiByteToWideChar (CP_UTF8, 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 = malloc (nbytes);
- if (!result)
- return NULL;
-
- n = MultiByteToWideChar (CP_UTF8, 0, string, -1, result, n);
- if (n < 0)
- {
- free (result);
- gpg_err_set_errno (EINVAL);
- result = NULL;
- }
- return result;
-}
-
-/* Convenience function. */
-static void
-free_wchar (wchar_t *string)
-{
- if (string)
- free (string);
-}
-
-
-
-assuan_fd_t
-assuan_fdopen (int fd)
-{
- return (assuan_fd_t)fd;
-}
-
-
-
-/* Sleep for the given number of microseconds. Default
- implementation. */
-void
-__assuan_usleep (assuan_context_t ctx, unsigned int usec)
-{
- if (usec)
- Sleep (usec / 1000);
-}
-
-
-
-/* Prepare a pipe. Returns a handle which is, depending on WRITE_END,
- will either act the read or as the write end of the pipe. The
- other value returned is a rendezvous id used to complete the pipe
- creation with _assuan_w32ce_finish_pipe. The rendezvous id may be
- passed to another process and that process may finish the pipe
- creation. This creates the interprocess pipe. The rendezvous id
- is not a handle but a plain number; there is no release function
- and care should be taken not to pass it to a function expecting a
- handle. */
-HANDLE
-_assuan_w32ce_prepare_pipe (int *r_rvid, int write_end)
-{
- HANDLE hd;
- LONG rvid;
-
- ActivateDevice (L"Drivers\\GnuPG_Device", 0);
-
- /* Note: Using "\\$device\\GPG1" should be identical to "GPG1:".
- However this returns an invalid parameter error without having
- called GPG_Init in the driver. The docs mention something about
- RegisterAFXEx but that API is not documented. */
- hd = CreateFile (L"GPG1:", write_end? GENERIC_WRITE : GENERIC_READ,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
- if (hd != INVALID_HANDLE_VALUE)
- {
- if (!DeviceIoControl (hd, GPGCEDEV_IOCTL_GET_RVID,
- NULL, 0, &rvid, sizeof rvid, NULL, NULL))
- {
- DWORD lastrc = GetLastError ();
- CloseHandle (hd);
- hd = INVALID_HANDLE_VALUE;
- SetLastError (lastrc);
- }
- else
- *r_rvid = rvid;
- }
-
- return hd;
-}
-
-
-/* Create a pipe. WRITE_END shall have the opposite value of the one
- pssed to _assuan_w32ce_prepare_pipe; see there for more
- details. */
-HANDLE
-_assuan_w32ce_finish_pipe (int rvid, int write_end)
-{
- HANDLE hd;
-
- if (!rvid)
- {
- SetLastError (ERROR_INVALID_HANDLE);
- return INVALID_HANDLE_VALUE;
- }
-
- hd = CreateFile (L"GPG1:", write_end? GENERIC_WRITE : GENERIC_READ,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL,NULL);
- if (hd != INVALID_HANDLE_VALUE)
- {
- if (!DeviceIoControl (hd, GPGCEDEV_IOCTL_MAKE_PIPE,
- &rvid, sizeof rvid, NULL, 0, NULL, NULL))
- {
- DWORD lastrc = GetLastError ();
- CloseHandle (hd);
- hd = INVALID_HANDLE_VALUE;
- SetLastError (lastrc);
- }
- }
-
- return hd;
-}
-
-
-/* WindowsCE does not provide a pipe feature. However we need
- something like a pipe to convey data between processes and in some
- cases within a process. This replacement is not only used by
- libassuan but exported and thus usable by gnupg and gpgme as well. */
-DWORD
-_assuan_w32ce_create_pipe (HANDLE *read_hd, HANDLE *write_hd,
- LPSECURITY_ATTRIBUTES sec_attr, DWORD size)
-{
- HANDLE hd[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE};
- int rvid;
- int rc = 0;
-
- hd[0] = _assuan_w32ce_prepare_pipe (&rvid, 0);
- if (hd[0] != INVALID_HANDLE_VALUE)
- {
- hd[1] = _assuan_w32ce_finish_pipe (rvid, 1);
- if (hd[1] != INVALID_HANDLE_VALUE)
- rc = 1;
- else
- {
- DWORD lastrc = GetLastError ();
- CloseHandle (hd[0]);
- hd[0] = INVALID_HANDLE_VALUE;
- SetLastError (lastrc);
- }
- }
-
- *read_hd = hd[0];
- *write_hd = hd[1];
- return rc;
-}
-
-
-/* Create a pipe with one inheritable end. Default implementation.
- If INHERIT_IDX is 0, the read end of the pipe is made inheritable;
- with INHERIT_IDX is 1 the write end will be inheritable. The
- question now is how we create an inheritable pipe end under windows
- CE were handles are process local objects? The trick we employ is
- to defer the actual creation to the other end: We create an
- incomplete pipe and pass a rendezvous id to the other end
- (process). The other end now uses the rendezvous id to lookup the
- pipe in our device driver, creates a new handle and uses that one
- to finally establish the pipe. */
-int
-__assuan_pipe (assuan_context_t ctx, assuan_fd_t fd[2], int inherit_idx)
-{
- HANDLE hd;
- int rvid;
-
- hd = _assuan_w32ce_prepare_pipe (&rvid, !inherit_idx);
- if (hd == INVALID_HANDLE_VALUE)
- {
- TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_pipe", ctx,
- "CreatePipe failed: %s", _assuan_w32_strerror (ctx, -1));
- gpg_err_set_errno (EIO);
- return -1;
- }
-
- if (inherit_idx)
- {
- fd[0] = hd;
- fd[1] = (void*)rvid;
- }
- else
- {
- fd[0] = (void*)rvid;
- fd[1] = hd;
- }
- return 0;
-}
-
-
-
-/* Close the given file descriptor, created with _assuan_pipe or one
- of the socket functions. Default implementation. */
-int
-__assuan_close (assuan_context_t ctx, assuan_fd_t fd)
-{
- int rc = closesocket (HANDLE2SOCKET(fd));
- int err = WSAGetLastError ();
-
- /* Note that gpg_err_set_errno on Windows CE overwrites
- WSAGetLastError() (via SetLastError()). */
- if (rc)
- gpg_err_set_errno (_assuan_sock_wsa2errno (err));
- if (rc && err == WSAENOTSOCK)
- {
- rc = CloseHandle (fd);
- if (rc)
- /* FIXME. */
- gpg_err_set_errno (EIO);
- }
- return rc;
-}
-
-
-
-ssize_t
-__assuan_read (assuan_context_t ctx, assuan_fd_t fd, void *buffer, size_t size)
-{
- /* Due to the peculiarities of the W32 API we can't use read for a
- network socket and thus we try to use recv first and fallback to
- read if recv detects that it is not a network socket. */
- int res;
-
- TRACE_BEG3 (ctx, ASSUAN_LOG_SYSIO, "__assuan_read", ctx,
- "fd=0x%x, buffer=%p, size=%i", fd, buffer, size);
-
-#ifdef HAVE_W32CE_SYSTEM
- /* This is a bit of a hack to support stdin over ssh. Note that
- fread buffers fully while getchar is line buffered. Weird, but
- that's the way it is. ASSUAN_STDIN and ASSUAN_STDOUT are
- special handle values that shouldn't occur in the wild. */
- if (fd == ASSUAN_STDIN)
- {
- int i = 0;
- int chr;
- while (i < size)
- {
- chr = getchar();
- if (chr == EOF)
- break;
- ((char*)buffer)[i++] = (char) chr;
- if (chr == '\n')
- break;
- }
- return TRACE_SYSRES (i);
- }
-#endif
-
- res = recv (HANDLE2SOCKET (fd), buffer, size, 0);
- if (res == -1)
- {
- TRACE_LOG1 ("recv failed: rc=%d", (int)WSAGetLastError ());
- switch (WSAGetLastError ())
- {
- case WSAENOTSOCK:
- {
- DWORD nread = 0;
-
- res = ReadFile (fd, buffer, size, &nread, NULL);
- if (! res)
- {
- TRACE_LOG1 ("ReadFile failed: rc=%d", (int)GetLastError ());
- switch (GetLastError ())
- {
- case ERROR_BROKEN_PIPE:
- gpg_err_set_errno (EPIPE);
- break;
-
- case ERROR_PIPE_NOT_CONNECTED:
- case ERROR_BUSY:
- gpg_err_set_errno (EAGAIN);
- break;
-
- default:
- gpg_err_set_errno (EIO);
- }
- res = -1;
- }
- else
- res = (int) nread;
- }
- break;
-
- case WSAEWOULDBLOCK:
- gpg_err_set_errno (EAGAIN);
- break;
-
- case ERROR_BROKEN_PIPE:
- gpg_err_set_errno (EPIPE);
- break;
-
- default:
- gpg_err_set_errno (EIO);
- break;
- }
- }
- return TRACE_SYSRES (res);
-}
-
-
-
-ssize_t
-__assuan_write (assuan_context_t ctx, assuan_fd_t fd, const void *buffer,
- size_t size)
-{
- /* Due to the peculiarities of the W32 API we can't use write for a
- network socket and thus we try to use send first and fallback to
- write if send detects that it is not a network socket. */
- int res;
-
- TRACE_BEG3 (ctx, ASSUAN_LOG_SYSIO, "__assuan_write", ctx,
- "fd=0x%x, buffer=%p, size=%i", fd, buffer, size);
-
-#ifdef HAVE_W32CE_SYSTEM
- /* This is a bit of a hack to support stdout over ssh. Note that
- fread buffers fully while getchar is line buffered. Weird, but
- that's the way it is. ASSUAN_STDIN and ASSUAN_STDOUT are
- special handle values that shouldn't occur in the wild. */
- if (fd == ASSUAN_STDOUT)
- {
- res = fwrite (buffer, 1, size, stdout);
- return TRACE_SYSRES (res);
- }
-#endif
-
- res = send ((int)fd, buffer, size, 0);
- if (res == -1 && WSAGetLastError () == WSAENOTSOCK)
- {
- DWORD nwrite;
-
- TRACE_LOG ("send call failed - trying WriteFile");
- res = WriteFile (fd, buffer, size, &nwrite, NULL);
- if (! res)
- {
- TRACE_LOG1 ("WriteFile failed: rc=%d", (int)GetLastError ());
- switch (GetLastError ())
- {
- case ERROR_BROKEN_PIPE:
- case ERROR_NO_DATA:
- gpg_err_set_errno (EPIPE);
- break;
-
- case ERROR_PIPE_NOT_CONNECTED:
- case ERROR_BUSY:
- gpg_err_set_errno (EAGAIN);
- break;
-
- default:
- gpg_err_set_errno (EIO);
- break;
- }
- res = -1;
- }
- else
- res = (int) nwrite;
- }
- else if (res == -1)
- TRACE_LOG1 ("send call failed: rc=%d", (int)GetLastError ());
- return TRACE_SYSRES (res);
-}
-
-
-
-int
-__assuan_recvmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg,
- int flags)
-{
- gpg_err_set_errno (ENOSYS);
- return -1;
-}
-
-
-
-
-int
-__assuan_sendmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg,
- int flags)
-{
- gpg_err_set_errno (ENOSYS);
- return -1;
-}
-
-
-
-
-/* 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 (assuan_context_t ctx, const char * const *argv,
- assuan_fd_t fd0, assuan_fd_t fd1, assuan_fd_t fd2,
- int fd2_isnull,
- char **cmdline)
-{
- int i, n;
- const char *s;
- char *buf, *p;
- char fdbuf[3*30];
-
- p = fdbuf;
- *p = 0;
- if (fd0 != ASSUAN_INVALID_FD)
- {
- snprintf (p, 25, "-&S0=%d ", (int)fd0);
- p += strlen (p);
- }
- if (fd1 != ASSUAN_INVALID_FD)
- {
- snprintf (p, 25, "-&S1=%d ", (int)fd1);
- p += strlen (p);
- }
- if (fd2 != ASSUAN_INVALID_FD)
- {
- if (fd2_isnull)
- strcpy (p, "-&S2=null ");
- else
- snprintf (p, 25, "-&S2=%d ", (int)fd2);
- p += strlen (p);
- }
-
- *cmdline = NULL;
- n = strlen (fdbuf);
- for (i=0; (s = argv[i]); i++)
- {
- if (!i)
- continue; /* Ignore argv[0]. */
- n += strlen (s) + 1 + 2; /* (1 space, 2 quoting) */
- for (; *s; s++)
- if (*s == '\"')
- n++; /* Need to double inner quotes. */
- }
- n++;
-
- buf = p = _assuan_malloc (ctx, n);
- if (! buf)
- return -1;
-
- p = stpcpy (p, fdbuf);
- for (i = 0; argv[i]; i++)
- {
- if (!i)
- continue; /* Ignore argv[0]. */
- if (i > 1)
- p = stpcpy (p, " ");
-
- if (! *argv[i]) /* Empty string. */
- p = stpcpy (p, "\"\"");
- else if (strpbrk (argv[i], " \t\n\v\f\""))
- {
- p = stpcpy (p, "\"");
- for (s = argv[i]; *s; s++)
- {
- *p++ = *s;
- if (*s == '\"')
- *p++ = *s;
- }
- *p++ = '\"';
- *p = 0;
- }
- else
- p = stpcpy (p, argv[i]);
- }
-
- *cmdline = buf;
- return 0;
-}
-
-
-int
-__assuan_spawn (assuan_context_t ctx, pid_t *r_pid, const char *name,
- const char **argv,
- assuan_fd_t fd_in, assuan_fd_t fd_out,
- assuan_fd_t *fd_child_list,
- void (*atfork) (void *opaque, int reserved),
- void *atforkvalue, unsigned int flags)
-{
- PROCESS_INFORMATION pi =
- {
- NULL, /* Returns process handle. */
- 0, /* Returns primary thread handle. */
- 0, /* Returns pid. */
- 0 /* Returns tid. */
- };
- assuan_fd_t fd;
- assuan_fd_t *fdp;
- assuan_fd_t fd_err;
- int fd_err_isnull = 0;
- char *cmdline;
-
- /* Dup stderr to /dev/null unless it is in the list of FDs to be
- passed to the child. Well we don't actually open nul because
- that is not available on Windows, but use our hack for it.
- Because an RVID of 0 is an invalid value and HANDLES will never
- have this value either, we test for this as well. */
-
- /* FIXME: As long as we can't decide whether a handle is a real
- handler or an rendezvous id we can't do anything with the
- FD_CHILD_LIST. We can't do much with stderr either, thus we
- better don't pass stderr to the child at all. If we would do so
- and it is not a rendezvous id the client would run into
- problems. */
- fd = assuan_fd_from_posix_fd (fileno (stderr));
- fdp = fd_child_list;
- if (fdp)
- {
- for (; *fdp != ASSUAN_INVALID_FD && *fdp != 0 && *fdp != fd; fdp++)
- ;
- }
- if (!fdp || *fdp == ASSUAN_INVALID_FD)
- fd_err_isnull = 1;
- fd_err = ASSUAN_INVALID_FD;
-
- if (build_w32_commandline (ctx, argv, fd_in, fd_out, fd_err, fd_err_isnull,
- &cmdline))
- {
- return -1;
- }
-
- TRACE2 (ctx, ASSUAN_LOG_SYSIO, "__assuan_spawn", ctx,
- "path=`%s' cmdline=`%s'", name, cmdline);
-
- {
- wchar_t *wcmdline, *wname;
-
- wcmdline = utf8_to_wchar (cmdline);
- _assuan_free (ctx, cmdline);
- if (!wcmdline)
- return -1;
-
- wname = utf8_to_wchar (name);
- if (!wname)
- {
- free_wchar (wcmdline);
- return -1;
- }
-
- if (!CreateProcess (wname, /* Program to start. */
- wcmdline, /* Command line arguments. */
- NULL, /* (not supported) */
- NULL, /* (not supported) */
- FALSE, /* (not supported) */
- (CREATE_SUSPENDED), /* Creation flags. */
- NULL, /* (not supported) */
- NULL, /* (not supported) */
- NULL, /* (not supported) */
- &pi /* Returns process information.*/
- ))
- {
- TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_spawn", ctx,
- "CreateProcess failed: %s", _assuan_w32_strerror (ctx, -1));
- free_wchar (wname);
- free_wchar (wcmdline);
- gpg_err_set_errno (EIO);
- return -1;
- }
- free_wchar (wname);
- free_wchar (wcmdline);
- }
-
- ResumeThread (pi.hThread);
-
- TRACE4 (ctx, ASSUAN_LOG_SYSIO, "__assuan_spawn", ctx,
- "CreateProcess ready: hProcess=%p hThread=%p"
- " dwProcessID=%d dwThreadId=%d\n",
- pi.hProcess, pi.hThread, (int) pi.dwProcessId, (int) pi.dwThreadId);
-
- CloseHandle (pi.hThread);
-
- *r_pid = (pid_t) pi.hProcess;
- return 0;
-}
-
-
-
-
-pid_t
-__assuan_waitpid (assuan_context_t ctx, pid_t pid, int nowait,
- int *status, int options)
-{
- CloseHandle ((HANDLE) pid);
- return 0;
-}
-
-
-
-int
-__assuan_socketpair (assuan_context_t ctx, int namespace, int style,
- int protocol, assuan_fd_t filedes[2])
-{
- gpg_err_set_errno (ENOSYS);
- return -1;
-}
-
-
-int
-__assuan_socket (assuan_context_t ctx, int namespace, int style, int protocol)
-{
- int res;
-
- res = socket (namespace, style, protocol);
- if (res == -1)
- gpg_err_set_errno (_assuan_sock_wsa2errno (WSAGetLastError ()));
- return res;
-}
-
-
-int
-__assuan_connect (assuan_context_t ctx, int sock, struct sockaddr *addr,
- socklen_t length)
-{
- int res;
-
- res = connect (sock, addr, length);
- if (res < 0)
- gpg_err_set_errno (_assuan_sock_wsa2errno (WSAGetLastError ()));
- return res;
-}
-
-
-
-/* The default system hooks for assuan contexts. */
-struct assuan_system_hooks _assuan_system_hooks =
- {
- ASSUAN_SYSTEM_HOOKS_VERSION,
- __assuan_usleep,
- __assuan_pipe,
- __assuan_close,
- __assuan_read,
- __assuan_write,
- __assuan_recvmsg,
- __assuan_sendmsg,
- __assuan_spawn,
- __assuan_waitpid,
- __assuan_socketpair,
- __assuan_socket,
- __assuan_connect
- };
diff --git a/src/system.c b/src/system.c
index fa13987..e5104bb 100644
--- a/src/system.c
+++ b/src/system.c
@@ -1,540 +1,536 @@
/* system.c - System support functions.
* Copyright (C) 2009 Free Software Foundation, Inc.
*
* This file is part of Assuan.
*
* Assuan 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.
*
* Assuan 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
* Lesser 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 .
* SPDX-License-Identifier: LGPL-2.1+
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include
#ifdef HAVE_SYS_TYPES_H
/* Solaris 8 needs sys/types.h before time.h. */
# include
#endif
#include
#ifdef HAVE_FCNTL_H
#include
#endif
#include "assuan-defs.h"
#include "debug.h"
#define DEBUG_SYSIO 0
/* Manage memory specific to a context. */
void *
_assuan_malloc (assuan_context_t ctx, size_t cnt)
{
return ctx->malloc_hooks.malloc (cnt);
}
void *
_assuan_realloc (assuan_context_t ctx, void *ptr, size_t cnt)
{
return ctx->malloc_hooks.realloc (ptr, cnt);
}
void *
_assuan_calloc (assuan_context_t ctx, size_t cnt, size_t elsize)
{
void *ptr;
size_t nbytes;
nbytes = cnt * elsize;
/* Check for overflow. */
if (elsize && nbytes / elsize != cnt)
{
gpg_err_set_errno (ENOMEM);
return NULL;
}
ptr = ctx->malloc_hooks.malloc (nbytes);
if (ptr)
memset (ptr, 0, nbytes);
return ptr;
}
void
_assuan_free (assuan_context_t ctx, void *ptr)
{
if (ptr)
ctx->malloc_hooks.free (ptr);
}
/* Release the memory at PTR using the allocation handler of the
context CTX. This is a convenience function. */
void
assuan_free (assuan_context_t ctx, void *ptr)
{
_assuan_free (ctx, ptr);
}
/* Copy the system hooks struct, paying attention to version
differences. SRC is usually from the user, DST MUST be from the
library. */
void
_assuan_system_hooks_copy (assuan_system_hooks_t dst,
assuan_system_hooks_t src)
{
/* Reset the defaults. */
if (dst != &_assuan_system_hooks)
memcpy (dst, &_assuan_system_hooks, sizeof (*dst));
dst->version = ASSUAN_SYSTEM_HOOKS_VERSION;
if (src->version >= 1)
{
dst->usleep = src->usleep;
dst->pipe = src->pipe;
dst->close = src->close;
dst->read = src->read;
dst->write = src->write;
dst->sendmsg = src->sendmsg;
dst->recvmsg = src->recvmsg;
dst->spawn = src->spawn;
dst->waitpid = src->waitpid;
dst->socketpair = src->socketpair;
}
if (src->version >= 2)
{
dst->socket = src->socket;
dst->connect = src->connect;
}
if (src->version > 2)
/* FIXME. Application uses newer version of the library. What to
do? */
;
}
/* Sleep for the given number of microseconds. */
void
_assuan_usleep (assuan_context_t ctx, unsigned int usec)
{
TRACE1 (ctx, ASSUAN_LOG_SYSIO, "_assuan_usleep", ctx,
"usec=%u", usec);
if (ctx->system.version)
(ctx->system.usleep) (ctx, usec);
else
{
_assuan_pre_syscall ();
__assuan_usleep (ctx, usec);
_assuan_post_syscall ();
}
}
/* Create a pipe with one inheritable end. */
int
_assuan_pipe (assuan_context_t ctx, assuan_fd_t fd[2], int inherit_idx)
{
int err;
TRACE_BEG2 (ctx, ASSUAN_LOG_SYSIO, "_assuan_pipe", ctx,
"inherit_idx=%i (Assuan uses it for %s)",
inherit_idx, inherit_idx ? "reading" : "writing");
if (ctx->system.version)
err = (ctx->system.pipe) (ctx, fd, inherit_idx);
else
err = __assuan_pipe (ctx, fd, inherit_idx);
if (err)
return TRACE_SYSRES (err);
return TRACE_SUC2 ("read=0x%x, write=0x%x", fd[0], fd[1]);
}
/* Close the given file descriptor, created with _assuan_pipe or one
of the socket functions. */
int
_assuan_close (assuan_context_t ctx, assuan_fd_t fd)
{
TRACE1 (ctx, ASSUAN_LOG_SYSIO, "_assuan_close", ctx,
"fd=0x%x", fd);
if (ctx->system.version)
return (ctx->system.close) (ctx, fd);
else
{
int res;
_assuan_pre_syscall ();
res = __assuan_close (ctx, fd);
_assuan_post_syscall ();
return res;
}
}
/* Same as assuan_close but used for the inheritable end of a
pipe. */
int
_assuan_close_inheritable (assuan_context_t ctx, assuan_fd_t fd)
{
TRACE1 (ctx, ASSUAN_LOG_SYSIO, "_assuan_close_inheritable", ctx,
"fd=0x%x", fd);
-#ifdef HAVE_W32CE_SYSTEM
- return 0; /* Nothing to do because it is a rendezvous id. */
-#else
if (ctx->system.version)
return (ctx->system.close) (ctx, fd);
else
{
int res;
_assuan_pre_syscall ();
res = __assuan_close (ctx, fd);
_assuan_post_syscall ();
return res;
}
-#endif
}
ssize_t
_assuan_read (assuan_context_t ctx, assuan_fd_t fd, void *buffer, size_t size)
{
#if DEBUG_SYSIO
ssize_t res;
TRACE_BEG3 (ctx, ASSUAN_LOG_SYSIO, "_assuan_read", ctx,
"fd=0x%x, buffer=%p, size=%i", fd, buffer, size);
if (ctx->system.version)
res = (ctx->system.read) (ctx, fd, buffer, size);
else
{
_assuan_pre_syscall ();
res = __assuan_read (ctx, fd, buffer, size);
_assuan_post_syscall ();
}
return TRACE_SYSRES (res);
#else
if (ctx->system.version)
return (ctx->system.read) (ctx, fd, buffer, size);
else
{
ssize_t res;
_assuan_pre_syscall ();
res = __assuan_read (ctx, fd, buffer, size);
_assuan_post_syscall ();
return res;
}
#endif
}
ssize_t
_assuan_write (assuan_context_t ctx, assuan_fd_t fd, const void *buffer,
size_t size)
{
#if DEBUG_SYSIO
ssize_t res;
TRACE_BEG3 (ctx, ASSUAN_LOG_SYSIO, "_assuan_write", ctx,
"fd=0x%x, buffer=%p, size=%i", fd, buffer, size);
if (ctx->system.version)
res = (ctx->system.write) (ctx, fd, buffer, size);
else
{
_assuan_pre_syscall ();
res = __assuan_write (ctx, fd, buffer, size);
_assuan_post_syscall ();
}
return TRACE_SYSRES (res);
#else
if (ctx->system.version)
return (ctx->system.write) (ctx, fd, buffer, size);
else
{
ssize_t res;
_assuan_pre_syscall ();
res = __assuan_write (ctx, fd, buffer, size);
_assuan_post_syscall ();
return res;
}
#endif
}
int
_assuan_recvmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg,
int flags)
{
#if DEBUG_SYSIO
ssize_t res;
TRACE_BEG3 (ctx, ASSUAN_LOG_SYSIO, "_assuan_recvmsg", ctx,
"fd=0x%x, msg=%p, flags=0x%x", fd, msg, flags);
if (ctx->system.version)
res = (ctx->system.recvmsg) (ctx, fd, msg, flags);
else
{
_assuan_pre_syscall ();
res = __assuan_recvmsg (ctx, fd, msg, flags);
_assuan_post_syscall ();
}
if (res > 0)
{
struct cmsghdr *cmptr;
TRACE_LOG2 ("msg->msg_iov[0] = { iov_base=%p, iov_len=%i }",
msg->msg_iov[0].iov_base, msg->msg_iov[0].iov_len);
TRACE_LOGBUF (msg->msg_iov[0].iov_base, res);
cmptr = CMSG_FIRSTHDR (msg);
if (cmptr)
{
void *data = CMSG_DATA (cmptr);
TRACE_LOG5 ("cmsg_len=0x%x (0x%x data), cmsg_level=0x%x, "
"cmsg_type=0x%x, first data int=0x%x", cmptr->cmsg_len,
cmptr->cmsg_len - (((char *)data) - ((char *)cmptr)),
cmptr->cmsg_level, cmptr->cmsg_type, *(int *)data);
}
}
return TRACE_SYSRES (res);
#else
if (ctx->system.version)
return (ctx->system.recvmsg) (ctx, fd, msg, flags);
else
{
ssize_t res;
_assuan_pre_syscall ();
res = __assuan_recvmsg (ctx, fd, msg, flags);
_assuan_post_syscall ();
return res;
}
#endif
}
int
_assuan_sendmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg,
int flags)
{
#if DEBUG_SYSIO
ssize_t res;
TRACE_BEG3 (ctx, ASSUAN_LOG_SYSIO, "_assuan_sendmsg", ctx,
"fd=0x%x, msg=%p, flags=0x%x", fd, msg, flags);
{
struct cmsghdr *cmptr;
TRACE_LOG2 ("msg->iov[0] = { iov_base=%p, iov_len=%i }",
msg->msg_iov[0].iov_base, msg->msg_iov[0].iov_len);
TRACE_LOGBUF (msg->msg_iov[0].iov_base, msg->msg_iov[0].iov_len);
cmptr = CMSG_FIRSTHDR (msg);
if (cmptr)
{
void *data = CMSG_DATA (cmptr);
TRACE_LOG5 ("cmsg_len=0x%x (0x%x data), cmsg_level=0x%x, "
"cmsg_type=0x%x, first data int=0x%x", cmptr->cmsg_len,
cmptr->cmsg_len - (((char *)data) - ((char *)cmptr)),
cmptr->cmsg_level, cmptr->cmsg_type, *(int *)data);
}
}
if (ctx->system.version)
res = (ctx->system.sendmsg) (ctx, fd, msg, flags);
else
{
_assuan_pre_syscall ();
res = __assuan_sendmsg (ctx, fd, msg, flags);
_assuan_post_syscall ();
}
return TRACE_SYSRES (res);
#else
if (ctx->system.version)
return (ctx->system.sendmsg) (ctx, fd, msg, flags);
else
{
ssize_t res;
_assuan_pre_syscall ();
res = __assuan_sendmsg (ctx, fd, msg, flags);
_assuan_post_syscall ();
return res;
}
#endif
}
/* Create a new process from NAME and ARGV. Provide FD_IN and FD_OUT
as stdin and stdout. Inherit the ASSUAN_INVALID_FD-terminated
FD_CHILD_LIST as given (no remapping), which must be inheritable.
On Unix, call ATFORK with ATFORKVALUE after fork and before exec. */
int
_assuan_spawn (assuan_context_t ctx, pid_t *r_pid, const char *name,
const char **argv,
assuan_fd_t fd_in, assuan_fd_t fd_out,
assuan_fd_t *fd_child_list,
void (*atfork) (void *opaque, int reserved),
void *atforkvalue, unsigned int flags)
{
int res;
int i;
TRACE_BEG6 (ctx, ASSUAN_LOG_CTX, "_assuan_spawn", ctx,
"name=%s,fd_in=0x%x,fd_out=0x%x,"
"atfork=%p,atforkvalue=%p,flags=%i",
name ? name : "(null)", fd_in, fd_out,
atfork, atforkvalue, flags);
if (name)
{
i = 0;
while (argv[i])
{
TRACE_LOG2 ("argv[%2i] = %s", i, argv[i]);
i++;
}
}
i = 0;
if (fd_child_list)
{
while (fd_child_list[i] != ASSUAN_INVALID_FD)
{
TRACE_LOG2 ("fd_child_list[%2i] = 0x%x", i, fd_child_list[i]);
i++;
}
}
if (ctx->system.version)
res = (ctx->system.spawn) (ctx, r_pid, name, argv, fd_in, fd_out,
fd_child_list, atfork, atforkvalue, flags);
else
res = __assuan_spawn (ctx, r_pid, name, argv, fd_in, fd_out,
fd_child_list, atfork, atforkvalue, flags);
if (name)
{
TRACE_LOG1 ("pid = 0x%x", *r_pid);
}
else
{
TRACE_LOG2 ("pid = 0x%x (%s)", *r_pid, *argv);
}
return TRACE_SYSERR (res);
}
/* FIXME: Add some sort of waitpid function that covers GPGME and
gpg-agent's use of assuan. */
pid_t
_assuan_waitpid (assuan_context_t ctx, pid_t pid, int action,
int *status, int options)
{
#if DEBUG_SYSIO
ssize_t res;
TRACE_BEG4 (ctx, ASSUAN_LOG_SYSIO, "_assuan_waitpid", ctx,
"pid=%i, action=%i, status=%p, options=%i",
pid, action, status, options);
if (ctx->system.version)
res = (ctx->system.waitpid) (ctx, pid, action, status, options);
else
{
_assuan_pre_syscall ();
res = __assuan_waitpid (ctx, pid, action, status, options);
_assuan_post_syscall ();
}
return TRACE_SYSRES (res);
#else
if (ctx->system.version)
return (ctx->system.waitpid) (ctx, pid, action, status, options);
else
{
ssize_t res;
_assuan_pre_syscall ();
res = __assuan_waitpid (ctx, pid, action, status, options);
_assuan_post_syscall ();
return res;
}
#endif
}
int
_assuan_socketpair (assuan_context_t ctx, int namespace, int style,
int protocol, assuan_fd_t filedes[2])
{
int res;
TRACE_BEG4 (ctx, ASSUAN_LOG_SYSIO, "_assuan_socketpair", ctx,
"namespace=%i,style=%i,protocol=%i,filedes=%p",
namespace, style, protocol, filedes);
if (ctx->system.version)
res = (ctx->system.socketpair) (ctx, namespace, style, protocol, filedes);
else
res = __assuan_socketpair (ctx, namespace, style, protocol, filedes);
if (res == 0)
TRACE_LOG2 ("filedes = { 0x%x, 0x%x }", filedes[0], filedes[1]);
return TRACE_SYSERR (res);
}
assuan_fd_t
_assuan_socket (assuan_context_t ctx, int namespace, int style, int protocol)
{
assuan_fd_t res;
TRACE_BEG3 (ctx, ASSUAN_LOG_SYSIO, "_assuan_socket", ctx,
"namespace=%i,style=%i,protocol=%i",
namespace, style, protocol);
if (ctx->system.version)
res = (ctx->system.socket) (ctx, namespace, style, protocol);
else
res = __assuan_socket (ctx, namespace, style, protocol);
return TRACE_SYSRES (res);
}
int
_assuan_connect (assuan_context_t ctx, assuan_fd_t sock,
struct sockaddr *addr, socklen_t length)
{
int res;
TRACE_BEG3 (ctx, ASSUAN_LOG_SYSIO, "_assuan_connect", ctx,
"socket=%i,addr=%p,length=%i", sock, addr, length);
if (ctx->system.version)
res = (ctx->system.connect) (ctx, sock, addr, length);
else
{
_assuan_pre_syscall ();
res = __assuan_connect (ctx, sock, addr, length);
_assuan_post_syscall ();
}
return TRACE_SYSRES (res);
}
diff --git a/src/sysutils.c b/src/sysutils.c
index 6c09e47..3778668 100644
--- a/src/sysutils.c
+++ b/src/sysutils.c
@@ -1,140 +1,53 @@
/* sysutils.c - System utilities
* Copyright (C) 2010 Free Software Foundation, Inc.
*
* This file is part of Assuan.
*
* Assuan 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.
*
* Assuan 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
* Lesser 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 .
* SPDX-License-Identifier: LGPL-2.1+
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include
#include
#include
#ifdef HAVE_W32_SYSTEM
# ifdef HAVE_WINSOCK2_H
# include
# endif
# include
-# ifdef HAVE_W32CE_SYSTEM
-# include
-# endif /*HAVE_W32CE_SYSTEM*/
#endif /*HAVE_W32_SYSTEM*/
#include "assuan-defs.h"
/* This is actually a dummy function to make sure that is module is
not empty. Some compilers barf on empty modules. */
const char *
_assuan_sysutils_blurb (void)
{
static const char blurb[] =
"\n\n"
"This is Libassuan " PACKAGE_VERSION " - The GnuPG IPC Library\n"
"Copyright 2001-2013 Free Software Foundation, Inc.\n"
"Copyright 2001-2020 g10 Code GmbH\n"
"\n"
"SPDX-License-Identifier: LGPL-2.1-or-later\n"
"(" BUILD_REVISION " " BUILD_TIMESTAMP ")\n"
"\n\n";
return blurb;
}
-
-
-/* Return a string from the Win32 Registry or NULL in case of error.
- The returned string is allocated using a plain malloc and thus the
- caller needs to call the standard free(). The string is looked up
- under HKEY_LOCAL_MACHINE. */
-#ifdef HAVE_W32CE_SYSTEM
-static char *
-w32_read_registry (const wchar_t *dir, const wchar_t *name)
-{
- HKEY handle;
- DWORD n, nbytes;
- wchar_t *buffer = NULL;
- char *result = NULL;
-
- if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &handle))
- return NULL; /* No need for a RegClose, so return immediately. */
-
- nbytes = 1;
- if (RegQueryValueEx (handle, name, 0, NULL, NULL, &nbytes))
- goto out;
- buffer = malloc ((n=nbytes+2));
- if (!buffer)
- goto out;
- if (RegQueryValueEx (handle, name, 0, NULL, (PBYTE)buffer, &n))
- {
- free (buffer);
- buffer = NULL;
- goto out;
- }
-
- n = WideCharToMultiByte (CP_UTF8, 0, buffer, nbytes, NULL, 0, NULL, NULL);
- if (n < 0 || (n+1) <= 0)
- goto out;
- result = malloc (n+1);
- if (!result)
- goto out;
- n = WideCharToMultiByte (CP_UTF8, 0, buffer, nbytes, result, n, NULL, NULL);
- if (n < 0)
- {
- free (result);
- result = NULL;
- goto out;
- }
- result[n] = 0;
-
- out:
- free (buffer);
- RegCloseKey (handle);
- return result;
-}
-#endif /*HAVE_W32CE_SYSTEM*/
-
-
-
-#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 *
-_assuan_getenv (const char *name)
-{
- static int initialized;
- static char *val_debug;
- static char *val_full_logging;
-
- if (!initialized)
- {
- val_debug = w32_read_registry (L"\\Software\\GNU\\libassuan",
- L"debug");
- val_full_logging = w32_read_registry (L"\\Software\\GNU\\libassuan",
- L"full_logging");
- initialized = 1;
- }
-
-
- if (!strcmp (name, "ASSUAN_DEBUG"))
- return val_debug;
- else if (!strcmp (name, "ASSUAN_FULL_LOGGING"))
- return val_full_logging;
- else
- return NULL;
-}
-#endif /*HAVE_W32CE_SYSTEM*/
diff --git a/src/w32ce-add.h b/src/w32ce-add.h
deleted file mode 100644
index 1f7d7db..0000000
--- a/src/w32ce-add.h
+++ /dev/null
@@ -1,34 +0,0 @@
-## w32ce-add.h - Include fragment to build assuan.h.
-## Copyright (C) 2010 Free Software Foundation, Inc.
-##
-## This file is part of Assuan.
-##
-## Assuan 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.
-##
-## Assuan 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
-## Lesser 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 .
-## SPDX-License-Identifier: LGPL-2.1+
-##
-##
-## This file is included by the mkheader tool. Lines starting with
-## a double hash mark are not copied to the destination file.
-
-HANDLE _assuan_w32ce_prepare_pipe (int *r_rvid, int write_end);
-HANDLE _assuan_w32ce_finish_pipe (int rvid, int write_end);
-DWORD _assuan_w32ce_create_pipe (HANDLE *read_hd, HANDLE *write_hd,
- LPSECURITY_ATTRIBUTES sec_attr, DWORD size);
-#define CreatePipe(a,b,c,d) _assuan_w32ce_create_pipe ((a),(b),(c),(d))
-
-/* Magic handle values. Let's hope those never occur legitimately as
- handles or sockets. (Sockets are numbered sequentially from 0,
- while handles seem aligned to wordsize. */
-#define ASSUAN_STDIN (void*)0x7ffffffd
-#define ASSUAN_STDOUT (void*)0x7fffffff
diff --git a/src/w32ce-fd-t.inc.h b/src/w32ce-fd-t.inc.h
deleted file mode 100644
index 70c7997..0000000
--- a/src/w32ce-fd-t.inc.h
+++ /dev/null
@@ -1,33 +0,0 @@
-## w32ce-fd-t.inc.h - Include fragment to build assuan.h.
-## Copyright (C) 2010 Free Software Foundation, Inc.
-##
-## This file is part of Assuan.
-##
-## Assuan 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.
-##
-## Assuan 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
-## Lesser 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 .
-## SPDX-License-Identifier: LGPL-2.1+
-##
-##
-## This file is included by the mkheader tool. Lines starting with
-## a double hash mark are not copied to the destination file.
-
-typedef void *assuan_fd_t;
-#define ASSUAN_INVALID_FD ((void*)(-1))
-#define ASSUAN_INVALID_PID ((pid_t) -1)
-static GPG_ERR_INLINE assuan_fd_t
-assuan_fd_from_posix_fd (int fd)
-{
- return (assuan_fd_t)(fd);
-}
-
-##EOF##
diff --git a/tests/Makefile.am b/tests/Makefile.am
index b547d37..f43c712 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1,51 +1,47 @@
# Makefile for Assuan regression tests
# Copyright (C) 2006 Free Software Foundation, Inc.
#
# This file is part of Assuan.
#
# Assuan 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 3 of
# the License, or (at your option) any later version.
#
# Assuan 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
# Lesser 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 .
## Process this file with automake to produce Makefile.in
TESTS_ENVIRONMENT =
-EXTRA_DIST = motd ce-createpipe.c
+EXTRA_DIST = motd
BUILT_SOURCES =
CLEANFILES =
TESTS = version
-if HAVE_W32CE_SYSTEM
-w32cetools = ce-createpipe ce-server
-endif
-
if HAVE_W32_SYSTEM
testtools =
else
TESTS += pipeconnect
testtools = socks5
endif
if USE_DESCRIPTOR_PASSING
TESTS += fdpassing
endif
AM_CFLAGS = $(GPG_ERROR_CFLAGS)
AM_LDFLAGS = -no-install
noinst_HEADERS = common.h
noinst_PROGRAMS = $(TESTS) $(w32cetools) $(testtools)
LDADD = ../src/libassuan.la $(GPG_ERROR_LIBS) \
@LDADD_FOR_TESTS_KLUDGE@
diff --git a/tests/ce-createpipe.c b/tests/ce-createpipe.c
deleted file mode 100644
index b44784c..0000000
--- a/tests/ce-createpipe.c
+++ /dev/null
@@ -1,179 +0,0 @@
-/* ce-createpipe.c - Test the W32CE CreatePipe implementation.
- Copyright (C) 2010 Free Software Foundation, Inc.
-
- This file is part of Assuan.
-
- Assuan 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 3 of
- the License, or (at your option) any later version.
-
- Assuan 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
- Lesser 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 .
- */
-
-#ifdef HAVE_CONFIG_H
-#include
-#endif
-
-#include
-#include
-#include
-#include
-#include
-
-#define WIN32_LEAN_AND_MEAN
-#include
-
-#include "common.h"
-
-#include "../src/assuan.h" /* We need the CreatePipe prototype. */
-
-
-static DWORD
-reader_thread (void *arg)
-{
- HANDLE hd = arg;
- DWORD nread;
- char buffer[16];
-
- for (;;)
- {
- if (!ReadFile (hd, buffer, sizeof buffer, &nread, FALSE))
- {
- log_error ("reader: ReadFile failed: rc=%d\n", (int)GetLastError ());
- break;
- }
- log_info ("reader: read %d bytes\n", (int)nread);
- log_printhex ("got: ", buffer, nread);
- }
-
- log_info ("reader: finished\n");
- CloseHandle (hd);
- return 0;
-}
-
-
-static DWORD
-writer_thread (void *arg)
-{
- HANDLE hd = arg;
- DWORD nwritten;
- int i = 0;
- int j;
- char buffer[20];
- int count;
-
- for (count=0; count < 30; count++)
- {
- for (j=0; j < sizeof buffer; j++)
- buffer[j] = i++;
-
- if (!WriteFile (hd, buffer, sizeof buffer, &nwritten, NULL))
- {
- log_error ("writer: WriteFile failed: rc=%d\n", (int)GetLastError ());
- break;
- }
- if (nwritten != sizeof buffer)
- log_info ("writer: wrote only %d bytes\n", (int)nwritten);
- }
-
- log_info ("writer: finished\n");
- CloseHandle (hd);
- return 0;
-}
-
-
-
-static void
-run_test (void)
-{
- HANDLE hd[2];
- HANDLE threads[2];
-
- if (!CreatePipe (&hd[0], &hd[1], NULL, 0))
- {
- log_error ("CreatePipe failed: rc=%d\n", (int)GetLastError ());
- return;
- }
- log_info ("pipe created read=%p write=%p\n", hd[0], hd[1]);
-
- threads[0] = CreateThread (NULL, 0, reader_thread, hd[0], 0, NULL);
- if (!threads[0])
- log_fatal ("error creating reader thread: rc=%d\n", (int)GetLastError ());
- else
- log_info ("reader thread created\n");
- threads[1] = CreateThread (NULL, 0, writer_thread, hd[1], 0, NULL);
- if (!threads[0])
- log_fatal ("error creating writer thread: rc=%d\n", (int)GetLastError ());
- else
- log_info ("writer thread created\n");
-
- switch (WaitForMultipleObjects (2, threads, FALSE, INFINITE))
- {
- case WAIT_OBJECT_0:
- log_info ("reader thread finished first\n");
- break;
- case WAIT_OBJECT_0 + 1:
- log_info ("writer thread finished first\n");
- break;
- default:
- log_error ("WFMO failed: rc=%d\n", (int)GetLastError ());
- break;
- }
-
-
-
- CloseHandle (threads[0]);
- CloseHandle (threads[1]);
-}
-
-
-
-/*
- M A I N
- */
-int
-main (int argc, char **argv)
-{
- int last_argc = -1;
-
- if (argc)
- {
- log_set_prefix (*argv);
- argc--; argv++;
- }
- while (argc && last_argc != argc )
- {
- last_argc = argc;
- if (!strcmp (*argv, "--help"))
- {
- printf ("usage: %s [options]\n"
- "\n"
- "Options:\n"
- " --verbose Show what is going on\n",
- log_get_prefix ());
- exit (0);
- }
- if (!strcmp (*argv, "--verbose"))
- {
- verbose = 1;
- argc--; argv++;
- }
- else if (!strcmp (*argv, "--debug"))
- {
- verbose = debug = 1;
- argc--; argv++;
- }
- }
-
- run_test ();
-
- return errorcount ? 1 : 0;
-}
-
diff --git a/tests/ce-server.c b/tests/ce-server.c
deleted file mode 100644
index 0565aee..0000000
--- a/tests/ce-server.c
+++ /dev/null
@@ -1,1418 +0,0 @@
-/* ce-server.c - An Assuan testbed for W32CE; server code
- Copyright (C) 2010 Free Software Foundation, Inc.
-
- This file is part of Assuan.
-
- Assuan 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 3 of
- the License, or (at your option) any later version.
-
- Assuan 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
- Lesser 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 .
- */
-
-#ifdef HAVE_CONFIG_H
-#include
-#endif
-
-#include
-#include
-#include
-#include
-#include
-#include
-#ifdef HAVE_W32_SYSTEM
-# define WIN32_LEAN_AND_MEAN
-# include
-#else
-# include
-# include
-# include
-# include
-# ifdef HAVE_SYS_SELECT_H
-# include
-# endif
-#endif
-#include
-
-#ifdef HAVE_W32CE_SYSTEM
-# ifndef FILE_ATTRIBUTE_ROMSTATICREF
-# define FILE_ATTRIBUTE_ROMSTATICREF FILE_ATTRIBUTE_OFFLINE
-# endif
-extern BOOL GetStdioPathW (int, wchar_t *, DWORD *);
-extern BOOL SetStdioPathW (int, const wchar_t *);
-#endif /*!HAVE_W32CE_SYSTEM*/
-
-#include "../src/assuan.h"
-
-#include "common.h"
-
-/* The port we are using by default. */
-static short server_port = 15898;
-
-/* Flag set to indicate a shutdown. */
-static int shutdown_pending;
-
-/* An object to keep track of file descriptors. */
-struct fdinfo_s
-{
- struct fdinfo_s *next;
- assuan_fd_t fd; /* The descriptor. */
-};
-typedef struct fdinfo_s *fdinfo_t;
-
-
-/* The local state of a connection. */
-struct state_s
-{
- /* The current working directory - access using get_cwd(). */
- char *cwd;
-
- /* If valid, a socket in listening state created by the dataport
- command. */
- assuan_fd_t dataport_listen_fd;
-
- /* If valid the socket accepted for the dataport. */
- assuan_fd_t dataport_accepted_fd;
-
- /* The error code from a dataport accept operation. */
- gpg_error_t dataport_accept_err;
-
- /* A list of all unused descriptors created by dataport commands. */
- fdinfo_t dataport_fds;
-
- /* The descriptor set by the DATAPORT command. */
- assuan_fd_t dataport_fd;
-};
-typedef struct state_s *state_t;
-
-
-
-/* Local prototypes. */
-static gpg_error_t cmd_newdataport_cont (void *opaque, gpg_error_t err,
- unsigned char *data, size_t datalen);
-
-
-
-/* A wrapper around read to make it work under Windows with HANDLES
- and socket descriptors. Takes care of EINTR on POSIX. */
-static int
-my_read (assuan_fd_t fd, void *buffer, size_t size)
-{
- int res;
-
-#ifdef HAVE_W32_SYSTEM
- res = recv (HANDLE2SOCKET (fd), buffer, size, 0);
- if (res == -1)
- {
- switch (WSAGetLastError ())
- {
- case WSAENOTSOCK:
- {
- DWORD nread = 0;
-
- res = ReadFile (fd, buffer, size, &nread, NULL);
- if (!res)
- {
- switch (GetLastError ())
- {
- case ERROR_BROKEN_PIPE:
- gpg_err_set_errno (EPIPE);
- break;
-
- default:
- gpg_err_set_errno (EIO);
- }
- res = -1;
- }
- else
- res = (int) nread;
- }
- break;
-
- case WSAEWOULDBLOCK:
- gpg_err_set_errno (EAGAIN);
- break;
-
- case ERROR_BROKEN_PIPE:
- gpg_err_set_errno (EPIPE);
- break;
-
- default:
- gpg_err_set_errno (EIO);
- break;
- }
- }
- return res;
-#else /*!HAVE_W32_SYSTEM*/
- do
- res = read (fd, buffer, size);
- while (res == -1 && errno == EINTR);
- return res;
-#endif /*!HAVE_W32_SYSTEM*/
-}
-
-
-/* Extended version of write(2) to guarantee that all bytes are
- written. Returns 0 on success or -1 and ERRNO on failure. NOTE:
- This function does not return the number of bytes written, so any
- error must be treated as fatal for this connection as the state of
- the receiver is unknown. This works best if blocking is allowed
- (so EAGAIN cannot occur). Under Windows this function handles
- socket descriptors and system handles. */
-static int
-my_writen (assuan_fd_t fd, const char *buffer, size_t length)
-{
- while (length)
- {
- int nwritten;
-#ifdef HAVE_W32_SYSTEM
- nwritten = send (HANDLE2SOCKET (fd), buffer, length, 0);
- if (nwritten == -1 && WSAGetLastError () == WSAENOTSOCK)
- {
- DWORD nwrite;
-
- nwritten = WriteFile (fd, buffer, length, &nwrite, NULL);
- if (!nwritten)
- {
- switch (GetLastError ())
- {
- case ERROR_BROKEN_PIPE:
- case ERROR_NO_DATA:
- gpg_err_set_errno (EPIPE);
- break;
-
- default:
- gpg_err_set_errno (EIO);
- break;
- }
- nwritten= -1;
- }
- else
- nwritten = (int)nwrite;
- }
-#else /*!HAVE_W32_SYSTEM*/
- nwritten = write (fd, buffer, length);
-#endif /*!HAVE_W32_SYSTEM*/
- if (nwritten < 0)
- {
- if (errno == EINTR)
- continue;
- return -1; /* write error */
- }
- length -= nwritten;
- buffer += nwritten;
- }
- return 0; /* okay */
-}
-
-
-
-static state_t
-new_state (void)
-{
- state_t state = xcalloc (1, sizeof *state);
- state->dataport_listen_fd = ASSUAN_INVALID_FD;
- state->dataport_accepted_fd = ASSUAN_INVALID_FD;
- state->dataport_fd = ASSUAN_INVALID_FD;
- return state;
-}
-
-static void
-release_state (state_t state)
-{
- fdinfo_t fi, fi2;
-
- if (!state)
- return;
-
- xfree (state->cwd);
-
- if (state->dataport_fd != ASSUAN_INVALID_FD)
- assuan_sock_close (state->dataport_fd);
- if (state->dataport_listen_fd != ASSUAN_INVALID_FD)
- assuan_sock_close (state->dataport_listen_fd);
- if (state->dataport_accepted_fd != ASSUAN_INVALID_FD)
- assuan_sock_close (state->dataport_accepted_fd);
-
- for (fi=state->dataport_fds; fi; fi = fi2)
- {
- fi2 = fi->next;
- if (fi->fd != ASSUAN_INVALID_FD)
- assuan_sock_close (fi->fd);
- }
-
- xfree (state);
-}
-
-
-/* Helper to print a message while leaving a command and to
- acknowledge the command. */
-static gpg_error_t
-leave_cmd (assuan_context_t ctx, gpg_error_t err)
-{
- if (err)
- {
- const char *name = assuan_get_command_name (ctx);
- if (!name)
- name = "?";
- if (gpg_err_source (err) == GPG_ERR_SOURCE_DEFAULT)
- log_error ("command '%s' failed: %s\n", name, gpg_strerror (err));
- else
- log_error ("command '%s' failed: %s <%s>\n", name,
- gpg_strerror (err), gpg_strsource (err));
- }
- return assuan_process_done (ctx, err);
-}
-
-
-#ifdef HAVE_W32CE_SYSTEM
-static char *
-wchar_to_utf8 (const wchar_t *string)
-{
- int n;
- size_t length = wcslen (string);
- char *result;
-
- n = WideCharToMultiByte (CP_UTF8, 0, string, length, NULL, 0, NULL, NULL);
- if (n < 0 || (n+1) <= 0)
- log_fatal ("WideCharToMultiByte failed\n");
-
- result = xmalloc (n+1);
- n = WideCharToMultiByte (CP_ACP, 0, string, length, result, n, NULL, NULL);
- if (n < 0)
- log_fatal ("WideCharToMultiByte failed\n");
-
- result[n] = 0;
- return result;
-}
-
-static wchar_t *
-utf8_to_wchar (const char *string)
-{
- int n;
- size_t length = strlen (string);
- wchar_t *result;
- size_t nbytes;
-
- n = MultiByteToWideChar (CP_UTF8, 0, string, length, NULL, 0);
- if (n < 0 || (n+1) <= 0)
- log_fatal ("MultiByteToWideChar failed\n");
-
- nbytes = (size_t)(n+1) * sizeof(*result);
- if (nbytes / sizeof(*result) != (n+1))
- log_fatal ("utf8_to_wchar: integer overflow\n");
- result = xmalloc (nbytes);
- n = MultiByteToWideChar (CP_UTF8, 0, string, length, result, n);
- if (n < 0)
- log_fatal ("MultiByteToWideChar failed\n");
- result[n] = 0;
-
- return result;
-}
-#endif /*HAVE_W32CE_SYSTEM*/
-
-#ifndef HAVE_W32CE_SYSTEM
-static char *
-gnu_getcwd (void)
-{
- size_t size = 100;
-
- while (1)
- {
- char *buffer = xmalloc (size);
- if (getcwd (buffer, size) == buffer)
- return buffer;
- xfree (buffer);
- if (errno != ERANGE)
- return 0;
- size *= 2;
- }
-}
-#endif /*!HAVE_W32CE_SYSTEM*/
-
-
-/* Return the current working directory. The returned string is valid
- as long as STATE->cwd is not changed. */
-static const char *
-get_cwd (state_t state)
-{
- if (!state->cwd)
- {
- /* No working directory yet. On WindowsCE make it the module
- directory of this process. */
-#ifdef HAVE_W32_SYSTEM
- char *p;
-#endif
-#ifdef HAVE_W32CE_SYSTEM
- wchar_t buf[MAX_PATH+1];
- size_t n;
-
- n = GetModuleFileName (NULL, buf, MAX_PATH);
- if (!n)
- state->cwd = xstrdup ("/");
- else
- {
- buf[n] = 0;
- state->cwd = wchar_to_utf8 (buf);
- p = strrchr (state->cwd, '\\');
- if (p)
- *p = 0;
- }
-#else
- state->cwd = gnu_getcwd ();
-#endif
-#ifdef HAVE_W32_SYSTEM
- for (p=state->cwd; *p; p++)
- if (*p == '\\')
- *p = '/';
-#endif /*HAVE_W32_SYSTEM*/
- }
-
- return state->cwd;
-}
-
-
-
-static gpg_error_t
-reset_notify (assuan_context_t ctx, char *line)
-{
- state_t state = assuan_get_pointer (ctx);
- fdinfo_t fi, fi2;
-
- /* Close all lingering dataport connections. */
- for (fi=state->dataport_fds; fi; fi = fi2)
- {
- fi2 = fi->next;
- if (fi->fd != ASSUAN_INVALID_FD)
- assuan_sock_close (fi->fd);
- }
- state->dataport_fds = NULL;
-
- return 0;
-}
-
-
-static gpg_error_t
-input_notify (assuan_context_t ctx, char *line)
-{
- state_t state = assuan_get_pointer (ctx);
- assuan_fd_t fd = assuan_get_input_fd (ctx);
- fdinfo_t fi;
-
- if (fd != ASSUAN_INVALID_FD)
- {
- /* The fd is now in use use - remove it from the unused list. */
- for (fi=state->dataport_fds; fi; fi = fi->next)
- if (fi->fd == fd)
- fi->fd = ASSUAN_INVALID_FD;
- }
-
- return 0;
-}
-
-
-static gpg_error_t
-output_notify (assuan_context_t ctx, char *line)
-{
- state_t state = assuan_get_pointer (ctx);
- assuan_fd_t fd = assuan_get_output_fd (ctx);
- fdinfo_t fi;
-
- if (fd != ASSUAN_INVALID_FD)
- {
- /* The fd is now in use - remove it from the unused list. */
- for (fi=state->dataport_fds; fi; fi = fi->next)
- if (fi->fd == fd)
- fi->fd = ASSUAN_INVALID_FD;
- }
-
- return 0;
-}
-
-
-
-static const char hlp_echo[] =
- "ECHO \n"
- "\n"
- "Print LINE as data lines.\n";
-static gpg_error_t
-cmd_echo (assuan_context_t ctx, char *line)
-{
- gpg_error_t err;
-
- err = assuan_send_data (ctx, line, strlen (line));
-
- return leave_cmd (ctx, err);
-}
-
-
-
-static const char hlp_cat[] =
- "CAT []\n"
- "\n"
- "Copy the content of FILENAME to the descriptor set by the OUTPUT\n"
- "command. If no OUTPUT command has been given, send the content\n"
- "using data lines. Without FILENAME take the content from the\n"
- "descriptor set by the INPUT command; if a DATAPORT has been set\n"
- "this descriptor is used for I/O and the INOPUT/OUTPUT descriptors\n"
- "are not touched.";
-static gpg_error_t
-cmd_cat (assuan_context_t ctx, char *line)
-{
- state_t state = assuan_get_pointer (ctx);
- gpg_error_t err = 0;
- assuan_fd_t fd_in = ASSUAN_INVALID_FD;
- assuan_fd_t fd_out = ASSUAN_INVALID_FD;
- FILE *fp_in = NULL;
- char buf[256];
- size_t nread;
- int use_dataport = 0;
-
- if (*line)
- {
- fp_in = fopen (line, "rb");
- if (!fp_in)
- err = gpg_error_from_syserror ();
- else
- fd_out = assuan_get_output_fd (ctx);
- }
- else if (state->dataport_fd != ASSUAN_INVALID_FD)
- {
- use_dataport = 1;
- fd_in = state->dataport_fd;
- fd_out = state->dataport_fd;
- }
- else if ((fd_in = assuan_get_input_fd (ctx)) != ASSUAN_INVALID_FD)
- {
- /* This FD is actually a socket descriptor. We can't fdopen it
- because under Windows we ust use recv(2) instead of read(2).
- Note that on POSIX systems there is no difference between
- libc file descriptors and socket descriptors. */
-
- fd_out = assuan_get_output_fd (ctx);
- }
- else
- err = gpg_error (GPG_ERR_ASS_NO_INPUT);
- if (err)
- goto leave;
-
- do
- {
- if (fp_in)
- {
- nread = fread (buf, 1, sizeof buf, fp_in);
- if (nread < sizeof buf)
- {
- if (ferror (fp_in))
- err = gpg_error_from_syserror ();
- else if (feof (fp_in))
- err = gpg_error (GPG_ERR_EOF);
- }
- }
- else
- {
- int n;
-
- nread = 0;
- n = my_read (fd_in, buf, sizeof buf);
- if (n < 0)
- err = gpg_error_from_syserror ();
- else if (!n)
- err = gpg_error (GPG_ERR_EOF);
- else
- nread = n;
- }
-
-
- if (fd_out != ASSUAN_INVALID_FD)
- {
- if (nread && my_writen (fd_out, buf, nread))
- err = gpg_error_from_syserror ();
- }
- else if (nread)
- err = assuan_send_data (ctx, buf, nread);
- }
- while (!err);
- if (gpg_err_code (err) == GPG_ERR_EOF)
- err = 0;
-
-leave:
- if (fp_in)
- fclose (fp_in);
- if (use_dataport)
- {
- if (state->dataport_fd != ASSUAN_INVALID_FD)
- {
- assuan_sock_close (state->dataport_fd);
- state->dataport_fd = ASSUAN_INVALID_FD;
- }
- }
- else
- {
- assuan_close_input_fd (ctx);
- assuan_close_output_fd (ctx);
- }
- return leave_cmd (ctx, err);
-}
-
-
-static const char hlp_pwd[] =
- "PWD\n"
- "\n"
- "Print the curent working directory of this session.\n";
-static gpg_error_t
-cmd_pwd (assuan_context_t ctx, char *line)
-{
- state_t state = assuan_get_pointer (ctx);
- gpg_error_t err;
- const char *string;
-
- string = get_cwd (state);
- err = assuan_send_data (ctx, string, strlen (string));
-
- return leave_cmd (ctx, err);
-}
-
-
-static const char hlp_cd[] =
- "CD [dir]\n"
- "\n"
- "Change the curretn directory of the session.\n";
-static gpg_error_t
-cmd_cd (assuan_context_t ctx, char *line)
-{
- state_t state = assuan_get_pointer (ctx);
- gpg_error_t err = 0;
- char *newdir, *p;
-
- for (p=line; *p; p++)
- if (*p == '\\')
- *p = '/';
-
- if (!*line)
- {
- xfree (state->cwd);
- state->cwd = NULL;
- get_cwd (state);
- }
- else
- {
- if (*line == '/')
- newdir = xstrdup (line);
- else
- newdir = xstrconcat (get_cwd (state), "/", line, NULL);
-
- while (strlen(newdir) > 1 && line[strlen(newdir)-1] == '/')
- line[strlen(newdir)-1] = 0;
- xfree (state->cwd);
- state->cwd = newdir;
- }
-
- return leave_cmd (ctx, err);
-}
-
-
-
-
-
-#ifdef HAVE_W32CE_SYSTEM
-static const char hlp_ls[] =
- "LS []\n"
- "\n"
- "List the files described by PATTERN.\n";
-static gpg_error_t
-cmd_ls (assuan_context_t ctx, char *line)
-{
- state_t state = assuan_get_pointer (ctx);
- gpg_error_t err;
- WIN32_FIND_DATA fi;
- char buf[500];
- HANDLE hd;
- char *p, *fname;
- wchar_t *wfname;
-
- if (!*line)
- fname = xstrconcat (get_cwd (state), "/*", NULL);
- else if (*line == '/' || *line == '\\')
- fname = xstrdup (line);
- else
- fname = xstrconcat (get_cwd (state), "/", line, NULL);
- for (p=fname; *p; p++)
- if (*p == '/')
- *p = '\\';
- assuan_write_status (ctx, "PATTERN", fname);
- wfname = utf8_to_wchar (fname);
- xfree (fname);
- hd = FindFirstFile (wfname, &fi);
- free (wfname);
- if (hd == INVALID_HANDLE_VALUE)
- {
- log_info ("FindFirstFile returned %d\n", GetLastError ());
- err = gpg_error_from_syserror (); /* Works for W32CE. */
- goto leave;
- }
-
- do
- {
- DWORD attr = fi.dwFileAttributes;
-
- fname = wchar_to_utf8 (fi.cFileName);
- snprintf (buf, sizeof buf,
- "%c%c%c%c%c%c%c%c%c%c%c%c%c %7lu%c %s\n",
- (attr & FILE_ATTRIBUTE_DIRECTORY)
- ? ((attr & FILE_ATTRIBUTE_DEVICE)? 'c':'d'):'-',
- (attr & FILE_ATTRIBUTE_READONLY)? 'r':'-',
- (attr & FILE_ATTRIBUTE_HIDDEN)? 'h':'-',
- (attr & FILE_ATTRIBUTE_SYSTEM)? 's':'-',
- (attr & FILE_ATTRIBUTE_ARCHIVE)? 'a':'-',
- (attr & FILE_ATTRIBUTE_COMPRESSED)? 'c':'-',
- (attr & FILE_ATTRIBUTE_ENCRYPTED)? 'e':'-',
- (attr & FILE_ATTRIBUTE_INROM)? 'R':'-',
- (attr & FILE_ATTRIBUTE_REPARSE_POINT)? 'P':'-',
- (attr & FILE_ATTRIBUTE_ROMMODULE)? 'M':'-',
- (attr & FILE_ATTRIBUTE_ROMSTATICREF)? 'R':'-',
- (attr & FILE_ATTRIBUTE_SPARSE_FILE)? 'S':'-',
- (attr & FILE_ATTRIBUTE_TEMPORARY)? 't':'-',
- (unsigned long)fi.nFileSizeLow,
- fi.nFileSizeHigh? 'X':' ',
- fname);
- free (fname);
- err = assuan_send_data (ctx, buf, strlen (buf));
- if (!err)
- err = assuan_send_data (ctx, NULL, 0);
- }
- while (!err && FindNextFile (hd, &fi));
- if (err)
- ;
- else if (GetLastError () == ERROR_NO_MORE_FILES)
- err = 0;
- else
- {
- log_info ("FindNextFile returned %d\n", GetLastError ());
- err = gpg_error_from_syserror ();
- }
- FindClose (hd);
-
- leave:
- return leave_cmd (ctx, err);
-}
-#endif /*HAVE_W32CE_SYSTEM*/
-
-
-#ifdef HAVE_W32CE_SYSTEM
-static const char hlp_run[] =
- "RUN []\n"
- "\n"
- "Run the program in FILENAME with the arguments ARGS.\n"
- "This creates a new process and waits for it to finish.\n"
- "FIXME: The process' stdin is connected to the file set by the\n"
- "INPUT command; stdout and stderr to the one set by OUTPUT.\n";
-static gpg_error_t
-cmd_run (assuan_context_t ctx, char *line)
-{
- /* state_t state = assuan_get_pointer (ctx); */
- gpg_error_t err;
- BOOL w32ret;
- PROCESS_INFORMATION pi = { NULL, 0, 0, 0 };
- char *p;
- wchar_t *pgmname = NULL;
- wchar_t *cmdline = NULL;
- int code;
- DWORD exc;
- int idx;
- struct {
- HANDLE hd[2];
- int oldname_valid;
- wchar_t oldname[MAX_PATH];
- } pipes[3];
-
- for (idx=0; idx < 3; idx++)
- {
- pipes[idx].hd[0] = pipes[idx].hd[1] = INVALID_HANDLE_VALUE;
- pipes[idx].oldname_valid = 0;
- }
-
- p = strchr (line, ' ');
- if (p)
- {
- *p = 0;
- pgmname = utf8_to_wchar (line);
- for (p++; *p && *p == ' '; p++)
- ;
- cmdline = utf8_to_wchar (p);
- }
- else
- pgmname = utf8_to_wchar (line);
- {
- char *tmp1 = wchar_to_utf8 (pgmname);
- char *tmp2 = wchar_to_utf8 (cmdline);
- log_info ("CreateProcess, path=`%s' cmdline=`%s'\n", tmp1, tmp2);
- xfree (tmp2);
- xfree (tmp1);
- }
-
- /* Redirect the standard handles. */
- /* Create pipes. */
- for (idx=0; idx < 3; idx++)
- {
- if (!_assuan_w32ce_create_pipe (&pipes[idx].hd[0], &pipes[idx].hd[1],
- NULL, 0))
- {
- err = gpg_error_from_syserror ();
- log_error ("CreatePipe failed: %d\n", GetLastError ());
- pipes[idx].hd[0] = pipes[idx].hd[1] = INVALID_HANDLE_VALUE;
- goto leave;
- }
- }
-
- /* Save currently assigned devices. */
- for (idx=0; idx < 3; idx++)
- {
- DWORD dwlen = MAX_PATH;
- if (!GetStdioPathW (idx, pipes[idx].oldname, &dwlen))
- {
- err = gpg_error_from_syserror ();
- log_error ("GetStdioPath failed: %d\n", GetLastError ());
- goto leave;
- }
- pipes[idx].oldname_valid = 1;
- }
-
- /* Connect the pipes. */
- {
- if (!SetStdioPathW (1, L"\\mystdout.log"))
- {
- err = gpg_error_from_syserror ();
- log_error ("SetStdioPathW(%d) failed: %d\n", idx, GetLastError ());
- goto leave;
- }
- if (!SetStdioPathW (2, L"\\mystderr.log"))
- {
- err = gpg_error_from_syserror ();
- log_error ("SetStdioPathW(%d) failed: %d\n", idx, GetLastError ());
- goto leave;
- }
- }
-
- /* Create the process, restore the devices and check the error. */
- w32ret = CreateProcess (pgmname, /* Program to start. */
- cmdline, /* Command line arguments. */
- NULL, /* Process security. Not used. */
- NULL, /* Thread security. Not used. */
- FALSE, /* Inherit handles. Not used. */
- CREATE_SUSPENDED, /* Creation flags. */
- NULL, /* Environment. Not used. */
- NULL, /* Use current dir. Not used. */
- NULL, /* Startup information. Not used. */
- &pi /* Returns process information. */
- );
- for (idx=0; idx < 3; idx++)
- {
- if (pipes[idx].oldname_valid)
- {
- if (!SetStdioPathW (idx, pipes[idx].oldname))
- log_error ("SetStdioPath(%d) failed during restore: %d\n",
- idx, GetLastError ());
- else
- pipes[idx].oldname_valid = 0;
- }
- }
- if (!w32ret)
- {
- /* Error checking after restore so that the messages are visible. */
- log_error ("CreateProcess failed: %d\n", GetLastError ());
- err = gpg_error_from_syserror ();
- goto leave;
- }
-
- log_info ("CreateProcess ready: hProcess=%p hThread=%p"
- " dwProcessID=%d dwThreadId=%d\n",
- pi.hProcess, pi.hThread,
- (int) pi.dwProcessId, (int) pi.dwThreadId);
-
- ResumeThread (pi.hThread);
- CloseHandle (pi.hThread);
-
- code = WaitForSingleObject (pi.hProcess, INFINITE);
- switch (code)
- {
- case WAIT_FAILED:
- err = gpg_error_from_syserror ();;
- log_error ("waiting for process %d to terminate failed: %d\n",
- (int)pi.dwProcessId, GetLastError ());
- break;
-
- case WAIT_OBJECT_0:
- if (!GetExitCodeProcess (pi.hProcess, &exc))
- {
- err = gpg_error_from_syserror ();;
- log_error ("error getting exit code of process %d: %s\n",
- (int)pi.dwProcessId, GetLastError () );
- }
- else if (exc)
- {
- log_info ("error running process: exit status %d\n", (int)exc);
- err = gpg_error (GPG_ERR_GENERAL);
- }
- else
- {
- err = 0;
- }
- break;
-
- default:
- err = gpg_error_from_syserror ();;
- log_error ("WaitForSingleObject returned unexpected "
- "code %d for pid %d\n", code, (int)pi.dwProcessId);
- break;
- }
- CloseHandle (pi.hProcess);
-
- leave:
- for (idx=0; idx < 3; idx++)
- {
- if (pipes[idx].oldname_valid)
- {
- if (!SetStdioPathW (idx, pipes[idx].oldname))
- log_error ("SetStdioPath(%d) failed during restore: %d\n",
- idx, GetLastError ());
- else
- pipes[idx].oldname_valid = 0;
- }
- }
- for (idx=0; idx < 3; idx++)
- {
- if (pipes[idx].hd[0] != INVALID_HANDLE_VALUE)
- CloseHandle (pipes[idx].hd[0]);
- if (pipes[idx].hd[1] != INVALID_HANDLE_VALUE)
- CloseHandle (pipes[idx].hd[1]);
- }
- xfree (cmdline);
- xfree (pgmname);
- return leave_cmd (ctx, err);
-}
-#endif /*HAVE_W32CE_SYSTEM*/
-
-
-
-
-
-static const char hlp_newdataport[] =
- "NEWDATAPORT\n"
- "\n"
- "Create a new dataport. The server creates a listening socket and\n"
- "issues the inquiry:\n"
- " INQUIRE CONNECT-TO \n"
- "The client is expected to connect to PORT of the server and confirm\n"
- "this by sending just an \"END\". In turn the server sends:\n"
- " S FDINFO \n"
- "With N being the local descriptor for the accepted connection. This\n"
- "descriptor may now be used with INPUT or OUTPUT commands.";
-struct cmd_dataport_locals
-{
- assuan_context_t ctx;
- int passthru;
- int port;
-};
-static gpg_error_t
-cmd_newdataport (assuan_context_t ctx, char *line)
-{
- state_t state = assuan_get_pointer (ctx);
- gpg_error_t err = 0;
- struct sockaddr_in addr;
- socklen_t addrlen;
- struct cmd_dataport_locals *cont;
- char inqline[100];
-
- cont = xmalloc (sizeof *cont);
- cont->ctx = ctx;
- cont->passthru = 0;
- cont->port = 0;
-
- if (state->dataport_listen_fd != ASSUAN_INVALID_FD)
- {
- log_error ("Oops, still listening on a dataport socket\n");
- state->dataport_listen_fd = ASSUAN_INVALID_FD;
- }
- if (state->dataport_accepted_fd != ASSUAN_INVALID_FD)
- {
- log_error ("Oops, still holding an accepted dataport socket\n");
- state->dataport_accepted_fd = ASSUAN_INVALID_FD;
- }
- state->dataport_accept_err = 0;
-
- state->dataport_listen_fd = assuan_sock_new (PF_INET, SOCK_STREAM, 0);
- if (state->dataport_listen_fd == ASSUAN_INVALID_FD)
- {
- err = gpg_error_from_syserror ();
- log_error ("socket() failed: %s\n", strerror (errno));
- goto leave;
- }
-
- addr.sin_family = AF_INET;
- addr.sin_port = 0;
- addr.sin_addr.s_addr = htonl (INADDR_ANY);
- if (assuan_sock_bind (state->dataport_listen_fd,
- (struct sockaddr *)&addr, sizeof addr))
- {
- err = gpg_error_from_syserror ();
- log_error ("listen() failed: %s\n", strerror (errno));
- goto leave;
- }
-
- if (listen (HANDLE2SOCKET (state->dataport_listen_fd), 1))
- {
- err = gpg_error_from_syserror ();
- log_error ("listen() failed: %s\n", strerror (errno));
- goto leave;
- }
-
- addrlen = sizeof addr;
- if (getsockname (HANDLE2SOCKET (state->dataport_listen_fd),
- (struct sockaddr *)&addr, &addrlen))
- {
- err = gpg_error_from_syserror ();
- log_error ("getsockname() failed: %s\n", strerror (errno));
- goto leave;
- }
- cont->port = ntohs (addr.sin_port);
-
- if (verbose)
- log_info ("server now also listening on port %d\n", cont->port);
- snprintf (inqline, sizeof inqline, "CONNECT-TO %d", cont->port);
- err = assuan_inquire_ext (ctx, inqline, 0, cmd_newdataport_cont, cont);
- if (!err)
- return 0; /* Transfer to continuation. */
-
- leave:
- cont->passthru = 1;
- return cmd_newdataport_cont (cont, err, NULL, 0);
-}
-
-/* Continuation used by cmd_newdataport. */
-static gpg_error_t
-cmd_newdataport_cont (void *opaque, gpg_error_t err,
- unsigned char *data, size_t datalen)
-{
- struct cmd_dataport_locals *cont = opaque;
- assuan_context_t ctx = cont->ctx;
- state_t state = assuan_get_pointer (ctx);
- char numbuf[35];
- fdinfo_t fi;
-
- if (cont->passthru || err)
- goto leave;
-
- err = state->dataport_accept_err;
- if (err)
- goto leave;
- if (state->dataport_listen_fd != ASSUAN_INVALID_FD
- || state->dataport_accepted_fd == ASSUAN_INVALID_FD)
- {
- err = gpg_error (GPG_ERR_MISSING_ACTION);
- goto leave;
- }
-
- for (fi = state->dataport_fds; fi; fi = fi->next)
- if (fi->fd == ASSUAN_INVALID_FD)
- break;
- if (!fi)
- {
- fi = xcalloc (1, sizeof *fi);
- fi->next = state->dataport_fds;
- state->dataport_fds = fi;
- }
- fi->fd = state->dataport_accepted_fd;
- state->dataport_accepted_fd = ASSUAN_INVALID_FD;
-
- /* Note that under Windows the FD is the socket descriptor. Socket
- descriptors are neither handles nor libc file descriptors. */
- snprintf (numbuf, sizeof numbuf, "%d", HANDLE2SOCKET (fi->fd));
- err = assuan_write_status (ctx, "FDINFO", numbuf);
-
- leave:
- if (state->dataport_listen_fd != ASSUAN_INVALID_FD)
- {
- assuan_sock_close (state->dataport_listen_fd);
- state->dataport_listen_fd = ASSUAN_INVALID_FD;
- }
- if (state->dataport_accepted_fd != ASSUAN_INVALID_FD)
- {
- assuan_sock_close (state->dataport_accepted_fd);
- state->dataport_accepted_fd = ASSUAN_INVALID_FD;
- }
- xfree (cont);
- return leave_cmd (ctx, err);
-}
-
-
-
-static const char hlp_dataport[] =
- "DATAPORT FD[=]\n"
- "\n"
- "Set the file descriptor to read and write data via port.\n"
- "This is similar to the \"INPUT\" and \"OUTPUT\" commands\n"
- "but useful for socketpairs.";
-static gpg_error_t
-cmd_dataport (assuan_context_t ctx, char *line)
-{
- state_t state = assuan_get_pointer (ctx);
- gpg_error_t err;
- assuan_fd_t fd;
-
- if (state->dataport_fd != ASSUAN_INVALID_FD)
- {
- assuan_sock_close (state->dataport_fd);
- state->dataport_fd = ASSUAN_INVALID_FD;
- }
-
- err = assuan_command_parse_fd (ctx, line, &fd);
- if (!err && fd != ASSUAN_INVALID_FD)
- {
- fdinfo_t fi;
-
- state->dataport_fd = fd;
-
- /* The fd is now in use use - remove it from the unused list. */
- for (fi=state->dataport_fds; fi; fi = fi->next)
- if (fi->fd == fd)
- fi->fd = ASSUAN_INVALID_FD;
- }
-
- return leave_cmd (ctx, err);
-}
-
-
-
-static const char hlp_getinfo[] =
- "GETINFO \n"
- "\n"
- "Multipurpose function to return a variety of information.\n"
- "Supported values for WHAT are:\n"
- "\n"
- " version - Return the version of the program.\n"
- " pid - Return the process id of the server.\n"
- " dataports - Return a list of usused dataports.";
-static gpg_error_t
-cmd_getinfo (assuan_context_t ctx, char *line)
-{
- state_t state = assuan_get_pointer (ctx);
- gpg_error_t err = 0;
- char numbuf[50];
-
- if (!strcmp (line, "version"))
- {
- const char *s = VERSION;
- err = assuan_send_data (ctx, s, strlen (s));
- }
- else if (!strcmp (line, "pid"))
- {
- snprintf (numbuf, sizeof numbuf, "%lu", (unsigned long)getpid ());
- err = assuan_send_data (ctx, numbuf, strlen (numbuf));
- }
- else if (!strcmp (line, "dataports"))
- {
- fdinfo_t fi;
- int any = 0;
-
- for (fi=state->dataport_fds; !err && fi; fi = fi->next)
- {
- if (fi->fd != ASSUAN_INVALID_FD)
- {
- snprintf (numbuf, sizeof numbuf, "%s%d",
- any? " ":"", HANDLE2SOCKET (fi->fd));
- any = 1;
- err = assuan_send_data (ctx, numbuf, strlen (numbuf));
- }
- }
- }
- else
- err = gpg_error (GPG_ERR_ASS_PARAMETER);
-
- return leave_cmd (ctx, err);
-}
-
-
-
-static const char hlp_shutdown[] =
- "SHUTDOWN\n"
- "\n"
- "Shutdown the server process\n";
-static gpg_error_t
-cmd_shutdown (assuan_context_t ctx, char *line)
-{
- (void)line;
- shutdown_pending = 1;
- return leave_cmd (ctx, 0);;
-}
-
-
-static gpg_error_t
-register_commands (assuan_context_t ctx)
-{
- static struct
- {
- const char *name;
- gpg_error_t (*handler) (assuan_context_t, char *line);
- const char * const help;
- } table[] =
- {
-#ifdef HAVE_W32CE_SYSTEM
- { "LS", cmd_ls, hlp_ls },
- { "RUN", cmd_run, hlp_run },
-#endif
- { "PWD", cmd_pwd, hlp_pwd },
- { "CD", cmd_cd, hlp_cd },
- { "ECHO", cmd_echo, hlp_echo },
- { "CAT", cmd_cat, hlp_cat },
- { "NEWDATAPORT", cmd_newdataport, hlp_newdataport },
- { "DATAPORT", cmd_dataport, hlp_dataport },
- { "INPUT", NULL },
- { "OUTPUT", NULL },
- { "GETINFO", cmd_getinfo, hlp_getinfo },
- { "SHUTDOWN", cmd_shutdown, hlp_shutdown },
- { NULL, NULL }
- };
- int i;
- gpg_error_t rc;
-
- for (i=0; table[i].name; i++)
- {
- rc = assuan_register_command (ctx, table[i].name,
- table[i].handler, table[i].help);
- if (rc)
- return rc;
- }
- return 0;
-}
-
-
-
-static assuan_fd_t
-get_connection_fd (assuan_context_t ctx)
-{
- assuan_fd_t fds[5];
-
- if (assuan_get_active_fds (ctx, 0, fds, DIM (fds)) < 1)
- log_fatal ("assuan_get_active_fds failed\n");
- if (fds[0] == ASSUAN_INVALID_FD)
- log_fatal ("assuan_get_active_fds returned invalid conenction fd\n");
- return fds[0];
-}
-
-
-/* Startup the server. */
-static void
-server (void)
-{
- gpg_error_t err;
- assuan_fd_t server_fd;
- assuan_sock_nonce_t server_nonce;
- int one = 1;
- struct sockaddr_in name;
- assuan_context_t ctx;
- state_t state = NULL;
-
- err = assuan_new (&ctx);
- if (err)
- log_fatal ("assuan_new failed: %s\n", gpg_strerror (err));
-
- server_fd = assuan_sock_new (PF_INET, SOCK_STREAM, 0);
- if (server_fd == ASSUAN_INVALID_FD)
- log_fatal ("socket() failed: %s\n", strerror (errno));
-
- if (setsockopt (HANDLE2SOCKET (server_fd),
- SOL_SOCKET, SO_REUSEADDR, (void*)&one, sizeof one))
- log_error ("setsockopt(SO_REUSEADDR) failed: %s\n", strerror (errno));
-
- name.sin_family = AF_INET;
- name.sin_port = htons (server_port);
- name.sin_addr.s_addr = htonl (INADDR_ANY);
- if (assuan_sock_bind (server_fd, (struct sockaddr *) &name, sizeof name))
- log_fatal ("bind() failed: %s\n", strerror (errno));
- if (assuan_sock_get_nonce ((struct sockaddr*)&name, sizeof name,
- &server_nonce))
- log_fatal ("assuan_sock_get_nonce failed: %s\n", strerror (errno));
-
- /* Register the nonce with the context so that assuan_accept knows
- about it. We can't do that directly in assuan_sock_bind because
- we want these socket wrappers to be context neutral and drop in
- replacement for the standard socket functions. */
- assuan_set_sock_nonce (ctx, &server_nonce);
-
- if (listen (HANDLE2SOCKET (server_fd), 5))
- log_fatal ("listen() failed: %s\n", strerror (errno));
-
- log_info ("server listening on port %hd\n", server_port);
-
- err = assuan_init_socket_server (ctx, server_fd, 0);
- if (err)
- log_fatal ("assuan_init_socket_server failed: %s\n", gpg_strerror (err));
-
- err = register_commands (ctx);
- if (err)
- log_fatal ("register_commands failed: %s\n", gpg_strerror(err));
-
- if (debug)
- assuan_set_log_stream (ctx, stderr);
-
- assuan_register_reset_notify (ctx, reset_notify);
- assuan_register_input_notify (ctx, input_notify);
- assuan_register_output_notify (ctx, output_notify);
-
-
- state = new_state ();
-
- assuan_set_pointer (ctx, state);
-
- while (!shutdown_pending)
- {
- int done;
-
- err = assuan_accept (ctx);
- if (err)
- {
- if (gpg_err_code (err) == GPG_ERR_EOF || err == -1)
- log_error ("assuan_accept failed: %s\n", gpg_strerror (err));
- break;
- }
-
- log_info ("client connected. Client's pid is %ld\n",
- (long)assuan_get_pid (ctx));
- do
- {
- /* We need to use select here so that we can accept
- supplemental connections from the client as requested by
- the DATAPORT command. */
- fd_set rfds;
- int connfd, datafd, max_fd;
-
- connfd = HANDLE2SOCKET (get_connection_fd (ctx));
- FD_ZERO (&rfds);
- FD_SET (connfd, &rfds);
- max_fd = connfd;
-
- if (state->dataport_listen_fd != ASSUAN_INVALID_FD)
- {
- datafd = HANDLE2SOCKET (state->dataport_listen_fd);
- FD_SET (datafd, &rfds);
- if (datafd > max_fd)
- max_fd = datafd;
- }
- else
- datafd = -1;
-
- if (select (max_fd + 1, &rfds, NULL, NULL, NULL) > 0)
- {
- if (datafd != -1 && FD_ISSET (datafd, &rfds))
- {
- struct sockaddr_in clnt_addr;
- socklen_t len = sizeof clnt_addr;
- int fd;
-
- fd = accept (datafd, (struct sockaddr*)&clnt_addr, &len);
- if (fd == -1)
- {
- err = gpg_err_code_from_syserror ();
- assuan_sock_close (state->dataport_listen_fd);
- state->dataport_listen_fd = ASSUAN_INVALID_FD;
- log_error ("accepting on dataport failed: %s\n",
- gpg_strerror (err));
- state->dataport_accept_err = err;
- err = 0;
- }
- else
- {
- /* No more need for the listening socket. */
- assuan_sock_close (state->dataport_listen_fd);
- state->dataport_listen_fd = ASSUAN_INVALID_FD;
- /* Record the accepted fd. */
- state->dataport_accept_err = 0;
- state->dataport_accepted_fd = SOCKET2HANDLE (fd);
- }
- }
-
- if (FD_ISSET (connfd, &rfds))
- {
- err = assuan_process_next (ctx, &done);
- }
- }
- }
- while (!err && !done && !shutdown_pending);
- if (err)
- log_error ("assuan_process failed: %s\n", gpg_strerror (err));
- }
-
- assuan_sock_close (server_fd);
- assuan_release (ctx);
- release_state (state);
-}
-
-
-
-
-
-/*
-
- M A I N
-
-*/
-int
-main (int argc, char **argv)
-{
- gpg_error_t err;
- int last_argc = -1;
-
- if (argc)
- {
- log_set_prefix (*argv);
- argc--; argv++;
- }
- while (argc && last_argc != argc )
- {
- last_argc = argc;
- if (!strcmp (*argv, "--help"))
- {
- printf (
- "usage: %s [options]\n"
- "\n"
- "Options:\n"
- " --verbose Show what is going on\n",
- log_get_prefix ());
- exit (0);
- }
- if (!strcmp (*argv, "--verbose"))
- {
- verbose = 1;
- argc--; argv++;
- }
- else if (!strcmp (*argv, "--debug"))
- {
- verbose = debug = 1;
- argc--; argv++;
- }
- }
-
- assuan_set_assuan_log_prefix (log_prefix);
- if (debug)
- assuan_set_assuan_log_stream (stderr);
-
- err = assuan_sock_init ();
- if (err)
- log_fatal ("assuan_sock_init failed: %s\n", gpg_strerror (err));
-
- log_info ("server starting...\n");
- server ();
- log_info ("server finished\n");
-
- assuan_sock_deinit ();
-
- return errorcount ? 1 : 0;
-}
diff --git a/tests/common.h b/tests/common.h
index c5ce811..dc3c073 100644
--- a/tests/common.h
+++ b/tests/common.h
@@ -1,289 +1,284 @@
/* common.h - Common functions for the tests.
* Copyright (C) 2006 Free Software Foundation, Inc.
*
* This file is part of Assuan.
*
* Assuan 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 3 of
* the License, or (at your option) any later version.
*
* Assuan 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
* Lesser 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 .
*/
#include
#if __GNUC__ >= 4
# define MY_GCC_A_SENTINEL(a) __attribute__ ((sentinel(a)))
#else
# define MY_GCC_A_SENTINEL(a)
#endif
-#ifdef HAVE_W32CE_SYSTEM
-#define getpid() GetCurrentProcessId ()
-#define getenv(a) (NULL)
-#endif
-
#if HAVE_W32_SYSTEM
#define SOCKET2HANDLE(s) ((void *)(s))
#define HANDLE2SOCKET(h) ((unsigned int)(h))
CRITICAL_SECTION _log_critsect;
#define _log_enter() do { EnterCriticalSection (&_log_critsect); } while (0)
#define _log_leave() do { LeaveCriticalSection (&_log_critsect); } while (0)
#else
#define SOCKET2HANDLE(s) (s)
#define HANDLE2SOCKET(h) (h)
#define _log_enter() do { } while (0)
#define _log_leave() do { } while (0)
#endif
#define DIM(v) (sizeof(v)/sizeof((v)[0]))
#define DIMof(type,member) DIM(((type *)0)->member)
char *xstrconcat (const char *s1, ...) MY_GCC_A_SENTINEL(0);
static const char *log_prefix;
static int errorcount;
static int verbose;
static int debug;
void *
xmalloc (size_t n)
{
char *p = malloc (n);
if (!p)
{
if (log_prefix)
fprintf (stderr, "%s[%u]: ", log_prefix, (unsigned int)getpid ());
fprintf (stderr, "out of core\n");
exit (1);
}
return p;
}
void *
xcalloc (size_t n, size_t m)
{
char *p = calloc (n, m);
if (!p)
{
_log_enter ();
if (log_prefix)
fprintf (stderr, "%s[%u]: ", log_prefix, (unsigned int)getpid ());
fprintf (stderr, "out of core\n");
_log_leave ();
exit (1);
}
return p;
}
void
xfree (void *a)
{
if (a)
free (a);
}
void *
xstrdup (const char *string)
{
char *p = xmalloc (strlen (string) + 1);
strcpy (p, string);
return p;
}
void
log_set_prefix (const char *s)
{
#ifdef HAVE_W32_SYSTEM
InitializeCriticalSection (&_log_critsect);
log_prefix = strrchr (s, '\\');
#else
log_prefix = strrchr (s, '/');
#endif
if (log_prefix)
log_prefix++;
else
log_prefix = s;
}
const char *
log_get_prefix (void)
{
return log_prefix? log_prefix:"";
}
void
log_info (const char *format, ...)
{
va_list arg_ptr ;
if (!verbose)
return;
va_start (arg_ptr, format) ;
_log_enter ();
if (log_prefix)
fprintf (stderr, "%s[%u]: ", log_prefix, (unsigned int)getpid ());
vfprintf (stderr, format, arg_ptr );
_log_leave ();
va_end (arg_ptr);
}
void
log_error (const char *format, ...)
{
va_list arg_ptr ;
va_start (arg_ptr, format) ;
_log_enter ();
if (log_prefix)
fprintf (stderr, "%s[%u]: ", log_prefix, (unsigned int)getpid ());
vfprintf (stderr, format, arg_ptr );
_log_leave ();
va_end (arg_ptr);
errorcount++;
}
void
log_fatal (const char *format, ...)
{
va_list arg_ptr ;
va_start (arg_ptr, format) ;
_log_enter ();
if (log_prefix)
fprintf (stderr, "%s[%u]: ", log_prefix, (unsigned int)getpid ());
vfprintf (stderr, format, arg_ptr );
_log_leave ();
va_end (arg_ptr);
exit (2);
}
void
log_printhex (const char *text, const void *buffer, size_t length)
{
const unsigned char *s;
_log_enter ();
if (log_prefix)
fprintf (stderr, "%s[%u]: ", log_prefix, (unsigned int)getpid ());
fputs (text, stderr);
for (s=buffer; length; s++, length--)
fprintf (stderr, "%02X", *s);
putc ('\n', stderr);
_log_leave ();
}
/* Prepend FNAME with the srcdir environment variable's value and
return an allocated filename. */
char *
prepend_srcdir (const char *fname)
{
static const char *srcdir;
char *result;
if (!srcdir && !(srcdir = getenv ("srcdir")))
srcdir = ".";
result = xmalloc (strlen (srcdir) + 1 + strlen (fname) + 1);
strcpy (result, srcdir);
strcat (result, "/");
strcat (result, fname);
return result;
}
#ifndef HAVE_STPCPY
#undef __stpcpy
#undef stpcpy
#ifndef weak_alias
# define __stpcpy stpcpy
#endif
char *
__stpcpy (char *a,const char *b)
{
while (*b)
*a++ = *b++;
*a = 0;
return (char*)a;
}
#ifdef libc_hidden_def
libc_hidden_def (__stpcpy)
#endif
#ifdef weak_alias
weak_alias (__stpcpy, stpcpy)
#endif
#ifdef libc_hidden_builtin_def
libc_hidden_builtin_def (stpcpy)
#endif
#endif
static char *
do_strconcat (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)
{
fprintf (stderr, "too many args in strconcat\n");
exit (1);
}
argc++;
}
needed++;
buffer = xmalloc (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 or dies on malloc error. */
char *
xstrconcat (const char *s1, ...)
{
va_list arg_ptr;
char *result;
if (!s1)
result = xstrdup ("");
else
{
va_start (arg_ptr, s1);
result = do_strconcat (s1, arg_ptr);
va_end (arg_ptr);
}
return result;
}
diff --git a/tests/pipeconnect.c b/tests/pipeconnect.c
index ddb4a06..b477af1 100644
--- a/tests/pipeconnect.c
+++ b/tests/pipeconnect.c
@@ -1,397 +1,347 @@
/* pipeconnect.c - Check the assuan_pipe_connect call.
Copyright (C) 2006, 2009, 2010 Free Software Foundation, Inc.
This file is part of Assuan.
Assuan 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 3 of
the License, or (at your option) any later version.
Assuan 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
Lesser 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 .
*/
/*
This tests creates a program which starts an assuan server and runs
some simple tests on it. The other program is actually the same
program but called with the option --server.
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include
#include
#include
#include
#include "../src/assuan.h"
#include "common.h"
static assuan_fd_t my_stdin = ASSUAN_INVALID_FD;
static assuan_fd_t my_stdout = ASSUAN_INVALID_FD;
static assuan_fd_t my_stderr = ASSUAN_INVALID_FD;
static gpg_error_t
cmd_echo (assuan_context_t ctx, char *line)
{
log_info ("got ECHO command (%s)\n", line);
assuan_send_data (ctx, line, strlen (line));
return 0;
}
static gpg_error_t
cmd_cat (assuan_context_t ctx, char *line)
{
assuan_fd_t fd, fdout;
int c;
FILE *fp, *fpout;
int nbytes;
log_info ("got CAT command (%s)\n", line);
fd = assuan_get_input_fd (ctx);
if (fd == ASSUAN_INVALID_FD)
return gpg_error (GPG_ERR_ASS_NO_INPUT);
fdout = assuan_get_output_fd (ctx);
if (fdout == ASSUAN_INVALID_FD)
return gpg_error (GPG_ERR_ASS_NO_OUTPUT);
fp = fdopen (fd, "r");
if (!fp)
{
log_error ("fdopen failed on input fd: %s\n", strerror (errno));
return gpg_error (GPG_ERR_ASS_GENERAL);
}
fpout = fdopen (fdout, "w");
if (!fpout)
{
log_error ("fdopen failed on output fd: %s\n", strerror (errno));
fclose (fp);
return gpg_error (GPG_ERR_ASS_GENERAL);
}
nbytes = 0;
while ( (c=getc (fp)) != -1)
{
putc (c, fpout);
nbytes++;
}
log_info ("done printing %d bytes to output fd\n", nbytes);
/* Fixme: This also closes the original fd. */
fclose (fp);
fclose (fpout);
return 0;
}
static gpg_error_t
server_register_commands (assuan_context_t ctx)
{
static struct
{
const char *name;
gpg_error_t (*handler) (assuan_context_t, char *line);
} table[] =
{
{ "ECHO", cmd_echo },
{ "CAT", cmd_cat },
{ "INPUT", NULL },
{ "OUTPUT", NULL },
{ NULL, NULL }
};
int i;
gpg_error_t rc;
for (i=0; table[i].name; i++)
{
rc = assuan_register_command (ctx, table[i].name, table[i].handler, NULL);
if (rc)
return rc;
}
return 0;
}
static void
run_server (int enable_debug)
{
int rc;
assuan_context_t ctx;
assuan_fd_t filedes[2];
filedes[0] = my_stdin;
filedes[1] = my_stdout;
rc = assuan_new (&ctx);
if (rc)
log_fatal ("assuan_new failed: %s\n", gpg_strerror (rc));
rc = assuan_init_pipe_server (ctx, filedes);
if (rc)
log_fatal ("assuan_init_pipe_server failed: %s\n",
gpg_strerror (rc));
rc = server_register_commands (ctx);
if (rc)
log_fatal ("register_commands failed: %s\n", gpg_strerror(rc));
if (enable_debug)
assuan_set_log_stream (ctx, stderr);
for (;;)
{
rc = assuan_accept (ctx);
if (rc)
{
if (rc != -1)
log_error ("assuan_accept failed: %s\n", gpg_strerror (rc));
break;
}
log_info ("client connected. Client's pid is %ld\n",
(long)assuan_get_pid (ctx));
rc = assuan_process (ctx);
if (rc)
log_error ("assuan_process failed: %s\n", gpg_strerror (rc));
}
assuan_release (ctx);
}
static gpg_error_t
data_cb (void *opaque, const void *buffer, size_t length)
{
(void)opaque;
if (buffer)
printf ("Received data `%.*s'\n", (int)length, (char*)buffer);
return 0;
}
static void
run_client (const char *servername)
{
gpg_error_t err;
assuan_context_t ctx;
assuan_fd_t no_close_fds[2];
const char *arglist[5];
no_close_fds[0] = fileno (stderr);
no_close_fds[1] = ASSUAN_INVALID_FD;
arglist[0] = servername;
arglist[1] = "--server";
arglist[2] = debug? "--debug" : verbose? "--verbose":NULL;
arglist[3] = NULL;
err = assuan_new (&ctx);
if (err)
log_fatal ("assuan_new failed: %s\n", gpg_strerror (err));
err = assuan_pipe_connect (ctx, servername, arglist, no_close_fds,
NULL, NULL, 0);
if (err)
{
log_error ("assuan_pipe_connect failed: %s\n",
gpg_strerror (err));
assuan_release (ctx);
return;
}
log_info ("server started; pid is %ld\n",
(long)assuan_get_pid (ctx));
err = assuan_transact (ctx, "ECHO Your lucky number is 3552664958674928. "
"Watch for it everywhere.",
data_cb, NULL, NULL, NULL, NULL, NULL);
if (err)
{
log_error ("sending ECHO failed: %s\n", gpg_strerror (err));
return;
}
err = assuan_transact (ctx, "BYE", NULL, NULL, NULL, NULL, NULL, NULL);
if (err)
{
log_error ("sending BYE failed: %s\n", gpg_strerror (err));
return;
}
assuan_release (ctx);
return;
}
static void
parse_std_file_handles (int *argcp, char ***argvp)
{
-#ifdef HAVE_W32CE_SYSTEM
- 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');
- switch (s[3] - '0')
- {
- case 0: my_stdin = fd; break;
- case 1: my_stdout = fd; break;
- case 2: my_stderr = fd; break;
- }
-
- 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;
- }
-#else
(void)argcp;
(void)argvp;
my_stdin = 0;
my_stdout = 1;
my_stderr = 2;
-#endif
}
/*
M A I N
*/
int
main (int argc, char **argv)
{
gpg_error_t err;
const char *myname = "no-pgm";
int last_argc = -1;
int server = 0;
int silent_client = 0;
int silent_server = 0;
parse_std_file_handles (&argc, &argv);
if (argc)
{
myname = *argv;
log_set_prefix (*argv);
argc--; argv++;
}
while (argc && last_argc != argc )
{
last_argc = argc;
if (!strcmp (*argv, "--help"))
{
printf ("usage: %s [options]\n"
"\n"
"Options:\n"
" --verbose Show what is going on\n"
" --server Run in server mode\n",
log_get_prefix ());
exit (0);
}
if (!strcmp (*argv, "--verbose"))
{
verbose = 1;
argc--; argv++;
}
else if (!strcmp (*argv, "--debug"))
{
verbose = debug = 1;
argc--; argv++;
}
else if (!strcmp (*argv, "--server"))
{
server = 1;
argc--; argv++;
}
else if (!strcmp (*argv, "--silent-server"))
{
silent_server = 1;
argc--; argv++;
}
else if (!strcmp (*argv, "--silent-client"))
{
silent_client = 1;
argc--; argv++;
}
else
log_fatal ("invalid option `%s' (try --help)\n", *argv);
}
log_set_prefix (xstrconcat (log_get_prefix (),
server? ".server":".client", NULL));
assuan_set_assuan_log_prefix (log_get_prefix ());
err = assuan_sock_init ();
if (err)
log_fatal ("socket init failed: %s\n", gpg_strerror (err));
if (server)
{
log_info ("server started\n");
if (debug && !silent_server)
assuan_set_assuan_log_stream (stderr);
run_server (debug && !silent_server);
log_info ("server finished\n");
}
else
{
log_info ("client started\n");
if (debug && !silent_client)
assuan_set_assuan_log_stream (stderr);
run_client (myname);
log_info ("client finished\n");
}
return errorcount ? 1 : 0;
}