diff options
author | Marcus Brinkmann <mb@g10code.com> | 2009-10-16 18:24:46 +0000 |
---|---|---|
committer | Marcus Brinkmann <mb@g10code.com> | 2009-10-16 18:24:46 +0000 |
commit | 5e15cf931706f9a6ae00d17569b97d636d6f2945 (patch) | |
tree | 5feff75cb4dabe4b198089ca05314e6ad5f8d827 | |
parent | 1dce00882d78e0bb30011067f383583f2b551172 (diff) | |
download | libassuan-5e15cf931706f9a6ae00d17569b97d636d6f2945.tar.gz |
2009-10-16 Marcus Brinkmann <marcus@g10code.de>
* autogen.sh: Remove --with-pth-prefix from configure invocation.
* configure.ac (_ASSUAN_IN_LIBASSUAN, PTH_SYSCALL_SOFT): Do not
set anymore.
(GNUPG_PATH_PTH): Don't invoke.
(HAVE_PTH): Remove conditional.
(LIBASSUAN_CONFIG_THREAD_MODULES): Removed.
doc/
2009-10-16 Marcus Brinkmann <marcus@g10code.com>
* assuan.texi: Remove documentation for thread support.
(assuan_pipe_connect_ext): Update prototype.
src/
2009-10-16 Marcus Brinkmann <marcus@g10code.com>
* conversion.c: Do not include <sys/types.h> and <time.h>.
* debug.h (TRACE_BEG6, TRACE4): New macros.
(TRACE_SYSERR): Pass _assuan_trace_context to _assuan_debug.
* context.c (assuan_set_pointer, assuan_get_pointer,
assuan_set_flag, assuan_get_flag, assuan_set_io_monitor,
assuan_set_error): Add trace messages.
* libassuan-config.in, libassuan.m4, Makefile.am: Remove PTH support.
* assuan.h (assuan_msghdr_t): New type.
(ASSUAN_INVALID_PID): New macro.
(ASSUAN_NO_FIXSIGNALS): New flag macro.
(ASSUAN_SYSTEM_HOOKS_VERSION): New macro.
(struct assuan_system_hooks, assuan_system_hooks_t): New types.
(assuan_pipe_connect, assuan_pipe_connect_ext): Don't make ARGV
const for name==NULL operation. Make fd_child_list an array of
assuan_fd_t.
(assuan_sock_init, assuan_sock_deinit, assuan_set_system_hooks,
assuan_ctx_set_system_hooks, __assuan_pipe, __assuan_close,
__assuan_spawn, __assuan_socketpair): New function prototypes.
(_ASSUAN_SYSTEM_PTH_IMPL, ASSUAN_SYSTEM_PTH_DECL,
ASSUAN_SYSTEM_PTH): New macros.
(_assuan_system_pth): New declaration.
* libassuan.vers, libassuan.defs: Add assuan_sock_init,
assuan_sock_deinit, __assuan_pipe, __assuan_close, __assuan_spawn,
__assuan_socketpair, assuan_set_system_hooks,
assuan_ctx_set_system_hooks.
* assuan-defs.h (struct assuan_io): Removed, move members to ...
(struct assuan_context_s): ... this to ENGINE. New flag
no_fixsignals. New member SYSTEM. Remove member IO.
(_assuan_pipe, _assuan_read, _assuan_write, _assuan_recvmsg,
_assuan_sendmsg, _assuan_spawn, _assuan_socketpair,
_assuan_system_hooks, _assuan_system_hooks_copy): New
declarations.
(_assuan_error_is_eagain, _assuan_waitpid, _assuan_usleep,
_assuan_close, _assuan_sock_new, _assuan_sock_connect,
_assuan_sock_bind, _assuan_sock_get_nonce,
_assuan_sock_check_nonce): Add context argument.
(_assuan_io_read, _assuan_io_write, _assuan_simple_sendmsg,
_assuan_simple_recvmsg): Removed.
* context.c (assuan_ctx_set_system_hooks): New function.
* assuan.c (assuan_set_system_hooks): New function.
(assuan_new_ext): Initialize CTX->system.
(assuan_release): Always output trace message.
* assuan-error.c (_assuan_error_is_eagain): Add ctx argument, pass
along to _assuan_usleep.
* assuan-inquire.c assuan-listen.c, assuan-socket-server.c,
assuan-handler.c, assuan-socket-connect.c, assuan-client.c,
assuan-pipe-connect.c, assuan-socket.c: Pass CTX argument to
functions that need it
(_assuan_sock_new, _assuan_sock_check_none, _assuan_close,
_assuan_error_is_eagain and many more).
* assuan-socket-server.c (assuan_init_socket_server_ext): Update
fields in CTX->engine instead of CTX->io.
* assuan-socket-connect (assuan_socket_connect_ext): Likewise.
* assuan-uds.c (uds_reader, uds_writer, uds_sendfd): Use
_assuan_recvmsg and _assuan_sendmsg instead of
_assuan_simple_recvmsg and _assuan_simple_sendmsg respectively.
(_assuan_init_uds_io): Update fields in CTX->engine instead of
CTX->io.
* assuan-buffer.c: Use functions in CTX->engine instead of CTX->io.
* assuan-pipe-server.c (assuan_init_pipe_server): Update
fields in CTX->engine instead of CTX->io.
* system.c: Include <sys/types.h>, <time.h>, <fcntl.h>, and
<windows.h> resp. <sys/wait.h>. Define MAX_OPEN_FDS.
(_assuan_system_hooks_copy, __assuan_usleep, _assuan_usleep,
__assuan_pipe, _assuan_pipe, __assuan_close, _assuan_close,
__assuan_read, _assuan_read, __assuan_write, _assuan_write,
__assuan_recvmsg, _assuan_recvmsg, __assuan_sendmsg,
_assuan_sendmsg, __assuan_spawn, _assuan_spawn, __assuan_waitpid,
_assuan_waitpid, __assuan_socketpair, _assuan_socketpair): New
functions.
(_assuan_system_hooks): New singleton.
* assuan-io.c (_assuan_waitpid, do_io_read, _assuan_io_read,
do_io_write, _assuan_io_write, _assuan_simple_sendmsg,
_assuan_simple_recvmsg, _assuan_usleep): Removed.
* assuan-pipe-connect (writen, build_w32_commandline,
create_inheritable_pipe): Removed (actually moved to system.c).
(fix_signals) [_ASSUAN_NO_FIXED_SIGNALS]: Still fix signals.
(do_finish): Move waitpid logic to _assuan_waitpid, just call
that.
(struct at_pipe_fork, struct at_socketpair_fork): New types.
(at_pipe_fork_cb, at_socketpair_fork_cb): New callback functions.
(pipe_connect_unix, pipe_connect_w32): Replaced by ...
(pipe_connect): ... this new function using new system functions.
(socketpair_connect): Reimplement to use new system functions.
(assuan_pipe_connect, assuan_pipe_connect_ext): Add trace message.
* assuan-socket.c (_assuan_close): Removed (moved to system.c).
(_assuan_sock_new, _assuan_sock_connect, _assuan_sock_bind,
_assuan_sock_get_nonce, _assuan_sock_check_nonce): Add context
argument. Use new system interface.
(sock_ctx): New singleton.
(assuan_sock_init, assuan_sock_deinit): New functions to
initialize and deinitialize the singleton.
-rw-r--r-- | ChangeLog | 9 | ||||
-rw-r--r-- | NEWS | 18 | ||||
-rwxr-xr-x | autogen.sh | 1 | ||||
-rw-r--r-- | configure.ac | 23 | ||||
-rw-r--r-- | doc/ChangeLog | 5 | ||||
-rw-r--r-- | doc/assuan.texi | 39 | ||||
-rw-r--r-- | src/ChangeLog | 114 | ||||
-rw-r--r-- | src/Makefile.am | 16 | ||||
-rw-r--r-- | src/assuan-buffer.c | 14 | ||||
-rw-r--r-- | src/assuan-client.c | 2 | ||||
-rw-r--r-- | src/assuan-defs.h | 96 | ||||
-rw-r--r-- | src/assuan-error.c | 6 | ||||
-rw-r--r-- | src/assuan-handler.c | 8 | ||||
-rw-r--r-- | src/assuan-inquire.c | 2 | ||||
-rw-r--r-- | src/assuan-io-pth.c | 170 | ||||
-rw-r--r-- | src/assuan-io.c | 174 | ||||
-rw-r--r-- | src/assuan-listen.c | 4 | ||||
-rw-r--r-- | src/assuan-pipe-connect.c | 779 | ||||
-rw-r--r-- | src/assuan-pipe-server.c | 8 | ||||
-rw-r--r-- | src/assuan-socket-connect.c | 17 | ||||
-rw-r--r-- | src/assuan-socket-server.c | 15 | ||||
-rw-r--r-- | src/assuan-socket.c | 103 | ||||
-rw-r--r-- | src/assuan-uds.c | 17 | ||||
-rw-r--r-- | src/assuan.c | 26 | ||||
-rw-r--r-- | src/assuan.h | 207 | ||||
-rw-r--r-- | src/context.c | 64 | ||||
-rw-r--r-- | src/conversion.c | 5 | ||||
-rw-r--r-- | src/debug.h | 12 | ||||
-rw-r--r-- | src/libassuan-config.in | 27 | ||||
-rw-r--r-- | src/libassuan.def | 9 | ||||
-rw-r--r-- | src/libassuan.m4 | 42 | ||||
-rw-r--r-- | src/libassuan.vers | 8 | ||||
-rw-r--r-- | src/system.c | 805 |
33 files changed, 1599 insertions, 1246 deletions
@@ -1,3 +1,12 @@ +2009-10-16 Marcus Brinkmann <marcus@g10code.de> + + * autogen.sh: Remove --with-pth-prefix from configure invocation. + * configure.ac (_ASSUAN_IN_LIBASSUAN, PTH_SYSCALL_SOFT): Do not + set anymore. + (GNUPG_PATH_PTH): Don't invoke. + (HAVE_PTH): Remove conditional. + (LIBASSUAN_CONFIG_THREAD_MODULES): Removed. + 2009-10-08 Marcus Brinkmann <marcus@g10code.de> * configure.ac: AC_REPLACE_FUNCS for vasprintf. @@ -13,7 +13,11 @@ Noteworthy changes in version 1.1.0 (unreleased) If you use assuan_pipe_connect or assuan_pipe_connect_ext 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(). + after fork(). If you use the assuan sock interface, you must call + assuan_sock_init after setting global context defaults. + + * 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: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -51,6 +55,18 @@ assuan_set_io_hooks REMOVED: Will come back in expanded form. assuan_io_hooks_t REMOVED: Will come back in expanded form. 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 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -77,7 +77,6 @@ if test "$1" = "--build-w32"; then ./configure --enable-maintainer-mode --prefix=${w32root} \ --host=${host} --build=${build} \ - --with-pth-prefix=${w32root} \ --disable-shared exit $? diff --git a/configure.ac b/configure.ac index dce02ad..b6353eb 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ # configure.ac - for libassuan -# Copyright (C) 2001, 2002, 2003, 2006, 2007 Free Software Foundation, Inc. +# Copyright (C) 2001-2003, 2006, 2007, 2009 Free Software Foundation, Inc. # # This file is part of Assuan. # @@ -132,16 +132,6 @@ if test "$GCC" = yes; then fi -AH_BOTTOM([ -#define _ASSUAN_IN_LIBASSUAN 1 - -/* We explicitly need to disable PTH's soft mapping as Debian - currently enables it by default for no reason. */ -#define PTH_SYSCALL_SOFT 0 - -]) - - # # Options depending on the host OS. # @@ -191,12 +181,6 @@ AC_SUBST(BUILD_TIMESTAMP) AC_SUBST(BUILD_FILEVERSION) AM_CONDITIONAL(HAVE_W32_SYSTEM, test "$have_w32_system" = yes) -# -# See whether we can build a Pth enabled version -# -GNUPG_PATH_PTH -AM_CONDITIONAL(HAVE_PTH, test "$have_pth" = "yes") - # Check for network libraries. They are needed for tests. AC_CHECK_FUNC(setsockopt, , AC_CHECK_LIB(socket, setsockopt, @@ -211,10 +195,6 @@ fi # For src/libassuan-config.in LIBASSUAN_CONFIG_LIB="-lassuan" LIBASSUAN_CONFIG_CFLAGS="" -LIBASSUAN_CONFIG_THREAD_MODULES= -if test "$have_pth" = yes; then -LIBASSUAN_CONFIG_THREAD_MODULES="pth" -fi LIBASSUAN_CONFIG_EXTRA_LIBS= if test x"$NETLIBS" != x; then LIBASSUAN_CONFIG_EXTRA_LIBS="$LIBASSUAN_CONFIG_EXTRA_LIBS $NETLIBS" @@ -222,7 +202,6 @@ fi AC_SUBST(LIBASSUAN_CONFIG_LIB) AC_SUBST(LIBASSUAN_CONFIG_CFLAGS) AC_SUBST(LIBASSUAN_CONFIG_API_VERSION) -AC_SUBST(LIBASSUAN_CONFIG_THREAD_MODULES) AC_SUBST(LIBASSUAN_CONFIG_EXTRA_LIBS) # Checks for header files. diff --git a/doc/ChangeLog b/doc/ChangeLog index c567640..6106e35 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,8 @@ +2009-10-16 Marcus Brinkmann <marcus@g10code.com> + + * assuan.texi: Remove documentation for thread support. + (assuan_pipe_connect_ext): Update prototype. + 2009-10-14 Werner Koch <wk@g10code.com> * assuan.texi (Utilities): Describe assuan_get_command_name. diff --git a/doc/assuan.texi b/doc/assuan.texi index adfc86d..5641aa0 100644 --- a/doc/assuan.texi +++ b/doc/assuan.texi @@ -465,10 +465,6 @@ specifying both options to @command{libassuan-config}: gcc -o foo foo.c $(libassuan-config --cflags --libs) @end example -If your application uses Pth or pthread, you need to pass the option -@option{--thread=pth} respective @option{--thread=pthread} to the -invocation of @command{libassuan-config}. - @node Automake @section Building sources using Automake @@ -498,36 +494,27 @@ AM_CPPFLAGS = $(LIBASSUAN_CFLAGS) LDADD = $(LIBASSUAN_LIBS) @end example -@defmac AM_PATH_LIBASSUAN_PTH (@ovar{minimum-version}, @ovar{action-if-found}, @ovar{action-if-not-found}) -Same as @code{AM_PATH_LIBASSUAN} but checks for the GNU Pth enabled -version of the library and defines @code{LIBASSUAN_PTH_CFLAGS} -@code{LIBASSUAN_PTH_LIBS} instead. Use this is you are using GNU Pth. -Note that you also need to pass the appropriate options for Pth to the -compiler and linker. -@end defmac - -@defmac AM_PATH_LIBASSUAN_PTHREAD (@ovar{minimum-version}, @ovar{action-if-found}, @ovar{action-if-not-found}) -Same as @code{AM_PATH_LIBASSUAN} but checks for the pthreads enabled -version of the library and defines @code{LIBASSUAN_PTHREAD_CFLAGS} -@code{LIBASSUAN_PTHREAD_LIBS} instead. Use this is you are using GNU Pth. -Note that you also need to pass the appropriate options for Pth to the -compiler and linker. -@end defmac - - @node Multi Threading @section Multi Threading -The @code{libassuan} library is thread-safe if you adhere to the following -requirements: +The @code{libassuan} library is designed so that it can be used in a +threaded application, if some rules are followed. @itemize @bullet @item Run the initialization functions before you actually start -to use threads. +to use threads. Specifically, the functions +@code{assuan_set_gpg_err_source}, @code{assuan_set_malloc_hooks} and +@code{assuan_set_log_cb} should not be called concurrently with +@code{assuan_new}. Use @code{assuan_new_ext} instead or ensure proper +serialization. @item Only one thread at a time may access an @code{libassuan} context. @item If you use the default log handler, use @code{assuan_set_assuan_log_stream} to setup a default log stream. +@item If you have callback functions shared by multiple functions, +the callback function must be reentrant for that purpose. +@code{libassuan} does not serialize invocation of callback functions +across contexts. @end itemize @@ -950,12 +937,12 @@ If the peer is not a simple pipe server but one using full-duplex sockets, the full-fledged variant of the above function should be used: -@deftypefun gpg_error_t assuan_pipe_connect_ext (@w{assuan_context_t *@var{ctx}},@w{const char *@var{name}}, @w{const char *@var{argv}[]}, @w{int *@var{fd_child_list}}, @w{void (*@var{atfork}) (void *, int)}, @w{void *@var{atforkvalue}}, @w{unsigned int @var{flags}}) +@deftypefun gpg_error_t assuan_pipe_connect_ext (@w{assuan_context_t *@var{ctx}},@w{const char *@var{name}}, @w{const char *@var{argv}[]}, @w{assuan_fd_t *@var{fd_child_list}}, @w{void (*@var{atfork}) (void *, int)}, @w{void *@var{atforkvalue}}, @w{unsigned int @var{flags}}) A call to this functions forks the current process and executes the program @var{name}, passing the arguments given in the NULL-terminated list @var{argv}. A list of file descriptors not to be closed may be -given using the @code{-1} terminated array @var{fd_child_list}. +given using the @code{ASSUAN_INVLID_FD} terminated array @var{fd_child_list}. If @var{name} is a null pointer, only a fork but no exec is done. Thus the child continues to run. However all file descriptors are diff --git a/src/ChangeLog b/src/ChangeLog index c9f2172..0d22b02 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,105 @@ +2009-10-16 Marcus Brinkmann <marcus@g10code.com> + + * conversion.c: Do not include <sys/types.h> and <time.h>. + * debug.h (TRACE_BEG6, TRACE4): New macros. + (TRACE_SYSERR): Pass _assuan_trace_context to _assuan_debug. + * context.c (assuan_set_pointer, assuan_get_pointer, + assuan_set_flag, assuan_get_flag, assuan_set_io_monitor, + assuan_set_error): Add trace messages. + + * libassuan-config.in, libassuan.m4, Makefile.am: Remove PTH support. + * assuan.h (assuan_msghdr_t): New type. + (ASSUAN_INVALID_PID): New macro. + (ASSUAN_NO_FIXSIGNALS): New flag macro. + (ASSUAN_SYSTEM_HOOKS_VERSION): New macro. + (struct assuan_system_hooks, assuan_system_hooks_t): New types. + (assuan_pipe_connect, assuan_pipe_connect_ext): Don't make ARGV + const for name==NULL operation. Make fd_child_list an array of + assuan_fd_t. + (assuan_sock_init, assuan_sock_deinit, assuan_set_system_hooks, + assuan_ctx_set_system_hooks, __assuan_pipe, __assuan_close, + __assuan_spawn, __assuan_socketpair): New function prototypes. + (_ASSUAN_SYSTEM_PTH_IMPL, ASSUAN_SYSTEM_PTH_DECL, + ASSUAN_SYSTEM_PTH): New macros. + (_assuan_system_pth): New declaration. + * libassuan.vers, libassuan.defs: Add assuan_sock_init, + assuan_sock_deinit, __assuan_pipe, __assuan_close, __assuan_spawn, + __assuan_socketpair, assuan_set_system_hooks, + assuan_ctx_set_system_hooks. + + * assuan-defs.h (struct assuan_io): Removed, move members to ... + (struct assuan_context_s): ... this to ENGINE. New flag + no_fixsignals. New member SYSTEM. Remove member IO. + (_assuan_pipe, _assuan_read, _assuan_write, _assuan_recvmsg, + _assuan_sendmsg, _assuan_spawn, _assuan_socketpair, + _assuan_system_hooks, _assuan_system_hooks_copy): New + declarations. + (_assuan_error_is_eagain, _assuan_waitpid, _assuan_usleep, + _assuan_close, _assuan_sock_new, _assuan_sock_connect, + _assuan_sock_bind, _assuan_sock_get_nonce, + _assuan_sock_check_nonce): Add context argument. + (_assuan_io_read, _assuan_io_write, _assuan_simple_sendmsg, + _assuan_simple_recvmsg): Removed. + + * context.c (assuan_ctx_set_system_hooks): New function. + * assuan.c (assuan_set_system_hooks): New function. + (assuan_new_ext): Initialize CTX->system. + (assuan_release): Always output trace message. + + * assuan-error.c (_assuan_error_is_eagain): Add ctx argument, pass + along to _assuan_usleep. + * assuan-inquire.c assuan-listen.c, assuan-socket-server.c, + assuan-handler.c, assuan-socket-connect.c, assuan-client.c, + assuan-pipe-connect.c, assuan-socket.c: Pass CTX argument to + functions that need it + (_assuan_sock_new, _assuan_sock_check_none, _assuan_close, + _assuan_error_is_eagain and many more). + * assuan-socket-server.c (assuan_init_socket_server_ext): Update + fields in CTX->engine instead of CTX->io. + * assuan-socket-connect (assuan_socket_connect_ext): Likewise. + * assuan-uds.c (uds_reader, uds_writer, uds_sendfd): Use + _assuan_recvmsg and _assuan_sendmsg instead of + _assuan_simple_recvmsg and _assuan_simple_sendmsg respectively. + (_assuan_init_uds_io): Update fields in CTX->engine instead of + CTX->io. + * assuan-buffer.c: Use functions in CTX->engine instead of CTX->io. + * assuan-pipe-server.c (assuan_init_pipe_server): Update + fields in CTX->engine instead of CTX->io. + + * system.c: Include <sys/types.h>, <time.h>, <fcntl.h>, and + <windows.h> resp. <sys/wait.h>. Define MAX_OPEN_FDS. + (_assuan_system_hooks_copy, __assuan_usleep, _assuan_usleep, + __assuan_pipe, _assuan_pipe, __assuan_close, _assuan_close, + __assuan_read, _assuan_read, __assuan_write, _assuan_write, + __assuan_recvmsg, _assuan_recvmsg, __assuan_sendmsg, + _assuan_sendmsg, __assuan_spawn, _assuan_spawn, __assuan_waitpid, + _assuan_waitpid, __assuan_socketpair, _assuan_socketpair): New + functions. + (_assuan_system_hooks): New singleton. + * assuan-io.c (_assuan_waitpid, do_io_read, _assuan_io_read, + do_io_write, _assuan_io_write, _assuan_simple_sendmsg, + _assuan_simple_recvmsg, _assuan_usleep): Removed. + + * assuan-pipe-connect (writen, build_w32_commandline, + create_inheritable_pipe): Removed (actually moved to system.c). + (fix_signals) [_ASSUAN_NO_FIXED_SIGNALS]: Still fix signals. + (do_finish): Move waitpid logic to _assuan_waitpid, just call + that. + (struct at_pipe_fork, struct at_socketpair_fork): New types. + (at_pipe_fork_cb, at_socketpair_fork_cb): New callback functions. + (pipe_connect_unix, pipe_connect_w32): Replaced by ... + (pipe_connect): ... this new function using new system functions. + (socketpair_connect): Reimplement to use new system functions. + (assuan_pipe_connect, assuan_pipe_connect_ext): Add trace message. + + * assuan-socket.c (_assuan_close): Removed (moved to system.c). + (_assuan_sock_new, _assuan_sock_connect, _assuan_sock_bind, + _assuan_sock_get_nonce, _assuan_sock_check_nonce): Add context + argument. Use new system interface. + (sock_ctx): New singleton. + (assuan_sock_init, assuan_sock_deinit): New functions to + initialize and deinitialize the singleton. + 2009-10-14 Werner Koch <wk@g10code.com> * assuan-defs.h (assuan_context_s): Add field CURRENT_CMD_NAME. @@ -7,6 +109,18 @@ 2009-10-08 Marcus Brinkmann <marcus@g10code.de> + * Makefile.am (libassuan_pth): Removed. + (lib_LTLIBRARIES): Remove $(libassuan_pth). + (libassuan_pth_la_SOURCES, libassuan_pth_la_CPPFLAGS) + (libassuan_pth_la_CFLAGS, libassuan_pth_la_LIBADD): Removed. + * libassuan.m4 (AM_PATH_LIBASSUAN_PTH, AM_PATH_LIBASSUAN_PTHREAD): + Removed. + * assuan-io-pth.c: Removed. + * libassuan-config.in (all_thread_modules): Removed. Also removed + option --thread. + +2009-10-08 Marcus Brinkmann <marcus@g10code.de> + * assuan.h (assuan_get_assuan_log_stream, assuan_set_assuan_log_stream): Remove prototypes. * libassuan.def: Remove assuan_get_assuan_log_stream, diff --git a/src/Makefile.am b/src/Makefile.am index 1e1c46b..bfbcfec 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -21,16 +21,10 @@ EXTRA_DIST = libassuan-config.in libassuan.m4 libassuan.vers \ versioninfo.rc.in libassuan.def INCLUDES = -I.. -I$(top_srcdir)/include -if HAVE_PTH -libassuan_pth = libassuan-pth.la -else -libassuan_pth = -endif - bin_SCRIPTS = libassuan-config m4datadir = $(datadir)/aclocal m4data_DATA = libassuan.m4 -lib_LTLIBRARIES = libassuan.la $(libassuan_pth) +lib_LTLIBRARIES = libassuan.la include_HEADERS = assuan.h if HAVE_LD_VERSION_SCRIPT @@ -107,11 +101,3 @@ libassuan_la_LDFLAGS = $(libassuan_res_ldflag) $(no_undefined) \ libassuan_la_DEPENDENCIES = @LTLIBOBJS@ \ $(srcdir)/libassuan.vers $(libassuan_deps) libassuan_la_LIBADD = @LTLIBOBJS@ @NETLIBS@ @GPG_ERROR_LIBS@ - -if HAVE_PTH -libassuan_pth_la_SOURCES = $(common_sources) assuan-io-pth.c -libassuan_pth_la_CPPFLAGS = $(AM_CPPFLAGS) @GPG_ERROR_CFLAGS@ @PTH_CFLAGS@ -libassuan_pth_la_CFLAGS = $(AM_CFLAGS) @GPG_ERROR_CFLAGS@ $(PTH_CFLAGS) -libassuan_pth_la_LIBADD = @LTLIBOBJS@ @NETLIBS@ @GPG_ERROR_LIBS@ @PTH_LIBS@ -endif - diff --git a/src/assuan-buffer.c b/src/assuan-buffer.c index 583d137..32a9aee 100644 --- a/src/assuan-buffer.c +++ b/src/assuan-buffer.c @@ -37,7 +37,7 @@ writen (assuan_context_t ctx, const char *buffer, size_t length) { while (length) { - ssize_t nwritten = ctx->io->writefnc (ctx, buffer, length); + ssize_t nwritten = ctx->engine.writefnc (ctx, buffer, length); if (nwritten < 0) { @@ -66,7 +66,7 @@ readline (assuan_context_t ctx, char *buf, size_t buflen, *r_nread = 0; while (nleft > 0) { - ssize_t n = ctx->io->readfnc (ctx, buf, nleft); + ssize_t n = ctx->engine.readfnc (ctx, buf, nleft); if (n < 0) { @@ -249,7 +249,7 @@ assuan_read_line (assuan_context_t ctx, char **line, size_t *linelen) { err = _assuan_read_line (ctx); } - while (_assuan_error_is_eagain (err)); + while (_assuan_error_is_eagain (ctx, err)); *line = ctx->inbound.line; *linelen = ctx->inbound.linelen; @@ -551,19 +551,19 @@ assuan_sendfd (assuan_context_t ctx, assuan_fd_t fd) return _assuan_error (ctx, GPG_ERR_NOT_IMPLEMENTED); #endif - if (! ctx->io->sendfd) + if (! ctx->engine.sendfd) return set_error (ctx, GPG_ERR_NOT_IMPLEMENTED, "server does not support sending and receiving " "of file descriptors"); - return ctx->io->sendfd (ctx, fd); + return ctx->engine.sendfd (ctx, fd); } gpg_error_t assuan_receivefd (assuan_context_t ctx, assuan_fd_t *fd) { - if (! ctx->io->receivefd) + if (! ctx->engine.receivefd) return set_error (ctx, GPG_ERR_NOT_IMPLEMENTED, "server does not support sending and receiving " "of file descriptors"); - return ctx->io->receivefd (ctx, fd); + return ctx->engine.receivefd (ctx, fd); } diff --git a/src/assuan-client.c b/src/assuan-client.c index aa74f81..1f860b8 100644 --- a/src/assuan-client.c +++ b/src/assuan-client.c @@ -49,7 +49,7 @@ _assuan_read_from_server (assuan_context_t ctx, int *okay, int *off) { rc = _assuan_read_line (ctx); } - while (_assuan_error_is_eagain (rc)); + while (_assuan_error_is_eagain (ctx, rc)); if (rc) return rc; line = ctx->inbound.line; diff --git a/src/assuan-defs.h b/src/assuan-defs.h index 95706d6..38f51ed 100644 --- a/src/assuan-defs.h +++ b/src/assuan-defs.h @@ -56,19 +56,6 @@ struct cmdtbl_s }; -/* A structure to dispatch I/O functions. */ -struct assuan_io -{ - /* 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 *); -}; - /* The context we use with most functions. */ struct assuan_context_s @@ -97,17 +84,30 @@ struct assuan_context_s { unsigned int no_waitpid : 1; unsigned int confidential : 1; + unsigned int no_fixsignals : 1; } 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; + /* 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; @@ -220,11 +220,6 @@ struct assuan_context_s assuan_fd_t input_fd; /* Set by the INPUT command. */ assuan_fd_t output_fd; /* Set by the OUTPUT command. */ - - /* io routines. */ - struct assuan_io *io; - - }; @@ -242,6 +237,38 @@ 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); +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, int filedes[2]); + +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); @@ -273,7 +300,7 @@ 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 (gpg_error_t err); +int _assuan_error_is_eagain (assuan_context_t ctx, gpg_error_t err); @@ -290,33 +317,22 @@ void _assuan_log_print_buffer (FILE *fp, const void *buffer, size_t length); /*-- assuan-io.c --*/ -pid_t _assuan_waitpid (pid_t pid, int *status, int options); - 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); -ssize_t _assuan_io_read (assuan_fd_t fd, void *buffer, size_t size); -ssize_t _assuan_io_write (assuan_fd_t fd, const void *buffer, size_t size); -#ifdef HAVE_W32_SYSTEM -int _assuan_simple_sendmsg (assuan_context_t ctx, void *msg); -int _assuan_simple_recvmsg (assuan_context_t ctx, void *msg); -#else -ssize_t _assuan_simple_sendmsg (assuan_context_t ctx, struct msghdr *msg); -ssize_t _assuan_simple_recvmsg (assuan_context_t ctx, struct msghdr *msg); -#endif - -void _assuan_usleep (unsigned int usec); - /*-- assuan-socket.c --*/ -int _assuan_close (assuan_fd_t fd); -assuan_fd_t _assuan_sock_new (int domain, int type, int proto); -int _assuan_sock_connect (assuan_fd_t sockfd, + +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_fd_t sockfd, struct sockaddr *addr, int addrlen); -int _assuan_sock_get_nonce (struct sockaddr *addr, int addrlen, - assuan_sock_nonce_t *nonce); -int _assuan_sock_check_nonce (assuan_fd_t fd, assuan_sock_nonce_t *nonce); +int _assuan_sock_bind (assuan_context_t ctx, assuan_fd_t sockfd, + struct sockaddr *addr, int addrlen); +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 int _assuan_sock_wsa2errno (int err); #endif diff --git a/src/assuan-error.c b/src/assuan-error.c index 60cb0d3..c45ca67 100644 --- a/src/assuan-error.c +++ b/src/assuan-error.c @@ -33,13 +33,13 @@ /* A small helper function to treat EAGAIN transparently to the caller. */ int -_assuan_error_is_eagain (gpg_error_t err) +_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 (100000); - return 1; + _assuan_usleep (ctx, 100000); + return 1; } else return 0; diff --git a/src/assuan-handler.c b/src/assuan-handler.c index fd41719..7291acd 100644 --- a/src/assuan-handler.c +++ b/src/assuan-handler.c @@ -219,6 +219,7 @@ std_handler_input (assuan_context_t ctx, char *line) return PROCESS_DONE (ctx, 0); } + /* Format is OUTPUT FD=<n> */ static gpg_error_t std_handler_output (assuan_context_t ctx, char *line) @@ -236,9 +237,6 @@ std_handler_output (assuan_context_t ctx, char *line) } - - - /* 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 */ @@ -592,7 +590,7 @@ process_next (assuan_context_t ctx) required to write full lines without blocking long after starting a partial line. */ rc = _assuan_read_line (ctx); - if (_assuan_error_is_eagain (rc)) + if (_assuan_error_is_eagain (ctx, rc)) return 0; if (rc) return rc; @@ -670,7 +668,7 @@ process_request (assuan_context_t ctx) { rc = _assuan_read_line (ctx); } - while (_assuan_error_is_eagain (rc)); + while (_assuan_error_is_eagain (ctx, rc)); if (rc) return rc; if (*ctx->inbound.line == '#' || !ctx->inbound.linelen) diff --git a/src/assuan-inquire.c b/src/assuan-inquire.c index dba7cb1..8772a15 100644 --- a/src/assuan-inquire.c +++ b/src/assuan-inquire.c @@ -176,7 +176,7 @@ assuan_inquire (assuan_context_t ctx, const char *keyword, { do rc = _assuan_read_line (ctx); - while (_assuan_error_is_eagain (rc)); + while (_assuan_error_is_eagain (ctx, rc)); if (rc) goto leave; line = (unsigned char *) ctx->inbound.line; diff --git a/src/assuan-io-pth.c b/src/assuan-io-pth.c deleted file mode 100644 index 7e438e9..0000000 --- a/src/assuan-io-pth.c +++ /dev/null @@ -1,170 +0,0 @@ -/* assuan-io-pth.c - Pth version of assua-io.c. - Copyright (C) 2002, 2004, 2006-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 <http://www.gnu.org/licenses/>. - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <sys/time.h> -#include <sys/types.h> -#ifdef HAVE_SYS_SOCKET_H -#include <sys/socket.h> -#endif -#if HAVE_SYS_UIO_H -# include <sys/uio.h> -#endif -#include <unistd.h> -#include <errno.h> -#ifdef HAVE_W32_SYSTEM -# include <windows.h> -#else -# include <sys/wait.h> -#endif -#include <pth.h> - -#include "assuan-defs.h" - - - -#ifndef HAVE_W32_SYSTEM -pid_t -_assuan_waitpid (pid_t pid, int *status, int options) -{ - return pth_waitpid (pid, status, options); -} -#endif - - -ssize_t -_assuan_simple_read (assuan_context_t ctx, void *buffer, size_t size) -{ - /* Fixme: For W32 we should better not cast the HANDLE type to int. - However, this requires changes in w32pth too. */ - return _assuan_io_read (ctx->inbound.fd, buffer, size); -} - -ssize_t -_assuan_simple_write (assuan_context_t ctx, const void *buffer, size_t size) -{ - return _assuan_io_write (ctx->outbound.fd, buffer, size); -} - -ssize_t -_assuan_io_read (assuan_fd_t fd, void *buffer, size_t size) -{ - return pth_read ((int)fd, buffer, size); -} - -ssize_t -_assuan_io_write (assuan_fd_t fd, const void *buffer, size_t size) -{ - return pth_write ((int)fd, buffer, size); -} - - -#ifdef HAVE_W32_SYSTEM -int -_assuan_simple_sendmsg (assuan_context_t ctx, void *msg) -#else -ssize_t -_assuan_simple_sendmsg (assuan_context_t ctx, struct msghdr *msg) -#endif -{ -#if defined(HAVE_W32_SYSTEM) - errno = ENOSYS; - return -1; -#else - /* Pth does not provide a sendmsg function. Thus we implement it here. */ - int ret; - int fd = ctx->outbound.fd; - int fdmode; - - fdmode = pth_fdmode (fd, PTH_FDMODE_POLL); - if (fdmode == PTH_FDMODE_ERROR) - { - errno = EBADF; - return -1; - } - if (fdmode == PTH_FDMODE_BLOCK) - { - fd_set fds; - - FD_ZERO (&fds); - FD_SET (fd, &fds); - while ( (ret = pth_select (fd+1, NULL, &fds, NULL, NULL)) < 0 - && errno == EINTR) - ; - if (ret < 0) - return -1; - } - - while ((ret = sendmsg (fd, msg, 0)) == -1 && errno == EINTR) - ; - return ret; -#endif -} - -#ifdef HAVE_W32_SYSTEM -int -_assuan_simple_recvmsg (assuan_context_t ctx, void *msg) -#else -ssize_t -_assuan_simple_recvmsg (assuan_context_t ctx, struct msghdr *msg) -#endif -{ -#if defined(HAVE_W32_SYSTEM) - errno = ENOSYS; - return -1; -#else - /* Pth does not provide a recvmsg function. Thus we implement it here. */ - int ret; - int fd = ctx->inbound.fd; - int fdmode; - - fdmode = pth_fdmode (fd, PTH_FDMODE_POLL); - if (fdmode == PTH_FDMODE_ERROR) - { - errno = EBADF; - return -1; - } - if (fdmode == PTH_FDMODE_BLOCK) - { - fd_set fds; - - FD_ZERO (&fds); - FD_SET (fd, &fds); - while ( (ret = pth_select (fd+1, &fds, NULL, NULL, NULL)) < 0 - && errno == EINTR) - ; - if (ret < 0) - return -1; - } - - while ((ret = recvmsg (fd, msg, 0)) == -1 && errno == EINTR) - ; - return ret; -#endif -} - - -void -_assuan_usleep (unsigned int usec) -{ - pth_usleep (usec); -} diff --git a/src/assuan-io.c b/src/assuan-io.c index 88accc3..c5bbc99 100644 --- a/src/assuan-io.c +++ b/src/assuan-io.c @@ -38,185 +38,15 @@ #include "assuan-defs.h" -#ifndef HAVE_W32_SYSTEM -pid_t -_assuan_waitpid (pid_t pid, int *status, int options) -{ - return waitpid (pid, status, options); -} -#endif - - -static ssize_t -do_io_read (assuan_fd_t fd, void *buffer, size_t size) -{ -#ifdef HAVE_W32_SYSTEM - /* 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 n; - - n = recv (HANDLE2SOCKET(fd), buffer, size, 0); - if (n == -1) - { - switch (WSAGetLastError ()) - { - case WSAENOTSOCK: - { - DWORD nread = 0; - - n = ReadFile (fd, buffer, size, &nread, NULL); - if (!n) - { - switch (GetLastError()) - { - case ERROR_BROKEN_PIPE: errno = EPIPE; break; - default: errno = EIO; - } - n = -1; - } - else - n = (int)nread; - } - break; - - case WSAEWOULDBLOCK: errno = EAGAIN; break; - case ERROR_BROKEN_PIPE: errno = EPIPE; break; - default: errno = EIO; break; - } - } - return n; -#else /*!HAVE_W32_SYSTEM*/ - return read (fd, buffer, size); -#endif /*!HAVE_W32_SYSTEM*/ -} - - -ssize_t -_assuan_io_read (assuan_fd_t fd, void *buffer, size_t size) -{ - return do_io_read (fd, buffer, size); -} - ssize_t _assuan_simple_read (assuan_context_t ctx, void *buffer, size_t size) { - return do_io_read (ctx->inbound.fd, buffer, size); + return _assuan_read (ctx, ctx->inbound.fd, buffer, size); } - -static ssize_t -do_io_write (assuan_fd_t fd, const void *buffer, size_t size) -{ -#ifdef HAVE_W32_SYSTEM - /* 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 n; - - n = send (HANDLE2SOCKET(fd), buffer, size, 0); - if (n == -1 && WSAGetLastError () == WSAENOTSOCK) - { - DWORD nwrite; - - n = WriteFile (fd, buffer, size, &nwrite, NULL); - if (!n) - { - switch (GetLastError ()) - { - case ERROR_BROKEN_PIPE: - case ERROR_NO_DATA: errno = EPIPE; break; - default: errno = EIO; break; - } - n = -1; - } - else - n = (int)nwrite; - } - return n; -#else /*!HAVE_W32_SYSTEM*/ - return write (fd, buffer, size); -#endif /*!HAVE_W32_SYSTEM*/ -} - -ssize_t -_assuan_io_write (assuan_fd_t fd, const void *buffer, size_t size) -{ - return do_io_write (fd, buffer, size); -} - ssize_t _assuan_simple_write (assuan_context_t ctx, const void *buffer, size_t size) { - return do_io_write (ctx->outbound.fd, buffer, size); + return _assuan_write (ctx, ctx->outbound.fd, buffer, size); } - - -#ifdef HAVE_W32_SYSTEM -int -_assuan_simple_sendmsg (assuan_context_t ctx, void *msg) -#else -ssize_t -_assuan_simple_sendmsg (assuan_context_t ctx, struct msghdr *msg) -#endif -{ -#ifdef HAVE_W32_SYSTEM - errno = ENOSYS; - return -1; -#else - int ret; - while ( (ret = sendmsg (ctx->outbound.fd, msg, 0)) == -1 && errno == EINTR) - ; - return ret; -#endif -} - - -#ifdef HAVE_W32_SYSTEM -int -_assuan_simple_recvmsg (assuan_context_t ctx, void *msg) -#else -ssize_t -_assuan_simple_recvmsg (assuan_context_t ctx, struct msghdr *msg) -#endif -{ -#ifdef HAVE_W32_SYSTEM - errno = ENOSYS; - return -1; -#else - int ret; - while ( (ret = recvmsg (ctx->inbound.fd, msg, 0)) == -1 && errno == EINTR) - ; - return ret; -#endif -} - - -void -_assuan_usleep (unsigned int usec) -{ - if (usec) - { -#ifdef HAVE_NANOSLEEP - struct timespec req; - struct timespec rem; - - req.tv_sec = 0; - req.tv_nsec = usec * 1000; - - while (nanosleep (&req, &rem) < 0 && errno == EINTR) - req = rem; - -#elif defined(HAVE_W32_SYSTEM) - Sleep (usec / 1000); -#else - struct timeval tv; - - tv.tv_sec = usec / 1000000; - tv.tv_usec = usec % 1000000; - select (0, NULL, NULL, NULL, &tv); -#endif - } -} - diff --git a/src/assuan-listen.c b/src/assuan-listen.c index 3f57922..2f6c8a3 100644 --- a/src/assuan-listen.c +++ b/src/assuan-listen.c @@ -138,7 +138,7 @@ assuan_close_input_fd (assuan_context_t ctx) { if (!ctx || ctx->input_fd == ASSUAN_INVALID_FD) return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE); - _assuan_close (ctx->input_fd); + _assuan_close (ctx, ctx->input_fd); ctx->input_fd = ASSUAN_INVALID_FD; return 0; } @@ -151,7 +151,7 @@ assuan_close_output_fd (assuan_context_t ctx) if (!ctx || ctx->output_fd == ASSUAN_INVALID_FD) return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE); - _assuan_close (ctx->output_fd); + _assuan_close (ctx, ctx->output_fd); ctx->output_fd = ASSUAN_INVALID_FD; return 0; } diff --git a/src/assuan-pipe-connect.c b/src/assuan-pipe-connect.c index c5e20e7..bdc59a4 100644 --- a/src/assuan-pipe-connect.c +++ b/src/assuan-pipe-connect.c @@ -62,7 +62,6 @@ static void fix_signals (void) { -#ifndef _ASSUAN_NO_FIXED_SIGNALS #ifndef HAVE_DOSISH_SYSTEM /* No SIGPIPE for these systems. */ static int fixed_signals; @@ -82,58 +81,28 @@ fix_signals (void) /* FIXME: This is not MT safe */ } #endif /*HAVE_DOSISH_SYSTEM*/ -#endif /*!_ASSUAN_NO_FIXED_SIGNALS*/ } -#ifndef HAVE_W32_SYSTEM -static int -writen (int fd, const char *buffer, size_t length) -{ - while (length) - { - int nwritten = write (fd, buffer, length); - - if (nwritten < 0) - { - if (errno == EINTR) - continue; - return -1; /* write error */ - } - length -= nwritten; - buffer += nwritten; - } - return 0; /* okay */ -} -#endif - static void do_finish (assuan_context_t ctx) { if (ctx->inbound.fd != ASSUAN_INVALID_FD) { - _assuan_close (ctx->inbound.fd); + _assuan_close (ctx, ctx->inbound.fd); if (ctx->inbound.fd == ctx->outbound.fd) ctx->outbound.fd = ASSUAN_INVALID_FD; ctx->inbound.fd = ASSUAN_INVALID_FD; } if (ctx->outbound.fd != ASSUAN_INVALID_FD) { - _assuan_close (ctx->outbound.fd); + _assuan_close (ctx, ctx->outbound.fd); ctx->outbound.fd = ASSUAN_INVALID_FD; } - if (ctx->pid != (pid_t)(-1) && ctx->pid) + if (ctx->pid != ASSUAN_INVALID_PID && ctx->pid) { -#ifndef HAVE_W32_SYSTEM -#ifndef _ASSUAN_USE_DOUBLE_FORK - if (!ctx->flags.no_waitpid) - _assuan_waitpid (ctx->pid, NULL, 0); - ctx->pid =(pid_t)(-1); -#endif -#else /*!HAVE_W32_SYSTEM*/ - CloseHandle ((HANDLE) ctx->pid); - ctx->pid = (pid_t) INVALID_HANDLE_VALUE; -#endif /*HAVE_W32_SYSTEM*/ + _assuan_waitpid (ctx, ctx->pid, ctx->flags.no_waitpid, NULL, 0); + ctx->pid = ASSUAN_INVALID_PID; } } @@ -166,178 +135,96 @@ initial_handshake (assuan_context_t ctx) return err; } + +struct at_pipe_fork +{ + void (*user_atfork) (void *opaque, int reserved); + void *user_atforkvalue; +}; + + +static void +at_pipe_fork_cb (void *opaque, int reserved) +{ + struct at_pipe_fork *atp = opaque; + + if (atp->user_atfork) + atp->user_atfork (atp->user_atforkvalue, reserved); #ifndef HAVE_W32_SYSTEM -#define pipe_connect pipe_connect_unix -/* Unix version of the pipe connection code. We use an extra macro to - make ChangeLog entries easier. */ + { + char mypidstr[50]; + + /* We store our parents pid in the environment so that the execed + assuan server is able to read the actual pid of the client. + The server can't use getppid because it might have been double + forked before the assuan server has been initialized. */ + sprintf (mypidstr, "%lu", (unsigned long) getpid ()); + setenv ("_assuan_pipe_connect_pid", mypidstr, 1); + + /* Make sure that we never pass a connection fd variable when + using a simple pipe. */ + unsetenv ("_assuan_connection_fd"); + } +#endif +} + + static gpg_error_t -pipe_connect_unix (assuan_context_t ctx, - const char *name, const char *const argv[], - int *fd_child_list, - void (*atfork) (void *opaque, int reserved), - void *atforkvalue, unsigned int flags) +pipe_connect (assuan_context_t ctx, + const char *name, const char **argv, + int *fd_child_list, + void (*atfork) (void *opaque, int reserved), + void *atforkvalue, unsigned int flags) { - int rp[2]; - int wp[2]; - pid_t pid; - char mypidstr[50]; gpg_error_t rc; - static struct assuan_io io = { _assuan_simple_read, _assuan_simple_write, - 0, 0 }; + assuan_fd_t rp[2]; + assuan_fd_t wp[2]; + pid_t pid; + int res; + struct at_pipe_fork atp; - (void)flags; + atp.user_atfork = atfork; + atp.user_atforkvalue = atforkvalue; if (!ctx || !name || !argv || !argv[0]) return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE); - fix_signals (); + if (! ctx->flags.no_fixsignals) + fix_signals (); - sprintf (mypidstr, "%lu", (unsigned long)getpid ()); - - if (pipe (rp) < 0) - return _assuan_error (ctx, GPG_ERR_ASS_GENERAL); + if (_assuan_pipe (ctx, rp, 1) < 0) + return _assuan_error (ctx, gpg_err_code_from_syserror ()); - if (pipe (wp) < 0) + if (_assuan_pipe (ctx, wp, 0) < 0) { - close (rp[0]); - close (rp[1]); - return _assuan_error (ctx, GPG_ERR_ASS_GENERAL); + _assuan_close (ctx, rp[0]); + _assuan_close (ctx, rp[1]); + return _assuan_error (ctx, gpg_err_code_from_syserror ()); } - /* FIXME: For GPGME we should better use _gpgme_io_spawn. The PID - stored here is actually soon useless. */ - pid = fork (); - if (pid < 0) + /* FIXME: Use atfork handler that closes child fds on Unix. */ + res = _assuan_spawn (ctx, &pid, name, argv, wp[0], rp[1], + fd_child_list, at_pipe_fork_cb, &atp, flags); + if (res < 0) { - close (rp[0]); - close (rp[1]); - close (wp[0]); - close (wp[1]); - return _assuan_error (ctx, GPG_ERR_ASS_GENERAL); + rc = gpg_err_code_from_syserror (); + _assuan_close (ctx, rp[0]); + _assuan_close (ctx, rp[1]); + _assuan_close (ctx, wp[0]); + _assuan_close (ctx, wp[1]); + return _assuan_error (ctx, rc); } - if (pid == 0) - { -#ifdef _ASSUAN_USE_DOUBLE_FORK - pid_t pid2; - - if ((pid2 = fork ()) == 0) -#endif - { - int i, n; - char errbuf[512]; - int *fdp; - - if (atfork) - atfork (atforkvalue, 0); - - /* Dup handles to stdin/stdout. */ - if (rp[1] != STDOUT_FILENO) - { - if (dup2 (rp[1], STDOUT_FILENO) == -1) - { - TRACE1 (ctx, ASSUAN_LOG_SYSIO, "pipe_connect_unix", ctx, - "dup2 failed in child: %s", strerror (errno)); - _exit (4); - } - } - if (wp[0] != STDIN_FILENO) - { - if (dup2 (wp[0], STDIN_FILENO) == -1) - { - TRACE1 (ctx, ASSUAN_LOG_SYSIO, "pipe_connect_unix", ctx, - "dup2 failed in child: %s", strerror (errno)); - _exit (4); - } - } - - /* Dup stderr to /dev/null unless it is in the list of FDs to be - passed to the child. */ - fdp = fd_child_list; - if (fdp) - { - for (; *fdp != -1 && *fdp != STDERR_FILENO; fdp++) - ; - } - if (!fdp || *fdp == -1) - { - int fd = open ("/dev/null", O_WRONLY); - if (fd == -1) - { - TRACE1 (ctx, ASSUAN_LOG_SYSIO, "pipe_connect_unix", ctx, - "can't open `/dev/null': %s", strerror (errno)); - _exit (4); - } - if (dup2 (fd, STDERR_FILENO) == -1) - { - TRACE1 (ctx, ASSUAN_LOG_SYSIO, "pipe_connect_unix", ctx, - "dup2(dev/null, 2) failed: %s", strerror (errno)); - _exit (4); - } - } - - - /* Close all files which will not be duped and are not in the - fd_child_list. */ - n = sysconf (_SC_OPEN_MAX); - if (n < 0) - n = MAX_OPEN_FDS; - for (i=0; i < n; i++) - { - if ( i == STDIN_FILENO || i == STDOUT_FILENO - || i == STDERR_FILENO) - continue; - fdp = fd_child_list; - if (fdp) - { - while (*fdp != -1 && *fdp != i) - fdp++; - } - - if (!(fdp && *fdp != -1)) - close(i); - } - errno = 0; - - /* We store our parents pid in the environment so that the - execed assuan server is able to read the actual pid of the - client. The server can't use getppid because it might have - been double forked before the assuan server has been - initialized. */ - setenv ("_assuan_pipe_connect_pid", mypidstr, 1); - - /* Make sure that we never pass a connection fd variable - when using a simple pipe. */ - unsetenv ("_assuan_connection_fd"); - - execv (name, (char *const *) argv); - /* oops - use the pipe to tell the parent about it */ - snprintf (errbuf, sizeof(errbuf)-1, - "ERR %d can't exec `%s': %.50s\n", - _assuan_error (ctx, GPG_ERR_ASS_SERVER_START), - name, strerror (errno)); - errbuf[sizeof(errbuf)-1] = 0; - writen (1, errbuf, strlen (errbuf)); - _exit (4); - } -#ifdef _ASSUAN_USE_DOUBLE_FORK - if (pid2 == -1) - _exit (1); - else - _exit (0); -#endif - } - -#ifdef _ASSUAN_USE_DOUBLE_FORK - _assuan_waitpid (pid, NULL, 0); - pid = -1; -#endif - - close (rp[1]); - close (wp[0]); + /* Close the stdin/stdout child fds in the parent. */ + _assuan_close (ctx, rp[1]); + _assuan_close (ctx, wp[0]); - ctx->io = &io; + ctx->engine.release = _assuan_disconnect; + ctx->engine.readfnc = _assuan_simple_read; + ctx->engine.writefnc = _assuan_simple_write; + ctx->engine.sendfd = NULL; + ctx->engine.receivefd = NULL; ctx->pipe_mode = 1; ctx->inbound.fd = rp[0]; /* Our inbound is read end of read pipe. */ ctx->outbound.fd = wp[1]; /* Our outbound is write end of write pipe. */ @@ -350,176 +237,133 @@ pipe_connect_unix (assuan_context_t ctx, _assuan_reset (ctx); return rc; } -#endif /*!HAVE_W32_SYSTEM*/ +/* FIXME: For socketpair_connect, use spawn function and add atfork + handler to do the right thing. Instead of stdin and stdout, we + extend the fd_child_list by fds[1]. */ + +#ifndef HAVE_W32_SYSTEM +struct at_socketpair_fork +{ + assuan_fd_t peer_fd; + void (*user_atfork) (void *opaque, int reserved); + void *user_atforkvalue; +}; + + +static void +at_socketpair_fork_cb (void *opaque, int reserved) +{ + struct at_socketpair_fork *atp = opaque; + + if (atp->user_atfork) + atp->user_atfork (atp->user_atforkvalue, reserved); + #ifndef HAVE_W32_SYSTEM + { + char mypidstr[50]; + + /* We store our parents pid in the environment so that the execed + assuan server is able to read the actual pid of the client. + The server can't use getppid because it might have been double + forked before the assuan server has been initialized. */ + sprintf (mypidstr, "%lu", (unsigned long) getpid ()); + setenv ("_assuan_pipe_connect_pid", mypidstr, 1); + + /* Now set the environment variable used to convey the + connection's file descriptor. */ + sprintf (mypidstr, "%d", atp->peer_fd); + if (setenv ("_assuan_connection_fd", mypidstr, 1)) + _exit (4); + } +#endif +} + + /* This function is similar to pipe_connect but uses a socketpair and sets the I/O up to use sendmsg/recvmsg. */ static gpg_error_t socketpair_connect (assuan_context_t ctx, - const char *name, const char *argv[], + const char *name, const char **argv, int *fd_child_list, void (*atfork) (void *opaque, int reserved), void *atforkvalue) { gpg_error_t err; + int idx; int fds[2]; char mypidstr[50]; pid_t pid; + int *child_fds = NULL; + int child_fds_cnt = 0; + struct at_socketpair_fork atp; + int rc; + + TRACE_BEG3 (ctx, ASSUAN_LOG_CTX, "socketpair_connect", ctx, + "name=%s,atfork=%p,atforkvalue=%p", name ? name : "(null)", + atfork, atforkvalue); + + atp.user_atfork = atfork; + atp.user_atforkvalue = atforkvalue; if (!ctx || (name && (!argv || !argv[0])) || (!name && !argv)) return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE); - fix_signals (); + if (! ctx->flags.no_fixsignals) + fix_signals (); sprintf (mypidstr, "%lu", (unsigned long)getpid ()); - if ( socketpair (AF_LOCAL, SOCK_STREAM, 0, fds) ) + while (fd_child_list[child_fds_cnt] != ASSUAN_INVALID_FD) + child_fds_cnt++; + child_fds = _assuan_malloc (ctx, (child_fds_cnt + 2) * sizeof (int)); + if (! child_fds) + return TRACE_ERR (gpg_err_code_from_syserror ()); + memcpy (&child_fds[1], fd_child_list, (child_fds_cnt + 1) * sizeof (int)); + + if (_assuan_socketpair (ctx, AF_LOCAL, SOCK_STREAM, 0, fds)) { - TRACE1 (ctx, ASSUAN_LOG_SYSIO, "socketpair_connect", ctx, - "socketpair failed: %s", strerror (errno)); - return _assuan_error (ctx, GPG_ERR_ASS_GENERAL); + TRACE_LOG1 ("socketpair failed: %s", strerror (errno)); + _assuan_free (ctx, child_fds); + return TRACE_ERR (GPG_ERR_ASS_GENERAL); } + atp.peer_fd = fds[1]; + child_fds[0] = fds[1]; - pid = fork (); - if (pid < 0) + + rc = _assuan_spawn (ctx, &pid, name, argv, ASSUAN_INVALID_FD, + ASSUAN_INVALID_FD, child_fds, at_socketpair_fork_cb, + &atp, 0); + if (rc < 0) { - close (fds[0]); - close (fds[1]); - /* FIXME: cleanup ctx */ - return _assuan_error (ctx, GPG_ERR_ASS_GENERAL); + err = gpg_err_code_from_syserror (); + _assuan_close (ctx, fds[0]); + _assuan_close (ctx, fds[1]); + _assuan_free (ctx, child_fds); + return TRACE_ERR (err); } - if (pid == 0) + /* For W32, the user needs to know the server-local names of the + inherited handles. Return them here. Note that the translation + of the peer socketpair fd (fd_child_list[0]) must be done by the + wrapper program based on the environment variable + _assuan_connection_fd. */ + for (idx = 0; fd_child_list[idx] != -1; idx++) + /* We add 1 to skip over the socketpair end. */ + fd_child_list[idx] = child_fds[idx + 1]; + + /* If this is the server child process, exit early. */ + if (! name && (*argv)[0] == 's') { -#ifdef _ASSUAN_USE_DOUBLE_FORK - pid_t pid2; - - if ((pid2 = fork ()) == 0) -#endif - { - int fd, i, n; - char errbuf[512]; - int *fdp; - - if (atfork) - atfork (atforkvalue, 0); - - /* Connect stdin and stdout to /dev/null. */ - fd = open ("/dev/null", O_RDONLY); - if (fd == -1 || dup2 (fd, STDIN_FILENO) == -1) - { - TRACE1 (ctx, ASSUAN_LOG_SYSIO, "socketpair_connect", ctx, - "dup2(dev/null) failed: %s", strerror (errno)); - _exit (4); - } - fd = open ("/dev/null", O_WRONLY); - if (fd == -1 || dup2 (fd, STDOUT_FILENO) == -1) - { - TRACE1 (ctx, ASSUAN_LOG_SYSIO, "socketpair_connect", ctx, - "dup2(dev/null) failed: %s", strerror (errno)); - _exit (4); - } - - /* Dup stderr to /dev/null unless it is in the list of FDs to be - passed to the child. */ - fdp = fd_child_list; - if (fdp) - { - for (; *fdp != -1 && *fdp != STDERR_FILENO; fdp++) - ; - } - if (!fdp || *fdp == -1) - { - fd = open ("/dev/null", O_WRONLY); - if (fd == -1 || dup2 (fd, STDERR_FILENO) == -1) - { - TRACE1 (ctx, ASSUAN_LOG_SYSIO, "socketpair_connect", ctx, - "dup2(dev/null) failed: %s", strerror (errno)); - _exit (4); - } - } - - - /* Close all files which will not be duped, are not in the - fd_child_list and are not the connection fd. */ - n = sysconf (_SC_OPEN_MAX); - if (n < 0) - n = MAX_OPEN_FDS; - for (i=0; i < n; i++) - { - if ( i == STDIN_FILENO || i == STDOUT_FILENO - || i == STDERR_FILENO || i == fds[1]) - continue; - fdp = fd_child_list; - if (fdp) - { - while (*fdp != -1 && *fdp != i) - fdp++; - } - - if (!(fdp && *fdp != -1)) - close(i); - } - errno = 0; - - /* We store our parents pid in the environment so that the - execed assuan server is able to read the actual pid of the - client. The server can't use getppid becuase it might have - been double forked before the assuan server has been - initialized. */ - setenv ("_assuan_pipe_connect_pid", mypidstr, 1); - - /* Now set the environment variable used to convey the - connection's file descriptor. */ - sprintf (mypidstr, "%d", fds[1]); - if (setenv ("_assuan_connection_fd", mypidstr, 1)) - { - TRACE1 (ctx, ASSUAN_LOG_SYSIO, "socketpair_connect", ctx, - "setenv failed: %s", strerror (errno)); - _exit (4); - } - - if (!name) - { - /* No name and no args given, thus we don't do an exec - but continue the forked process. */ - *argv = "server"; - - /* FIXME: Cleanup. */ - return 0; - } - - execv (name, (char *const *) argv); - /* oops - use the pipe to tell the parent about it */ - snprintf (errbuf, sizeof(errbuf)-1, - "ERR %d can't exec `%s': %.50s\n", - _assuan_error (ctx, GPG_ERR_ASS_SERVER_START), - name, strerror (errno)); - errbuf[sizeof(errbuf)-1] = 0; - writen (fds[1], errbuf, strlen (errbuf)); - _exit (4); - } -#ifdef _ASSUAN_USE_DOUBLE_FORK - if (pid2 == -1) - _exit (1); - else - _exit (0); -#endif + _assuan_free (ctx, child_fds); + _assuan_close (ctx, fds[0]); + return 0; } - if (! name) - *argv = "client"; - -#ifdef _ASSUAN_USE_DOUBLE_FORK - _assuan_waitpid (pid, NULL, 0); - pid = -1; -#endif - - close (fds[1]); + _assuan_close (ctx, fds[1]); ctx->pipe_mode = 1; ctx->inbound.fd = fds[0]; @@ -535,282 +379,6 @@ socketpair_connect (assuan_context_t ctx, } #endif /*!HAVE_W32_SYSTEM*/ - - -#ifdef HAVE_W32_SYSTEM -/* 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, char **cmdline) -{ - int i, n; - const char *s; - char *buf, *p; - - *cmdline = NULL; - n = 0; - for (i=0; (s=argv[i]); i++) - { - n += strlen (s) + 1 + 2; /* (1 space, 2 quoting */ - for (; *s; s++) - if (*s == '\"') - n++; /* Need to double inner quotes. */ - } - n++; - - buf = p = _assuan_malloc (ctx, n); - if (!buf) - return -1; - - for (i=0; argv[i]; i++) - { - if (i) - 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; -} -#endif /*HAVE_W32_SYSTEM*/ - - -#ifdef HAVE_W32_SYSTEM -/* Create pipe where one end end is inheritable. */ -static int -create_inheritable_pipe (assuan_context_t ctx, - assuan_fd_t filedes[2], int for_write) -{ - HANDLE r, w, h; - SECURITY_ATTRIBUTES sec_attr; - - memset (&sec_attr, 0, sizeof sec_attr ); - sec_attr.nLength = sizeof sec_attr; - sec_attr.bInheritHandle = FALSE; - - if (!CreatePipe (&r, &w, &sec_attr, 0)) - { - TRACE1 (ctx, ASSUAN_LOG_SYSIO, "create_inheritable_pipe", ctx, - "CreatePipe failed: %s", _assuan_w32_strerror (ctx, -1)); - return -1; - } - - if (!DuplicateHandle (GetCurrentProcess(), for_write? r : w, - GetCurrentProcess(), &h, 0, - TRUE, DUPLICATE_SAME_ACCESS )) - { - TRACE1 (ctx, ASSUAN_LOG_SYSIO, "create_inheritable_pipe", ctx, - "DuplicateHandle failed: %s", _assuan_w32_strerror (ctx, -1)); - CloseHandle (r); - CloseHandle (w); - return -1; - } - if (for_write) - { - CloseHandle (r); - r = h; - } - else - { - CloseHandle (w); - w = h; - } - - filedes[0] = r; - filedes[1] = w; - return 0; -} -#endif /*HAVE_W32_SYSTEM*/ - - -#ifdef HAVE_W32_SYSTEM -#define pipe_connect pipe_connect_w32 -/* W32 version of the pipe connection code. */ -static gpg_error_t -pipe_connect_w32 (assuan_context_t ctx, - const char *name, const char *const argv[], - int *fd_child_list, - void (*atfork) (void *opaque, int reserved), - void *atforkvalue, unsigned int flags) -{ - gpg_error_t err; - assuan_fd_t rp[2]; - assuan_fd_t wp[2]; - char mypidstr[50]; - char *cmdline; - SECURITY_ATTRIBUTES sec_attr; - PROCESS_INFORMATION pi = - { - NULL, /* Returns process handle. */ - 0, /* Returns primary thread handle. */ - 0, /* Returns pid. */ - 0 /* Returns tid. */ - }; - STARTUPINFO si; - int fd, *fdp; - HANDLE nullfd = INVALID_HANDLE_VALUE; - static struct assuan_io io = { _assuan_simple_read, _assuan_simple_write, - 0, 0 }; - - if (!ctx || !name || !argv || !argv[0]) - return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE); - - fix_signals (); - - sprintf (mypidstr, "%lu", (unsigned long)getpid ()); - - /* Build the command line. */ - if (build_w32_commandline (ctx, argv, &cmdline)) - return _assuan_error (ctx, gpg_err_code_from_syserror ()); - - /* Create thew two pipes. */ - if (create_inheritable_pipe (ctx, rp, 0)) - { - _assuan_free (ctx, cmdline); - return _assuan_error (ctx, GPG_ERR_ASS_GENERAL); - } - - if (create_inheritable_pipe (ctx, wp, 1)) - { - CloseHandle (rp[0]); - CloseHandle (rp[1]); - _assuan_free (ctx, cmdline); - return _assuan_error (ctx, GPG_ERR_ASS_GENERAL); - } - - - /* fixme: Actually we should set the "_assuan_pipe_connect_pid" env - variable. However this requires us to write a full environment - handler, because the strings are expected in sorted order. The - suggestion given in the MS Reference Library, to save the old - value, changeit, create proces and restore it, is not thread - safe. */ - - /* Start the process. */ - memset (&sec_attr, 0, sizeof sec_attr ); - sec_attr.nLength = sizeof sec_attr; - sec_attr.bInheritHandle = FALSE; - - memset (&si, 0, sizeof si); - si.cb = sizeof (si); - si.dwFlags = STARTF_USESTDHANDLES; - si.hStdInput = wp[0]; - si.hStdOutput = rp[1]; - - /* Dup stderr to /dev/null unless it is in the list of FDs to be - passed to the child. */ - fd = fileno (stderr); - fdp = fd_child_list; - if (fdp) - { - for (; *fdp != -1 && *fdp != fd; fdp++) - ; - } - if (!fdp || *fdp == -1) - { - nullfd = CreateFile ("nul", GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, OPEN_EXISTING, 0, NULL); - if (nullfd == INVALID_HANDLE_VALUE) - { - TRACE1 (ctx, ASSUAN_LOG_SYSIO, "pipe_connect_w32", ctx, - "can't open `nul': %s", _assuan_w32_strerror (ctx, -1)); - CloseHandle (rp[0]); - CloseHandle (rp[1]); - CloseHandle (wp[0]); - CloseHandle (wp[1]); - _assuan_free (ctx, cmdline); - /* FIXME: Cleanup? */ - return -1; - } - si.hStdError = nullfd; - } - else - si.hStdError = (void*)_get_osfhandle (fd); - - - /* Note: We inherit all handles flagged as inheritable. This seems - to be a security flaw but there seems to be no way of selecting - handles to inherit. */ - /* _assuan_log_printf ("CreateProcess, path=`%s' cmdline=`%s'\n", */ - /* name, cmdline); */ - if (!CreateProcess (name, /* Program to start. */ - cmdline, /* Command line arguments. */ - &sec_attr, /* Process security attributes. */ - &sec_attr, /* Thread security attributes. */ - TRUE, /* Inherit handles. */ - (CREATE_DEFAULT_ERROR_MODE - | ((flags & 128)? DETACHED_PROCESS : 0) - | GetPriorityClass (GetCurrentProcess ()) - | CREATE_SUSPENDED), /* Creation flags. */ - NULL, /* Environment. */ - NULL, /* Use current drive/directory. */ - &si, /* Startup information. */ - &pi /* Returns process information. */ - )) - { - TRACE1 (ctx, ASSUAN_LOG_SYSIO, "pipe_connect_w32", ctx, - "CreateProcess failed: %s", _assuan_w32_strerror (ctx, -1)); - CloseHandle (rp[0]); - CloseHandle (rp[1]); - CloseHandle (wp[0]); - CloseHandle (wp[1]); - if (nullfd != INVALID_HANDLE_VALUE) - CloseHandle (nullfd); - _assuan_free (ctx, cmdline); - /* FIXME: Cleanup? */ - return _assuan_error (ctx, GPG_ERR_ASS_GENERAL); - } - _assuan_free (ctx, cmdline); - cmdline = NULL; - if (nullfd != INVALID_HANDLE_VALUE) - { - CloseHandle (nullfd); - nullfd = INVALID_HANDLE_VALUE; - } - - CloseHandle (rp[1]); - CloseHandle (wp[0]); - - /* _assuan_log_printf ("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); - - ctx->io = &io; - ctx->engine.release = _assuan_disconnect; - ctx->pipe_mode = 1; - ctx->inbound.fd = rp[0]; /* Our inbound is read end of read pipe. */ - ctx->outbound.fd = wp[1]; /* Our outbound is write end of write pipe. */ - ctx->deinit_handler = do_deinit; - ctx->finish_handler = do_finish; - ctx->pid = (pid_t) pi.hProcess; - - err = initial_handshake (ctx); - if (err) - _assuan_reset (ctx); - return err; -} -#endif /*HAVE_W32_SYSTEM*/ - /* Connect to a server over a pipe, creating the assuan context and returning it in CTX. The server filename is NAME, the argument @@ -820,6 +388,9 @@ gpg_error_t assuan_pipe_connect (assuan_context_t ctx, const char *name, const char *argv[], int *fd_child_list) { + TRACE1 (ctx, ASSUAN_LOG_CTX, "assuan_pipe_connect", ctx, + "name=%s", name ? name : "(null)"); + return pipe_connect (ctx, name, argv, fd_child_list, NULL, NULL, 0); } @@ -860,6 +431,9 @@ assuan_pipe_connect_ext (assuan_context_t ctx, void (*atfork) (void *opaque, int reserved), void *atforkvalue, unsigned int flags) { + TRACE2 (ctx, ASSUAN_LOG_CTX, "assuan_pipe_connect_ext", ctx, + "name=%s,flags=0x%x", name ? name : "(null)", flags); + if ((flags & 1)) { #ifdef HAVE_W32_SYSTEM @@ -873,3 +447,4 @@ assuan_pipe_connect_ext (assuan_context_t ctx, return pipe_connect (ctx, name, argv, fd_child_list, atfork, atforkvalue, flags); } + diff --git a/src/assuan-pipe-server.c b/src/assuan-pipe-server.c index 3c30d48..7849fa5 100644 --- a/src/assuan-pipe-server.c +++ b/src/assuan-pipe-server.c @@ -77,8 +77,6 @@ assuan_init_pipe_server (assuan_context_t ctx, int filedes[2]) assuan_fd_t infd = ASSUAN_INVALID_FD; assuan_fd_t outfd = ASSUAN_INVALID_FD; int is_usd = 0; - static struct assuan_io io = { _assuan_simple_read, _assuan_simple_write, - 0, 0 }; rc = _assuan_register_std_commands (ctx); if (rc) @@ -117,6 +115,10 @@ assuan_init_pipe_server (assuan_context_t ctx, int filedes[2]) ctx->is_server = 1; ctx->engine.release = deinit_pipe_server; + ctx->engine.readfnc = _assuan_simple_read; + ctx->engine.writefnc = _assuan_simple_write; + ctx->engine.sendfd = NULL; + ctx->engine.receivefd = NULL; ctx->pipe_mode = 1; s = getenv ("_assuan_pipe_connect_pid"); @@ -135,8 +137,6 @@ assuan_init_pipe_server (assuan_context_t ctx, int filedes[2]) _assuan_init_uds_io (ctx); ctx->deinit_handler = _assuan_uds_deinit; } - else - ctx->io = &io; return 0; } diff --git a/src/assuan-socket-connect.c b/src/assuan-socket-connect.c index ac2df5b..21997f0 100644 --- a/src/assuan-socket-connect.c +++ b/src/assuan-socket-connect.c @@ -58,12 +58,12 @@ do_finish (assuan_context_t ctx) { if (ctx->inbound.fd != ASSUAN_INVALID_FD) { - _assuan_close (ctx->inbound.fd); + _assuan_close (ctx, ctx->inbound.fd); ctx->inbound.fd = ASSUAN_INVALID_FD; } if (ctx->outbound.fd != ASSUAN_INVALID_FD) { - _assuan_close (ctx->outbound.fd); + _assuan_close (ctx, ctx->outbound.fd); ctx->outbound.fd = ASSUAN_INVALID_FD; } } @@ -96,8 +96,6 @@ assuan_socket_connect_ext (assuan_context_t ctx, const char *name, pid_t server_pid, unsigned int flags) { - static struct assuan_io io = { _assuan_simple_read, _assuan_simple_write, - NULL, NULL }; gpg_error_t err; assuan_fd_t fd; struct sockaddr_un srvr_addr; @@ -120,7 +118,7 @@ assuan_socket_connect_ext (assuan_context_t ctx, if (strlen (name)+1 >= sizeof srvr_addr.sun_path) return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE); - fd = _assuan_sock_new (PF_LOCAL, SOCK_STREAM, 0); + fd = _assuan_sock_new (ctx, PF_LOCAL, SOCK_STREAM, 0); if (fd == ASSUAN_INVALID_FD) { TRACE1 (ctx, ASSUAN_LOG_SYSIO, "assuan_socket_connect_ext", ctx, @@ -135,17 +133,20 @@ assuan_socket_connect_ext (assuan_context_t ctx, srvr_addr.sun_path[sizeof (srvr_addr.sun_path) - 1] = 0; len = SUN_LEN (&srvr_addr); - if ( _assuan_sock_connect (fd, (struct sockaddr *) &srvr_addr, len) == -1 ) + if (_assuan_sock_connect (ctx, fd, (struct sockaddr *) &srvr_addr, len) == -1) { TRACE2 (ctx, ASSUAN_LOG_SYSIO, "assuan_socket_connect_ext", ctx, "can't connect to `%s': %s\n", name, strerror (errno)); /* FIXME: Cleanup */ - _assuan_close (fd); + _assuan_close (ctx, fd); return _assuan_error (ctx, GPG_ERR_ASS_CONNECT_FAILED); } - ctx->io = &io; ctx->engine.release = _assuan_disconnect; + ctx->engine.readfnc = _assuan_simple_read; + ctx->engine.writefnc = _assuan_simple_write; + ctx->engine.sendfd = NULL; + ctx->engine.receivefd = NULL; ctx->deinit_handler = ((flags&1))? _assuan_uds_deinit : do_deinit; ctx->finish_handler = do_finish; ctx->inbound.fd = fd; diff --git a/src/assuan-socket-server.c b/src/assuan-socket-server.c index b46a4e7..3487b19 100644 --- a/src/assuan-socket-server.c +++ b/src/assuan-socket-server.c @@ -96,9 +96,9 @@ accept_connection (assuan_context_t ctx) { return _assuan_error (ctx, gpg_err_code_from_syserror ()); } - if (_assuan_sock_check_nonce (fd, &ctx->listen_nonce)) + if (_assuan_sock_check_nonce (ctx, fd, &ctx->listen_nonce)) { - _assuan_close (fd); + _assuan_close (ctx, fd); return _assuan_error (ctx, GPG_ERR_ASS_ACCEPT_FAILED); } @@ -112,12 +112,12 @@ finish_connection (assuan_context_t ctx) { if (ctx->inbound.fd != ASSUAN_INVALID_FD) { - _assuan_close (ctx->inbound.fd); + _assuan_close (ctx, ctx->inbound.fd); ctx->inbound.fd = ASSUAN_INVALID_FD; } if (ctx->outbound.fd != ASSUAN_INVALID_FD) { - _assuan_close (ctx->outbound.fd); + _assuan_close (ctx, ctx->outbound.fd); ctx->outbound.fd = ASSUAN_INVALID_FD; } } @@ -155,15 +155,16 @@ assuan_init_socket_server_ext (assuan_context_t ctx, assuan_fd_t fd, unsigned int flags) { gpg_error_t rc; - static struct assuan_io io = { _assuan_simple_read, _assuan_simple_write, - 0, 0 }; rc = _assuan_register_std_commands (ctx); if (rc) return rc; - ctx->io = &io; ctx->engine.release = deinit_socket_server; + ctx->engine.readfnc = _assuan_simple_read; + ctx->engine.writefnc = _assuan_simple_write; + ctx->engine.sendfd = NULL; + ctx->engine.receivefd = NULL; ctx->is_server = 1; if (flags & 2) ctx->pipe_mode = 1; /* We want a second accept to indicate EOF. */ diff --git a/src/assuan-socket.c b/src/assuan-socket.c index e638503..a6ee7a4 100644 --- a/src/assuan-socket.c +++ b/src/assuan-socket.c @@ -144,33 +144,11 @@ read_port_and_nonce (const char *fname, unsigned short *port, char *nonce) #endif /*HAVE_W32_SYSTEM*/ - -int -_assuan_close (assuan_fd_t fd) -{ -#ifdef HAVE_W32_SYSTEM - int rc = closesocket (HANDLE2SOCKET(fd)); - if (rc) - errno = _assuan_sock_wsa2errno (WSAGetLastError ()); - if (rc && WSAGetLastError () == WSAENOTSOCK) - { - rc = CloseHandle (fd); - if (rc) - /* FIXME. */ - errno = EIO; - } - return rc; -#else - return close (fd); -#endif -} - - /* 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 (int domain, int type, int proto) +_assuan_sock_new (assuan_context_t ctx, int domain, int type, int proto) { #ifdef HAVE_W32_SYSTEM assuan_fd_t res; @@ -187,7 +165,8 @@ _assuan_sock_new (int domain, int type, int proto) int -_assuan_sock_connect (assuan_fd_t sockfd, struct sockaddr *addr, int addrlen) +_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) @@ -199,7 +178,7 @@ _assuan_sock_connect (assuan_fd_t sockfd, struct sockaddr *addr, int addrlen) int ret; unaddr = (struct sockaddr_un *)addr; - if (read_port_and_nonce (unaddr->sun_path, &port, nonce)) + if (read_port_and_nonce (ctx, unaddr->sun_path, &port, nonce)) return -1; myaddr.sin_family = AF_INET; @@ -216,7 +195,7 @@ _assuan_sock_connect (assuan_fd_t sockfd, struct sockaddr *addr, int addrlen) if (!ret) { /* Send the nonce. */ - ret = _assuan_io_write (sockfd, nonce, 16); + ret = _assuan_write (ctx, sockfd, nonce, 16); if (ret >= 0 && ret != 16) { errno = EIO; @@ -240,7 +219,8 @@ _assuan_sock_connect (assuan_fd_t sockfd, struct sockaddr *addr, int addrlen) int -_assuan_sock_bind (assuan_fd_t sockfd, struct sockaddr *addr, int addrlen) +_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) @@ -312,8 +292,8 @@ _assuan_sock_bind (assuan_fd_t sockfd, struct sockaddr *addr, int addrlen) int -_assuan_sock_get_nonce (struct sockaddr *addr, int addrlen, - assuan_sock_nonce_t *nonce) +_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) @@ -328,7 +308,7 @@ _assuan_sock_get_nonce (struct sockaddr *addr, int addrlen, } nonce->length = 16; unaddr = (struct sockaddr_un *)addr; - if (read_port_and_nonce (unaddr->sun_path, &port, nonce->nonce)) + if (read_port_and_nonce (ctx, unaddr->sun_path, &port, nonce->nonce)) return -1; } else @@ -346,7 +326,8 @@ _assuan_sock_get_nonce (struct sockaddr *addr, int addrlen, int -_assuan_sock_check_nonce (assuan_fd_t fd, assuan_sock_nonce_t *nonce) +_assuan_sock_check_nonce (assuan_context_t ctx, assuan_fd_t fd, + assuan_sock_nonce_t *nonce) { #ifdef HAVE_W32_SYSTEM char buffer[16], *p; @@ -367,12 +348,12 @@ _assuan_sock_check_nonce (assuan_fd_t fd, assuan_sock_nonce_t *nonce) errno = EINVAL; return -1; } - + p = buffer; nleft = 16; while (nleft) { - n = _assuan_io_read (SOCKET2HANDLE(fd), p, nleft); + n = _assuan_read (ctx, SOCKET2HANDLE(fd), p, nleft); if (n < 0 && errno == EINTR) ; else if (n < 0 && errno == EAGAIN) @@ -404,39 +385,83 @@ _assuan_sock_check_nonce (assuan_fd_t fd, assuan_sock_nonce_t *nonce) /* Public API. */ + +/* 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; + +gpg_error_t +assuan_sock_init () +{ + gpg_error_t err; +#ifdef HAVE_W32_SYSTEM + WSADATA wsadat; +#endif + + if (sock_ctx != NULL) + return 0; + + err = assuan_new (&sock_ctx); + +#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); +} + + int assuan_sock_close (assuan_fd_t fd) { - return _assuan_close (fd); + return _assuan_close (sock_ctx, fd); } assuan_fd_t assuan_sock_new (int domain, int type, int proto) { - return _assuan_sock_new (domain, type, proto); + return _assuan_sock_new (sock_ctx, domain, type, proto); } int assuan_sock_connect (assuan_fd_t sockfd, struct sockaddr *addr, int addrlen) { - return _assuan_sock_connect (sockfd, addr, addrlen); + return _assuan_sock_connect (sock_ctx, sockfd, addr, addrlen); } int assuan_sock_bind (assuan_fd_t sockfd, struct sockaddr *addr, int addrlen) { - return _assuan_sock_bind (sockfd, addr, addrlen); + return _assuan_sock_bind (sock_ctx, sockfd, addr, addrlen); } int assuan_sock_get_nonce (struct sockaddr *addr, int addrlen, assuan_sock_nonce_t *nonce) { - return _assuan_sock_get_nonce (addr, addrlen, 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 (fd, nonce); + return _assuan_sock_check_nonce (sock_ctx, fd, nonce); } diff --git a/src/assuan-uds.c b/src/assuan-uds.c index 1c2d106..2bec03d 100644 --- a/src/assuan-uds.c +++ b/src/assuan-uds.c @@ -107,7 +107,7 @@ uds_reader (assuan_context_t ctx, void *buf, size_t buflen) msg.msg_controllen = sizeof (control_u.control); #endif - len = _assuan_simple_recvmsg (ctx, &msg); + len = _assuan_recvmsg (ctx, ctx->inbound.fd, &msg, 0); if (len < 0) return -1; if (len == 0) @@ -133,7 +133,7 @@ uds_reader (assuan_context_t ctx, void *buf, size_t buflen) TRACE1 (ctx, ASSUAN_LOG_SYSIO, "uds_reader", ctx, "too many descriptors pending - " "closing received descriptor %d", fd); - _assuan_close (fd); + _assuan_close (ctx, fd); } else ctx->uds.pendingfds[ctx->uds.pendingfdscount++] = fd; @@ -181,7 +181,7 @@ uds_writer (assuan_context_t ctx, const void *buf, size_t buflen) iovec.iov_base = (void*)buf; iovec.iov_len = buflen; - len = _assuan_simple_sendmsg (ctx, &msg); + len = _assuan_sendmsg (ctx, ctx->outbound.fd, &msg, 0); return len; #else /*HAVE_W32_SYSTEM*/ @@ -231,7 +231,7 @@ uds_sendfd (assuan_context_t ctx, assuan_fd_t fd) cmptr->cmsg_type = SCM_RIGHTS; *((int*)CMSG_DATA (cmptr)) = fd; - len = _assuan_simple_sendmsg (ctx, &msg); + len = _assuan_sendmsg (ctx, ctx->outbound.fd, &msg, 0); if (len < 0) { int saved_errno = errno; @@ -281,7 +281,7 @@ _assuan_uds_close_fds (assuan_context_t ctx) int i; for (i = 0; i < ctx->uds.pendingfdscount; i++) - _assuan_close (ctx->uds.pendingfds[i]); + _assuan_close (ctx, ctx->uds.pendingfds[i]); ctx->uds.pendingfdscount = 0; } @@ -307,10 +307,11 @@ _assuan_uds_deinit (assuan_context_t ctx) void _assuan_init_uds_io (assuan_context_t ctx) { - static struct assuan_io io = { uds_reader, uds_writer, - uds_sendfd, uds_receivefd }; + ctx->engine.readfnc = uds_reader; + ctx->engine.writefnc = uds_writer; + ctx->engine.sendfd = uds_sendfd; + ctx->engine.receivefd = uds_receivefd; - ctx->io = &io; ctx->uds.buffer = 0; ctx->uds.bufferoffset = 0; ctx->uds.buffersize = 0; diff --git a/src/assuan.c b/src/assuan.c index 4848ec4..31263d4 100644 --- a/src/assuan.c +++ b/src/assuan.c @@ -92,6 +92,13 @@ assuan_get_log_cb (assuan_log_cb_t *log_cb, void **log_cb_data) } +void +assuan_set_system_hooks (assuan_system_hooks_t system_hooks) +{ + _assuan_system_hooks_copy (&_assuan_system_hooks, system_hooks); +} + + /* Create a new Assuan context. The initial parameters are all needed in the creation of the context. */ gpg_error_t @@ -123,6 +130,7 @@ assuan_new_ext (assuan_context_t *r_ctx, gpg_err_source_t err_source, return TRACE_ERR (gpg_err_code_from_syserror ()); memcpy (ctx, &wctx, sizeof (*ctx)); + ctx->system = _assuan_system_hooks; /* FIXME: Delegate to subsystems/engines, as the FDs are not our responsibility (we don't deallocate them, for example). */ @@ -168,13 +176,13 @@ _assuan_reset (assuan_context_t ctx) void assuan_release (assuan_context_t ctx) { - if (ctx) - { - TRACE (ctx, ASSUAN_LOG_CTX, "assuan_release", ctx); - - _assuan_reset (ctx); - /* None of the members that are our responsibility requires - deallocation. */ - _assuan_free (ctx, ctx); - } + TRACE (ctx, ASSUAN_LOG_CTX, "assuan_release", ctx); + + if (! ctx) + return; + + _assuan_reset (ctx); + /* None of the members that are our responsibility requires + deallocation. */ + _assuan_free (ctx, ctx); } diff --git a/src/assuan.h b/src/assuan.h index c0b1fea..c63e396 100644 --- a/src/assuan.h +++ b/src/assuan.h @@ -33,30 +33,19 @@ #endif #endif /*!_ASSUAN_NO_SOCKET_WRAPPER*/ +#ifdef _WIN32 +typedef void *assuan_msghdr_t; +#else +typedef struct msghdr *assuan_msghdr_t; +#endif + #include <gpg-error.h> /* Compile time configuration: #define _ASSUAN_NO_SOCKET_WRAPPER - Do not include the definitions for the socket wrapper feature. - - The follwing macros are used internally in the implementation of - libassuan: - - #define _ASSUAN_NO_PTH - - This avoids inclusion of special GNU Pth hacks. - - #define _ASSUAN_NO_FIXED_SIGNALS - - This disables changing of certain signal handler; i.e. SIGPIPE. - - #define _ASSUAN_USE_DOUBLE_FORK - - Use a double fork approach when connecting to a server through - a pipe. - */ + Do not include the definitions for the socket wrapper feature. */ #ifdef __cplusplus @@ -95,9 +84,11 @@ typedef struct assuan_context_s *assuan_context_t; #ifdef _WIN32 typedef void *assuan_fd_t; #define ASSUAN_INVALID_FD ((void*)(-1)) +#define ASSUAN_INVALID_PID ((pid_t) -1) #else typedef int assuan_fd_t; #define ASSUAN_INVALID_FD (-1) +#define ASSUAN_INVALID_PID ((pid_t) -1) #endif @@ -208,6 +199,8 @@ typedef unsigned int assuan_flag_t; /* This flag indicates whether Assuan logging is in confidential mode. You can use assuan_{begin,end}_condidential to change the mode. */ #define ASSUAN_CONFIDENTIAL 2 +/* This flag suppresses fix up of signal handlers for pipes. */ +#define ASSUAN_NO_FIXSIGNALS 3 /* For context CTX, set the flag FLAG to VALUE. Values for flags are usually 1 or 0 but certain flags might allow for other values; @@ -243,6 +236,52 @@ typedef unsigned int (*assuan_io_monitor_t) (assuan_context_t ctx, void *hook, void assuan_set_io_monitor (assuan_context_t ctx, assuan_io_monitor_t io_monitor, void *hook_data); + +#define ASSUAN_SYSTEM_HOOKS_VERSION 1 +struct assuan_system_hooks +{ + /* Always set to ASSUAN_SYTEM_HOOKS_VERSION. */ + int version; + + /* Sleep for the given number of microseconds. */ + void (*usleep) (assuan_context_t ctx, unsigned int usec); + + /* Create a pipe with an inheritable end. */ + int (*pipe) (assuan_context_t ctx, assuan_fd_t fd[2], int inherit_idx); + + /* Close the given file descriptor, created with _assuan_pipe or one + of the socket functions. */ + int (*close) (assuan_context_t ctx, assuan_fd_t fd); + + + ssize_t (*read) (assuan_context_t ctx, assuan_fd_t fd, void *buffer, + size_t size); + ssize_t (*write) (assuan_context_t ctx, assuan_fd_t fd, + const void *buffer, size_t size); + + int (*recvmsg) (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg, + int flags); + int (*sendmsg) (assuan_context_t ctx, assuan_fd_t fd, + const assuan_msghdr_t msg, int flags); + + /* If NAME is NULL, don't exec, just fork. FD_CHILD_LIST is + modified to reflect the value of the FD in the peer process (on + Windows). */ + int (*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); + + /* If action is 0, like waitpid. If action is 1, just release the PID? */ + pid_t (*waitpid) (assuan_context_t ctx, pid_t pid, + int action, int *status, int options); + int (*socketpair) (assuan_context_t ctx, int namespace, int style, + int protocol, assuan_fd_t filedes[2]); +}; +typedef struct assuan_system_hooks *assuan_system_hooks_t; + /* Configuration of the default log handler. */ @@ -328,11 +367,11 @@ void assuan_set_sock_nonce (assuan_context_t ctx, assuan_sock_nonce_t *nonce); gpg_error_t assuan_pipe_connect (assuan_context_t ctx, const char *name, const char *argv[], - int *fd_child_list); + assuan_fd_t *fd_child_list); gpg_error_t assuan_pipe_connect_ext (assuan_context_t ctx, const char *name, const char *argv[], - int *fd_child_list, + assuan_fd_t *fd_child_list, void (*atfork) (void *, int), void *atforkvalue, unsigned int flags); @@ -401,6 +440,8 @@ gpg_error_t assuan_set_error (assuan_context_t ctx, gpg_error_t err, const char /* These are socket wrapper functions to support an emulation of Unix domain sockets on Windows W32. */ +gpg_error_t assuan_sock_init (void); +void assuan_sock_deinit (void); int assuan_sock_close (assuan_fd_t fd); assuan_fd_t assuan_sock_new (int domain, int type, int proto); int assuan_sock_connect (assuan_fd_t sockfd, @@ -410,6 +451,132 @@ int assuan_sock_get_nonce (struct sockaddr *addr, int addrlen, assuan_sock_nonce_t *nonce); int assuan_sock_check_nonce (assuan_fd_t fd, assuan_sock_nonce_t *nonce); + +/* Set the default or per context system callbacks. This is + irreversible. */ +void assuan_set_system_hooks (assuan_system_hooks_t system_hooks); + +void assuan_ctx_set_system_hooks (assuan_context_t ctx, + assuan_system_hooks_t system_hooks); + +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_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 __assuan_socketpair (assuan_context_t ctx, int namespace, int style, + int protocol, assuan_fd_t filedes[2]); + +#ifdef _WIN32 +#define _ASSUAN_SYSTEM_PTH_IMPL \ + static int _assuan_pth_recvmsg (assuan_context_t ctx, assuan_fd_t fd, \ + assuan_msghdr_t msg, int flags) \ + { \ + (void) ctx; \ + errno = ENOSYS; \ + return -1; \ + } \ + static int _assuan_pth_sendmsg (assuan_context_t ctx, assuan_fd_t fd, \ + const assuan_msghdr_t msg, int flags) \ + { \ + (void) ctx; \ + errno = ENOSYS; \ + return -1; \ + } +#else +#define _ASSUAN_SYSTEM_PTH_IMPL \ + static int _assuan_pth_recvmsg (assuan_context_t ctx, assuan_fd_t fd, \ + assuan_msghdr_t msg, int flags) \ + { \ + /* Pth does not provide a recvmsg function. We implement it. */ \ + int ret; \ + int fdmode; \ + \ + (void) ctx; \ + fdmode = pth_fdmode (fd, PTH_FDMODE_POLL); \ + if (fdmode == PTH_FDMODE_ERROR) \ + { \ + errno = EBADF; \ + return -1; \ + } \ + if (fdmode == PTH_FDMODE_BLOCK) \ + { \ + fd_set fds; \ + \ + FD_ZERO (&fds); \ + FD_SET (fd, &fds); \ + while ((ret = pth_select (fd + 1, &fds, NULL, NULL, NULL)) < 0 \ + && errno == EINTR) \ + ; \ + if (ret < 0) \ + return -1; \ + } \ + \ + while ((ret = recvmsg (fd, msg, flags)) == -1 && errno == EINTR) \ + ; \ + return ret; \ + } \ + static int _assuan_pth_sendmsg (assuan_context_t ctx, assuan_fd_t fd, \ + const assuan_msghdr_t msg, int flags) \ + { \ + /* Pth does not provide a sendmsg function. We implement it. */ \ + int ret; \ + int fdmode; \ + \ + (void) ctx; \ + fdmode = pth_fdmode (fd, PTH_FDMODE_POLL); \ + if (fdmode == PTH_FDMODE_ERROR) \ + { \ + errno = EBADF; \ + return -1; \ + } \ + if (fdmode == PTH_FDMODE_BLOCK) \ + { \ + fd_set fds; \ + \ + FD_ZERO (&fds); \ + FD_SET (fd, &fds); \ + while ((ret = pth_select (fd + 1, NULL, &fds, NULL, NULL)) < 0 \ + && errno == EINTR) \ + ; \ + if (ret < 0) \ + return -1; \ + } \ + \ + while ((ret = sendmsg (fd, msg, flags)) == -1 && errno == EINTR) \ + ; \ + return ret; \ + } +#endif + + +#define ASSUAN_SYSTEM_PTH_IMPL \ + static void _assuan_pth_usleep (assuan_context_t ctx, unsigned int usec) \ + { (void) ctx; pth_usleep (usec); } \ + static ssize_t _assuan_pth_read (assuan_context_t ctx, assuan_fd_t fd, \ + void *buffer, size_t size) \ + { (void) ctx; return pth_read (fd, buffer, size); } \ + static ssize_t _assuan_pth_write (assuan_context_t ctx, assuan_fd_t fd, \ + const void *buffer, size_t size) \ + { (void) ctx; return pth_write (fd, buffer, size); } \ + _ASSUAN_SYSTEM_PTH_IMPL \ + static pid_t _assuan_pth_waitpid (assuan_context_t ctx, pid_t pid, \ + int nowait, int *status, int options) \ + { (void) ctx; \ + if (!nowait) return pth_waitpid (pid, status, options); \ + else return 0; } \ + \ + struct assuan_system_hooks _assuan_system_pth = \ + { ASSUAN_SYSTEM_HOOKS_VERSION, _assuan_pth_usleep, __assuan_pipe, \ + __assuan_close, _assuan_pth_read, _assuan_pth_write, \ + _assuan_pth_recvmsg, _assuan_pth_sendmsg, \ + __assuan_spawn, _assuan_pth_waitpid, __assuan_socketpair } + +extern struct assuan_system_hooks _assuan_system_pth; +#define ASSUAN_SYSTEM_PTH &_assuan_system_pth + #ifdef __cplusplus } diff --git a/src/context.c b/src/context.c index d87672b..3e707ca 100644 --- a/src/context.c +++ b/src/context.c @@ -28,10 +28,13 @@ /* Set user-data in a context. */ void -assuan_set_pointer (assuan_context_t ctx, void *pointer) +assuan_set_pointer (assuan_context_t ctx, void *user_pointer) { + TRACE1 (ctx, ASSUAN_LOG_CTX, "assuan_set_pointer", ctx, + "user_pointer=%p", user_pointer); + if (ctx) - ctx->user_pointer = pointer; + ctx->user_pointer = user_pointer; } @@ -39,6 +42,9 @@ assuan_set_pointer (assuan_context_t ctx, void *pointer) void * assuan_get_pointer (assuan_context_t ctx) { + TRACE1 (ctx, ASSUAN_LOG_CTX, "assuan_get_pointer", ctx, + "ctx->user_pointer=%p", ctx ? ctx->user_pointer : NULL); + if (! ctx) return NULL; @@ -52,6 +58,9 @@ assuan_get_pointer (assuan_context_t ctx) void assuan_set_flag (assuan_context_t ctx, assuan_flag_t flag, int value) { + TRACE2 (ctx, ASSUAN_LOG_CTX, "assuan_set_flag", ctx, + "flag=%i,value=%i", flag, value); + if (!ctx) return; @@ -64,6 +73,10 @@ assuan_set_flag (assuan_context_t ctx, assuan_flag_t flag, int value) case ASSUAN_CONFIDENTIAL: ctx->flags.confidential = value; break; + + case ASSUAN_NO_FIXSIGNALS: + ctx->flags.no_fixsignals = value; + break; } } @@ -72,18 +85,29 @@ assuan_set_flag (assuan_context_t ctx, assuan_flag_t flag, int value) int assuan_get_flag (assuan_context_t ctx, assuan_flag_t flag) { + int res = 0; + TRACE_BEG1 (ctx, ASSUAN_LOG_CTX, "assuan_get_flag", ctx, + "flag=%i", flag); + if (! ctx) return 0; switch (flag) { case ASSUAN_NO_WAITPID: - return ctx->flags.no_waitpid; + res = ctx->flags.no_waitpid; + break; + case ASSUAN_CONFIDENTIAL: - return ctx->flags.confidential; + res = ctx->flags.confidential; + break; + + case ASSUAN_NO_FIXSIGNALS: + res = ctx->flags.no_fixsignals; + break; } - return 0; + return TRACE_SUC1 ("flag_value=%i", res); } @@ -103,15 +127,31 @@ assuan_end_confidential (assuan_context_t ctx) } +/* Set the system callbacks. */ +void +assuan_ctx_set_system_hooks (assuan_context_t ctx, + assuan_system_hooks_t system_hooks) +{ + TRACE2 (ctx, ASSUAN_LOG_CTX, "assuan_set_system_hooks", ctx, + "system_hooks=%p (version %i)", system_hooks, + system_hooks->version); + + _assuan_system_hooks_copy (&ctx->system, system_hooks); +} + + /* Set the IO monitor function. */ void assuan_set_io_monitor (assuan_context_t ctx, assuan_io_monitor_t io_monitor, void *hook_data) { - if (ctx) - { - ctx->io_monitor = io_monitor; - ctx->io_monitor_data = hook_data; - } + TRACE2 (ctx, ASSUAN_LOG_CTX, "assuan_set_io_monitor", ctx, + "io_monitor=%p,hook_data=%p", io_monitor, hook_data); + + if (! ctx) + return; + + ctx->io_monitor = io_monitor; + ctx->io_monitor_data = hook_data; } @@ -121,6 +161,10 @@ void assuan_set_io_monitor (assuan_context_t ctx, gpg_error_t assuan_set_error (assuan_context_t ctx, gpg_error_t err, const char *text) { + TRACE4 (ctx, ASSUAN_LOG_CTX, "assuan_set_error", ctx, + "err=%i (%s,%s),text=%s", err, gpg_strsource (err), + gpg_strerror (err), text); + ctx->err_no = err; ctx->err_str = text; return err; diff --git a/src/conversion.c b/src/conversion.c index af5026e..88a7fd0 100644 --- a/src/conversion.c +++ b/src/conversion.c @@ -1,6 +1,6 @@ /* conversion.c - String conversion helper functions. Copyright (C) 2000 Werner Koch (dd9jn) - Copyright (C) 2001, 2002, 2003, 2004, 2007 g10 Code GmbH + Copyright (C) 2001, 2002, 2003, 2004, 2007, 2009 g10 Code GmbH This file is part of Assuan. @@ -25,9 +25,6 @@ #include <stdlib.h> #include <string.h> -/* Solaris 8 needs sys/types.h before time.h. */ -#include <sys/types.h> -#include <time.h> #include <errno.h> #include <ctype.h> diff --git a/src/debug.h b/src/debug.h index 13e5419..4b4a41d 100644 --- a/src/debug.h +++ b/src/debug.h @@ -123,6 +123,12 @@ void _assuan_debug_buffer (assuan_context_t ctx, unsigned int cat, "%s (%s=%p): enter: " fmt "\n", \ _assuan_trace_func, _assuan_trace_tagname, \ _assuan_trace_tag, arg1, arg2, arg3, arg4), 0 +#define TRACE_BEG6(ctx, lvl, name, tag, fmt, arg1, arg2, arg3, arg4,arg5,arg6) \ + _TRACE (ctx, lvl, name, tag); \ + _assuan_debug (_assuan_trace_context, _assuan_trace_level, \ + "%s (%s=%p): enter: " fmt "\n", \ + _assuan_trace_func, _assuan_trace_tagname, \ + _assuan_trace_tag, arg1, arg2, arg3, arg4, arg5, arg6), 0 #define TRACE_BEG8(ctx, lvl, name, tag, fmt, arg1, arg2, arg3, arg4, \ arg5, arg6, arg7, arg8) \ @@ -149,6 +155,10 @@ void _assuan_debug_buffer (assuan_context_t ctx, unsigned int cat, _assuan_debug (ctx, lvl, "%s (%s=%p): call: " fmt "\n", \ name, STRINGIFY (tag), (void *) (uintptr_t) tag, arg1, \ arg2, arg3), 0 +#define TRACE4(ctx, lvl, name, tag, fmt, arg1, arg2, arg3, arg4) \ + _assuan_debug (ctx, lvl, "%s (%s=%p): call: " fmt "\n", \ + name, STRINGIFY (tag), (void *) (uintptr_t) tag, arg1, \ + arg2, arg3, arg4), 0 #define TRACE6(ctx, lvl, name, tag, fmt, arg1, arg2, arg3, arg4, arg5, arg6) \ _assuan_debug (ctx, lvl, "%s (%s=%p): call: " fmt "\n", \ name, STRINGIFY (tag), (void *) (uintptr_t) tag, arg1, \ @@ -171,7 +181,7 @@ void _assuan_debug_buffer (assuan_context_t ctx, unsigned int cat, _assuan_trace_tag, strerror (errno)), (res)) #define TRACE_SYSERR(res) \ res == 0 ? ((void) (TRACE_SUC1 ("result=%i", res)), (res)) : \ - (_assuan_debug (_assuan_trace_level, "%s (%s=%p): error: %s\n", \ + (_assuan_debug (_assuan_trace_context, _assuan_trace_level, "%s (%s=%p): error: %s\n", \ _assuan_trace_func, _assuan_trace_tagname, \ _assuan_trace_tag, strerror (res)), (res)) diff --git a/src/libassuan-config.in b/src/libassuan-config.in index 50c9805..561ff96 100644 --- a/src/libassuan-config.in +++ b/src/libassuan-config.in @@ -18,8 +18,6 @@ lib="@LIBASSUAN_CONFIG_LIB@" extralibs="@LIBASSUAN_CONFIG_EXTRA_LIBS@ $gpg_error_libs" cflags="@LIBASSUAN_CONFIG_CFLAGS@ $gpg_error_cflags" api_version="@LIBASSUAN_CONFIG_API_VERSION@" -all_thread_modules="@LIBASSUAN_CONFIG_THREAD_MODULES@" -thread_module= prefix=@prefix@ exec_prefix=@exec_prefix@ includes="" @@ -31,18 +29,11 @@ echo_prefix=no echo_exec_prefix=no -if test x"$all_thread_modules" = x; then - all_thread_modules="none pthread" -else - all_thread_modules="none pthread $all_thread_modules" -fi - usage() { cat <<EOF Usage: $PGM [OPTIONS] Options: - [--thread={`echo "${all_thread_modules}" | sed 's/ /|/g'`}] [--prefix[=DIR]] [--exec-prefix[=DIR]] [--version] @@ -82,22 +73,6 @@ while test $# -gt 0; do --api-version) echo_api_version=yes ;; - --thread=*) - for mod in $all_thread_modules; do - if test "$mod" = "$optarg"; then - thread_module="-$mod" - fi - done - if test "x$thread_module" = "x"; then - usage 1 1>&2 - fi - if test "$thread_module" = "-none"; then - thread_module="" - fi - if test "$thread_module" = "-pthread"; then - thread_module="" - fi - ;; --cflags) echo_cflags=yes ;; @@ -145,5 +120,5 @@ if test "$echo_libs" = "yes"; then fi done fi - echo $libdirs $lib${thread_module} $extralibs + echo $libdirs $lib $extralibs fi diff --git a/src/libassuan.def b/src/libassuan.def index b2450d8..9750748 100644 --- a/src/libassuan.def +++ b/src/libassuan.def @@ -84,7 +84,16 @@ EXPORTS assuan_transact @63 assuan_write_line @64 assuan_write_status @65 + assuan_sock_init + assuan_sock_deinit assuan_get_command_name @66 + __assuan_pipe + __assuan_close + __assuan_spawn + __assuan_socketpair + assuan_set_system_hooks + assuan_ctx_set_system_hooks + ; END diff --git a/src/libassuan.m4 b/src/libassuan.m4 index 004eee3..bac1be8 100644 --- a/src/libassuan.m4 +++ b/src/libassuan.m4 @@ -131,45 +131,3 @@ AC_DEFUN([AM_PATH_LIBASSUAN], AC_SUBST(LIBASSUAN_CFLAGS) AC_SUBST(LIBASSUAN_LIBS) ]) - - -dnl AM_PATH_LIBASSUAN_PTH([MINIMUM-VERSION, -dnl [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]]) -dnl Test for libassuan and define LIBASSUAN_PTH_CFLAGS and LIBASSUAN_PTH_LIBS -dnl -AC_DEFUN([AM_PATH_LIBASSUAN_PTH], -[ _AM_PATH_LIBASSUAN_COMMON($1,pth) - if test $ok = yes; then - LIBASSUAN_PTH_CFLAGS=`$LIBASSUAN_CONFIG $libassuan_config_args --thread=pth --cflags` - LIBASSUAN_PTH_LIBS=`$LIBASSUAN_CONFIG $libassuan_config_args --thread=pth --libs` - ifelse([$2], , :, [$2]) - else - LIBASSUAN_PTH_CFLAGS="" - LIBASSUAN_PTH_LIBS="" - ifelse([$3], , :, [$3]) - fi - AC_SUBST(LIBASSUAN_PTH_CFLAGS) - AC_SUBST(LIBASSUAN_PTH_LIBS) -]) - - -dnl AM_PATH_LIBASSUAN_PTHREAD([MINIMUM-VERSION, -dnl [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]]) -dnl Test for libassuan and define LIBASSUAN_PTHREAD_CFLAGS -dnl and LIBASSUAN_PTHREAD_LIBS -dnl -AC_DEFUN([AM_PATH_LIBASSUAN_PTHREAD], -[ _AM_PATH_LIBASSUAN_COMMON($1,pthread) - if test $ok = yes; then - LIBASSUAN_PTHREAD_CFLAGS=`$LIBASSUAN_CONFIG $libassuan_config_args --thread=pthread --cflags` - LIBASSUAN_PTHREAD_LIBS=`$LIBASSUAN_CONFIG $libassuan_config_args --thread=pthread --libs` - ifelse([$2], , :, [$2]) - else - LIBASSUAN_PTHREAD_CFLAGS="" - LIBASSUAN_PTHREAD_LIBS="" - ifelse([$3], , :, [$3]) - fi - AC_SUBST(LIBASSUAN_PTHREAD_CFLAGS) - AC_SUBST(LIBASSUAN_PTHREAD_LIBS) -]) - diff --git a/src/libassuan.vers b/src/libassuan.vers index e4f6a7a..9b5b5e0 100644 --- a/src/libassuan.vers +++ b/src/libassuan.vers @@ -91,6 +91,14 @@ LIBASSUAN_1.0 { assuan_new_ext; assuan_new; assuan_release; + assuan_sock_init; + assuan_sock_deinit; + __assuan_pipe; + __assuan_close; + __assuan_spawn; + __assuan_socketpair; + assuan_set_system_hooks; + assuan_ctx_set_system_hooks; local: *; diff --git a/src/system.c b/src/system.c index dd0c079..91a5a10 100644 --- a/src/system.c +++ b/src/system.c @@ -24,10 +24,25 @@ #include <stdlib.h> #include <errno.h> +/* Solaris 8 needs sys/types.h before time.h. */ +#include <sys/types.h> +#include <time.h> +#include <fcntl.h> +#ifdef HAVE_W32_SYSTEM +# include <windows.h> +#else +# include <sys/wait.h> +#endif #include "assuan-defs.h" #include "debug.h" +#ifdef _POSIX_OPEN_MAX +#define MAX_OPEN_FDS _POSIX_OPEN_MAX +#else +#define MAX_OPEN_FDS 20 +#endif + /* Manage memory specific to a context. */ @@ -70,3 +85,793 @@ _assuan_free (assuan_context_t ctx, void *ptr) if (ptr) ctx->malloc_hooks.free (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) + +{ + memset (dst, '\0', 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 > 1) + /* FIXME. Application uses newer version of the library. What to + do? */ + ; +} + + +/* Sleep for the given number of microseconds. Default + implementation. */ +static void +__assuan_usleep (assuan_context_t ctx, unsigned int usec) +{ + if (! usec) + return; + +#ifdef HAVE_NANOSLEEP + { + struct timespec req; + struct timespec rem; + + req.tv_sec = 0; + req.tv_nsec = usec * 1000; + + while (nanosleep (&req, &rem) < 0 && errno == EINTR) + req = rem; + } +#elif defined(HAVE_W32_SYSTEM) + Sleep (usec / 1000); +#else + { + struct timeval tv; + + tv.tv_sec = usec / 1000000; + tv.tv_usec = usec % 1000000; + select (0, NULL, NULL, NULL, &tv); + } +#endif +} + + +/* 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); + + return (ctx->system.usleep) (ctx, usec); +} + + +/* Create a pipe with one inheritable end. Default implementation. */ +int +__assuan_pipe (assuan_context_t ctx, assuan_fd_t fd[2], int inherit_idx) +{ +#ifdef HAVE_W32_SYSTEM + HANDLE rh; + HANDLE wh; + HANDLE th; + SECURITY_ATTRIBUTES sec_attr; + TRACE_BEG2 (ctx, ASSUAN_LOG_SYSIO, "__assuan_pipe", ctx, + "inherit_idx=%i (Assuan uses it for %s)", + inherit_idx, inherit_idx ? "reading" : "writing"); + + memset (&sec_attr, 0, sizeof (sec_attr)); + sec_attr.nLength = sizeof (sec_attr); + sec_attr.bInheritHandle = FALSE; + + if (! CreatePipe (&rh, &wh, &sec_attr, 0)) + { + TRACE_LOG1 ("CreatePipe failed: %s", _assuan_w32_strerror (ctx, -1)); + errno = EIO; + return TRACE_SYSRES (-1); + } + + if (! DuplicateHandle (GetCurrentProcess(), (inherit_idx == 0) ? rh : wh, + GetCurrentProcess(), &th, 0, + TRUE, DUPLICATE_SAME_ACCESS )) + { + TRACE_LOG1 ("DuplicateHandle failed: %s", _assuan_w32_strerror (ctx, -1)); + CloseHandle (rh); + CloseHandle (wh); + errno = EIO; + return TRACE_SYSRES (-1); + } + if (inherit_idx == 0) + { + CloseHandle (rh); + rh = th; + } + else + { + CloseHandle (wh); + wh = th; + } + + fd[0] = rh; + fd[1] = wh; + + return TRACE_SUC (); +#else + return pipe (fd); +#endif +} + + +/* Create a pipe with one inheritable end. */ +int +_assuan_pipe (assuan_context_t ctx, assuan_fd_t fd[2], int inherit_idx) +{ + return (ctx->system.pipe) (ctx, fd, inherit_idx); +} + + +/* 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) +{ +#ifdef HAVE_W32_SYSTEM + int rc = closesocket (HANDLE2SOCKET(fd)); + if (rc) + errno = _assuan_sock_wsa2errno (WSAGetLastError ()); + if (rc && WSAGetLastError () == WSAENOTSOCK) + { + rc = CloseHandle (fd); + if (rc) + /* FIXME. */ + errno = EIO; + } + return rc; +#else + return close (fd); +#endif +} + + +/* 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); + + return (ctx->system.close) (ctx, fd); +} + + +static ssize_t +__assuan_read (assuan_context_t ctx, assuan_fd_t fd, void *buffer, size_t size) +{ +#ifdef HAVE_W32_SYSTEM + /* 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; + + 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: + errno = EPIPE; + break; + + default: + errno = EIO; + } + res = -1; + } + else + res = (int) nread; + } + break; + + case WSAEWOULDBLOCK: + errno = EAGAIN; + break; + + case ERROR_BROKEN_PIPE: + errno = EPIPE; + break; + + default: + errno = EIO; + break; + } + } + return res; +#else /*!HAVE_W32_SYSTEM*/ + return read (fd, buffer, size); +#endif /*!HAVE_W32_SYSTEM*/ +} + + +ssize_t +_assuan_read (assuan_context_t ctx, assuan_fd_t fd, void *buffer, size_t size) +{ + return (ctx->system.read) (ctx, fd, buffer, size); +} + + +static ssize_t +__assuan_write (assuan_context_t ctx, assuan_fd_t fd, const void *buffer, + size_t size) +{ +#ifdef HAVE_W32_SYSTEM + /* 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; + + res = send (HANDLE2SOCKET (fd), buffer, size, 0); + if (res == -1 && WSAGetLastError () == WSAENOTSOCK) + { + DWORD nwrite; + + res = WriteFile (fd, buffer, size, &nwrite, NULL); + if (! res) + { + switch (GetLastError ()) + { + case ERROR_BROKEN_PIPE: + case ERROR_NO_DATA: + errno = EPIPE; + break; + + default: + errno = EIO; + break; + } + res = -1; + } + else + res = (int) nwrite; + } + return res; +#else /*!HAVE_W32_SYSTEM*/ + return write (fd, buffer, size); +#endif /*!HAVE_W32_SYSTEM*/ +} + + +ssize_t +_assuan_write (assuan_context_t ctx, assuan_fd_t fd, const void *buffer, + size_t size) +{ + return (ctx->system.write) (ctx, fd, buffer, size); +} + + +static int +__assuan_recvmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg, + int flags) +{ +#ifdef HAVE_W32_SYSTEM + errno = ENOSYS; + return -1; +#else + int ret; + do + ret = recvmsg (fd, msg, flags); + while (ret == -1 && errno == EINTR); + + return ret; +#endif +} + + +int +_assuan_recvmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg, + int flags) +{ + return (ctx->system.recvmsg) (ctx, fd, msg, flags); +} + + +static int +__assuan_sendmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg, + int flags) +{ +#ifdef HAVE_W32_SYSTEM + errno = ENOSYS; + return -1; +#else + int ret; + do + ret = sendmsg (fd, msg, flags); + while (ret == -1 && errno == EINTR); + + return ret; +#endif +} + + +int +_assuan_sendmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg, + int flags) +{ + return (ctx->system.sendmsg) (ctx, fd, msg, flags); +} + + +#ifdef HAVE_W32_SYSTEM +/* 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, + char **cmdline) +{ + int i, n; + const char *s; + char *buf, *p; + + *cmdline = NULL; + n = 0; + for (i=0; (s = argv[i]); i++) + { + n += strlen (s) + 1 + 2; /* (1 space, 2 quoting */ + for (; *s; s++) + if (*s == '\"') + n++; /* Need to double inner quotes. */ + } + n++; + + buf = p = _assuan_malloc (ctx, n); + if (! buf) + return -1; + + for (i = 0; argv[i]; i++) + { + if (i) + 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) +{ + SECURITY_ATTRIBUTES sec_attr; + PROCESS_INFORMATION pi = + { + NULL, /* Returns process handle. */ + 0, /* Returns primary thread handle. */ + 0, /* Returns pid. */ + 0 /* Returns tid. */ + }; + STARTUPINFO si; + int fd; + int *fdp; + char *cmdline; + HANDLE nullfd = INVALID_HANDLE_VALUE; + + /* fixme: Actually we should set the "_assuan_pipe_connect_pid" env + variable. However this requires us to write a full environment + handler, because the strings are expected in sorted order. The + suggestion given in the MS Reference Library, to save the old + value, changeit, create proces and restore it, is not thread + safe. */ + + /* Build the command line. */ + if (build_w32_commandline (ctx, argv, &cmdline)) + return -1; + + /* Start the process. */ + memset (&sec_attr, 0, sizeof sec_attr); + sec_attr.nLength = sizeof sec_attr; + sec_attr.bInheritHandle = FALSE; + + memset (&si, 0, sizeof si); + si.cb = sizeof (si); + si.dwFlags = STARTF_USESTDHANDLES; + /* FIXME: Dup to nul if ASSUAN_INVALID_FD. */ + si.hStdInput = fd_in; + si.hStdOutput = fd_out; + + /* Dup stderr to /dev/null unless it is in the list of FDs to be + passed to the child. */ + fd = fileno (stderr); + fdp = fd_child_list; + if (fdp) + { + for (; *fdp != -1 && *fdp != fd; fdp++) + ; + } + if (!fdp || *fdp == -1) + { + nullfd = CreateFile ("nul", GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, 0, NULL); + if (nullfd == INVALID_HANDLE_VALUE) + { + TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_spawn", ctx, + "can't open `nul': %s", w32_strerror (ctx, -1)); + _assuan_free (cmdline); + return -1; + } + si.hStdError = nullfd; + } + else + si.hStdError = (void*)_get_osfhandle (fd); + + + /* Note: We inherit all handles flagged as inheritable. This seems + to be a security flaw but there seems to be no way of selecting + handles to inherit. */ + /* _assuan_log_printf ("CreateProcess, path=`%s' cmdline=`%s'\n", */ + /* name, cmdline); */ + if (!CreateProcess (name, /* Program to start. */ + cmdline, /* Command line arguments. */ + &sec_attr, /* Process security attributes. */ + &sec_attr, /* Thread security attributes. */ + TRUE, /* Inherit handles. */ + (CREATE_DEFAULT_ERROR_MODE + | ((flags & 128)? DETACHED_PROCESS : 0) + | GetPriorityClass (GetCurrentProcess ()) + | CREATE_SUSPENDED), /* Creation flags. */ + NULL, /* Environment. */ + NULL, /* Use current drive/directory. */ + &si, /* Startup information. */ + &pi /* Returns process information. */ + )) + { + TRACE1 (ctx, ASSUAN_LOG_SYSIO, "pipe_connect_w32", ctx, + "CreateProcess failed: %s", w32_strerror (ctx, -1)); + _assuan_free (cmdline); + if (nullfd != INVALID_HANDLE_VALUE) + CloseHandle (nullfd); + + errno = EIO; + return -1; + } + + _assuan_free (cmdline); + if (nullfd != INVALID_HANDLE_VALUE) + CloseHandle (nullfd); + + ResumeThread (pi.hThread); + CloseHandle (pi.hThread); + + /* _assuan_log_printf ("CreateProcess ready: hProcess=%p hThread=%p" */ + /* " dwProcessID=%d dwThreadId=%d\n", */ + /* pi.hProcess, pi.hThread, */ + /* (int) pi.dwProcessId, (int) pi.dwThreadId); */ + + *r_pid = (pid_t) pi.hProcess; + + /* No need to modify peer process, as we don't change the handle + names. However this also means we are not safe, as we inherit + too many handles. Should use approach similar to gpgme and glib + using a helper process. */ + + return 0; +} + +#else + +static int +writen (int fd, const char *buffer, size_t length) +{ + while (length) + { + int nwritten = write (fd, buffer, length); + + if (nwritten < 0) + { + if (errno == EINTR) + continue; + return -1; /* write error */ + } + length -= nwritten; + buffer += nwritten; + } + return 0; /* okay */ +} + + +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 pid; + + pid = fork (); + if (pid < 0) + return -1; + + if (pid == 0) + { + /* Child process (server side). */ + int i; + int n; + char errbuf[512]; + int *fdp; + int fdnul; + + if (atfork) + atfork (atforkvalue, 0); + + fdnul = open ("/dev/null", O_WRONLY); + if (fdnul == -1) + { + TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_spawn", ctx, + "can't open `/dev/null': %s", strerror (errno)); + _exit (4); + } + + /* Dup handles to stdin/stdout. */ + if (fd_out != STDOUT_FILENO) + { + if (dup2 (fd_out == ASSUAN_INVALID_FD ? fdnul : fd_out, + STDOUT_FILENO) == -1) + { + TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_spawn", ctx, + "dup2 failed in child: %s", strerror (errno)); + _exit (4); + } + } + + if (fd_in != STDIN_FILENO) + { + if (dup2 (fd_in == ASSUAN_INVALID_FD ? fdnul : fd_in, + STDIN_FILENO) == -1) + { + TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_spawn", ctx, + "dup2 failed in child: %s", strerror (errno)); + _exit (4); + } + } + + /* Dup stderr to /dev/null unless it is in the list of FDs to be + passed to the child. */ + fdp = fd_child_list; + if (fdp) + { + for (; *fdp != -1 && *fdp != STDERR_FILENO; fdp++) + ; + } + if (!fdp || *fdp == -1) + { + if (dup2 (fdnul, STDERR_FILENO) == -1) + { + TRACE1 (ctx, ASSUAN_LOG_SYSIO, "pipe_connect_unix", ctx, + "dup2(dev/null, 2) failed: %s", strerror (errno)); + _exit (4); + } + } + close (fdnul); + + /* Close all files which will not be duped and are not in the + fd_child_list. */ + n = sysconf (_SC_OPEN_MAX); + if (n < 0) + n = MAX_OPEN_FDS; + for (i = 0; i < n; i++) + { + if (i == STDIN_FILENO || i == STDOUT_FILENO || i == STDERR_FILENO) + continue; + fdp = fd_child_list; + if (fdp) + { + while (*fdp != -1 && *fdp != i) + fdp++; + } + + if (!(fdp && *fdp != -1)) + close (i); + } + errno = 0; + + if (! name) + { + /* No name and no args given, thus we don't do an exec + but continue the forked process. */ + *argv = "server"; + + /* FIXME: Cleanup. */ + return 0; + } + + execv (name, (char *const *) argv); + + /* oops - use the pipe to tell the parent about it */ + snprintf (errbuf, sizeof(errbuf)-1, + "ERR %d can't exec `%s': %.50s\n", + _assuan_error (ctx, GPG_ERR_ASS_SERVER_START), + name, strerror (errno)); + errbuf[sizeof(errbuf)-1] = 0; + writen (1, errbuf, strlen (errbuf)); + _exit (4); + } + + if (! name) + *argv = "client"; + + *r_pid = pid; + + return 0; +} +#endif /* ! HAVE_W32_SYSTEM */ + + +/* 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; + while (fd_child_list[i] != ASSUAN_INVALID_FD) + { + TRACE_LOG2 ("fd_child_list[%2i] = 0x%x", i, fd_child_list[i]); + i++; + } + + res = (ctx->system.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. */ +static pid_t +__assuan_waitpid (assuan_context_t ctx, pid_t pid, int nowait, + int *status, int options) +{ +#ifndef HAVE_W32_SYSTEM + /* We can't just release the PID, a waitpid is mandatory. But + NOWAIT in POSIX systems just means the caller already did the + waitpid for this child. */ + if (! nowait) + return waitpid (pid, NULL, 0); +#else /* ! HAVE_W32_SYSTEM */ + CloseHandle ((HANDLE) pid); +#endif /* HAVE_W32_SYSTEM */ +} + + +pid_t +_assuan_waitpid (assuan_context_t ctx, pid_t pid, int action, + int *status, int options) +{ + return (ctx->system.waitpid) (ctx, pid, action, status, options); +} + + +int +__assuan_socketpair (assuan_context_t ctx, int namespace, int style, + int protocol, int filedes[2]) +{ +#if HAVE_W32_SYSTEM + errno = ENOSYS; + return -1; +#else + return socketpair (namespace, style, protocol, filedes); +#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); + + res = (ctx->system.socketpair) (ctx, namespace, style, protocol, filedes); + if (res == 0) + TRACE_LOG2 ("filedes = { 0x%x, 0x%x }", filedes[0], filedes[1]); + + return TRACE_SYSERR (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 + }; |