diff options
author | Marcus Brinkmann <mb@g10code.com> | 2009-09-21 01:08:08 +0000 |
---|---|---|
committer | Marcus Brinkmann <mb@g10code.com> | 2009-09-21 01:08:08 +0000 |
commit | cd87e56dac64c74d45f42838fc1049848f8aadcd (patch) | |
tree | ff70f9a6e8601305d06bebb55709350d3d8dbae4 | |
parent | 0650eaa24a8a54dbfb1d5aea113ffd7a1536861a (diff) | |
download | libassuan-cd87e56dac64c74d45f42838fc1049848f8aadcd.tar.gz |
2009-09-19 Marcus Brinkmann <marcus@g10code.de>
* tests/fdpassing.c: Update to new API.
* configure.ac: Check for stdint.h and inttypes.h. Invoke
AC_TYPE_UINTPTR_T.
doc/
2009-09-21 Marcus Brinkmann <marcus@g10code.de>
* assuan.texi: Update to new API.
src/
2009-09-19 Marcus Brinkmann <marcus@g10code.de>
* src/libassuan.vers, src/libassuan.def: Update to new API.
* assuan.c, context.c, system.c, debug.c: New files.
* Makefile.am (common_sources): Add assuan.c, context.c, system.c
and debug.c.
* assuan.h: Include <stdarg.h>. Fix inclusion of <gpg-error.h>.
(_ASSUAN_EXT_SYM_PREFIX, _ASSUAN_PREFIX1, _ASSUAN_PREFIX2)
(_ASSUAN_PREFIX): Remove support for renaming the whole library,
now that we have a stable shared library interface that can evolve
to cover all needs (particularly those of GPGME).
(assuan_malloc_hooks, assuan_malloc_hooks_t, assuan_log_cb_t)
(assuan_io_monitor_t): New types.
(ASSUAN_LOG_INIT, ASSUAN_LOG_CTX, ASSUAN_LOG_ENGINE)
(ASSUAN_LOG_DATA, ASSUAN_LOG_SYSIO, ASSUAN_IO_FROM_PEER)
(ASSUAN_IO_TO_PEER, ASSUAN_IO_MONITOR_NOLOG)
(ASSUAN_IO_MONITOR_IGNORE): New symbols.
(assuan_set_gpg_err_source, assuan_get_gpg_err_source)
(assuan_get_malloc_hooks, assuan_set_log_cb, assuan_get_log_cb)
(assuan_new, assuan_new_ext, assuan_release): New function
prototypes.
(assuan_init_pipe_server, assuan_init_socket_server)
(assuan_init_socket_server_ext, assuan_pipe_connect)
(assuan_pipe_connect_ext, assuan_socket_connect)
(assuan_socket_connect_ext): Take a context argument instead of
pointer to context.
(assuan_deinit_server, assuan_disconnect)
(assuan_set_assuan_err_source): Remove function prototypes.
* assuan-defs.h (ASSUAN_GCC_A_PURE): Moved here from XXX
(_assuan_error): New macro.
(struct assuan_context_s): New members err_source, w32_strerror,
malloc_hooks, log_cb, log_cb_data: New members. Move confidential
into flags. New member engine.
(_assuan_log_handler, _assuan_error_default, _assuan_disconnect):
New prototypes.
(_assuan_new_context): Remove prototype.
(_assuan_malloc, _assuan_calloc, _assuan_realloc, _assuan_free):
Add context argument to prototype.
* assuan-util.c (alloc_func, realloc_func, free_func): Remove
global variables.
(assuan_set_malloc_hooks, _assuan_malloc, _assuan_realloc)
(_assuan_calloc, _assuan_free, assuan_set_pointer)
(assuan_get_pointer, assuan_begin_confidential)
(assuan_end_confidential, assuan_set_io_monitor, assuan_set_flag)
(assuan_get_flag): Move functions to ...
* assuan-client.c: Add ctx argument to all invocations of
_assuan_error.
* assuan-socket-server.c, assuan-socket-connect.c,
assuan-connect.c: Likewise.
* assuan-buffer.c: Likewise. Also update access to confidential
flag.
* assuan-uds.c: Add ctx argument to all invocations of
_assuan_malloc, _assuan_realloc, _assuan_calloc, _assuan_free and
_assuan_error.
* assuan_listen.c, assuan-inquire.c, assuan-handler.c: Likewise.
* assuan-error.c (err_source): Remove global variable.
(assuan_set_assuan_err_source): Removed function.
(_assuan_w32_strerror): Moved here from assuan-logging.c and made
thread-safe.
(_assuan_error): Removed function (is now macro).
* assuan-handler.c: Update access to confidential flag.
* assuan-socket-server.c (accept_connection_bottom): Update access
to confidential flag in context.
(assuan_init_socket_server, assuan_init_socket_server_ext): Take
ctx argument instead of pointer to ctx.
* assuan-inquire.c (init_membuf, put_membuf, get_membuf)
(free_membuf): Take context argument and change all callers.
* assuan-socket-server.c (assuan_socket_connect)
(assuan_socket_connect_ext): Take ctx argument instead of pointer
to ctx.
* assuan-pipe-connect.c (initial_handshake, pipe_connect_unix)
(socketpair_connect, assuan_pipe_connect)
(assuan_pipe_connect_ext): Likewise.
(socketpair_connect): Now that ctx is not a pointer argument
anymore, return if we are server or client in the argv argument.
* assuan-logging.c (_assuan_log_handler): New function.
(_assuan_w32_strerror): Move to assuan-error.c
* assuan-connect.c (assuan_disconnect): Renamed to ...
(_assuan_disconnect): ... this.
* assuan-pipe-server.c (_assuan_new_context): Removed function.
(assuan_init_pipe_server): Take ctx argument instead of pointer to
ctx.
(_assuan_release_context): Removed function.
(_assuan_deinit_server): Reimplement.
35 files changed, 2205 insertions, 1335 deletions
@@ -1,3 +1,9 @@ +2009-09-19 Marcus Brinkmann <marcus@g10code.de> + + * tests/fdpassing.c: Update to new API. + * configure.ac: Check for stdint.h and inttypes.h. Invoke + AC_TYPE_UINTPTR_T. + 2009-09-08 Marcus Brinkmann <marcus@g10code.de> * m4/gpg-error.m4: New file. @@ -1,23 +1,55 @@ -Noteworthy changes in version 1.1.0 +Noteworthy changes in version 1.1.0 (unreleased) ------------------------------------------------ * Now using libtool and builds a DSO. * Lots of interface cleanups. See below for details of the most - important changes. + important changes. Here is a quick note on how to upgrade: + + For each invocation of the connect or server functions, allocate a + context with assuan_new and use that. Instead of assuan_disconnect + or assuan_deinit_server, call assuan_release. Use + assuan_set_gpg_err_source instead of assuan_set_assuan_err_source. + If you use assuan_pipe_connect 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(). * Interface changes relative to the 1.0.5 release: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -_ASSUAN_ONLY_GPG_ERRORS Removed. -assuan_init_connected_socket_server Removed. -assuan_strerror Removed. -assuan_pipe_connect2 Removed. +_ASSUAN_ONLY_GPG_ERRORS REMOVED +assuan_set_assuan_err_source REMOVED: Use assuan_set_gpg_err_source. +assuan_set_gpg_err_source NEW +assuan_get_gpg_err_source NEW +assuan_strerror REMOVED ASSUAN_* Error values removed. -assuan_error_t Removed. -AssuanError Removed. -AssuanCommand Removed. -assuan_flag_t Changed from enum to unsigned int. -ASSUAN_CONTENT Removed. +assuan_error_t REMOVED +AssuanError REMOVED +assuan_init_connected_socket_server REMOVED +assuan_pipe_connect2 REMOVED +AssuanCommand REMOVED +assuan_flag_t CHANGED: From enum to unsigned int. +ASSUAN_CONTENT REMOVED +assuan_disconnect REMOVED: Use assuan_release. +assuan_deinit_server REMOVED: Use assuan_release. +assuan_get_malloc_hooks NEW +assuan_set_log_cb NEW +assuan_get_log_cb NEW +assuan_new_ext NEW +assuan_new NEW +assuan_release NEW +assuan_init_socket_server CHANGED: Take ctx arg instead of pointer to ctx. +assuan_init_socket_server_ext CHANGED: Take ctx arg instead of pointer to ctx. +assuan_socket_connect CHANGED: Take ctx arg instead of pointer to ctx. +assuan_socket_connect_ext CHANGED: Take ctx arg instead of pointer to ctx. +assuan_pipe_connect CHANGED: Take ctx arg instead of pointer to ctx. + If NAME is NULL, ARGV will contain fork result. +assuan_pipe_connect_ext CHANGED: Take ctx arg instead of pointer to ctx. + If NAME is NULL, ARGV will contain fork result. +assuan_init_pipe_server CHANGED: Take ctx arg instead of pointer to ctx. +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. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Noteworthy changes in version 1.0.5 (2008-05-25) @@ -2,13 +2,14 @@ * Check that we have Pth-ed all blocking fucntions. * When turning libassuan into a shared library, provide a general version as well as a Pth-enabled one. +* Even better, allow replacing all these I/O and spawn functions on + a per-context basis at runtime (like the old assuan_set_io_hooks but better). * assuan_transact returns immediately on an error in the callback function. It might be better to return the error to the caller. As an example see dirmngr-client, where we need to send empty responses for unknown inquiries, albeit dirmngr itself would handle the returns for assuan_inquire gracefully. We need to check all applications whether it is safe to change this. - * XOPEN_SOURCE and snprintf See Peter O'Gorman's mail. diff --git a/configure.ac b/configure.ac index 381d317..4bc5f85 100644 --- a/configure.ac +++ b/configure.ac @@ -227,7 +227,8 @@ AC_SUBST(LIBASSUAN_CONFIG_EXTRA_LIBS) # Checks for header files. AC_HEADER_STDC -AC_CHECK_HEADERS([string.h locale.h sys/uio.h]) +AC_CHECK_HEADERS([string.h locale.h sys/uio.h stdint.h inttypes.h]) +AC_TYPE_UINTPTR_T # Checks for typedefs, structures, and compiler characteristics. AC_C_CONST diff --git a/doc/ChangeLog b/doc/ChangeLog index b9e6e94..95441d5 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,7 @@ +2009-09-21 Marcus Brinkmann <marcus@g10code.de> + + * assuan.texi: Update to new API. + 2009-09-01 Marcus Brinkmann <marcus@g10code.de> * assuan.texi: (External I/O Loop Server): Document diff --git a/doc/assuan.texi b/doc/assuan.texi index 67ba8b3..a3ec0a3 100644 --- a/doc/assuan.texi +++ b/doc/assuan.texi @@ -374,7 +374,7 @@ No operation. Returns OK without any action. Libassuan is used with gpg-error style error codes. It is recommended to set the error source to a different value than the default @code{GPG_ERR_SOURCE_UNKNOWN} by calling @ref{function -assuan_set_assuan_err_source} early. +assuan_set_gpg_err_source} early. @c @@ -428,7 +428,7 @@ directory in which the header file is located to the compilers include file search path (via the @option{-I} option). However, the path to the include file is determined at the time the -source is configured. To solve this problem, @sc{libgcrypt} ships with +source is configured. To solve this problem, @code{libassuan} ships with a small helper program @command{libassuan-config} that knows the path to the include file and other configuration options. The options that need to be added to the compiler invocation at compile time are output by the @@ -519,14 +519,15 @@ compiler and linker. @node Multi Threading @section Multi Threading -The @sc{libgcrypt} library is thread-safe if you adhere to the following +The @code{libassuan} library is thread-safe if you adhere to the following requirements: @itemize @bullet @item Run the initialization functions before you actually start to use threads. @item Only one thread at a time may access an @code{libassuan} context. -@item Use @code{assuan_set_assuan_log_stream} to setup a default log stream. +@item If you use the default log handler, use +@code{assuan_set_assuan_log_stream} to setup a default log stream. @end itemize @@ -537,9 +538,11 @@ to use threads. @chapter Generalities @menu -* Data Types:: Data types used by @code{libassuan}. -* Initializing the library:: How to initialize the library. -* Reading and Writing:: How to communicate with the peer. +* Data Types:: Data types used by @code{libassuan}. +* Initializing the library:: How to initialize the library. +* Default Log Handler:: How to configure the default log handler. +* Contexts:: How to work with contexts. +* Reading and Writing:: How to communicate with the peer. @end menu @@ -548,14 +551,14 @@ to use threads. @section Data Types used by the library @sc{Assuan} uses a context to keep the state for a connection. The -following data type is used ace: +following data type is used for that: @deftp {Data type} assuan_context_t The @code{assuan_context_t} type is a pointer to an object maintained -internally by the library. Certain @sc{Assuan} functions allocate -such a context and return it to the caller using this data type. Other -functions take this data type to access the state created by these -functions. +internally by the library. Contexts are allocated with +@code{assuan_new} or @code{assuan_new_ext} and released with +@code{assuan_release}. Other functions take this data type to access +the state created by these functions. @end deftp @@ -574,23 +577,139 @@ some initialization hooks provided which are often useful. These should be called as early as possible and in a multi-threaded application before a second thread is created. +These functions initialize default values that are used at context +creation with @code{assuan_new}. As there can only be one default, +all values can also be set directly with @code{assuan_new_ext} or with +context-specific functions after context creation. + If your application uses its own memory allocation functions or wrappers it is good idea to tell @code{libassuan} about it so it can make use of the -same functions or wrappers. You do this with +same functions or wrappers: + +@deftp {Data type} {struct assuan_malloc_hooks} +This structure is used to store the memory allocation callback +interface functions. It has the following members, whose semantics +are identical to the corresponding system functions: + +@table @code +@item void *(*malloc) (size_t cnt) +This is the function called by @sc{Assuan} to allocate memory for a context. + +@item void *(*realloc) (void *ptr, size_t cnt) +This is the function called by @sc{Assuan} to reallocate memory for a context. + +@item void (*free) (void *ptr) +This is the function called by @sc{Assuan} to release memory for a context. +@end table +@end deftp + +@deftp {Data type} {assuan_malloc_hooks_t} +This is a pointer to a @code{struct assuan_malloc_hooks}. +@end deftp + +/* Get the default malloc hooks. */ +assuan_malloc_hooks_t assuan_get_malloc_hooks (void); + +@deftypefun void assuan_set_malloc_hooks (@w{assuan_malloc_hooks_t @var{malloc_hooks}}) +This function sets the default allocation hooks for new contexts +allocated with @code{assuan_new}. You need to provide all three +functions. Those functions need to behave exactly as their standard +counterparts @code{malloc}, @code{realloc} and @code{free}. If you +write your own functions, please take care to set @code{errno} +whenever an error has occurred. +@end deftypefun + +@deftypefun assuan_malloc_hooks_t assuan_get_malloc_hooks () +This function gets the default allocation hooks for new contexts +allocated with @code{assuan_new}. The result structure is statically +allocated and should not be modified. +@end deftypefun -@deftypefun void assuan_set_malloc_hooks (@w{void *(*@var{malloc_func})(size_t)}, @w{void *(*@var{realloc_func})(void *, size_t)}, @w{void (*@var{free_func})(void*)}) -You need to provide all three functions. Those functions need to behave -exactly as their standard counterparts (@code{malloc}, @code{realloc} -and @code{free}). If you write your own functions, please take care to -set @code{errno} whenever an error has occurred. +The @sc{Assuan} library uses @code{libgpg-error} error values, which +consist and error code and an error source. The default source used +by contexts allocated with @code{assuan_new} can be set with the +following function. + +@anchor{function assuan_set_gpg_err_source} +@deftypefun void assuan_set_gpg_err_source (@w{gpg_err_source_t @var{err_source}}) +This function sets the default error source for errors generated by +contexts allocated with @code{assuan_new}. + +One way to call this function is +@smallexample +assuan_set_assuan_err_source (GPG_ERR_SOURCE_DEFAULT); +@end smallexample +@end deftypefun + +@deftypefun gpg_err_source_t assuan_get_gpg_err_source (void) +This function gets the default error source for errors generated by +contexts allocated with @code{assuan_new}. @end deftypefun @noindent To integrate assuan logging and diagnostics into your own logging system, you may use the following two functions: +@deftp {Data type} {int (*assuan_log_cb_t) (@w{assuan_context_t @var{ctx}}, @w{void *@var{hook_value}}, @w{unsigned int @var{cat}}, @w{const char *@var{msg}})} +The user-provided callback function takes a context @var{ctx}, for +which the message @var{msg} was generated, and a hook value +@var{hook_value} that was supplied when the log handler was registered +for the context with @code{assuan_set_log_cb}, and a category +@var{cat}. The category is one of: + +@table @code +@item ASSUAN_LOG_INIT +@item ASSUAN_LOG_CTX +@item ASSUAN_LOG_ENGINE +@item ASSUAN_LOG_DATA +@item ASSUAN_LOG_SYSIO +@end table + +The user may then, depending on the category, write the message to a +log file or treat it in some other way. + +If @var{msg} is a null pointer, then no message should be logged, but +the function should return 1 if it is interested in log messages with +the category @var{cat}. If it is not interested, 0 should be +returned. This allows @code{libassuan} to suppress the generation of +expensive debug output. +@end deftp + +@deftypefun void assuan_set_log_cb (@w{assuan_log_cb_t @var{log_cb}}, @w{void *@var{log_cb_data}}) +This function sets the default logging handler for log messages +generated by contexts allocated with @code{assuan_new}. +@end deftypefun + +@deftypefun void assuan_get_log_cb (@w{assuan_log_cb_t *@var{log_cb}}, @w{void **@var{log_cb_data}}) +This function gets the default logging handler for log messages +generated by contexts allocated with @code{assuan_new}. +@end deftypefun + +You do not need to set a log handler, as @sc{Assuan} provides a +configurable default log handler that should be suitable for most +purposes. Logging can be disabled completely by setting the log +handler to a null pointer. + +@node Default Log Handler +@section Default Log Handler + +The default log handler can be configured by the following functions: + +@deftypefun void assuan_set_assuan_log_prefix (@w{const char *@var{text}}) +Set the prefix to be used at the start of a line emitted by assuan +on the log stream to @var{text}. The default is the empty string. +@end deftypefun + + +@deftypefun @w{const char *} assuan_get_assuan_log_prefix (void) +Return the prefix to be used at the start of a line emitted by assuan +on the log stream. The default implementation returns the empty +string. +@end deftypefun + + @deftypefun void assuan_set_assuan_log_stream (FILE *@var{fp}) -This sets the stream to which @code{libassuan} should log messages not +This sets the default log stream to which @code{libassuan} should log messages not associated with a specific context to @var{fp}. The default is to log to @code{stderr}. This default value is also changed by using @code{assuan_set_log_stream} (to set a logging stream for a specific @@ -599,21 +718,145 @@ thread-safe and thus it is highly recommended to use this function to setup a proper default. @end deftypefun -@deftypefun void assuan_set_assuan_log_prefix (@w{const char *@var{text}}) -Set the prefix to be used at the start of a line emitted by assuan -on the log stream to @var{text}. The default is the empty string. + +@deftypefun @w{FILE *} assuan_get_assuan_log_stream (void) +Return the stream which is currently being using for global logging. @end deftypefun -@anchor{function assuan_set_assuan_err_source} -@deftypefun void assuan_set_assuan_err_source (@w{int @var{errsource}}) -Set the error source for error values generated by @code{libassuan}. -@var{errsource} is one of the @code{libgpg-error} sources. The usual -way to call this function is +The log stream used by the default log handler can also be set on a +per context basis. + +@deftypefun void assuan_set_log_stream (@w{assuan_context_t @var{ctx}}, @w{FILE *@var{fp}}) +Enable debugging for the context @var{ctx} and write all debugging +output to the stdio stream @var{fp}. If the default log stream (used +for non-context specific events) has not yet been set, a call to this +functions implicitly sets this stream also to @var{fp}. +@end deftypefun + + +@node Contexts +@section How to work with contexts + +Some operations work globally on the library, but most operate in a +context, which saves state across operations. To allow the use of +@code{libassuan} in mixed environments, such as in a library using +GPGME and an application using GPGME, the context is very extensive +and covers utilitary information like memory allocation callbacks as +well as specific information associated with client/server operations. + +@deftypefun gpg_error_t assuan_new (@w{assuan_context_t *@var{ctx_p}}) +The function @code{assuan_new} creates a new context, using the global +default memory allocation, log handler and @code{libgpg-error} source. +It is equivalent to + @smallexample -assuan_set_assuan_err_source (GPG_ERR_SOURCE_DEFAULT); +gpg_error_t err; +assuan_log_cb_t log_cb; +void *log_cb_data; + +assuan_get_log_cb (&log_cb, &log_cb_data); +err = assuan_new_ext (ctx_p, assuan_get_gpg_err_source (), + assuan_get_malloc_hooks (), log_cb, log_cb_data); +@end smallexample + +As you can see, this is not thread-safe. Take care not to modify the +memory allocation hooks or log callback handler concurrently with +@code{assuan_new}. + +The function returns an error if a memory allocation error occurs, and +0 with the new context in @var{ctx_p} otherwise. +@end deftypefun + +@deftypefun gpg_error_t assuan_new_ext (@w{assuan_context_t *@var{ctx_p}}, @w{gpg_err_source_t @var{err_source}}, @w{assuan_malloc_hooks_t @var{malloc_hooks}}, @w{assuan_log_cb_t @var{log_cb}}, @w{void *@var{log_cb_data}}) +The function @code{assuan_new_ext} creates a new context using the +supplied @code{libgpg-error} error source @var{err_source}, the memory +allocation hooks @var{malloc_hooks} and the log handler @var{log_cb} +with the user data @var{log_cb_data}. +@end deftypefun + +After the context has been used, it can be destroyed again. + +@deftypefun void assuan_release (assuan_context_t ctx) +The function @code{assuan_release} destroys the context CTX and +releases all associated resources. +@end deftypefun + +Other properties of the context beside the memory allocation handler, +the log handler, and the @code{libgpg-error} source can be set after +context creation. Here are some of them: + +@deftypefun void assuan_set_pointer (@w{assuan_context_t @var{ctx}}, @w{void *@var{pointer}}) + +Store the arbitrary pointer value @var{pointer} into the context +@var{ctx}. This is useful to provide command handlers with additional +application context. +@end deftypefun + +@deftypefun void* assuan_get_pointer (@w{assuan_context_t @var{ctx}}) + +This returns the pointer for context @var{ctx} which has been set using +the above function. A common way to use it is by setting the pointer +before starting the processing loop and to retrieve it right at the +start of a command handler: +@smallexample +static int +cmd_foo (assuan_context_t ctx, char *line) +@{ + ctrl_t ctrl = assuan_get_pointer (ctx); + ... +@} +@end smallexample +@end deftypefun + + +@deftypefun void assuan_set_flag (@w{assuan_context_t @var{ctx}}, @w{assuan_flag_t @var{flag}}, @w{int @var{value}}) + +Set the the @var{flag} for context @var{ctx} to @var{value}. Values for +flags are usually 1 or 0 but certain flags might need other values. + +@deftp {Data type} assuan_flag_t +The flags are all named and collected in an @code{enum} for better readability. +Currently only one flag is defined: + +@table @code +@item ASSUAN_NO_WAITPID +When using a pipe server, by default Libassuan will wait for the forked +process to die in @code{assuan_disconnect}. In certain cases this is +not desirable. By setting this flag, a call to @code{waitpid} will be +suppressed and the caller is responsible to cleanup the child process. +@item ASSUAN_CONFIDENTIAL +Uses to return the state of the confidential logging mode. +@end table +@end deftp +@end deftypefun + +@deftypefun int assuan_get_flag (@w{assuan_context_t @var{ctx}}, @w{assuan_flag_t @var{flag}}) +Return the value of @var{flag} in context @var{ctx}. +@end deftypefun + + +@deftypefun void assuan_begin_confidential (@w{assuan_context_t @var{ctx}}) +Put the logging feature into confidential mode. This is to avoid +logging of sensitive data. + +This is identical to: +@smallexample +assuan_set_flag (ctx, ASSUAN_CONFIDENTIAL, 1); @end smallexample @end deftypefun + +@deftypefun void assuan_end_confidential (@w{assuan_context_t @var{ctx}}) +Get the logging feature out of confidential mode. All data will be +logged again (if logging is enabled). + +This is identical to: +@smallexample +assuan_set_flag (ctx, ASSUAN_CONFIDENTIAL, 0); +@end smallexample +@end deftypefun + + @node Reading and Writing @section How to communicate with the peer @@ -667,7 +910,31 @@ sending this @code{END} itself. This function returns @code{0} on success or an error value. @end deftypefun +The input and output of data can be controlled at a higher level using +an I/O monitor. +@deftp {Data type} {unsigned int (*assuan_io_monitor_t) (@w{assuan_context_t @var{ctx}}, @w{void *@var{hook_value}}, @w{int @var{inout}}, @w{const char *@var{line}}, @w{size_t @var{linelen}})} +The monitor function is called right after a line has been received, +if @var{inout} is @code{ASSUAN_IO_FROM_PEER}, or just before it is +send, if @var{inout} is @code{ASSUAN_IO_TO_PEER}. The +@var{hook_value} is provided by the user when registering the I/O +monitor function with a context using @code{assuan_set_io_monitor}. +The callback function should return the bitwise OR of some (or none) of the +following flags: + +@table @code +@item ASSUAN_IO_MONITOR_NOLOG +Active logging of this line is suppressed. This can reduce debug +output in the case of a frequent message. +@item ASSUAN_IO_MONITOR_IGNORE +The whole output line is discarded. +@end table +@end deftp + +@deftypefun void assuan_set_io_monitor (@w{assuan_context_t @var{ctx}}, @w{assuan_io_monitor_t @var{io_monitor}}, @w{void *@var{hook_data}}) +This function registers an I/O monitor @var{io_monitor} for the +context @var{ctx} with the hook value @var{hook_data}. +@end deftypefun @c @@ -683,18 +950,19 @@ 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 *const @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{int *@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}. -If @var{name} as well as @var{argv} are given as @code{NULL}, only a -fork but no exec is done. Thus the child continues to run. However all -file descriptors are closed and some special environment variables are -set. To let the caller detect whether the child or the parent continues, -the child returns with a @var{ctx} set to @code{NULL}. +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 +closed and some special environment variables are set. To let the +caller detect whether the child or the parent continues, the parent +returns with @code{"client"} returned in @var{argv} and the child +returns with @code{"server"} in @var{argv}. If @var{atfork} is not NULL, this function is called in the child right after the fork and the value @var{atforkvalue} is passed as the first @@ -724,7 +992,7 @@ new console is created and pops up a console window when starting the server For a pipe-based server you can also use the following legacy function: -@deftypefun gpg_error_t assuan_pipe_connect (@w{assuan_context_t *@var{ctx}},@w{const char *@var{name}}, @w{const char *const @var{argv}[]}, @w{int *@var{fd_child_list}}) +@deftypefun gpg_error_t assuan_pipe_connect (@w{assuan_context_t *@var{ctx}},@w{const char *@var{name}}, @w{const char *@var{argv}[]}, @w{int *@var{fd_child_list}}) A call to @code{assuan_pipe_connect} is equivalent to a call to @code{assuan_pipe_connect_ext} with @code{flags} being 0 and without @@ -1050,19 +1318,6 @@ string @var{line}. For logging purposes, it is often useful to use such a custom hello line which may tell version numbers and such. Linefeeds are allowed in this string, however, each line needs to be shorter than the Assuan line length limit. - -@end deftypefun - -@noindent -As a last initialization step, debugging may be enabled for the -current connection. This is done using - -@deftypefun void assuan_set_log_stream (@w{assuan_context_t @var{ctx}}, @w{FILE *@var{fp}}) - -Enable debugging for the context @var{ctx} and write all debugging -output to the stdio stream @var{fp}. If the default log stream (used -for non-context specific events) has not yet been set, a call to this -functions implicitly sets this stream also to @var{fp}. @end deftypefun @noindent @@ -1354,32 +1609,6 @@ Some of these functions provide information not available with the general functions. - -@deftypefun void assuan_set_pointer (@w{assuan_context_t @var{ctx}}, @w{void *@var{pointer}}) - -Store the arbitrary pointer value @var{pointer} into the context -@var{ctx}. This is useful to provide command handlers with additional -application context. -@end deftypefun - -@deftypefun void* assuan_get_pointer (@w{assuan_context_t @var{ctx}}) - -This returns the pointer for context @var{ctx} which has been set using -the above function. A common way to use it is by setting the pointer -before starting the processing loop and to retrieve it right at the -start of a command handler: -@smallexample -static int -cmd_foo (assuan_context_t ctx, char *line) -@{ - ctrl_t ctrl = assuan_get_pointer (ctx); - ... -@} -@end smallexample -@end deftypefun - - - @deftypefun gpg_error_t assuan_write_status (@w{assuan_context_t @var{ctx}}, @w{const char *@var{keyword}}, @w{const char *@var{text}}) This is a convenience function for a server to send a status line. You @@ -1489,34 +1718,6 @@ that error to humans. @end deftypefun -@deftypefun void assuan_set_flag (@w{assuan_context_t @var{ctx}}, @w{assuan_flag_t @var{flag}}, @w{int @var{value}}) - -Set the the @var{flag} for context @var{ctx} to @var{value}. Values for -flags are usually 1 or 0 but certain flags might need other values. - -@deftp {Data type} assuan_flag_t -The flags are all named and collected in an @code{enum} for better readability. -Currently only one flag is defined: - -@table @code -@item ASSUAN_NO_WAITPID -When using a pipe server, by default Libassuan will wait for the forked -process to die in @code{assuan_disconnect}. In certain cases this is -not desirable. By setting this flag, a call to @code{waitpid} will be -suppressed and the caller is responsible to cleanup the child process. -@item ASSUAN_CONFIDENTIAL -Uses to return the state of the confidential logging mode. For changing -this mode the functions @code{assuan_begin_confidential} and -@code{assuan_end_confidential} should be used. -@end table -@end deftp - -@end deftypefun - -@deftypefun int assuan_get_flag (@w{assuan_context_t @var{ctx}}, @w{assuan_flag_t @var{flag}}) -Return the value of @var{flag} in context @var{ctx}. -@end deftypefun - @deftypefun pid_t assuan_get_pid (@w{assuan_context_t @var{ctx}}) @@ -1570,40 +1771,6 @@ thus an entire assuan line may be read without triggering any actual I/O. @end deftypefun -@deftypefun void assuan_set_io_monitor (@w{assuan_context_t @var{ctx}}, @w{unsigned int} (*@var{monitor})(@w{assuan_context_t @var{ctx}}, @w{int @var{direction}}, @w{const char *@var{line}}, @w{size_t @var{linelen}})) - -This function registers an I/O monitor for the context @var{ctx}. Such -a monitor function is called right after a line has been received or -just before it is send. With @var{direction} set to 1 the monitor has -been called for an output operation; 0 obviosuly means it has been -called for an input operation. If the monitor sets bit 0 in the return -value, any active logging of the line will be suppressed. With bit 1 -set, the entire line will be ignored. -@end deftypefun - -@deftypefun void assuan_begin_confidential (@w{assuan_context_t @var{ctx}}) - -Put the logging feature into confidential mode. This is to avoid -logging of sensitive data. -@end deftypefun - -@deftypefun void assuan_end_confidential (@w{assuan_context_t @var{ctx}}) - -Get the logging feature out of confidential mode. All data will be -logged again (if logging is enabled). -@end deftypefun - -@deftypefun FILE* assuan_get_assuan_log_stream (void) - -Return the stream which is currently being using for global logging. -@end deftypefun - -@deftypefun @w{const char*} assuan_get_assuan_log_prefix (void) - -Return the prefix to be used at the start of a line emitted by assuan -on the log stream. The default implementation returns the empty -string. -@end deftypefun @c diff --git a/src/ChangeLog b/src/ChangeLog index c561abc..627d369 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,88 @@ +2009-09-19 Marcus Brinkmann <marcus@g10code.de> + + * src/libassuan.vers, src/libassuan.def: Update to new API. + * assuan.c, context.c, system.c, debug.c: New files. + * Makefile.am (common_sources): Add assuan.c, context.c, system.c + and debug.c. + * assuan.h: Include <stdarg.h>. Fix inclusion of <gpg-error.h>. + (_ASSUAN_EXT_SYM_PREFIX, _ASSUAN_PREFIX1, _ASSUAN_PREFIX2) + (_ASSUAN_PREFIX): Remove support for renaming the whole library, + now that we have a stable shared library interface that can evolve + to cover all needs (particularly those of GPGME). + (assuan_malloc_hooks, assuan_malloc_hooks_t, assuan_log_cb_t) + (assuan_io_monitor_t): New types. + (ASSUAN_LOG_INIT, ASSUAN_LOG_CTX, ASSUAN_LOG_ENGINE) + (ASSUAN_LOG_DATA, ASSUAN_LOG_SYSIO, ASSUAN_IO_FROM_PEER) + (ASSUAN_IO_TO_PEER, ASSUAN_IO_MONITOR_NOLOG) + (ASSUAN_IO_MONITOR_IGNORE): New symbols. + (assuan_set_gpg_err_source, assuan_get_gpg_err_source) + (assuan_get_malloc_hooks, assuan_set_log_cb, assuan_get_log_cb) + (assuan_new, assuan_new_ext, assuan_release): New function + prototypes. + (assuan_init_pipe_server, assuan_init_socket_server) + (assuan_init_socket_server_ext, assuan_pipe_connect) + (assuan_pipe_connect_ext, assuan_socket_connect) + (assuan_socket_connect_ext): Take a context argument instead of + pointer to context. + (assuan_deinit_server, assuan_disconnect) + (assuan_set_assuan_err_source): Remove function prototypes. + * assuan-defs.h (ASSUAN_GCC_A_PURE): Moved here from XXX + (_assuan_error): New macro. + (struct assuan_context_s): New members err_source, w32_strerror, + malloc_hooks, log_cb, log_cb_data: New members. Move confidential + into flags. New member engine. + (_assuan_log_handler, _assuan_error_default, _assuan_disconnect): + New prototypes. + (_assuan_new_context): Remove prototype. + (_assuan_malloc, _assuan_calloc, _assuan_realloc, _assuan_free): + Add context argument to prototype. + * assuan-util.c (alloc_func, realloc_func, free_func): Remove + global variables. + (assuan_set_malloc_hooks, _assuan_malloc, _assuan_realloc) + (_assuan_calloc, _assuan_free, assuan_set_pointer) + (assuan_get_pointer, assuan_begin_confidential) + (assuan_end_confidential, assuan_set_io_monitor, assuan_set_flag) + (assuan_get_flag): Move functions to ... + * assuan-client.c: Add ctx argument to all invocations of + _assuan_error. + * assuan-socket-server.c, assuan-socket-connect.c, + assuan-connect.c: Likewise. + * assuan-buffer.c: Likewise. Also update access to confidential + flag. + * assuan-uds.c: Add ctx argument to all invocations of + _assuan_malloc, _assuan_realloc, _assuan_calloc, _assuan_free and + _assuan_error. + * assuan_listen.c, assuan-inquire.c, assuan-handler.c: Likewise. + * assuan-error.c (err_source): Remove global variable. + (assuan_set_assuan_err_source): Removed function. + (_assuan_w32_strerror): Moved here from assuan-logging.c and made + thread-safe. + (_assuan_error): Removed function (is now macro). + * assuan-handler.c: Update access to confidential flag. + * assuan-socket-server.c (accept_connection_bottom): Update access + to confidential flag in context. + (assuan_init_socket_server, assuan_init_socket_server_ext): Take + ctx argument instead of pointer to ctx. + * assuan-inquire.c (init_membuf, put_membuf, get_membuf) + (free_membuf): Take context argument and change all callers. + * assuan-socket-server.c (assuan_socket_connect) + (assuan_socket_connect_ext): Take ctx argument instead of pointer + to ctx. + * assuan-pipe-connect.c (initial_handshake, pipe_connect_unix) + (socketpair_connect, assuan_pipe_connect) + (assuan_pipe_connect_ext): Likewise. + (socketpair_connect): Now that ctx is not a pointer argument + anymore, return if we are server or client in the argv argument. + * assuan-logging.c (_assuan_log_handler): New function. + (_assuan_w32_strerror): Move to assuan-error.c + * assuan-connect.c (assuan_disconnect): Renamed to ... + (_assuan_disconnect): ... this. + * assuan-pipe-server.c (_assuan_new_context): Removed function. + (assuan_init_pipe_server): Take ctx argument instead of pointer to + ctx. + (_assuan_release_context): Removed function. + (_assuan_deinit_server): Reimplement. + 2009-09-01 Marcus Brinkmann <marcus@g10code.de> * assuan.h: Change types in all functions from int to gpg_error_t @@ -10,7 +95,7 @@ (accept_connection, finish_connection): Likewise. (assuan_init_connected_socket_server): Remove. * assuan-defs.h (struct assuan_context_s): Change return type of - accept_handler and finish_handler to gpg_error_t. + accept_handler and finish_handler to gpg_error_t. Add io_monitor_data. * assuan-pipe-connect.c (do_finish): Change to void. * assuan-inquire.c (_assuan_inquire_ext_cb): Change type of RC from int to gpg_error_t. diff --git a/src/Makefile.am b/src/Makefile.am index 4f6aec3..1e1c46b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -42,7 +42,11 @@ endif common_sources = \ assuan-defs.h \ - assuan-util.c \ + assuan.c \ + context.c \ + system.c \ + debug.c \ + conversion.c \ assuan-error.c \ assuan-buffer.c \ assuan-handler.c \ diff --git a/src/assuan-buffer.c b/src/assuan-buffer.c index e973341..583d137 100644 --- a/src/assuan-buffer.c +++ b/src/assuan-buffer.c @@ -103,7 +103,7 @@ _assuan_read_line (assuan_context_t ctx) char *endp = 0; if (ctx->inbound.eof) - return _assuan_error (GPG_ERR_EOF); + return _assuan_error (ctx, GPG_ERR_EOF); atticlen = ctx->inbound.attic.linelen; if (atticlen) @@ -149,7 +149,7 @@ _assuan_read_line (assuan_context_t ctx) } errno = saved_errno; - return _assuan_error (gpg_err_code_from_syserror ()); + return _assuan_error (ctx, gpg_err_code_from_syserror ()); } if (!nread) { @@ -159,7 +159,7 @@ _assuan_read_line (assuan_context_t ctx) assuan_get_assuan_log_prefix (), (unsigned int)getpid (), (int)ctx->inbound.fd); - return _assuan_error (GPG_ERR_EOF); + return _assuan_error (ctx, GPG_ERR_EOF); } ctx->inbound.attic.pending = 0; @@ -190,20 +190,20 @@ _assuan_read_line (assuan_context_t ctx) ctx->inbound.linelen = endp - line; - monitor_result = (ctx->io_monitor - ? ctx->io_monitor (ctx, 0, - ctx->inbound.line, - ctx->inbound.linelen) - : 0); - if ( (monitor_result & 2) ) + monitor_result = 0; + if (ctx->io_monitor) + monitor_result = ctx->io_monitor (ctx, ctx->io_monitor_data, 0, + ctx->inbound.line, + ctx->inbound.linelen); + if (monitor_result & ASSUAN_IO_MONITOR_IGNORE) ctx->inbound.linelen = 0; - if (ctx->log_fp && !(monitor_result & 1)) + if (ctx->log_fp && !(monitor_result & ASSUAN_IO_MONITOR_NOLOG)) { fprintf (ctx->log_fp, "%s[%u.%d] DBG: <- ", assuan_get_assuan_log_prefix (), (unsigned int)getpid (), (int)ctx->inbound.fd); - if (ctx->confidential) + if (ctx->flags.confidential) fputs ("[Confidential data not shown]", ctx->log_fp); else _assuan_log_print_buffer (ctx->log_fp, @@ -221,9 +221,9 @@ _assuan_read_line (assuan_context_t ctx) (unsigned int)getpid (), (int)ctx->inbound.fd); *line = 0; ctx->inbound.linelen = 0; - return _assuan_error (ctx->inbound.eof - ? GPG_ERR_ASS_INCOMPLETE_LINE - : GPG_ERR_ASS_LINE_TOO_LONG); + return _assuan_error (ctx, ctx->inbound.eof + ? GPG_ERR_ASS_INCOMPLETE_LINE + : GPG_ERR_ASS_LINE_TOO_LONG); } } @@ -243,7 +243,7 @@ assuan_read_line (assuan_context_t ctx, char **line, size_t *linelen) gpg_error_t err; if (!ctx) - return _assuan_error (GPG_ERR_ASS_INV_VALUE); + return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE); do { @@ -288,17 +288,17 @@ _assuan_write_line (assuan_context_t ctx, const char *prefix, len = ASSUAN_LINELENGTH - prefixlen - 2 - 1; } - monitor_result = (ctx->io_monitor - ? ctx->io_monitor (ctx, 1, line, len) - : 0); + monitor_result = 0; + if (ctx->io_monitor) + monitor_result = ctx->io_monitor (ctx, ctx->io_monitor_data, 1, line, len); /* Fixme: we should do some kind of line buffering. */ - if (ctx->log_fp && !(monitor_result & 1)) + if (ctx->log_fp && !(monitor_result & ASSUAN_IO_MONITOR_NOLOG)) { fprintf (ctx->log_fp, "%s[%u.%d] DBG: -> ", assuan_get_assuan_log_prefix (), (unsigned int)getpid (), (int)ctx->inbound.fd); - if (ctx->confidential) + if (ctx->flags.confidential) fputs ("[Confidential data not shown]", ctx->log_fp); else { @@ -309,22 +309,22 @@ _assuan_write_line (assuan_context_t ctx, const char *prefix, putc ('\n', ctx->log_fp); } - if (prefixlen && !(monitor_result & 2)) + if (prefixlen && !(monitor_result & ASSUAN_IO_MONITOR_IGNORE)) { rc = writen (ctx, prefix, prefixlen); if (rc) - rc = _assuan_error (gpg_err_code_from_syserror ()); + rc = _assuan_error (ctx, gpg_err_code_from_syserror ()); } - if (!rc && !(monitor_result & 2)) + if (!rc && !(monitor_result & ASSUAN_IO_MONITOR_IGNORE)) { rc = writen (ctx, line, len); if (rc) - rc = _assuan_error (gpg_err_code_from_syserror ()); + rc = _assuan_error (ctx, gpg_err_code_from_syserror ()); if (!rc) { rc = writen (ctx, "\n", 1); if (rc) - rc = _assuan_error (gpg_err_code_from_syserror ()); + rc = _assuan_error (ctx, gpg_err_code_from_syserror ()); } } return rc; @@ -338,7 +338,7 @@ assuan_write_line (assuan_context_t ctx, const char *line) const char *str; if (! ctx) - return _assuan_error (GPG_ERR_ASS_INV_VALUE); + return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE); /* Make sure that we never take a LF from the user - this might violate the protocol. */ @@ -403,20 +403,20 @@ _assuan_cookie_write_data (void *cookie, const char *buffer, size_t orig_size) } - monitor_result = (ctx->io_monitor - ? ctx->io_monitor (ctx, 1, - ctx->outbound.data.line, linelen) - : 0); + monitor_result = 0; + if (ctx->io_monitor) + monitor_result = ctx->io_monitor (ctx, ctx->io_monitor_data, 1, + ctx->outbound.data.line, linelen); if (linelen >= LINELENGTH-2-2) { - if (ctx->log_fp && !(monitor_result & 1)) + if (ctx->log_fp && !(monitor_result & ASSUAN_IO_MONITOR_NOLOG)) { fprintf (ctx->log_fp, "%s[%u.%d] DBG: -> ", assuan_get_assuan_log_prefix (), (unsigned int)getpid (), (int)ctx->inbound.fd); - if (ctx->confidential) + if (ctx->flags.confidential) fputs ("[Confidential data not shown]", ctx->log_fp); else _assuan_log_print_buffer (ctx->log_fp, @@ -426,7 +426,7 @@ _assuan_cookie_write_data (void *cookie, const char *buffer, size_t orig_size) } *line++ = '\n'; linelen++; - if ( !(monitor_result & 2) + if ( !(monitor_result & ASSUAN_IO_MONITOR_IGNORE) && writen (ctx, ctx->outbound.data.line, linelen)) { ctx->outbound.data.error = gpg_err_code_from_syserror (); @@ -459,19 +459,19 @@ _assuan_cookie_write_flush (void *cookie) linelen = ctx->outbound.data.linelen; line += linelen; - monitor_result = (ctx->io_monitor - ? ctx->io_monitor (ctx, 1, - ctx->outbound.data.line, linelen) - : 0); + monitor_result = 0; + if (ctx->io_monitor) + monitor_result = ctx->io_monitor (ctx, ctx->io_monitor_data, 1, + ctx->outbound.data.line, linelen); if (linelen) { - if (ctx->log_fp && !(monitor_result & 1)) + if (ctx->log_fp && !(monitor_result & ASSUAN_IO_MONITOR_NOLOG)) { fprintf (ctx->log_fp, "%s[%u.%d] DBG: -> ", assuan_get_assuan_log_prefix (), (unsigned int)getpid (), (int)ctx->inbound.fd); - if (ctx->confidential) + if (ctx->flags.confidential) fputs ("[Confidential data not shown]", ctx->log_fp); else _assuan_log_print_buffer (ctx->log_fp, @@ -480,7 +480,7 @@ _assuan_cookie_write_flush (void *cookie) } *line++ = '\n'; linelen++; - if (! (monitor_result & 2) + if (! (monitor_result & ASSUAN_IO_MONITOR_IGNORE) && writen (ctx, ctx->outbound.data.line, linelen)) { ctx->outbound.data.error = gpg_err_code_from_syserror (); @@ -517,9 +517,9 @@ gpg_error_t assuan_send_data (assuan_context_t ctx, const void *buffer, size_t length) { if (!ctx) - return _assuan_error (GPG_ERR_ASS_INV_VALUE); + return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE); if (!buffer && length > 1) - return _assuan_error (GPG_ERR_ASS_INV_VALUE); + return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE); if (!buffer) { /* flush what we have */ @@ -548,7 +548,7 @@ assuan_sendfd (assuan_context_t ctx, assuan_fd_t fd) #ifdef USE_DESCRIPTOR_PASSING return 0; #else - return _assuan_error (GPG_ERR_NOT_IMPLEMENTED); + return _assuan_error (ctx, GPG_ERR_NOT_IMPLEMENTED); #endif if (! ctx->io->sendfd) diff --git a/src/assuan-client.c b/src/assuan-client.c index 3d3748c..aa74f81 100644 --- a/src/assuan-client.c +++ b/src/assuan-client.c @@ -109,7 +109,7 @@ _assuan_read_from_server (assuan_context_t ctx, int *okay, int *off) *off = 3; } else - rc = _assuan_error (GPG_ERR_ASS_INV_RESPONSE); + rc = _assuan_error (ctx, GPG_ERR_ASS_INV_RESPONSE); return rc; } @@ -169,7 +169,7 @@ assuan_transact (assuan_context_t ctx, else if (okay == 2) { if (!data_cb) - rc = _assuan_error (GPG_ERR_ASS_NO_DATA_CB); + rc = _assuan_error (ctx, GPG_ERR_ASS_NO_DATA_CB); else { char *s, *d; @@ -198,7 +198,7 @@ assuan_transact (assuan_context_t ctx, { assuan_write_line (ctx, "END"); /* get out of inquire mode */ _assuan_read_from_server (ctx, &okay, &off); /* dummy read */ - rc = _assuan_error (GPG_ERR_ASS_NO_INQUIRE_CB); + rc = _assuan_error (ctx, GPG_ERR_ASS_NO_INQUIRE_CB); } else { @@ -219,7 +219,7 @@ assuan_transact (assuan_context_t ctx, else if (okay == 5) { if (!data_cb) - rc = _assuan_error (GPG_ERR_ASS_NO_DATA_CB); + rc = _assuan_error (ctx, GPG_ERR_ASS_NO_DATA_CB); else { rc = data_cb (data_cb_arg, NULL, 0); diff --git a/src/assuan-connect.c b/src/assuan-connect.c index c2c7f42..f5540a1 100644 --- a/src/assuan-connect.c +++ b/src/assuan-connect.c @@ -36,18 +36,24 @@ /* Disconnect and release the context CTX. */ void -assuan_disconnect (assuan_context_t ctx) +_assuan_disconnect (assuan_context_t ctx) { - if (ctx) - { - assuan_write_line (ctx, "BYE"); - ctx->finish_handler (ctx); - ctx->deinit_handler (ctx); - ctx->deinit_handler = NULL; - _assuan_release_context (ctx); - } + assuan_write_line (ctx, "BYE"); + ctx->finish_handler (ctx); + ctx->finish_handler = NULL; + ctx->deinit_handler (ctx); + ctx->deinit_handler = NULL; + + _assuan_inquire_release (ctx); + _assuan_free (ctx, ctx->hello_line); + ctx->hello_line = NULL; + _assuan_free (ctx, ctx->okay_line); + ctx->okay_line = NULL; + _assuan_free (ctx, ctx->cmdtbl); + ctx->cmdtbl = NULL; } + /* Return the PID of the peer or -1 if not known. This function works in some situations where assuan_get_ucred fails. */ pid_t @@ -65,9 +71,9 @@ gpg_error_t assuan_get_peercred (assuan_context_t ctx, pid_t *pid, uid_t *uid, gid_t *gid) { if (!ctx) - return _assuan_error (GPG_ERR_ASS_INV_VALUE); + return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE); if (!ctx->peercred.valid) - return _assuan_error (GPG_ERR_ASS_GENERAL); + return _assuan_error (ctx, GPG_ERR_ASS_GENERAL); #ifdef HAVE_SO_PEERCRED if (pid) diff --git a/src/assuan-defs.h b/src/assuan-defs.h index 5fc14f4..1d6acee 100644 --- a/src/assuan-defs.h +++ b/src/assuan-defs.h @@ -31,6 +31,12 @@ #include "assuan.h" +#if __GNUC__ > 2 +# define ASSUAN_GCC_A_PURE __attribute__ ((__pure__)) +#else +# define ASSUAN_GCC_A_PURE +#endif + #ifndef HAVE_W32_SYSTEM #define DIRSEP_C '/' #else @@ -39,6 +45,9 @@ #define LINELENGTH ASSUAN_LINELENGTH +/* Generate an error code specific to a context. */ +#define _assuan_error(ctx, errcode) gpg_err_make ((ctx)->err_source, errcode) + struct cmdtbl_s { @@ -60,40 +69,71 @@ struct assuan_io gpg_error_t (*receivefd) (assuan_context_t, assuan_fd_t *); }; - -/* The global variable with the optional hook fucntions. */ -extern struct assuan_io_hooks _assuan_io_hooks; - - + /* The context we use with most functions. */ struct assuan_context_s { - gpg_error_t err_no; - const char *err_str; + /* Members managed by the generic routines in assuan.c. */ + + /* The error source for errors generated from this context. */ + gpg_err_source_t err_source; + +#ifdef HAVE_W32_SYSTEM + /* The per-context w32 error string. */ + char w32_strerror[256]; +#endif + + /* The allocation hooks. */ + struct assuan_malloc_hooks malloc_hooks; + + /* Logging callback handler. */ + assuan_log_cb_t log_cb; + void *log_cb_data; + + void *user_pointer; /* Context specific flags (cf. assuan_flag_t). */ struct { - unsigned int no_waitpid : 1; /* See ASSUAN_NO_WAITPID. */ + unsigned int no_waitpid : 1; + unsigned int confidential : 1; } flags; - int confidential; + /* If set, this is called right before logging an I/O line. */ + assuan_io_monitor_t io_monitor; + void *io_monitor_data; + + /* 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); + } engine; + + + /* Engine specific or other subsystem members. */ + + /* assuan-logging.c. Does not require deallocation from us. */ + FILE *log_fp; + + /* assuan-util.c */ + gpg_error_t err_no; + const char *err_str; + int is_server; /* Set if this is context belongs to a server */ int in_inquire; int in_process_next; int in_command; /* The following members are used by assuan_inquire_ext. */ - int (*inquire_cb) (void *cb_data, int rc, unsigned char *buf, size_t len); + gpg_error_t (*inquire_cb) (void *cb_data, gpg_error_t rc, + unsigned char *buf, size_t len); void *inquire_cb_data; void *inquire_membuf; char *hello_line; char *okay_line; /* See assuan_set_okay_line() */ - void *user_pointer; /* For assuan_get_pointer and assuan_set_pointer (). */ - - FILE *log_fp; struct { assuan_fd_t fd; @@ -155,7 +195,7 @@ struct assuan_context_s void (*deinit_handler)(assuan_context_t); gpg_error_t (*accept_handler)(assuan_context_t); - gpg_error_t (*finish_handler)(assuan_context_t); + void (*finish_handler)(assuan_context_t); struct cmdtbl_s *cmdtbl; size_t cmdtbl_used; /* used entries */ @@ -170,27 +210,35 @@ struct assuan_context_s /* This function is called right after a command has been processed. It may be used to command related cleanup. */ - void (*post_cmd_notify_fnc)(assuan_context_t, int); - - /* If set, this is called right before logging an I/O line. With - DIRECTION set to 1 it is called for an output oeration; 0 means - an input operation. If bit 0 is set in the return value, the - logging of the line will be suppressed. With bit 1 set, the - entire line will be ignored. */ - unsigned int (*io_monitor)(assuan_context_t ctx, - int direction, - const char *line, - size_t linelen); + void (*post_cmd_notify_fnc)(assuan_context_t, gpg_error_t); + assuan_fd_t input_fd; /* Set by the INPUT command. */ assuan_fd_t output_fd; /* Set by the OUTPUT command. */ /* io routines. */ struct assuan_io *io; + + }; + +/* Release all resources associated with an engine operation. */ +void _assuan_reset (assuan_context_t ctx); + +/* Default log handler. */ +int _assuan_log_handler (assuan_context_t ctx, void *hook, + unsigned int cat, const char *msg); + + +/* Manage memory specific to a context. */ +void *_assuan_malloc (assuan_context_t ctx, size_t cnt); +void *_assuan_realloc (assuan_context_t ctx, void *ptr, size_t cnt); +void *_assuan_calloc (assuan_context_t ctx, size_t cnt, size_t elsize); +void _assuan_free (assuan_context_t ctx, void *ptr); + + /*-- assuan-pipe-server.c --*/ -gpg_error_t _assuan_new_context (assuan_context_t *r_ctx); void _assuan_release_context (assuan_context_t ctx); /*-- assuan-uds.c --*/ @@ -223,16 +271,9 @@ void _assuan_inquire_release (assuan_context_t ctx); int _assuan_error_is_eagain (gpg_error_t err); -/*-- assuan-util.c --*/ -void *_assuan_malloc (size_t n); -void *_assuan_calloc (size_t n, size_t m); -void *_assuan_realloc (void *p, size_t n); -void _assuan_free (void *p); - -gpg_error_t _assuan_error (gpg_err_code_t errcode); #define set_error(c,e,t) \ - assuan_set_error ((c), _assuan_error (e), (t)) + assuan_set_error ((c), _assuan_error (c,e), (t)) #ifdef HAVE_W32_SYSTEM const char *_assuan_w32_strerror (int ec); @@ -241,15 +282,7 @@ const char *_assuan_w32_strerror (int ec); /*-- assuan-logging.c --*/ -void _assuan_set_default_log_stream (FILE *fp); - -void _assuan_log_printf (const char *format, ...) -#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 ) - __attribute__ ((format (printf,1,2))) -#endif - ; -void _assuan_log_print_buffer (FILE *fp, const void *buffer, size_t length); -void _assuan_log_sanitized_string (const char *string); +void _assuan_log_print_buffer (FILE *fp, const void *buffer, size_t length); /*-- assuan-io.c --*/ @@ -322,4 +355,10 @@ int putc_unlocked (int c, FILE *stream); #endif +void _assuan_disconnect (assuan_context_t ctx); + +/* Encode the C formatted string SRC and return the malloc'ed result. */ +char *_assuan_encode_c_string (assuan_context_t ctx, const char *src); + + #endif /*ASSUAN_DEFS_H*/ diff --git a/src/assuan-error.c b/src/assuan-error.c index 4eba7ff..60cb0d3 100644 --- a/src/assuan-error.c +++ b/src/assuan-error.c @@ -29,30 +29,6 @@ #include "assuan.h" #include "assuan-defs.h" -/* If true the modern gpg-error style error codes are used in the - API. */ -static gpg_err_source_t err_source; - -/* Enable gpg-error style error codes. ERRSOURCE is one of gpg-error - sources. Note, that this function is not thread-safe and should be - used right at startup. Switching back to the old style mode is not - supported. */ -void -assuan_set_assuan_err_source (gpg_err_source_t errsource) -{ - errsource &= 0xff; - err_source = errsource ? errsource : 31 /*GPG_ERR_SOURCE_ANY*/; -} - - -/* Helper to map old style Assuan error codes to gpg-error codes. - This is used internally to keep an compatible ABI. */ -gpg_error_t -_assuan_error (gpg_err_code_t errcode) -{ - return gpg_err_make (err_source, errcode); -} - /* A small helper function to treat EAGAIN transparently to the caller. */ @@ -68,3 +44,20 @@ _assuan_error_is_eagain (gpg_error_t err) else return 0; } + + + +#ifdef HAVE_W32_SYSTEM +char * +_assuan_w32_strerror (assuan_context_t ctx, int ec) +{ + if (ec == -1) + ec = (int)GetLastError (); + FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, ec, + MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), + ctx->w32_strerror, sizeof (ctx->w32_strerror) - 1, NULL); + + return ctx->w32_strerror; +} +#endif + diff --git a/src/assuan-handler.c b/src/assuan-handler.c index 057d7e7..da5d4bf 100644 --- a/src/assuan-handler.c +++ b/src/assuan-handler.c @@ -27,7 +27,7 @@ #include <errno.h> #include "assuan-defs.h" - +#include "debug.h" #define spacep(p) (*(p) == ' ' || *(p) == '\t') @@ -123,7 +123,7 @@ std_handler_bye (assuan_context_t ctx, char *line) assuan_close_input_fd (ctx); assuan_close_output_fd (ctx); /* pretty simple :-) */ - return PROCESS_DONE (ctx, _assuan_error (GPG_ERR_EOF)); + return PROCESS_DONE (ctx, _assuan_error (ctx, GPG_ERR_EOF)); } static gpg_error_t @@ -287,7 +287,7 @@ assuan_register_command (assuan_context_t ctx, cmd_name = NULL; if (!cmd_name) - return _assuan_error (GPG_ERR_ASS_INV_VALUE); + return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE); if (!handler) { /* find a default handler. */ @@ -308,18 +308,18 @@ assuan_register_command (assuan_context_t ctx, if (!ctx->cmdtbl) { ctx->cmdtbl_size = 50; - ctx->cmdtbl = _assuan_calloc (ctx->cmdtbl_size, sizeof *ctx->cmdtbl); + ctx->cmdtbl = _assuan_calloc (ctx, ctx->cmdtbl_size, sizeof *ctx->cmdtbl); if (!ctx->cmdtbl) - return _assuan_error (gpg_err_code_from_syserror ()); + return _assuan_error (ctx, gpg_err_code_from_syserror ()); ctx->cmdtbl_used = 0; } else if (ctx->cmdtbl_used >= ctx->cmdtbl_size) { struct cmdtbl_s *x; - x = _assuan_realloc ( ctx->cmdtbl, (ctx->cmdtbl_size+10) * sizeof *x); + x = _assuan_realloc (ctx, ctx->cmdtbl, (ctx->cmdtbl_size+10) * sizeof *x); if (!x) - return _assuan_error (gpg_err_code_from_syserror ()); + return _assuan_error (ctx, gpg_err_code_from_syserror ()); ctx->cmdtbl = x; ctx->cmdtbl_size += 50; } @@ -335,7 +335,7 @@ assuan_register_post_cmd_notify (assuan_context_t ctx, void (*fnc)(assuan_context_t, gpg_error_t)) { if (!ctx) - return _assuan_error (GPG_ERR_ASS_INV_VALUE); + return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE); ctx->post_cmd_notify_fnc = fnc; return 0; } @@ -345,7 +345,7 @@ assuan_register_bye_notify (assuan_context_t ctx, void (*fnc)(assuan_context_t)) { if (!ctx) - return _assuan_error (GPG_ERR_ASS_INV_VALUE); + return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE); ctx->bye_notify_fnc = fnc; return 0; } @@ -355,7 +355,7 @@ assuan_register_reset_notify (assuan_context_t ctx, void (*fnc)(assuan_context_t)) { if (!ctx) - return _assuan_error (GPG_ERR_ASS_INV_VALUE); + return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE); ctx->reset_notify_fnc = fnc; return 0; } @@ -365,7 +365,7 @@ assuan_register_cancel_notify (assuan_context_t ctx, void (*fnc)(assuan_context_t)) { if (!ctx) - return _assuan_error (GPG_ERR_ASS_INV_VALUE); + return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE); ctx->cancel_notify_fnc = fnc; return 0; } @@ -376,7 +376,7 @@ assuan_register_option_handler (assuan_context_t ctx, const char*, const char*)) { if (!ctx) - return _assuan_error (GPG_ERR_ASS_INV_VALUE); + return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE); ctx->option_handler_fnc = fnc; return 0; } @@ -386,7 +386,7 @@ assuan_register_input_notify (assuan_context_t ctx, void (*fnc)(assuan_context_t, const char *)) { if (!ctx) - return _assuan_error (GPG_ERR_ASS_INV_VALUE); + return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE); ctx->input_notify_fnc = fnc; return 0; } @@ -396,7 +396,7 @@ assuan_register_output_notify (assuan_context_t ctx, void (*fnc)(assuan_context_t, const char *)) { if (!ctx) - return _assuan_error (GPG_ERR_ASS_INV_VALUE); + return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE); ctx->output_notify_fnc = fnc; return 0; } @@ -508,7 +508,7 @@ gpg_error_t assuan_process_done (assuan_context_t ctx, gpg_error_t rc) { if (!ctx->in_command) - return _assuan_error (GPG_ERR_ASS_GENERAL); + return _assuan_error (ctx, GPG_ERR_ASS_GENERAL); ctx->in_command = 0; @@ -557,10 +557,10 @@ assuan_process_done (assuan_context_t ctx, gpg_error_t rc) if (ctx->post_cmd_notify_fnc) ctx->post_cmd_notify_fnc (ctx, rc); - ctx->confidential = 0; + ctx->flags.confidential = 0; if (ctx->okay_line) { - _assuan_free (ctx->okay_line); + _assuan_free (ctx, ctx->okay_line); ctx->okay_line = NULL; } @@ -613,7 +613,8 @@ process_next (assuan_context_t ctx) /* Should not happen. The client is sending data while we are in a command and not waiting for an inquire. We log an error and discard it. */ - _assuan_log_printf ("unexpected client data\n"); + TRACE0 (ctx, ASSUAN_LOG_DATA, "process_next", ctx, + "unexpected client data"); rc = 0; } @@ -649,7 +650,7 @@ process_request (assuan_context_t ctx) gpg_error_t rc; if (ctx->in_inquire) - return _assuan_error (GPG_ERR_ASS_NESTED_COMMANDS); + return _assuan_error (ctx, GPG_ERR_ASS_NESTED_COMMANDS); do { @@ -798,22 +799,22 @@ gpg_error_t assuan_set_okay_line (assuan_context_t ctx, const char *line) { if (!ctx) - return _assuan_error (GPG_ERR_ASS_INV_VALUE); + return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE); if (!line) { - _assuan_free (ctx->okay_line); + _assuan_free (ctx, ctx->okay_line); ctx->okay_line = NULL; } else { /* FIXME: we need to use gcry_is_secure() to test whether we should allocate the entire line in secure memory */ - char *buf = _assuan_malloc (3 + strlen(line) + 1); + char *buf = _assuan_malloc (ctx, 3 + strlen(line) + 1); if (!buf) - return _assuan_error (gpg_err_code_from_syserror ()); + return _assuan_error (ctx, gpg_err_code_from_syserror ()); strcpy (buf, "OK "); strcpy (buf+3, line); - _assuan_free (ctx->okay_line); + _assuan_free (ctx, ctx->okay_line); ctx->okay_line = buf; } return 0; @@ -831,7 +832,7 @@ assuan_write_status (assuan_context_t ctx, gpg_error_t ae; if ( !ctx || !keyword) - return _assuan_error (GPG_ERR_ASS_INV_VALUE); + return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE); if (!text) text = ""; @@ -847,7 +848,7 @@ assuan_write_status (assuan_context_t ctx, } ae = assuan_write_line (ctx, buffer); } - else if ( (helpbuf = _assuan_malloc (n)) ) + else if ( (helpbuf = _assuan_malloc (ctx, n)) ) { strcpy (helpbuf, "S "); strcat (helpbuf, keyword); @@ -857,7 +858,7 @@ assuan_write_status (assuan_context_t ctx, strcat (helpbuf, text); } ae = assuan_write_line (ctx, helpbuf); - _assuan_free (helpbuf); + _assuan_free (ctx, helpbuf); } else ae = 0; diff --git a/src/assuan-inquire.c b/src/assuan-inquire.c index 55ab280..dba7cb1 100644 --- a/src/assuan-inquire.c +++ b/src/assuan-inquire.c @@ -52,7 +52,8 @@ struct membuf the code with out of core checks. */ static void -init_membuf (struct membuf *mb, int initiallen, size_t maxlen) +init_membuf (assuan_context_t ctx, + struct membuf *mb, int initiallen, size_t maxlen) { mb->len = 0; mb->size = initiallen; @@ -60,13 +61,14 @@ init_membuf (struct membuf *mb, int initiallen, size_t maxlen) mb->too_large = 0; mb->maxlen = maxlen; /* we need to allocate one byte more for get_membuf */ - mb->buf = _assuan_malloc (initiallen+1); + mb->buf = _assuan_malloc (ctx, initiallen + 1); if (!mb->buf) mb->out_of_core = 1; } static void -put_membuf (struct membuf *mb, const void *buf, size_t len) +put_membuf (assuan_context_t ctx, + struct membuf *mb, const void *buf, size_t len) { if (mb->out_of_core || mb->too_large) return; @@ -83,7 +85,7 @@ put_membuf (struct membuf *mb, const void *buf, size_t len) mb->size += len + 1024; /* we need to allocate one byte more for get_membuf */ - p = _assuan_realloc (mb->buf, mb->size+1); + p = _assuan_realloc (ctx, mb->buf, mb->size + 1); if (!p) { mb->out_of_core = 1; @@ -96,13 +98,13 @@ put_membuf (struct membuf *mb, const void *buf, size_t len) } static void * -get_membuf (struct membuf *mb, size_t *len) +get_membuf (assuan_context_t ctx, struct membuf *mb, size_t *len) { char *p; if (mb->out_of_core || mb->too_large) { - _assuan_free (mb->buf); + _assuan_free (ctx, mb->buf); mb->buf = NULL; return NULL; } @@ -116,9 +118,9 @@ get_membuf (struct membuf *mb, size_t *len) } static void -free_membuf (struct membuf *mb) +free_membuf (assuan_context_t ctx, struct membuf *mb) { - _assuan_free (mb->buf); + _assuan_free (ctx, mb->buf); mb->buf = NULL; } @@ -148,20 +150,20 @@ assuan_inquire (assuan_context_t ctx, const char *keyword, int nodataexpected; if (!ctx || !keyword || (10 + strlen (keyword) >= sizeof (cmdbuf))) - return _assuan_error (GPG_ERR_ASS_INV_VALUE); + return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE); nodataexpected = !r_buffer && !r_length && !maxlen; if (!nodataexpected && (!r_buffer || !r_length)) - return _assuan_error (GPG_ERR_ASS_INV_VALUE); + return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE); if (!ctx->is_server) - return _assuan_error (GPG_ERR_ASS_NOT_A_SERVER); + return _assuan_error (ctx, GPG_ERR_ASS_NOT_A_SERVER); if (ctx->in_inquire) - return _assuan_error (GPG_ERR_ASS_NESTED_COMMANDS); + return _assuan_error (ctx, GPG_ERR_ASS_NESTED_COMMANDS); ctx->in_inquire = 1; if (nodataexpected) memset (&mb, 0, sizeof mb); /* avoid compiler warnings */ else - init_membuf (&mb, maxlen? maxlen:1024, maxlen); + init_membuf (ctx, &mb, maxlen? maxlen:1024, maxlen); strcpy (stpcpy (cmdbuf, "INQUIRE "), keyword); rc = assuan_write_line (ctx, cmdbuf); @@ -186,12 +188,12 @@ assuan_inquire (assuan_context_t ctx, const char *keyword, break; /* END command received*/ if (line[0] == 'C' && line[1] == 'A' && line[2] == 'N') { - rc = _assuan_error (GPG_ERR_ASS_CANCELED); + rc = _assuan_error (ctx, GPG_ERR_ASS_CANCELED); goto leave; } if (line[0] != 'D' || line[1] != ' ' || nodataexpected) { - rc = _assuan_error (GPG_ERR_ASS_UNEXPECTED_CMD); + rc = _assuan_error (ctx, GPG_ERR_ASS_UNEXPECTED_CMD); goto leave; } if (linelen < 3) @@ -204,7 +206,7 @@ assuan_inquire (assuan_context_t ctx, const char *keyword, { for (;linelen && *p != '%'; linelen--, p++) ; - put_membuf (&mb, line, p-line); + put_membuf (ctx, &mb, line, p-line); if (linelen > 2) { /* handle escaping */ unsigned char tmp[1]; @@ -212,27 +214,27 @@ assuan_inquire (assuan_context_t ctx, const char *keyword, *tmp = xtoi_2 (p); p += 2; linelen -= 3; - put_membuf (&mb, tmp, 1); + put_membuf (ctx, &mb, tmp, 1); } line = p; } if (mb.too_large) { - rc = _assuan_error (GPG_ERR_ASS_TOO_MUCH_DATA); + rc = _assuan_error (ctx, GPG_ERR_ASS_TOO_MUCH_DATA); goto leave; } } if (!nodataexpected) { - *r_buffer = get_membuf (&mb, r_length); + *r_buffer = get_membuf (ctx, &mb, r_length); if (!*r_buffer) - rc = _assuan_error (gpg_err_code_from_syserror ()); + rc = _assuan_error (ctx, gpg_err_code_from_syserror ()); } leave: if (!nodataexpected) - free_membuf (&mb); + free_membuf (ctx, &mb); ctx->in_inquire = 0; return rc; } @@ -245,7 +247,7 @@ _assuan_inquire_release (assuan_context_t ctx) { if (ctx->inquire_membuf) { - free_membuf (ctx->inquire_membuf); + free_membuf (ctx, ctx->inquire_membuf); free (ctx->inquire_membuf); } ctx->in_inquire = 0; @@ -268,7 +270,7 @@ _assuan_inquire_ext_cb (assuan_context_t ctx) if (line[0] == 'C' && line[1] == 'A' && line[2] == 'N') { - rc = _assuan_error (GPG_ERR_ASS_CANCELED); + rc = _assuan_error (ctx, GPG_ERR_ASS_CANCELED); goto leave; } if (line[0] == 'E' && line[1] == 'N' && line[2] == 'D' @@ -280,7 +282,7 @@ _assuan_inquire_ext_cb (assuan_context_t ctx) if (line[0] != 'D' || line[1] != ' ' || mb == NULL) { - rc = _assuan_error (GPG_ERR_ASS_UNEXPECTED_CMD); + rc = _assuan_error (ctx, GPG_ERR_ASS_UNEXPECTED_CMD); goto leave; } @@ -294,7 +296,7 @@ _assuan_inquire_ext_cb (assuan_context_t ctx) { for (;linelen && *p != '%'; linelen--, p++) ; - put_membuf (mb, line, p-line); + put_membuf (ctx, mb, line, p-line); if (linelen > 2) { /* handle escaping */ unsigned char tmp[1]; @@ -302,13 +304,13 @@ _assuan_inquire_ext_cb (assuan_context_t ctx) *tmp = xtoi_2 (p); p += 2; linelen -= 3; - put_membuf (mb, tmp, 1); + put_membuf (ctx, mb, tmp, 1); } line = p; } if (mb->too_large) { - rc = _assuan_error (GPG_ERR_ASS_TOO_MUCH_DATA); + rc = _assuan_error (ctx, GPG_ERR_ASS_TOO_MUCH_DATA); goto leave; } @@ -321,10 +323,10 @@ _assuan_inquire_ext_cb (assuan_context_t ctx) if (mb) { - buf = get_membuf (mb, &buf_len); + buf = get_membuf (ctx, mb, &buf_len); if (!buf) - rc = _assuan_error (gpg_err_code_from_syserror ()); - free_membuf (mb); + rc = _assuan_error (ctx, gpg_err_code_from_syserror ()); + free_membuf (ctx, mb); free (mb); ctx->inquire_membuf = NULL; } @@ -359,22 +361,22 @@ assuan_inquire_ext (assuan_context_t ctx, const char *keyword, size_t maxlen, char cmdbuf[LINELENGTH-10]; /* (10 = strlen ("INQUIRE ")+CR,LF) */ if (!ctx || !keyword || (10 + strlen (keyword) >= sizeof (cmdbuf))) - return _assuan_error (GPG_ERR_ASS_INV_VALUE); + return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE); if (!ctx->is_server) - return _assuan_error (GPG_ERR_ASS_NOT_A_SERVER); + return _assuan_error (ctx, GPG_ERR_ASS_NOT_A_SERVER); if (ctx->in_inquire) - return _assuan_error (GPG_ERR_ASS_NESTED_COMMANDS); + return _assuan_error (ctx, GPG_ERR_ASS_NESTED_COMMANDS); mb = malloc (sizeof (struct membuf)); if (!mb) - return _assuan_error (gpg_err_code_from_syserror ()); - init_membuf (mb, maxlen ? maxlen : 1024, maxlen); + return _assuan_error (ctx, gpg_err_code_from_syserror ()); + init_membuf (ctx, mb, maxlen ? maxlen : 1024, maxlen); strcpy (stpcpy (cmdbuf, "INQUIRE "), keyword); rc = assuan_write_line (ctx, cmdbuf); if (rc) { - free_membuf (mb); + free_membuf (ctx, mb); free (mb); return rc; } diff --git a/src/assuan-io-pth.c b/src/assuan-io-pth.c index e24d435..7e438e9 100644 --- a/src/assuan-io-pth.c +++ b/src/assuan-io-pth.c @@ -56,47 +56,24 @@ _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. */ - ssize_t retval; - - if (_assuan_io_hooks.read_hook - && _assuan_io_hooks.read_hook (ctx, ctx->inbound.fd, - buffer, size, &retval) == 1) - return retval; - return _assuan_io_read (ctx->inbound.fd, buffer, size); } ssize_t _assuan_simple_write (assuan_context_t ctx, const void *buffer, size_t size) { - ssize_t retval; - - if (_assuan_io_hooks.write_hook - && _assuan_io_hooks.write_hook (ctx, ctx->outbound.fd, - buffer, size, &retval) == 1) - return retval; return _assuan_io_write (ctx->outbound.fd, buffer, size); } ssize_t _assuan_io_read (assuan_fd_t fd, void *buffer, size_t size) { - ssize_t retval; - - if (_assuan_io_hooks.read_hook - && _assuan_io_hooks.read_hook (NULL, fd, buffer, size, &retval) == 1) - return retval; return pth_read ((int)fd, buffer, size); } ssize_t _assuan_io_write (assuan_fd_t fd, const void *buffer, size_t size) { - ssize_t retval; - - if (_assuan_io_hooks.write_hook - && _assuan_io_hooks.write_hook (NULL, fd, buffer, size, &retval) == 1) - return retval; return pth_write ((int)fd, buffer, size); } diff --git a/src/assuan-io.c b/src/assuan-io.c index 80e26ea..88accc3 100644 --- a/src/assuan-io.c +++ b/src/assuan-io.c @@ -95,25 +95,12 @@ do_io_read (assuan_fd_t fd, void *buffer, size_t size) ssize_t _assuan_io_read (assuan_fd_t fd, void *buffer, size_t size) { - ssize_t retval; - - if (_assuan_io_hooks.read_hook - && _assuan_io_hooks.read_hook (NULL, fd, buffer, size, &retval) == 1) - return retval; - return do_io_read (fd, buffer, size); } ssize_t _assuan_simple_read (assuan_context_t ctx, void *buffer, size_t size) { - ssize_t retval; - - if (_assuan_io_hooks.read_hook - && _assuan_io_hooks.read_hook (ctx, ctx->inbound.fd, - buffer, size, &retval) == 1) - return retval; - return do_io_read (ctx->inbound.fd, buffer, size); } @@ -156,24 +143,12 @@ do_io_write (assuan_fd_t fd, const void *buffer, size_t size) ssize_t _assuan_io_write (assuan_fd_t fd, const void *buffer, size_t size) { - ssize_t retval; - - if (_assuan_io_hooks.write_hook - && _assuan_io_hooks.write_hook (NULL, fd, buffer, size, &retval) == 1) - return retval; return do_io_write (fd, buffer, size); } ssize_t _assuan_simple_write (assuan_context_t ctx, const void *buffer, size_t size) { - ssize_t retval; - - if (_assuan_io_hooks.write_hook - && _assuan_io_hooks.write_hook (ctx, ctx->outbound.fd, - buffer, size, &retval) == 1) - return retval; - return do_io_write (ctx->outbound.fd, buffer, size); } diff --git a/src/assuan-listen.c b/src/assuan-listen.c index 7a17181..3f57922 100644 --- a/src/assuan-listen.c +++ b/src/assuan-listen.c @@ -33,17 +33,17 @@ gpg_error_t assuan_set_hello_line (assuan_context_t ctx, const char *line) { if (!ctx) - return _assuan_error (GPG_ERR_ASS_INV_VALUE); + return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE); if (!line) { - _assuan_free (ctx->hello_line); + _assuan_free (ctx, ctx->hello_line); ctx->hello_line = NULL; } else { - char *buf = _assuan_malloc (3+strlen(line)+1); + char *buf = _assuan_malloc (ctx, 3 + strlen (line) + 1); if (!buf) - return _assuan_error (gpg_err_code_from_syserror ()); + return _assuan_error (ctx, gpg_err_code_from_syserror ()); if (strchr (line, '\n')) strcpy (buf, line); else @@ -51,7 +51,7 @@ assuan_set_hello_line (assuan_context_t ctx, const char *line) strcpy (buf, "OK "); strcpy (buf+3, line); } - _assuan_free (ctx->hello_line); + _assuan_free (ctx, ctx->hello_line); ctx->hello_line = buf; } return 0; @@ -76,7 +76,7 @@ assuan_accept (assuan_context_t ctx) const char *p, *pend; if (!ctx) - return _assuan_error (GPG_ERR_ASS_INV_VALUE); + return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE); if (ctx->pipe_mode > 1) return -1; /* second invocation for pipemode -> terminate */ @@ -137,7 +137,7 @@ gpg_error_t assuan_close_input_fd (assuan_context_t ctx) { if (!ctx || ctx->input_fd == ASSUAN_INVALID_FD) - return _assuan_error (GPG_ERR_ASS_INV_VALUE); + return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE); _assuan_close (ctx->input_fd); ctx->input_fd = ASSUAN_INVALID_FD; return 0; @@ -149,7 +149,7 @@ gpg_error_t assuan_close_output_fd (assuan_context_t ctx) { if (!ctx || ctx->output_fd == ASSUAN_INVALID_FD) - return _assuan_error (GPG_ERR_ASS_INV_VALUE); + return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE); _assuan_close (ctx->output_fd); ctx->output_fd = ASSUAN_INVALID_FD; diff --git a/src/assuan-logging.c b/src/assuan-logging.c index 576f84a..0e57579 100644 --- a/src/assuan-logging.c +++ b/src/assuan-logging.c @@ -32,25 +32,17 @@ #include "assuan-defs.h" -static char prefix_buffer[80]; -static FILE *_assuan_log; -static int full_logging; + +/* The default log handler is useful for global logging, but it should + only be used by one user of libassuan at a time. Libraries that + use libassuan can register their own log handler. */ -void -_assuan_set_default_log_stream (FILE *fp) -{ - if (!_assuan_log) - { - _assuan_log = fp; - full_logging = !!getenv ("ASSUAN_FULL_LOGGING"); - } -} +/* A common prefix for all log messages. */ +static char prefix_buffer[80]; -void -assuan_set_assuan_log_stream (FILE *fp) -{ - _assuan_log = fp; -} +/* A global flag read from the environment to check if to enable full + logging of buffer data. */ +static int full_logging; /* Set the per context log stream. Also enable the default log stream @@ -63,20 +55,13 @@ assuan_set_log_stream (assuan_context_t ctx, FILE *fp) if (ctx->log_fp) fflush (ctx->log_fp); ctx->log_fp = fp; - _assuan_set_default_log_stream (fp); + full_logging = !!getenv ("ASSUAN_FULL_LOGGING"); } } -FILE * -assuan_get_assuan_log_stream (void) -{ - return _assuan_log ? _assuan_log : stderr; -} - - -/* Set the prefix to be used for logging to TEXT or - resets it to the default if TEXT is NULL. */ +/* Set the prefix to be used for logging to TEXT or resets it to the + default if TEXT is NULL. */ void assuan_set_assuan_log_prefix (const char *text) { @@ -89,38 +74,48 @@ assuan_set_assuan_log_prefix (const char *text) *prefix_buffer = 0; } + +/* Get the prefix to be used for logging. */ const char * assuan_get_assuan_log_prefix (void) { return prefix_buffer; } - -void -_assuan_log_printf (const char *format, ...) + +/* Default log handler. */ +int +_assuan_log_handler (assuan_context_t ctx, void *hook, unsigned int cat, + const char *msg) { - va_list arg_ptr; FILE *fp; const char *prf; - int save_errno = errno; - - fp = assuan_get_assuan_log_stream (); + int saved_errno = errno; + + /* For now. */ + if (msg == NULL) + return 1; + + fp = ctx->log_fp; + if (!fp) + return 0; + prf = assuan_get_assuan_log_prefix (); if (*prf) fprintf (fp, "%s[%u]: ", prf, (unsigned int)getpid ()); - va_start (arg_ptr, format); - vfprintf (fp, format, arg_ptr ); - va_end (arg_ptr); + fprintf (fp, "%s", msg); /* If the log stream is a file, the output would be buffered. This is bad for debugging, thus we flush the stream if FORMAT ends with a LF. */ - if (format && *format && format[strlen(format)-1] == '\n') + if (msg && *msg && msg[strlen (msg) - 1] == '\n') fflush (fp); - errno = save_errno; -} + errno = saved_errno; + return 0; +} + /* Dump a possibly binary string (used for debugging). Distinguish ascii text from binary and print it accordingly. This function takes FILE pointer arg because logging may be enabled on a per @@ -162,84 +157,3 @@ _assuan_log_print_buffer (FILE *fp, const void *buffer, size_t length) #endif } } - -/* Log a user supplied string. Escapes non-printable before - printing. */ -void -_assuan_log_sanitized_string (const char *string) -{ - const unsigned char *s = (const unsigned char *) string; - FILE *fp = assuan_get_assuan_log_stream (); - - if (! *s) - return; - -#ifdef HAVE_FLOCKFILE - flockfile (fp); -#endif - - for (; *s; s++) - { - int c = 0; - - switch (*s) - { - case '\r': - c = 'r'; - break; - - case '\n': - c = 'n'; - break; - - case '\f': - c = 'f'; - break; - - case '\v': - c = 'v'; - break; - - case '\b': - c = 'b'; - break; - - default: - if ((isascii (*s) && isprint (*s)) || (*s >= 0x80)) - putc_unlocked (*s, fp); - else - { - putc_unlocked ('\\', fp); - fprintf (fp, "x%02x", *s); - } - } - - if (c) - { - putc_unlocked ('\\', fp); - putc_unlocked (c, fp); - } - } - -#ifdef HAVE_FUNLOCKFILE - funlockfile (fp); -#endif -} - - - -#ifdef HAVE_W32_SYSTEM -const char * -_assuan_w32_strerror (int ec) -{ - static char strerr[256]; - - if (ec == -1) - ec = (int)GetLastError (); - FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, ec, - MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), - strerr, sizeof (strerr)-1, NULL); - return strerr; -} - -#endif /*HAVE_W32_SYSTEM*/ diff --git a/src/assuan-pipe-connect.c b/src/assuan-pipe-connect.c index 92d3926..15b5232 100644 --- a/src/assuan-pipe-connect.c +++ b/src/assuan-pipe-connect.c @@ -36,6 +36,7 @@ #endif #include "assuan-defs.h" +#include "debug.h" /* Hacks for Slowaris. */ #ifndef PF_LOCAL @@ -146,27 +147,22 @@ do_deinit (assuan_context_t ctx) /* Helper for pipe_connect. */ static gpg_error_t -initial_handshake (assuan_context_t *ctx) +initial_handshake (assuan_context_t ctx) { int okay, off; gpg_error_t err; - err = _assuan_read_from_server (*ctx, &okay, &off); + err = _assuan_read_from_server (ctx, &okay, &off); if (err) - _assuan_log_printf ("can't connect server: %s\n", - gpg_strerror (err)); + TRACE1 (ctx, ASSUAN_LOG_SYSIO, "initial_handshake", ctx, + "can't connect server: %s", gpg_strerror (err)); else if (okay != 1) { - _assuan_log_printf ("can't connect server: `%s'\n", - (*ctx)->inbound.line); - err = _assuan_error (GPG_ERR_ASS_CONNECT_FAILED); + TRACE1 (ctx, ASSUAN_LOG_SYSIO, "initial_handshake", ctx, + "can't connect server: `%s'", ctx->inbound.line); + err = _assuan_error (ctx, GPG_ERR_ASS_CONNECT_FAILED); } - if (err) - { - assuan_disconnect (*ctx); - *ctx = NULL; - } return err; } @@ -176,70 +172,57 @@ initial_handshake (assuan_context_t *ctx) /* Unix version of the pipe connection code. We use an extra macro to make ChangeLog entries easier. */ static gpg_error_t -pipe_connect_unix (assuan_context_t *ctx, +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) { - gpg_error_t err; 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 }; (void)flags; if (!ctx || !name || !argv || !argv[0]) - return _assuan_error (GPG_ERR_ASS_INV_VALUE); + return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE); fix_signals (); sprintf (mypidstr, "%lu", (unsigned long)getpid ()); if (pipe (rp) < 0) - return _assuan_error (GPG_ERR_ASS_GENERAL); + return _assuan_error (ctx, GPG_ERR_ASS_GENERAL); if (pipe (wp) < 0) { close (rp[0]); close (rp[1]); - return _assuan_error (GPG_ERR_ASS_GENERAL); + return _assuan_error (ctx, GPG_ERR_ASS_GENERAL); } - err = _assuan_new_context (ctx); - if (err) - { - close (rp[0]); - close (rp[1]); - close (wp[0]); - close (wp[1]); - return err; - } - (*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; - /* FIXME: For GPGME we should better use _gpgme_io_spawn. The PID stored here is actually soon useless. */ - (*ctx)->pid = fork (); - if ((*ctx)->pid < 0) + pid = fork (); + if (pid < 0) { close (rp[0]); close (rp[1]); close (wp[0]); close (wp[1]); - _assuan_release_context (*ctx); - return _assuan_error (GPG_ERR_ASS_GENERAL); + return _assuan_error (ctx, GPG_ERR_ASS_GENERAL); } - if ((*ctx)->pid == 0) + if (pid == 0) { #ifdef _ASSUAN_USE_DOUBLE_FORK - pid_t pid; + pid_t pid2; - if ((pid = fork ()) == 0) + if ((pid2 = fork ()) == 0) #endif { int i, n; @@ -254,8 +237,8 @@ pipe_connect_unix (assuan_context_t *ctx, { if (dup2 (rp[1], STDOUT_FILENO) == -1) { - _assuan_log_printf ("dup2 failed in child: %s\n", - strerror (errno)); + TRACE1 (ctx, ASSUAN_LOG_SYSIO, "pipe_connect_unix", ctx, + "dup2 failed in child: %s", strerror (errno)); _exit (4); } } @@ -263,8 +246,8 @@ pipe_connect_unix (assuan_context_t *ctx, { if (dup2 (wp[0], STDIN_FILENO) == -1) { - _assuan_log_printf ("dup2 failed in child: %s\n", - strerror (errno)); + TRACE1 (ctx, ASSUAN_LOG_SYSIO, "pipe_connect_unix", ctx, + "dup2 failed in child: %s", strerror (errno)); _exit (4); } } @@ -282,14 +265,14 @@ pipe_connect_unix (assuan_context_t *ctx, int fd = open ("/dev/null", O_WRONLY); if (fd == -1) { - _assuan_log_printf ("can't open `/dev/null': %s\n", - strerror (errno)); + 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) { - _assuan_log_printf ("dup2(dev/null, 2) failed: %s\n", - strerror (errno)); + TRACE1 (ctx, ASSUAN_LOG_SYSIO, "pipe_connect_unix", ctx, + "dup2(dev/null, 2) failed: %s", strerror (errno)); _exit (4); } } @@ -332,14 +315,14 @@ pipe_connect_unix (assuan_context_t *ctx, /* 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 (GPG_ERR_ASS_SERVER_START), + _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 (pid == -1) + if (pid2 == -1) _exit (1); else _exit (0); @@ -347,14 +330,25 @@ pipe_connect_unix (assuan_context_t *ctx, } #ifdef _ASSUAN_USE_DOUBLE_FORK - _assuan_waitpid ((*ctx)->pid, NULL, 0); - (*ctx)->pid = -1; + _assuan_waitpid (pid, NULL, 0); + pid = -1; #endif close (rp[1]); close (wp[0]); - return initial_handshake (ctx); + ctx->io = &io; + 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; + + rc = initial_handshake (ctx); + if (rc) + _assuan_reset (ctx); + return rc; } #endif /*!HAVE_W32_SYSTEM*/ @@ -363,8 +357,8 @@ pipe_connect_unix (assuan_context_t *ctx, /* 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 *const argv[], +socketpair_connect (assuan_context_t ctx, + const char *name, const char *argv[], int *fd_child_list, void (*atfork) (void *opaque, int reserved), void *atforkvalue) @@ -372,11 +366,12 @@ socketpair_connect (assuan_context_t *ctx, gpg_error_t err; int fds[2]; char mypidstr[50]; + pid_t pid; if (!ctx || (name && (!argv || !argv[0])) - || (!name && argv)) - return _assuan_error (GPG_ERR_ASS_INV_VALUE); + || (!name && !argv)) + return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE); fix_signals (); @@ -384,40 +379,26 @@ socketpair_connect (assuan_context_t *ctx, if ( socketpair (AF_LOCAL, SOCK_STREAM, 0, fds) ) { - _assuan_log_printf ("socketpair failed: %s\n", strerror (errno)); - return _assuan_error (GPG_ERR_ASS_GENERAL); + TRACE1 (ctx, ASSUAN_LOG_SYSIO, "socketpair_connect", ctx, + "socketpair failed: %s", strerror (errno)); + return _assuan_error (ctx, GPG_ERR_ASS_GENERAL); } - - err = _assuan_new_context (ctx); - if (err) - { - close (fds[0]); - close (fds[1]); - return err; - } - (*ctx)->pipe_mode = 1; - (*ctx)->inbound.fd = fds[0]; - (*ctx)->outbound.fd = fds[0]; - _assuan_init_uds_io (*ctx); - (*ctx)->deinit_handler = _assuan_uds_deinit; - (*ctx)->finish_handler = do_finish; - - (*ctx)->pid = fork (); - if ((*ctx)->pid < 0) + + pid = fork (); + if (pid < 0) { close (fds[0]); close (fds[1]); - _assuan_release_context (*ctx); - *ctx = NULL; - return _assuan_error (GPG_ERR_ASS_GENERAL); + /* FIXME: cleanup ctx */ + return _assuan_error (ctx, GPG_ERR_ASS_GENERAL); } - if ((*ctx)->pid == 0) + if (pid == 0) { #ifdef _ASSUAN_USE_DOUBLE_FORK - pid_t pid; + pid_t pid2; - if ((pid = fork ()) == 0) + if ((pid2 = fork ()) == 0) #endif { int fd, i, n; @@ -431,15 +412,15 @@ socketpair_connect (assuan_context_t *ctx, fd = open ("/dev/null", O_RDONLY); if (fd == -1 || dup2 (fd, STDIN_FILENO) == -1) { - _assuan_log_printf ("dup2(dev/null) failed: %s\n", - strerror (errno)); + 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) { - _assuan_log_printf ("dup2(dev/null) failed: %s\n", - strerror (errno)); + TRACE1 (ctx, ASSUAN_LOG_SYSIO, "socketpair_connect", ctx, + "dup2(dev/null) failed: %s", strerror (errno)); _exit (4); } @@ -456,8 +437,8 @@ socketpair_connect (assuan_context_t *ctx, fd = open ("/dev/null", O_WRONLY); if (fd == -1 || dup2 (fd, STDERR_FILENO) == -1) { - _assuan_log_printf ("dup2(dev/null) failed: %s\n", - strerror (errno)); + TRACE1 (ctx, ASSUAN_LOG_SYSIO, "socketpair_connect", ctx, + "dup2(dev/null) failed: %s", strerror (errno)); _exit (4); } } @@ -497,46 +478,60 @@ socketpair_connect (assuan_context_t *ctx, sprintf (mypidstr, "%d", fds[1]); if (setenv ("_assuan_connection_fd", mypidstr, 1)) { - _assuan_log_printf ("setenv failed: %s\n", strerror (errno)); + TRACE1 (ctx, ASSUAN_LOG_SYSIO, "socketpair_connect", ctx, + "setenv failed: %s", strerror (errno)); _exit (4); } - if (!name && !argv) + if (!name) { /* No name and no args given, thus we don't do an exec but continue the forked process. */ - _assuan_release_context (*ctx); - *ctx = NULL; - return 0; + *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 (GPG_ERR_ASS_SERVER_START), + _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 (pid == -1) + if (pid2 == -1) _exit (1); else _exit (0); #endif } + if (! name) + *argv = "client"; #ifdef _ASSUAN_USE_DOUBLE_FORK - _assuan_waitpid ((*ctx)->pid, NULL, 0); - (*ctx)->pid = -1; + _assuan_waitpid (pid, NULL, 0); + pid = -1; #endif close (fds[1]); + + ctx->pipe_mode = 1; + ctx->inbound.fd = fds[0]; + ctx->outbound.fd = fds[0]; + ctx->deinit_handler = _assuan_uds_deinit; + ctx->finish_handler = do_finish; + _assuan_init_uds_io (ctx); - return initial_handshake (ctx); + err = initial_handshake (ctx); + if (err) + _assuan_reset (ctx); + return err; } #endif /*!HAVE_W32_SYSTEM*/ @@ -598,7 +593,8 @@ build_w32_commandline (const char * const *argv, char **cmdline) #ifdef HAVE_W32_SYSTEM /* Create pipe where one end end is inheritable. */ static int -create_inheritable_pipe (assuan_fd_t filedes[2], int for_write) +create_inheritable_pipe (assuan_context_t ctx, + assuan_fd_t filedes[2], int for_write) { HANDLE r, w, h; SECURITY_ATTRIBUTES sec_attr; @@ -609,7 +605,8 @@ create_inheritable_pipe (assuan_fd_t filedes[2], int for_write) if (!CreatePipe (&r, &w, &sec_attr, 0)) { - _assuan_log_printf ("CreatePipe failed: %s\n", w32_strerror (-1)); + TRACE1 (ctx, ASSUAN_LOG_SYSIO, "create_inheritable_pipe", ctx, + "CreatePipe failed: %s", w32_strerror (ctx, -1)); return -1; } @@ -617,7 +614,8 @@ create_inheritable_pipe (assuan_fd_t filedes[2], int for_write) GetCurrentProcess(), &h, 0, TRUE, DUPLICATE_SAME_ACCESS )) { - _assuan_log_printf ("DuplicateHandle failed: %s\n", w32_strerror (-1)); + TRACE1 (ctx, ASSUAN_LOG_SYSIO, "create_inheritable_pipe", ctx, + "DuplicateHandle failed: %s", w32_strerror (ctx, -1)); CloseHandle (r); CloseHandle (w); return -1; @@ -644,7 +642,7 @@ create_inheritable_pipe (assuan_fd_t filedes[2], int for_write) #define pipe_connect pipe_connect_w32 /* W32 version of the pipe connection code. */ static gpg_error_t -pipe_connect_w32 (assuan_context_t *ctx, +pipe_connect_w32 (assuan_context_t ctx, const char *name, const char *const argv[], int *fd_child_list, void (*atfork) (void *opaque, int reserved), @@ -666,9 +664,11 @@ pipe_connect_w32 (assuan_context_t *ctx, 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 (GPG_ERR_ASS_INV_VALUE); + return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE); fix_signals (); @@ -676,41 +676,23 @@ pipe_connect_w32 (assuan_context_t *ctx, /* Build the command line. */ if (build_w32_commandline (argv, &cmdline)) - return _assuan_error (gpg_err_code_from_syserror ()); + return _assuan_error (ctx, gpg_err_code_from_syserror ()); /* Create thew two pipes. */ - if (create_inheritable_pipe (rp, 0)) + if (create_inheritable_pipe (ctx, rp, 0)) { _assuan_free (cmdline); - return _assuan_error (GPG_ERR_ASS_GENERAL); + return _assuan_error (ctx, GPG_ERR_ASS_GENERAL); } - if (create_inheritable_pipe (wp, 1)) + if (create_inheritable_pipe (ctx, wp, 1)) { CloseHandle (rp[0]); CloseHandle (rp[1]); _assuan_free (cmdline); - return _assuan_error (GPG_ERR_ASS_GENERAL); + return _assuan_error (ctx, GPG_ERR_ASS_GENERAL); } - - err = _assuan_new_context (ctx); - if (err) - { - CloseHandle (rp[0]); - CloseHandle (rp[1]); - CloseHandle (wp[0]); - CloseHandle (wp[1]); - _assuan_free (cmdline); - return _assuan_error (GPG_ERR_ASS_GENERAL); - } - - (*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; - /* fixme: Actually we should set the "_assuan_pipe_connect_pid" env variable. However this requires us to write a full environment @@ -746,13 +728,14 @@ pipe_connect_w32 (assuan_context_t *ctx, NULL, OPEN_EXISTING, 0, NULL); if (nullfd == INVALID_HANDLE_VALUE) { - _assuan_log_printf ("can't open `nul': %s\n", w32_strerror (-1)); + TRACE1 (ctx, ASSUAN_LOG_SYSIO, "pipe_connect_w32", ctx, + "can't open `nul': %s", w32_strerror (ctx, -1)); CloseHandle (rp[0]); CloseHandle (rp[1]); CloseHandle (wp[0]); CloseHandle (wp[1]); _assuan_free (cmdline); - _assuan_release_context (*ctx); + /* FIXME: Cleanup? */ return -1; } si.hStdError = nullfd; @@ -781,7 +764,8 @@ pipe_connect_w32 (assuan_context_t *ctx, &pi /* Returns process information. */ )) { - _assuan_log_printf ("CreateProcess failed: %s\n", w32_strerror (-1)); + TRACE1 (ctx, ASSUAN_LOG_SYSIO, "pipe_connect_w32", ctx, + "CreateProcess failed: %s", w32_strerror (ctx, -1)); CloseHandle (rp[0]); CloseHandle (rp[1]); CloseHandle (wp[0]); @@ -789,8 +773,8 @@ pipe_connect_w32 (assuan_context_t *ctx, if (nullfd != INVALID_HANDLE_VALUE) CloseHandle (nullfd); _assuan_free (cmdline); - _assuan_release_context (*ctx); - return _assuan_error (GPG_ERR_ASS_GENERAL); + /* FIXME: Cleanup? */ + return _assuan_error (ctx, GPG_ERR_ASS_GENERAL); } _assuan_free (cmdline); cmdline = NULL; @@ -810,9 +794,20 @@ pipe_connect_w32 (assuan_context_t *ctx, ResumeThread (pi.hThread); CloseHandle (pi.hThread); - (*ctx)->pid = (pid_t) pi.hProcess; - return initial_handshake (ctx); + 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*/ @@ -822,8 +817,8 @@ pipe_connect_w32 (assuan_context_t *ctx, vector in ARGV. FD_CHILD_LIST is a -1 terminated list of file descriptors not to close in the child. */ gpg_error_t -assuan_pipe_connect (assuan_context_t *ctx, const char *name, - const char *const argv[], int *fd_child_list) +assuan_pipe_connect (assuan_context_t ctx, const char *name, + const char *argv[], int *fd_child_list) { return pipe_connect (ctx, name, argv, fd_child_list, NULL, NULL, 0); } @@ -852,14 +847,15 @@ assuan_pipe_connect (assuan_context_t *ctx, const char *name, console window when starting the server - If NAME as well as ARGV are NULL, no exec is done but the same - process is continued. However all file descriptors are closed and - some special environment variables are set. To let the caller - detect whether the child or the parent continues, the child returns - a CTX of NULL. */ + If NAME is NULL, no exec is done but the same process is continued. + However all file descriptors are closed and some special + environment variables are set. To let the caller detect whether the + child or the parent continues, the child returns "client" or + "server" in *ARGV (but it is sufficient to check only the first + character). */ gpg_error_t -assuan_pipe_connect_ext (assuan_context_t *ctx, - const char *name, const char *const argv[], +assuan_pipe_connect_ext (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) @@ -867,7 +863,7 @@ assuan_pipe_connect_ext (assuan_context_t *ctx, if ((flags & 1)) { #ifdef HAVE_W32_SYSTEM - return _assuan_error (GPG_ERR_NOT_IMPLEMENTED); + return _assuan_error (ctx, GPG_ERR_NOT_IMPLEMENTED); #else return socketpair_connect (ctx, name, argv, fd_child_list, atfork, atforkvalue); @@ -877,4 +873,3 @@ 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 a732db7..3c30d48 100644 --- a/src/assuan-pipe-server.c +++ b/src/assuan-pipe-server.c @@ -47,48 +47,10 @@ accept_connection (assuan_context_t ctx) return 0; } -static gpg_error_t +static void finish_connection (assuan_context_t ctx) { /* This is a NOP for a pipe server */ - return 0; -} - -/* Create a new context. Note that the handlers are set up for a pipe - server/client - this way we don't need extra dummy functions */ -gpg_error_t -_assuan_new_context (assuan_context_t *r_ctx) -{ - static struct assuan_io io = { _assuan_simple_read, - _assuan_simple_write, - 0, 0 }; - - assuan_context_t ctx; - gpg_error_t rc; - - *r_ctx = NULL; - ctx = _assuan_calloc (1, sizeof *ctx); - if (!ctx) - return _assuan_error (gpg_err_code_from_syserror ()); - ctx->input_fd = ASSUAN_INVALID_FD; - ctx->output_fd = ASSUAN_INVALID_FD; - - ctx->inbound.fd = ASSUAN_INVALID_FD; - ctx->outbound.fd = ASSUAN_INVALID_FD; - ctx->io = &io; - - ctx->listen_fd = ASSUAN_INVALID_FD; - /* Use the pipe server handler as a default. */ - ctx->deinit_handler = deinit_pipe_server; - ctx->accept_handler = accept_connection; - ctx->finish_handler = finish_connection; - - rc = _assuan_register_std_commands (ctx); - if (rc) - _assuan_free (ctx); - else - *r_ctx = ctx; - return rc; } @@ -107,86 +69,92 @@ is_valid_socket (const char *s) gpg_error_t -assuan_init_pipe_server (assuan_context_t *r_ctx, int filedes[2]) +assuan_init_pipe_server (assuan_context_t ctx, int filedes[2]) { - int rc; + const char *s; + unsigned long ul; + gpg_error_t rc; + 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_new_context (r_ctx); - if (!rc) - { - assuan_context_t ctx = *r_ctx; - const char *s; - unsigned long ul; + rc = _assuan_register_std_commands (ctx); + if (rc) + return rc; - ctx->is_server = 1; #ifdef HAVE_W32_SYSTEM - /* MS Windows has so many different types of handle that one - needs to tranlsate them at many place forth and back. Also - make sure that the file descriptors are in binary mode. */ - setmode (filedes[0], O_BINARY); - setmode (filedes[1], O_BINARY); - ctx->inbound.fd = (void*)_get_osfhandle (filedes[0]); - ctx->outbound.fd = (void*)_get_osfhandle (filedes[1]); + /* MS Windows has so many different types of handle that one needs + to tranlsate them at many place forth and back. Also make sure + that the file descriptors are in binary mode. */ + setmode (filedes[0], O_BINARY); + setmode (filedes[1], O_BINARY); + infd = (void*)_get_osfhandle (filedes[0]); + outfd = (void*)_get_osfhandle (filedes[1]); #else - s = getenv ("_assuan_connection_fd"); - if (s && *s && is_valid_socket (s) ) - { - /* Well, we are called with an bi-directional file - descriptor. Prepare for using sendmsg/recvmsg. In this - case we ignore the passed file descriptors. */ - ctx->inbound.fd = ctx->outbound.fd = atoi (s); - _assuan_init_uds_io (ctx); - ctx->deinit_handler = _assuan_uds_deinit; - } - else if (filedes && filedes[0] != ASSUAN_INVALID_FD - && filedes[1] != ASSUAN_INVALID_FD ) - { - /* Standard pipe server. */ - ctx->inbound.fd = filedes[0]; - ctx->outbound.fd = filedes[1]; - } - else - { - _assuan_release_context (*r_ctx); - *r_ctx = NULL; - return _assuan_error (GPG_ERR_ASS_SERVER_START); - } -#endif - ctx->pipe_mode = 1; - - s = getenv ("_assuan_pipe_connect_pid"); - if (s && (ul=strtoul (s, NULL, 10)) && ul) - ctx->pid = (pid_t)ul; - else - ctx->pid = (pid_t)-1; + s = getenv ("_assuan_connection_fd"); + if (s && *s && is_valid_socket (s)) + { + /* Well, we are called with an bi-directional file descriptor. + Prepare for using sendmsg/recvmsg. In this case we ignore + the passed file descriptors. */ + infd = atoi (s); + outfd = atoi (s); + is_usd = 1; } - return rc; -} + else if (filedes && filedes[0] != ASSUAN_INVALID_FD + && filedes[1] != ASSUAN_INVALID_FD ) + { + /* Standard pipe server. */ + infd = filedes[0]; + outfd = filedes[1]; + } + else + return _assuan_error (ctx, GPG_ERR_ASS_SERVER_START); +#endif + ctx->is_server = 1; + ctx->engine.release = deinit_pipe_server; + ctx->pipe_mode = 1; -void -_assuan_release_context (assuan_context_t ctx) -{ - if (ctx) + s = getenv ("_assuan_pipe_connect_pid"); + if (s && (ul=strtoul (s, NULL, 10)) && ul) + ctx->pid = (pid_t)ul; + else + ctx->pid = (pid_t)-1; + ctx->accept_handler = accept_connection; + ctx->finish_handler = finish_connection; + ctx->deinit_handler = deinit_pipe_server; + ctx->inbound.fd = infd; + ctx->outbound.fd = outfd; + + if (is_usd) { - _assuan_inquire_release (ctx); - _assuan_free (ctx->hello_line); - _assuan_free (ctx->okay_line); - _assuan_free (ctx->cmdtbl); - _assuan_free (ctx); + _assuan_init_uds_io (ctx); + ctx->deinit_handler = _assuan_uds_deinit; } + else + ctx->io = &io; + + return 0; } + void -assuan_deinit_server (assuan_context_t ctx) +_assuan_deinit_server (assuan_context_t ctx) { - if (ctx) - { - /* We use this function pointer to avoid linking other server - when not needed but still allow for a generic deinit function. */ - ctx->deinit_handler (ctx); - ctx->deinit_handler = NULL; - _assuan_release_context (ctx); - } + /* We use this function pointer to avoid linking other server when + not needed but still allow for a generic deinit function. */ + ctx->deinit_handler (ctx); + ctx->deinit_handler = NULL; + + _assuan_inquire_release (ctx); + _assuan_free (ctx, ctx->hello_line); + ctx->hello_line = NULL; + _assuan_free (ctx, ctx->okay_line); + ctx->okay_line = NULL; + _assuan_free (ctx, ctx->cmdtbl); + ctx->cmdtbl = NULL; } diff --git a/src/assuan-socket-connect.c b/src/assuan-socket-connect.c index 8a8cb92..ac2df5b 100644 --- a/src/assuan-socket-connect.c +++ b/src/assuan-socket-connect.c @@ -33,6 +33,7 @@ #endif #include "assuan-defs.h" +#include "debug.h" /* Hacks for Slowaris. */ #ifndef PF_LOCAL @@ -52,18 +53,22 @@ #endif -static int +static void do_finish (assuan_context_t ctx) { if (ctx->inbound.fd != ASSUAN_INVALID_FD) { _assuan_close (ctx->inbound.fd); + ctx->inbound.fd = ASSUAN_INVALID_FD; + } + if (ctx->outbound.fd != ASSUAN_INVALID_FD) + { + _assuan_close (ctx->outbound.fd); + ctx->outbound.fd = ASSUAN_INVALID_FD; } - ctx->inbound.fd = ASSUAN_INVALID_FD; - ctx->outbound.fd = ASSUAN_INVALID_FD; - return 0; } + static void do_deinit (assuan_context_t ctx) { @@ -75,10 +80,10 @@ do_deinit (assuan_context_t ctx) Assuan context in CTX. SERVER_PID is currently not used but may become handy in the future. */ gpg_error_t -assuan_socket_connect (assuan_context_t *r_ctx, +assuan_socket_connect (assuan_context_t ctx, const char *name, pid_t server_pid) { - return assuan_socket_connect_ext (r_ctx, name, server_pid, 0); + return assuan_socket_connect_ext (ctx, name, server_pid, 0); } @@ -87,22 +92,21 @@ assuan_socket_connect (assuan_context_t *r_ctx, become handy in the future. With flags set to 1 sendmsg and recvmsg are used. */ gpg_error_t -assuan_socket_connect_ext (assuan_context_t *r_ctx, +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_context_t ctx; assuan_fd_t fd; struct sockaddr_un srvr_addr; size_t len; const char *s; - if (!r_ctx || !name) - return _assuan_error (GPG_ERR_ASS_INV_VALUE); - *r_ctx = NULL; + + if (!ctx || !name) + return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE); /* We require that the name starts with a slash, so that we eventually can reuse this function for other socket types. To @@ -111,23 +115,18 @@ assuan_socket_connect_ext (assuan_context_t *r_ctx, if (*s && s[1] == ':') s += 2; if (*s != DIRSEP_C && *s != '/') - return _assuan_error (GPG_ERR_ASS_INV_VALUE); + return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE); if (strlen (name)+1 >= sizeof srvr_addr.sun_path) - return _assuan_error (GPG_ERR_ASS_INV_VALUE); - - err = _assuan_new_context (&ctx); - if (err) - return err; - ctx->deinit_handler = ((flags&1))? _assuan_uds_deinit : do_deinit; - ctx->finish_handler = do_finish; + return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE); fd = _assuan_sock_new (PF_LOCAL, SOCK_STREAM, 0); if (fd == ASSUAN_INVALID_FD) { - _assuan_log_printf ("can't create socket: %s\n", strerror (errno)); - _assuan_release_context (ctx); - return _assuan_error (GPG_ERR_ASS_GENERAL); + TRACE1 (ctx, ASSUAN_LOG_SYSIO, "assuan_socket_connect_ext", ctx, + "can't create socket: %s", strerror (errno)); + /* FIXME: Cleanup */ + return _assuan_error (ctx, GPG_ERR_ASS_GENERAL); } memset (&srvr_addr, 0, sizeof srvr_addr); @@ -138,43 +137,46 @@ assuan_socket_connect_ext (assuan_context_t *r_ctx, if ( _assuan_sock_connect (fd, (struct sockaddr *) &srvr_addr, len) == -1 ) { - _assuan_log_printf ("can't connect to `%s': %s\n", - name, strerror (errno)); - _assuan_release_context (ctx); + 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); - return _assuan_error (GPG_ERR_ASS_CONNECT_FAILED); + return _assuan_error (ctx, GPG_ERR_ASS_CONNECT_FAILED); } - + + ctx->io = &io; + ctx->engine.release = _assuan_disconnect; + ctx->deinit_handler = ((flags&1))? _assuan_uds_deinit : do_deinit; + ctx->finish_handler = do_finish; ctx->inbound.fd = fd; ctx->outbound.fd = fd; - ctx->io = &io; - if ((flags&1)) + + if (flags & 1) _assuan_init_uds_io (ctx); - + /* initial handshake */ { int okay, off; err = _assuan_read_from_server (ctx, &okay, &off); if (err) - _assuan_log_printf ("can't connect to server: %s\n", - gpg_strerror (err)); + TRACE1 (ctx, ASSUAN_LOG_SYSIO, "assuan_socket_connect_ext", ctx, + "can't connect to server: %s\n", gpg_strerror (err)); else if (okay != 1) { - /*LOG ("can't connect to server: `");*/ - _assuan_log_sanitized_string (ctx->inbound.line); - fprintf (assuan_get_assuan_log_stream (), "'\n"); - err = _assuan_error (GPG_ERR_ASS_CONNECT_FAILED); + char *sname = _assuan_encode_c_string (ctx, ctx->inbound.line); + if (sname) + { + TRACE1 (ctx, ASSUAN_LOG_SYSIO, "assuan_socket_connect_ext", ctx, + "can't connect to server: %s", sname); + _assuan_free (ctx, sname); + } + err = _assuan_error (ctx, GPG_ERR_ASS_CONNECT_FAILED); } } - + if (err) - { - assuan_disconnect (ctx); - } - else - *r_ctx = ctx; - return 0; -} - + _assuan_reset (ctx); + return err; +} diff --git a/src/assuan-socket-server.c b/src/assuan-socket-server.c index a205b9e..b46a4e7 100644 --- a/src/assuan-socket-server.c +++ b/src/assuan-socket-server.c @@ -41,9 +41,6 @@ #include "assuan-defs.h" -static struct assuan_io io = { _assuan_simple_read, _assuan_simple_write, - NULL, NULL }; - static gpg_error_t accept_connection_bottom (assuan_context_t ctx) { @@ -80,7 +77,7 @@ accept_connection_bottom (assuan_context_t ctx) ctx->outbound.data.linelen = 0; ctx->outbound.data.error = 0; - ctx->confidential = 0; + ctx->flags.confidential = 0; return 0; } @@ -97,28 +94,32 @@ accept_connection (assuan_context_t ctx) (struct sockaddr*)&clnt_addr, &len )); if (fd == ASSUAN_INVALID_FD) { - return _assuan_error (gpg_err_code_from_syserror ()); + return _assuan_error (ctx, gpg_err_code_from_syserror ()); } if (_assuan_sock_check_nonce (fd, &ctx->listen_nonce)) { _assuan_close (fd); - return _assuan_error (GPG_ERR_ASS_ACCEPT_FAILED); + return _assuan_error (ctx, GPG_ERR_ASS_ACCEPT_FAILED); } ctx->connected_fd = fd; return accept_connection_bottom (ctx); } -static gpg_error_t + +static void finish_connection (assuan_context_t ctx) { if (ctx->inbound.fd != ASSUAN_INVALID_FD) { _assuan_close (ctx->inbound.fd); + ctx->inbound.fd = ASSUAN_INVALID_FD; + } + if (ctx->outbound.fd != ASSUAN_INVALID_FD) + { + _assuan_close (ctx->outbound.fd); + ctx->outbound.fd = ASSUAN_INVALID_FD; } - ctx->inbound.fd = ASSUAN_INVALID_FD; - ctx->outbound.fd = ASSUAN_INVALID_FD; - return 0; } @@ -126,14 +127,22 @@ static void deinit_socket_server (assuan_context_t ctx) { finish_connection (ctx); + + _assuan_inquire_release (ctx); + _assuan_free (ctx, ctx->hello_line); + ctx->hello_line = NULL; + _assuan_free (ctx, ctx->okay_line); + ctx->okay_line = NULL; + _assuan_free (ctx, ctx->cmdtbl); + ctx->cmdtbl = NULL; } /* Initialize a server for the socket LISTEN_FD which has already be put into listen mode */ gpg_error_t -assuan_init_socket_server (assuan_context_t *r_ctx, assuan_fd_t listen_fd) +assuan_init_socket_server (assuan_context_t ctx, assuan_fd_t listen_fd) { - return assuan_init_socket_server_ext (r_ctx, listen_fd, 0); + return assuan_init_socket_server_ext (ctx, listen_fd, 0); } @@ -142,18 +151,21 @@ assuan_init_socket_server (assuan_context_t *r_ctx, assuan_fd_t listen_fd) 1 - FD has already been accepted. */ gpg_error_t -assuan_init_socket_server_ext (assuan_context_t *r_ctx, assuan_fd_t fd, +assuan_init_socket_server_ext (assuan_context_t ctx, assuan_fd_t fd, unsigned int flags) { - assuan_context_t ctx; - int rc; + 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; - *r_ctx = NULL; - ctx = _assuan_calloc (1, sizeof *ctx); - if (!ctx) - return _assuan_error (gpg_err_code_from_syserror ()); + ctx->io = &io; + ctx->engine.release = deinit_socket_server; ctx->is_server = 1; - if ((flags & 2)) + if (flags & 2) ctx->pipe_mode = 1; /* We want a second accept to indicate EOF. */ ctx->input_fd = ASSUAN_INVALID_FD; ctx->output_fd = ASSUAN_INVALID_FD; @@ -177,15 +189,12 @@ assuan_init_socket_server_ext (assuan_context_t *r_ctx, assuan_fd_t fd, : accept_connection); ctx->finish_handler = finish_connection; - ctx->io = &io; if ((flags & 1)) _assuan_init_uds_io (ctx); rc = _assuan_register_std_commands (ctx); if (rc) - _assuan_free (ctx); - else - *r_ctx = ctx; + _assuan_reset (ctx); return rc; } diff --git a/src/assuan-uds.c b/src/assuan-uds.c index 9497992..1c2d106 100644 --- a/src/assuan-uds.c +++ b/src/assuan-uds.c @@ -41,6 +41,7 @@ #include <assert.h> #include "assuan-defs.h" +#include "debug.h" #ifdef USE_DESCRIPTOR_PASSING /* Provide replacement for missing CMSG maccros. We assume that @@ -75,7 +76,7 @@ uds_reader (assuan_context_t ctx, void *buf, size_t buflen) if (!ctx->uds.bufferallocated) { - ctx->uds.buffer = _assuan_malloc (2048); + ctx->uds.buffer = _assuan_malloc (ctx, 2048); if (!ctx->uds.buffer) return gpg_error_from_syserror (); ctx->uds.bufferallocated = 2048; @@ -121,15 +122,17 @@ uds_reader (assuan_context_t ctx, void *buf, size_t buflen) { if (cmptr->cmsg_level != SOL_SOCKET || cmptr->cmsg_type != SCM_RIGHTS) - _assuan_log_printf ("unexpected ancillary data received\n"); + TRACE0 (ctx, ASSUAN_LOG_SYSIO, "uds_reader", ctx, + "unexpected ancillary data received"); else { int fd = *((int*)CMSG_DATA (cmptr)); if (ctx->uds.pendingfdscount >= DIM (ctx->uds.pendingfds)) { - _assuan_log_printf ("too many descriptors pending - " - "closing received descriptor %d\n", fd); + TRACE1 (ctx, ASSUAN_LOG_SYSIO, "uds_reader", ctx, + "too many descriptors pending - " + "closing received descriptor %d", fd); _assuan_close (fd); } else @@ -232,14 +235,15 @@ uds_sendfd (assuan_context_t ctx, assuan_fd_t fd) if (len < 0) { int saved_errno = errno; - _assuan_log_printf ("uds_sendfd: %s\n", strerror (errno)); + TRACE1 (ctx, ASSUAN_LOG_SYSIO, "uds_sendfd", ctx, + "uds_sendfd: %s", strerror (errno)); errno = saved_errno; - return _assuan_error (gpg_err_code_from_syserror ()); + return _assuan_error (ctx, gpg_err_code_from_syserror ()); } else return 0; #else - return _assuan_error (GPG_ERR_NOT_IMPLEMENTED); + return _assuan_error (ctx, GPG_ERR_NOT_IMPLEMENTED); #endif } @@ -252,8 +256,9 @@ uds_receivefd (assuan_context_t ctx, assuan_fd_t *fd) if (!ctx->uds.pendingfdscount) { - _assuan_log_printf ("no pending file descriptors!\n"); - return _assuan_error (GPG_ERR_ASS_GENERAL); + TRACE0 (ctx, ASSUAN_LOG_SYSIO, "uds_receivefd", ctx, + "no pending file descriptors"); + return _assuan_error (ctx, GPG_ERR_ASS_GENERAL); } assert (ctx->uds.pendingfdscount <= DIM(ctx->uds.pendingfds)); @@ -264,7 +269,7 @@ uds_receivefd (assuan_context_t ctx, assuan_fd_t *fd) return 0; #else - return _assuan_error (GPG_ERR_NOT_IMPLEMENTED); + return _assuan_error (ctx, GPG_ERR_NOT_IMPLEMENTED); #endif } @@ -291,7 +296,7 @@ _assuan_uds_deinit (assuan_context_t ctx) { assert (ctx->uds.bufferallocated); ctx->uds.bufferallocated = 0; - _assuan_free (ctx->uds.buffer); + _assuan_free (ctx, ctx->uds.buffer); } _assuan_uds_close_fds (ctx); diff --git a/src/assuan-util.c b/src/assuan-util.c index e12b44e..e69de29 100644 --- a/src/assuan-util.c +++ b/src/assuan-util.c @@ -1,190 +0,0 @@ -/* assuan-util.c - Utility functions for Assuan - Copyright (C) 2001-2005, 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 <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <ctype.h> -#include <errno.h> - -#include "assuan-defs.h" - -static void *(*alloc_func)(size_t n) = malloc; -static void *(*realloc_func)(void *p, size_t n) = realloc; -static void (*free_func)(void*) = free; - -struct assuan_io_hooks _assuan_io_hooks; - - -void -assuan_set_malloc_hooks (void *(*new_alloc_func)(size_t n), - void *(*new_realloc_func)(void *p, size_t n), - void (*new_free_func)(void*)) -{ - alloc_func = new_alloc_func; - realloc_func = new_realloc_func; - free_func = new_free_func; -} - - -void -assuan_set_io_hooks (assuan_io_hooks_t io_hooks) -{ - _assuan_io_hooks.read_hook = NULL; - _assuan_io_hooks.write_hook = NULL; - if (io_hooks) - { - _assuan_io_hooks.read_hook = io_hooks->read_hook; - _assuan_io_hooks.write_hook = io_hooks->write_hook; - } -} - - -void * -_assuan_malloc (size_t n) -{ - return alloc_func (n); -} - -void * -_assuan_realloc (void *a, size_t n) -{ - return realloc_func (a, n); -} - -void * -_assuan_calloc (size_t n, size_t m) -{ - void *p; - size_t nbytes; - - nbytes = n * m; - if (m && nbytes / m != n) - { - errno = ENOMEM; - return NULL; - } - - p = _assuan_malloc (nbytes); - if (p) - memset (p, 0, nbytes); - return p; -} - -void -_assuan_free (void *p) -{ - if (p) - free_func (p); -} - - -/* Store the error in the context so that the error sending function - can take out a descriptive text. Inside the assuan code, use the - macro set_error instead of this function. */ -gpg_error_t -assuan_set_error (assuan_context_t ctx, gpg_error_t err, const char *text) -{ - ctx->err_no = err; - ctx->err_str = text; - return err; -} - -void -assuan_set_pointer (assuan_context_t ctx, void *pointer) -{ - if (ctx) - ctx->user_pointer = pointer; -} - -void * -assuan_get_pointer (assuan_context_t ctx) -{ - return ctx? ctx->user_pointer : NULL; -} - - -void -assuan_begin_confidential (assuan_context_t ctx) -{ - if (ctx) - { - ctx->confidential = 1; - } -} - -void -assuan_end_confidential (assuan_context_t ctx) -{ - if (ctx) - { - ctx->confidential = 0; - } -} - - -void -assuan_set_io_monitor (assuan_context_t ctx, - unsigned int (*monitor)(assuan_context_t ctx, - int direction, - const char *line, - size_t linelen)) -{ - if (ctx) - { - ctx->io_monitor = monitor; - } -} - - - - -/* 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; - see the description of the type assuan_flag_t for details. */ -void -assuan_set_flag (assuan_context_t ctx, assuan_flag_t flag, int value) -{ - if (!ctx) - return; - switch (flag) - { - case ASSUAN_NO_WAITPID: ctx->flags.no_waitpid = value; break; - case ASSUAN_CONFIDENTIAL: ctx->confidential = value; break; - } -} - -/* Return the VALUE of FLAG in context CTX. */ -int -assuan_get_flag (assuan_context_t ctx, assuan_flag_t flag) -{ - if (!ctx) - return 0; - switch (flag) - { - case ASSUAN_NO_WAITPID: return ctx->flags.no_waitpid; - case ASSUAN_CONFIDENTIAL: return ctx->confidential; - } - return 0; -} - diff --git a/src/assuan.c b/src/assuan.c new file mode 100644 index 0000000..d2c9f17 --- /dev/null +++ b/src/assuan.c @@ -0,0 +1,177 @@ +/* assuan.c - Global interface (not specific to context). + Copyright (C) 2009 Free Software Foundation, Inc. + + This file is part of Assuan. + + Assuan is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + Assuan is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> + +#include "assuan-defs.h" +#include "debug.h" + + +/* Global default state. */ + +/* The default error source gor generated error codes. */ +static gpg_err_source_t _assuan_default_err_source = GPG_ERR_SOURCE_USER_1; + +/* The default memory management functions. */ +static struct assuan_malloc_hooks _assuan_default_malloc_hooks = + { malloc, realloc, free }; + +/* The default logging handler. */ +static assuan_log_cb_t _assuan_default_log_cb = _assuan_log_handler; +static void *_assuan_default_log_cb_data = NULL; + + +/* Set the default gpg error source. */ +void +assuan_set_gpg_err_source (gpg_err_source_t errsource) +{ + _assuan_default_err_source = errsource; +} + + +/* Get the default gpg error source. */ +gpg_err_source_t +assuan_get_gpg_err_source (void) +{ + return _assuan_default_err_source; +} + + +/* Set the default malloc hooks. */ +void +assuan_set_malloc_hooks (assuan_malloc_hooks_t malloc_hooks) +{ + _assuan_default_malloc_hooks = *malloc_hooks; +} + + +/* Get the default malloc hooks. */ +assuan_malloc_hooks_t +assuan_get_malloc_hooks (void) +{ + return &_assuan_default_malloc_hooks; +} + + +/* Set the default log callback handler. */ +void +assuan_set_log_cb (assuan_log_cb_t log_cb, void *log_cb_data) +{ + _assuan_default_log_cb = log_cb; + _assuan_default_log_cb_data = log_cb_data; +} + + +/* Get the default log callback handler. */ +void +assuan_get_log_cb (assuan_log_cb_t *log_cb, void **log_cb_data) +{ + *log_cb = _assuan_default_log_cb; + *log_cb_data = _assuan_default_log_cb_data; +} + + +/* Create a new Assuan context. The initial parameters are all needed + in the creation of the context. */ +gpg_error_t +assuan_new_ext (assuan_context_t *r_ctx, gpg_err_source_t err_source, + assuan_malloc_hooks_t malloc_hooks, assuan_log_cb_t log_cb, + void *log_cb_data) +{ + struct assuan_context_s wctx; + assuan_context_t ctx; + + /* Set up a working context so we can use standard functions. */ + memset (&wctx, 0, sizeof (wctx)); + wctx.err_source = err_source; + wctx.malloc_hooks = *malloc_hooks; + wctx.log_cb = log_cb; + wctx.log_cb_data = log_cb_data; + + /* Need a new block for the trace macros to work. */ + { + TRACE_BEG8 (&wctx, ASSUAN_LOG_CTX, "assuan_new_ext", r_ctx, + "err_source = %i (%s), malloc_hooks = %p (%p, %p, %p), " + "log_cb = %p, log_cb_data = %p", err_source, + gpg_strsource (err_source), malloc_hooks, malloc_hooks->malloc, + malloc_hooks->realloc, malloc_hooks->free, log_cb, log_cb_data); + + *r_ctx = NULL; + ctx = _assuan_malloc (&wctx, sizeof (*ctx)); + if (!ctx) + return TRACE_ERR (gpg_err_code_from_syserror ()); + + memcpy (ctx, &wctx, sizeof (*ctx)); + + /* FIXME: Delegate to subsystems/engines, as the FDs are not our + responsibility (we don't deallocate them, for example). */ + ctx->input_fd = ASSUAN_INVALID_FD; + ctx->output_fd = ASSUAN_INVALID_FD; + ctx->inbound.fd = ASSUAN_INVALID_FD; + ctx->outbound.fd = ASSUAN_INVALID_FD; + ctx->listen_fd = ASSUAN_INVALID_FD; + + *r_ctx = ctx; + + return TRACE_SUC1 ("ctx=%p", ctx); + } +} + + +/* Create a new context with default arguments. */ +gpg_error_t +assuan_new (assuan_context_t *r_ctx) +{ + return assuan_new_ext (r_ctx, _assuan_default_err_source, + &_assuan_default_malloc_hooks, + _assuan_default_log_cb, + _assuan_default_log_cb_data); +} + + +/* Release all resources associated with an engine operation. */ +void +_assuan_reset (assuan_context_t ctx) +{ + if (ctx->engine.release) + { + (*ctx->engine.release) (ctx); + ctx->engine.release = NULL; + } + + // FIXME: Clean standard commands +} + + +/* Release all resources associated with the given context. */ +void +assuan_release (assuan_context_t 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); +} diff --git a/src/assuan.h b/src/assuan.h index 105862f..9e7db89 100644 --- a/src/assuan.h +++ b/src/assuan.h @@ -1,5 +1,5 @@ /* assuan.h - Definitions for the Assuan IPC library - * Copyright (C) 2001-2003, 2005, 2007-2009 Free Software Foundation, Inc. + Copyright (C) 2001-2003, 2005, 2007-2009 Free Software Foundation, Inc. This file is part of Assuan. @@ -23,24 +23,21 @@ #include <stdio.h> #include <sys/types.h> #include <unistd.h> +#include <stdarg.h> + #ifndef _ASSUAN_NO_SOCKET_WRAPPER #ifdef _WIN32 #include <ws2tcpip.h> #else #include <sys/socket.h> #endif - -#include <gpg-error.h> - #endif /*!_ASSUAN_NO_SOCKET_WRAPPER*/ -/* To use this file with libraries the following macros are useful: +#include <gpg-error.h> - #define _ASSUAN_EXT_SYM_PREFIX _foo_ - - This prefixes all external symbols with "_foo_". +/* Compile time configuration: - #define _ASSUAN_NO_SOCKET_WRAPPER + #define _ASSUAN_NO_SOCKET_WRAPPER Do not include the definitions for the socket wrapper feature. @@ -62,137 +59,6 @@ */ -#ifdef _ASSUAN_EXT_SYM_PREFIX -#define _ASSUAN_PREFIX1(x,y) x ## y -#define _ASSUAN_PREFIX2(x,y) _ASSUAN_PREFIX1(x,y) -#define _ASSUAN_PREFIX(x) _ASSUAN_PREFIX2(_ASSUAN_EXT_SYM_PREFIX,x) -#define assuan_ _ASSUAN_PREFIX(assuan_) -#define assuan_register_command _ASSUAN_PREFIX(assuan_register_command) -#define assuan_register_post_cmd_notify \ - _ASSUAN_PREFIX(assuan_register_post_cmd_notify) -#define assuan_register_bye_notify _ASSUAN_PREFIX(assuan_register_bye_notify) -#define assuan_register_reset_notify \ - _ASSUAN_PREFIX(assuan_register_reset_notify) -#define assuan_register_cancel_notify \ - _ASSUAN_PREFIX(assuan_register_cancel_notify) -#define assuan_register_input_notify \ - _ASSUAN_PREFIX(assuan_register_input_notify) -#define assuan_register_output_notify \ - _ASSUAN_PREFIX(assuan_register_output_notify) -#define assuan_register_option_handler \ - _ASSUAN_PREFIX(assuan_register_option_handler) -#define assuan_process _ASSUAN_PREFIX(assuan_process) -#define assuan_process_next _ASSUAN_PREFIX(assuan_process_next) -#define assuan_process_done _ASSUAN_PREFIX(assuan_process_done) -#define assuan_get_active_fds _ASSUAN_PREFIX(assuan_get_active_fds) -#define assuan_get_data_fp _ASSUAN_PREFIX(assuan_get_data_fp) -#define assuan_set_okay_line _ASSUAN_PREFIX(assuan_set_okay_line) -#define assuan_write_status _ASSUAN_PREFIX(assuan_write_status) -#define assuan_command_parse_fd _ASSUAN_PREFIX(assuan_command_parse_fd) -#define assuan_set_hello_line _ASSUAN_PREFIX(assuan_set_hello_line) -#define assuan_accept _ASSUAN_PREFIX(assuan_accept) -#define assuan_get_input_fd _ASSUAN_PREFIX(assuan_get_input_fd) -#define assuan_get_output_fd _ASSUAN_PREFIX(assuan_get_output_fd) -#define assuan_close_input_fd _ASSUAN_PREFIX(assuan_close_input_fd) -#define assuan_close_output_fd _ASSUAN_PREFIX(assuan_close_output_fd) -#define assuan_init_pipe_server _ASSUAN_PREFIX(assuan_init_pipe_server) -#define assuan_deinit_server _ASSUAN_PREFIX(assuan_deinit_server) -#define assuan_init_socket_server _ASSUAN_PREFIX(assuan_init_socket_server) -#define assuan_init_socket_server_ext \ - _ASSUAN_PREFIX(assuan_init_socket_server_ext) -#define assuan_pipe_connect _ASSUAN_PREFIX(assuan_pipe_connect) -#define assuan_pipe_connect_ext _ASSUAN_PREFIX(assuan_pipe_connect_ext) -#define assuan_socket_connect _ASSUAN_PREFIX(assuan_socket_connect) -#define assuan_socket_connect_ext _ASSUAN_PREFIX(assuan_socket_connect_ext) -#define assuan_disconnect _ASSUAN_PREFIX(assuan_disconnect) -#define assuan_get_pid _ASSUAN_PREFIX(assuan_get_pid) -#define assuan_get_peercred _ASSUAN_PREFIX(assuan_get_peercred) -#define assuan_transact _ASSUAN_PREFIX(assuan_transact) -#define assuan_inquire _ASSUAN_PREFIX(assuan_inquire) -#define assuan_inquire_ext _ASSUAN_PREFIX(assuan_inquire_ext) -#define assuan_read_line _ASSUAN_PREFIX(assuan_read_line) -#define assuan_pending_line _ASSUAN_PREFIX(assuan_pending_line) -#define assuan_write_line _ASSUAN_PREFIX(assuan_write_line) -#define assuan_send_data _ASSUAN_PREFIX(assuan_send_data) -#define assuan_sendfd _ASSUAN_PREFIX(assuan_sendfd) -#define assuan_receivefd _ASSUAN_PREFIX(assuan_receivefd) -#define assuan_set_malloc_hooks _ASSUAN_PREFIX(assuan_set_malloc_hooks) -#define assuan_set_io_hooks _ASSUAN_PREFIX(assuan_set_io_hooks) -#define assuan_set_log_stream _ASSUAN_PREFIX(assuan_set_log_stream) -#define assuan_set_error _ASSUAN_PREFIX(assuan_set_error) -#define assuan_set_pointer _ASSUAN_PREFIX(assuan_set_pointer) -#define assuan_get_pointer _ASSUAN_PREFIX(assuan_get_pointer) -#define assuan_set_io_monitor _ASSUAN_PREFIX(assuan_set_io_monitor) -#define assuan_begin_confidential _ASSUAN_PREFIX(assuan_begin_confidential) -#define assuan_end_confidential _ASSUAN_PREFIX(assuan_end_confidential) -#define assuan_set_assuan_err_source \ - _ASSUAN_PREFIX(assuan_set_assuan_err_source) -#define assuan_set_assuan_log_stream \ - _ASSUAN_PREFIX(assuan_set_assuan_log_stream) -#define assuan_get_assuan_log_stream \ - _ASSUAN_PREFIX(assuan_get_assuan_log_stream) -#define assuan_get_assuan_log_prefix \ - _ASSUAN_PREFIX(assuan_get_assuan_log_prefix) -#define assuan_set_flag _ASSUAN_PREFIX(assuan_set_flag) -#define assuan_get_flag _ASSUAN_PREFIX(assuan_get_flag) -#define assuan_set_assuan_log_prefix \ - _ASSUAN_PREFIX(assuan_set_assuan_log_prefix) -#define assuan_sock_close _ASSUAN_PREFIX(assuan_sock_close) -#define assuan_sock_new _ASSUAN_PREFIX(assuan_sock_new) -#define assuan_sock_connect _ASSUAN_PREFIX(assuan_sock_connect) -#define assuan_sock_bind _ASSUAN_PREFIX(assuan_sock_bind) -#define assuan_sock_get_nonce _ASSUAN_PREFIX(assuan_sock_get_nonce) -#define assuan_sock_check_nonce _ASSUAN_PREFIX(assuan_sock_check_nonce) - - -/* And now the internal functions, argh... */ -#define _assuan_read_line _ASSUAN_PREFIX(_assuan_read_line) -#define _assuan_cookie_write_data _ASSUAN_PREFIX(_assuan_cookie_write_data) -#define _assuan_cookie_write_flush _ASSUAN_PREFIX(_assuan_cookie_write_flush) -#define _assuan_read_from_server _ASSUAN_PREFIX(_assuan_read_from_server) -#define _assuan_domain_init _ASSUAN_PREFIX(_assuan_domain_init) -#define _assuan_register_std_commands \ - _ASSUAN_PREFIX(_assuan_register_std_commands) -#define _assuan_simple_read _ASSUAN_PREFIX(_assuan_simple_read) -#define _assuan_simple_write _ASSUAN_PREFIX(_assuan_simple_write) -#define _assuan_io_read _ASSUAN_PREFIX(_assuan_io_read) -#define _assuan_io_write _ASSUAN_PREFIX(_assuan_io_write) -#define _assuan_io_hooks _ASSUAN_PREFIX(_assuan_io_hooks) -#define _assuan_new_context _ASSUAN_PREFIX(_assuan_new_context) -#define _assuan_release_context _ASSUAN_PREFIX(_assuan_release_context) -#define _assuan_malloc _ASSUAN_PREFIX(_assuan_malloc) -#define _assuan_realloc _ASSUAN_PREFIX(_assuan_realloc) -#define _assuan_calloc _ASSUAN_PREFIX(_assuan_calloc) -#define _assuan_free _ASSUAN_PREFIX(_assuan_free) -#define _assuan_log_print_buffer _ASSUAN_PREFIX(_assuan_log_print_buffer) -#define _assuan_log_sanitized_string \ - _ASSUAN_PREFIX(_assuan_log_sanitized_string) -#define _assuan_log_printf _ASSUAN_PREFIX(_assuan_log_printf) -#define _assuan_set_default_log_stream \ - _ASSUAN_PREFIX(_assuan_set_default_log_stream) -#define _assuan_w32_strerror _ASSUAN_PREFIX(_assuan_w32_strerror) -#define _assuan_gpg_strerror_r _ASSUAN_PREFIX(_assuan_gpg_strerror_r) -#define _assuan_gpg_strsource _ASSUAN_PREFIX(_assuan_gpg_strsource) -#define _assuan_write_line _ASSUAN_PREFIX(_assuan_write_line) -#define _assuan_error _ASSUAN_PREFIX(_assuan_error) -#define _assuan_error_is_eagain _ASSUAN_PREFIX(_assuan_error_is_eagain) -#define _assuan_init_uds_io _ASSUAN_PREFIX(_assuan_init_uds_io) -#define _assuan_uds_close_fds _ASSUAN_PREFIX(_assuan_uds_close_fds) -#define _assuan_uds_deinit _ASSUAN_PREFIX(_assuan_uds_deinit) -#define _assuan_simple_recvmsg _ASSUAN_PREFIX(_assuan_simple_recvmsg) -#define _assuan_simple_sendmsg _ASSUAN_PREFIX(_assuan_simple_sendmsg) -#define _assuan_waitpid _ASSUAN_PREFIX(_assuan_waitpid) -#define _assuan_sock_wsa2errno _ASSUAN_PREFIX(_assuan_sock_wsa2errno) -#define _assuan_sock_close _ASSUAN_PREFIX(_assuan_sock_close) -#define _assuan_sock_new _ASSUAN_PREFIX(_assuan_sock_new) -#define _assuan_sock_connect _ASSUAN_PREFIX(_assuan_sock_connect) -#define _assuan_sock_bind _ASSUAN_PREFIX(_assuan_sock_bind) -#define _assuan_sock_get_nonce _ASSUAN_PREFIX(_assuan_sock_get_nonce) -#define _assuan_sock_check_nonce _ASSUAN_PREFIX(_assuan_sock_check_nonce) - -#endif /*_ASSUAN_EXT_SYM_PREFIX*/ - - #ifdef __cplusplus extern "C" { @@ -217,20 +83,6 @@ extern "C" #endif -/* Definitions of flags for assuan_set_flag(). */ -typedef unsigned int assuan_flag_t; - -/* When using a pipe server, by default Assuan will wait for the - forked process to die in assuan_disconnect. In certain cases this - is not desirable. By setting this flag, the waitpid will be - skipped and the caller is responsible to cleanup a forked - process. */ -#define ASSUAN_NO_WAITPID 1 -/* This flag indicates whether Assuan logging is in confidential - mode. Use assuan_{begin,end}_condidential to change the mode. */ -#define ASSUAN_CONFIDENTIAL 2 - - #define ASSUAN_LINELENGTH 1002 /* 1000 + [CR,]LF */ struct assuan_context_s; @@ -279,19 +131,146 @@ struct sockaddr_un }; #endif + +/* Global interface. */ -/* Definition of hook functions used to conditionally replace the - default I/O functions. */ -struct assuan_io_hooks +struct assuan_malloc_hooks { - int (*read_hook)(assuan_context_t, assuan_fd_t, void *, size_t, ssize_t *); - int (*write_hook)(assuan_context_t, assuan_fd_t fd, - const void *, size_t, ssize_t *); + void *(*malloc) (size_t cnt); + void *(*realloc) (void *ptr, size_t cnt); + void (*free) (void *ptr); }; -typedef struct assuan_io_hooks *assuan_io_hooks_t; +typedef struct assuan_malloc_hooks *assuan_malloc_hooks_t; + +/* Categories for log messages. */ +#define ASSUAN_LOG_INIT 1 +#define ASSUAN_LOG_CTX 2 +#define ASSUAN_LOG_ENGINE 3 +#define ASSUAN_LOG_DATA 4 +#define ASSUAN_LOG_SYSIO 5 + +/* If MSG is NULL, return true/false depending on if this category is + logged. This is used to probe before expensive log message + generation (buffer dumps). */ +typedef int (*assuan_log_cb_t) (assuan_context_t ctx, void *hook, + unsigned int cat, const char *msg); + +/* Set the default gpg error source. */ +void assuan_set_gpg_err_source (gpg_err_source_t errsource); + +/* Get the default gpg error source. */ +gpg_err_source_t assuan_get_gpg_err_source (void); + + +/* Set the default malloc hooks. */ +void assuan_set_malloc_hooks (assuan_malloc_hooks_t malloc_hooks); + +/* Get the default malloc hooks. */ +assuan_malloc_hooks_t assuan_get_malloc_hooks (void); + + +/* Set the default log callback handler. */ +void assuan_set_log_cb (assuan_log_cb_t log_cb, void *log_cb_data); + +/* Get the default log callback handler. */ +void assuan_get_log_cb (assuan_log_cb_t *log_cb, void **log_cb_data); + + +/* Create a new Assuan context. The initial parameters are all needed + in the creation of the context. */ +gpg_error_t assuan_new_ext (assuan_context_t *ctx, gpg_err_source_t errsource, + assuan_malloc_hooks_t malloc_hooks, + assuan_log_cb_t log_cb, void *log_cb_data); + +/* Create a new context with default arguments. */ +gpg_error_t assuan_new (assuan_context_t *ctx); + +/* Release all resources associated with the given context. */ +void assuan_release (assuan_context_t ctx); + +/* Set user-data in a context. */ +void assuan_set_pointer (assuan_context_t ctx, void *pointer); + +/* Get user-data in a context. */ +void *assuan_get_pointer (assuan_context_t ctx); + + +/* Definitions of flags for assuan_set_flag(). */ +typedef unsigned int assuan_flag_t; + +/* When using a pipe server, by default Assuan will wait for the + forked process to die in assuan_release. In certain cases this + is not desirable. By setting this flag, the waitpid will be + skipped and the caller is responsible to cleanup a forked + process. */ +#define ASSUAN_NO_WAITPID 1 +/* 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 + +/* 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; + see the description of the type assuan_flag_t for details. */ +void assuan_set_flag (assuan_context_t ctx, assuan_flag_t flag, int value); + +/* Return the VALUE of FLAG in context CTX. */ +int assuan_get_flag (assuan_context_t ctx, assuan_flag_t flag); + + +/* Same as assuan_set_flag (ctx, ASSUAN_NO_WAITPID, 1). */ +void assuan_begin_confidential (assuan_context_t ctx); + +/* Same as assuan_set_flag (ctx, ASSUAN_NO_WAITPID, 0). */ +void assuan_end_confidential (assuan_context_t ctx); + + +/* Direction values for assuan_set_io_monitor. */ +#define ASSUAN_IO_FROM_PEER 0 +#define ASSUAN_IO_TO_PEER 1 + +/* Return flags of I/O monitor. */ +#define ASSUAN_IO_MONITOR_NOLOG 1 +#define ASSUAN_IO_MONITOR_IGNORE 2 + +/* The IO monitor gets to see all I/O on the context, and can return + ASSUAN_IO_MONITOR_* bits to control actions on it. */ +typedef unsigned int (*assuan_io_monitor_t) (assuan_context_t ctx, void *hook, + int inout, const char *line, + size_t linelen); + +/* Set the IO monitor function. */ +void assuan_set_io_monitor (assuan_context_t ctx, + assuan_io_monitor_t io_monitor, void *hook_data); + +/* Configuration of the default log handler. */ +/* Set the stream to which assuan should log message not associated + with a context. By default, this is stderr. The default value + will be changed when the first log stream is associated with a + context. Note, that this function is not thread-safe and should + in general be used right at startup. */ +extern void assuan_set_assuan_log_stream (FILE *fp); + +/* Return the stream which is currently being using for global logging. */ +extern FILE *assuan_get_assuan_log_stream (void); + +/* Set the prefix to be used at the start of a line emitted by assuan + on the log stream. The default is the empty string. Note, that + this function is not thread-safe and should in general be used + right at startup. */ +void assuan_set_assuan_log_prefix (const char *text); + +/* Return a prefix to be used at the start of a line emitted by assuan + on the log stream. The default implementation returns the empty + string, i.e. "" */ +const char *assuan_get_assuan_log_prefix (void); + +/* Set the per context log stream for the default log handler. */ +void assuan_set_log_stream (assuan_context_t ctx, FILE *fp); + + /*-- assuan-handler.c --*/ gpg_error_t assuan_register_command (assuan_context_t ctx, const char *cmd_string, @@ -344,41 +323,40 @@ gpg_error_t assuan_close_output_fd (assuan_context_t ctx); /*-- assuan-pipe-server.c --*/ -gpg_error_t assuan_init_pipe_server (assuan_context_t *r_ctx, int filedes[2]); -void assuan_deinit_server (assuan_context_t ctx); +gpg_error_t assuan_init_pipe_server (assuan_context_t ctx, int filedes[2]); /*-- assuan-socket-server.c --*/ -gpg_error_t assuan_init_socket_server (assuan_context_t *r_ctx, +gpg_error_t assuan_init_socket_server (assuan_context_t ctx, assuan_fd_t listen_fd); -gpg_error_t assuan_init_socket_server_ext (assuan_context_t *r_ctx, +gpg_error_t assuan_init_socket_server_ext (assuan_context_t ctx, assuan_fd_t fd, unsigned int flags); void assuan_set_sock_nonce (assuan_context_t ctx, assuan_sock_nonce_t *nonce); /*-- assuan-pipe-connect.c --*/ -gpg_error_t assuan_pipe_connect (assuan_context_t *ctx, +gpg_error_t assuan_pipe_connect (assuan_context_t ctx, const char *name, - const char *const argv[], + const char *argv[], int *fd_child_list); -gpg_error_t assuan_pipe_connect_ext (assuan_context_t *ctx, +gpg_error_t assuan_pipe_connect_ext (assuan_context_t ctx, const char *name, - const char *const argv[], + const char *argv[], int *fd_child_list, void (*atfork) (void *, int), void *atforkvalue, unsigned int flags); /*-- assuan-socket-connect.c --*/ -gpg_error_t assuan_socket_connect (assuan_context_t *ctx, +gpg_error_t assuan_socket_connect (assuan_context_t ctx, const char *name, pid_t server_pid); -gpg_error_t assuan_socket_connect_ext (assuan_context_t *ctx, + +gpg_error_t assuan_socket_connect_ext (assuan_context_t ctx, const char *name, pid_t server_pid, unsigned int flags); /*-- assuan-connect.c --*/ -void assuan_disconnect (assuan_context_t ctx); pid_t assuan_get_pid (assuan_context_t ctx); #ifndef _WIN32 gpg_error_t assuan_get_peercred (assuan_context_t ctx, @@ -424,63 +402,8 @@ gpg_error_t assuan_receivefd (assuan_context_t ctx, assuan_fd_t *fd); /*-- assuan-util.c --*/ -void assuan_set_malloc_hooks ( void *(*new_alloc_func)(size_t n), - void *(*new_realloc_func)(void *p, size_t n), - void (*new_free_func)(void*) ); -void assuan_set_io_hooks (assuan_io_hooks_t io_hooks); -void assuan_set_log_stream (assuan_context_t ctx, FILE *fp); gpg_error_t assuan_set_error (assuan_context_t ctx, gpg_error_t err, const char *text); -void assuan_set_pointer (assuan_context_t ctx, void *pointer); -void *assuan_get_pointer (assuan_context_t ctx); - -void assuan_begin_confidential (assuan_context_t ctx); -void assuan_end_confidential (assuan_context_t ctx); - -void assuan_set_io_monitor (assuan_context_t ctx, - unsigned int (*monitor)(assuan_context_t ctx, - int direction, - const char *line, - size_t linelen)); - -/* 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; - see the description of the type assuan_flag_t for details. */ -void assuan_set_flag (assuan_context_t ctx, assuan_flag_t flag, int value); - -/* Return the VALUE of FLAG in context CTX. */ -int assuan_get_flag (assuan_context_t ctx, assuan_flag_t flag); - -/*-- assuan-errors.c --*/ - -/* Enable gpg-error style error codes. ERRSOURCE is one of gpg-error - sources. Note, that this function is not thread-safe and should be - used right at startup. Switching back to the old style mode is not - supported. */ -void assuan_set_assuan_err_source (gpg_err_source_t errsource); - -/*-- assuan-logging.c --*/ - -/* Set the stream to which assuan should log message not associated - with a context. By default, this is stderr. The default value - will be changed when the first log stream is associated with a - context. Note, that this function is not thread-safe and should - in general be used right at startup. */ -extern void assuan_set_assuan_log_stream (FILE *fp); - -/* Return the stream which is currently being using for global logging. */ -extern FILE *assuan_get_assuan_log_stream (void); - -/* Set the prefix to be used at the start of a line emitted by assuan - on the log stream. The default is the empty string. Note, that - this function is not thread-safe and should in general be used - right at startup. */ -void assuan_set_assuan_log_prefix (const char *text); - -/* Return a prefix to be used at the start of a line emitted by assuan - on the log stream. The default implementation returns the empty - string, i.e. "" */ -const char *assuan_get_assuan_log_prefix (void); /*-- assuan-socket.c --*/ diff --git a/src/context.c b/src/context.c new file mode 100644 index 0000000..d87672b --- /dev/null +++ b/src/context.c @@ -0,0 +1,127 @@ +/* context.c - Context specific interface. + Copyright (C) 2009 Free Software Foundation, Inc. + + This file is part of Assuan. + + Assuan is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + Assuan is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "assuan-defs.h" +#include "debug.h" + + +/* Set user-data in a context. */ +void +assuan_set_pointer (assuan_context_t ctx, void *pointer) +{ + if (ctx) + ctx->user_pointer = pointer; +} + + +/* Get user-data in a context. */ +void * +assuan_get_pointer (assuan_context_t ctx) +{ + if (! ctx) + return NULL; + + return ctx->user_pointer; +} + + +/* 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; + see the description of the type assuan_flag_t for details. */ +void +assuan_set_flag (assuan_context_t ctx, assuan_flag_t flag, int value) +{ + if (!ctx) + return; + + switch (flag) + { + case ASSUAN_NO_WAITPID: + ctx->flags.no_waitpid = value; + break; + + case ASSUAN_CONFIDENTIAL: + ctx->flags.confidential = value; + break; + } +} + + +/* Return the VALUE of FLAG in context CTX. */ +int +assuan_get_flag (assuan_context_t ctx, assuan_flag_t flag) +{ + if (! ctx) + return 0; + + switch (flag) + { + case ASSUAN_NO_WAITPID: + return ctx->flags.no_waitpid; + case ASSUAN_CONFIDENTIAL: + return ctx->flags.confidential; + } + + return 0; +} + + +/* Same as assuan_set_flag (ctx, ASSUAN_NO_WAITPID, 1). */ +void +assuan_begin_confidential (assuan_context_t ctx) +{ + assuan_set_flag (ctx, ASSUAN_CONFIDENTIAL, 1); +} + + +/* Same as assuan_set_flag (ctx, ASSUAN_NO_WAITPID, 0). */ +void +assuan_end_confidential (assuan_context_t ctx) +{ + assuan_set_flag (ctx, ASSUAN_CONFIDENTIAL, 0); +} + + +/* 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; + } +} + + +/* Store the error in the context so that the error sending function + can take out a descriptive text. Inside the assuan code, use the + macro set_error instead of this function. */ +gpg_error_t +assuan_set_error (assuan_context_t ctx, gpg_error_t err, const char *text) +{ + ctx->err_no = err; + ctx->err_str = text; + return err; +} diff --git a/src/conversion.c b/src/conversion.c new file mode 100644 index 0000000..af5026e --- /dev/null +++ b/src/conversion.c @@ -0,0 +1,116 @@ +/* conversion.c - String conversion helper functions. + Copyright (C) 2000 Werner Koch (dd9jn) + Copyright (C) 2001, 2002, 2003, 2004, 2007 g10 Code GmbH + + This file is part of Assuan. + + Assuan is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + Assuan is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#if HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> +#include <string.h> +/* Solaris 8 needs sys/types.h before time.h. */ +#include <sys/types.h> +#include <time.h> +#include <errno.h> +#include <ctype.h> + +#include "assuan-defs.h" +#include "debug.h" + + +/* Convert the number NR to a hexadecimal string. Returns the tail + pointer. */ +static char * +_assuan_bytetohex (int nr, char *str) +{ + static char hexdigits[] = "0123456789abcdef"; + int i; + +#define NROFHEXDIGITS 2 + for (i = 0; i < NROFHEXDIGITS; i++) + { + int digit = (nr >> (i << 2)) & 0xf; + *(str++) = hexdigits[digit]; + } + return str; +} + + +/* Encode the C formatted string SRC and return the malloc'ed result. */ +char * +_assuan_encode_c_string (assuan_context_t ctx, const char *src) +{ + const unsigned char *istr; + char *res; + char *ostr; + + ostr = _assuan_malloc (ctx, 4 * strlen (src) + 1); + if (! *ostr) + return NULL; + + res = ostr; + + for (istr = (const unsigned char *) src; *istr; istr++) + { + int c = 0; + + switch (*istr) + { + case '\r': + c = 'r'; + break; + + case '\n': + c = 'n'; + break; + + case '\f': + c = 'f'; + break; + + case '\v': + c = 'v'; + break; + + case '\b': + c = 'b'; + break; + + default: + if ((isascii (*istr) && isprint (*istr)) || (*istr >= 0x80)) + *(ostr++) = *istr; + else + { + *(ostr++) = '\\'; + *(ostr++) = 'x'; + ostr = _assuan_bytetohex (*istr, ostr); + } + } + + if (c) + { + *(ostr++) = '\\'; + *(ostr++) = c; + } + } + *(ostr) = '\0'; + + return res; +} diff --git a/src/debug.c b/src/debug.c new file mode 100644 index 0000000..1a0df7e --- /dev/null +++ b/src/debug.c @@ -0,0 +1,179 @@ +/* debug.c - helpful output in desperate situations + Copyright (C) 2000 Werner Koch (dd9jn) + Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2009 g10 Code GmbH + + This file is part of Assuan. + + Assuan is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + Assuan is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#if HAVE_CONFIG_H +#include <config.h> +#endif +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <unistd.h> +#include <ctype.h> +#include <errno.h> +#ifndef HAVE_DOSISH_SYSTEM +# include <sys/types.h> +# include <sys/stat.h> +# include <fcntl.h> +#endif +#include <assert.h> + +#include "assuan-defs.h" +#include "debug.h" + + +/* Log the formatted string FORMAT at debug category CAT or higher. */ +void +_assuan_debug (assuan_context_t ctx, unsigned int cat, const char *format, ...) +{ + va_list arg_ptr; + int saved_errno; + char *msg; + int res; + + if (ctx->log_cb == NULL) + return; + + saved_errno = errno; + va_start (arg_ptr, format); + res = vasprintf (&msg, format, arg_ptr); + va_end (arg_ptr); + if (res < 0) + return; + ctx->log_cb (ctx, ctx->log_cb_data, cat, msg); + errno = saved_errno; +} + + +/* Start a new debug line in *LINE, logged at level LEVEL or higher, + and starting with the formatted string FORMAT. */ +void +_assuan_debug_begin (assuan_context_t ctx, + void **line, unsigned int cat, const char *format, ...) +{ + va_list arg_ptr; + int res; + + *line = NULL; + /* Probe if this wants to be logged based on category. */ + if (! ctx->log_cb || + ! (*ctx->log_cb) (ctx, ctx->log_cb_data, cat, NULL)) + return; + + va_start (arg_ptr, format); + res = vasprintf ((char **) line, format, arg_ptr); + va_end (arg_ptr); + if (res < 0) + *line = NULL; +} + + +/* Add the formatted string FORMAT to the debug line *LINE. */ +void +_assuan_debug_add (assuan_context_t ctx, void **line, const char *format, ...) +{ + va_list arg_ptr; + char *toadd; + char *result; + int res; + + if (!*line) + return; + + va_start (arg_ptr, format); + res = vasprintf (&toadd, format, arg_ptr); + va_end (arg_ptr); + if (res < 0) + { + free (*line); + *line = NULL; + } + res = asprintf (&result, "%s%s", *(char **) line, toadd); + free (toadd); + free (*line); + if (res < 0) + *line = NULL; + else + *line = result; +} + + +/* Finish construction of *LINE and send it to the debug output + stream. */ +void +_assuan_debug_end (assuan_context_t ctx, void **line, unsigned int cat) +{ + if (!*line) + return; + + /* Force logging here by using category ~0. */ + _assuan_debug (ctx, ~0, "%s", *line); + free (*line); + *line = NULL; +} + + +#define TOHEX(val) (((val) < 10) ? ((val) + '0') : ((val) - 10 + 'a')) + +void +_assuan_debug_buffer (assuan_context_t ctx, unsigned int cat, + const char *const fmt, const char *const func, + const char *const tagname, void *tag, + const char *const buffer, size_t len) +{ + int idx = 0; + int j; + + /* Probe if this wants to be logged based on category. */ + if (! ctx->log_cb || + ! (*ctx->log_cb) (ctx, ctx->log_cb_data, cat, NULL)) + return; + + while (idx < len) + { + char str[51]; + char *strp = str; + char *strp2 = &str[34]; + + for (j = 0; j < 16; j++) + { + unsigned char val; + if (idx < len) + { + val = buffer[idx++]; + *(strp++) = TOHEX (val >> 4); + *(strp++) = TOHEX (val % 16); + *(strp2++) = isprint (val) ? val : '.'; + } + else + { + *(strp++) = ' '; + *(strp++) = ' '; + } + if (j == 7) + *(strp++) = ' '; + } + *(strp++) = ' '; + *(strp2) = '\0'; + + _assuan_debug (ctx, cat, fmt, func, tagname, tag, str); + } +} diff --git a/src/debug.h b/src/debug.h new file mode 100644 index 0000000..13e5419 --- /dev/null +++ b/src/debug.h @@ -0,0 +1,260 @@ +/* debug.h - interface to debugging functions + Copyright (C) 2002, 2004, 2005, 2007 g10 Code GmbH + + This file is part of Assuan. + + Assuan is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + Assuan is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#ifndef DEBUG_H +#define DEBUG_H + +#include <string.h> +#ifdef HAVE_STDINT_H +#include <stdint.h> +#endif +#ifdef HAVE_INTTYPES_H +#include <inttypes.h> +#endif + +#include "assuan-defs.h" + +/* Indirect stringification, requires __STDC__ to work. */ +#define STRINGIFY(v) #v +#define XSTRINGIFY(v) STRINGIFY(v) + + + +/* Remove path components from filenames (i.e. __FILE__) for cleaner + logs. */ +static inline const char *_assuan_debug_srcname (const char *file) + ASSUAN_GCC_A_PURE; + +static inline const char * +_assuan_debug_srcname (const char *file) +{ + const char *s = strrchr (file, '/'); + return s ? s + 1 : file; +} + + +/* Called early to initialize the logging. */ +void _assuan_debug_subsystem_init (void); + +/* Log the formatted string FORMAT at debug level LEVEL or higher. */ +void _assuan_debug (assuan_context_t ctx, unsigned int cat, + const char *format, ...); + +/* Start a new debug line in *LINE, logged at level LEVEL or higher, + and starting with the formatted string FORMAT. */ +void _assuan_debug_begin (assuan_context_t ctx, + void **helper, unsigned int cat, + const char *format, ...); + +/* Add the formatted string FORMAT to the debug line *LINE. */ +void _assuan_debug_add (assuan_context_t ctx, + void **helper, const char *format, ...); + +/* Finish construction of *LINE and send it to the debug output + stream. */ +void _assuan_debug_end (assuan_context_t ctx, + void **helper, unsigned int cat); + +void _assuan_debug_buffer (assuan_context_t ctx, unsigned int cat, + const char *const fmt, + const char *const func, const char *const tagname, + void *tag, const char *const buffer, size_t len); + + +/* Trace support. */ + +#define _TRACE(ctx, lvl, name, tag) \ + assuan_context_t _assuan_trace_context = ctx; \ + int _assuan_trace_level = lvl; \ + const char *const _assuan_trace_func = name; \ + const char *const _assuan_trace_tagname = STRINGIFY (tag); \ + void *_assuan_trace_tag = (void *) (uintptr_t) tag + +#define TRACE_BEG(ctx,lvl, name, tag) \ + _TRACE (ctx, lvl, name, tag); \ + _assuan_debug (_assuan_trace_context, _assuan_trace_level, \ + "%s (%s=%p): enter\n", \ + _assuan_trace_func, _assuan_trace_tagname, \ + _assuan_trace_tag), 0 +#define TRACE_BEG0(ctx, lvl, name, tag, fmt) \ + _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), 0 +#define TRACE_BEG1(ctx, lvl, name, tag, fmt, arg1) \ + _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), 0 +#define TRACE_BEG2(ctx, lvl, name, tag, fmt, arg1, arg2) \ + _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), 0 +#define TRACE_BEG3(ctx, lvl, name, tag, fmt, arg1, arg2, arg3) \ + _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), 0 +#define TRACE_BEG4(ctx, lvl, name, tag, fmt, arg1, arg2, arg3, arg4) \ + _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), 0 + +#define TRACE_BEG8(ctx, lvl, name, tag, fmt, arg1, arg2, arg3, arg4, \ + arg5, arg6, arg7, arg8) \ + _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, arg7, arg8), 0 + +#define TRACE(ctx, lvl, name, tag) \ + _assuan_debug (ctx, lvl, "%s (%s=%p): call\n", \ + name, STRINGIFY (tag), (void *) (uintptr_t) tag), 0 +#define TRACE0(ctx, lvl, name, tag, fmt) \ + _assuan_debug (ctx, lvl, "%s (%s=%p): call: " fmt "\n", \ + name, STRINGIFY (tag), (void *) (uintptr_t) tag), 0 +#define TRACE1(ctx, lvl, name, tag, fmt, arg1) \ + _assuan_debug (ctx, lvl, "%s (%s=%p): call: " fmt "\n", \ + name, STRINGIFY (tag), (void *) (uintptr_t) tag, arg1), 0 +#define TRACE2(ctx, lvl, name, tag, fmt, arg1, arg2) \ + _assuan_debug (ctx, lvl, "%s (%s=%p): call: " fmt "\n", \ + name, STRINGIFY (tag), (void *) (uintptr_t) tag, arg1, \ + arg2), 0 +#define TRACE3(ctx, lvl, name, tag, fmt, arg1, arg2, arg3) \ + _assuan_debug (ctx, lvl, "%s (%s=%p): call: " fmt "\n", \ + name, STRINGIFY (tag), (void *) (uintptr_t) tag, arg1, \ + arg2, arg3), 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, \ + arg2, arg3, arg4, arg5, arg6), 0 + +#define TRACE_ERR(err) \ + err == 0 ? (TRACE_SUC ()) : \ + (_assuan_debug (_assuan_trace_context, _assuan_trace_level, \ + "%s (%s=%p): error: %s <%s>\n", \ + _assuan_trace_func, _assuan_trace_tagname, \ + _assuan_trace_tag, gpg_strerror (err), \ + gpg_strsource (ctx->err_source)), \ + _assuan_error (ctx, err)) + +/* The cast to void suppresses GCC warnings. */ +#define TRACE_SYSRES(res) \ + res >= 0 ? ((void) (TRACE_SUC1 ("result=%i", res)), (res)) : \ + (_assuan_debug (_assuan_trace_context, _assuan_trace_level, "%s (%s=%p): error: %s\n", \ + _assuan_trace_func, _assuan_trace_tagname, \ + _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_trace_func, _assuan_trace_tagname, \ + _assuan_trace_tag, strerror (res)), (res)) + +#define TRACE_SUC() \ + _assuan_debug (_assuan_trace_context, _assuan_trace_level, \ + "%s (%s=%p): leave\n", \ + _assuan_trace_func, _assuan_trace_tagname, \ + _assuan_trace_tag), 0 +#define TRACE_SUC0(fmt) \ + _assuan_debug (_assuan_trace_context, _assuan_trace_level, \ + "%s (%s=%p): leave: " fmt "\n", \ + _assuan_trace_func, _assuan_trace_tagname, \ + _assuan_trace_tag), 0 +#define TRACE_SUC1(fmt, arg1) \ + _assuan_debug (_assuan_trace_context, _assuan_trace_level, \ + "%s (%s=%p): leave: " fmt "\n", \ + _assuan_trace_func, _assuan_trace_tagname, \ + _assuan_trace_tag, arg1), 0 +#define TRACE_SUC2(fmt, arg1, arg2) \ + _assuan_debug (_assuan_trace_context, _assuan_trace_level, \ + "%s (%s=%p): leave: " fmt "\n", \ + _assuan_trace_func, _assuan_trace_tagname, \ + _assuan_trace_tag, arg1, arg2), 0 +#define TRACE_SUC5(fmt, arg1, arg2, arg3, arg4, arg5) \ + _assuan_debug (_assuan_trace_context, _assuan_trace_level, \ + "%s (%s=%p): leave: " fmt "\n", \ + _assuan_trace_func, _assuan_trace_tagname, \ + _assuan_trace_tag, arg1, arg2, arg3, arg4, arg5), 0 + +#define TRACE_LOG(fmt) \ + _assuan_debug (_assuan_trace_context, _assuan_trace_level, \ + "%s (%s=%p): check: " fmt "\n", \ + _assuan_trace_func, _assuan_trace_tagname, \ + _assuan_trace_tag), 0 +#define TRACE_LOG1(fmt, arg1) \ + _assuan_debug (_assuan_trace_context, _assuan_trace_level, \ + "%s (%s=%p): check: " fmt "\n", \ + _assuan_trace_func, _assuan_trace_tagname, \ + _assuan_trace_tag, arg1), 0 +#define TRACE_LOG2(fmt, arg1, arg2) \ + _assuan_debug (_assuan_trace_context, _assuan_trace_level, \ + "%s (%s=%p): check: " fmt "\n", \ + _assuan_trace_func, _assuan_trace_tagname, \ + _assuan_trace_tag, arg1, arg2), 0 +#define TRACE_LOG3(fmt, arg1, arg2, arg3) \ + _assuan_debug (_assuan_trace_context, _assuan_trace_level, \ + "%s (%s=%p): check: " fmt "\n", \ + _assuan_trace_func, _assuan_trace_tagname, \ + _assuan_trace_tag, arg1, arg2, arg3), 0 +#define TRACE_LOG4(fmt, arg1, arg2, arg3, arg4) \ + _assuan_debug (_assuan_trace_context, _assuan_trace_level, \ + "%s (%s=%p): check: " fmt "\n", \ + _assuan_trace_func, _assuan_trace_tagname, \ + _assuan_trace_tag, arg1, arg2, arg3, arg4), 0 +#define TRACE_LOG6(fmt, arg1, arg2, arg3, arg4, arg5, arg6) \ + _assuan_debug (_assuan_trace_context, _assuan_trace_level, \ + "%s (%s=%p): check: " fmt "\n", \ + _assuan_trace_func, _assuan_trace_tagname, \ + _assuan_trace_tag, arg1, arg2, arg3, arg4, arg5, \ + arg6), 0 + +#define TRACE_LOGBUF(buf, len) \ + _assuan_debug_buffer (_assuan_trace_context, _assuan_trace_level, \ + "%s (%s=%p): check: %s", \ + _assuan_trace_func, _assuan_trace_tagname, \ + _assuan_trace_tag, buf, len) + +#define TRACE_SEQ(hlp,fmt) \ + _assuan_debug_begin (_assuan_trace_context, &(hlp), \ + "%s (%s=%p): check: " fmt, \ + _assuan_trace_func, _assuan_trace_tagname, \ + _assuan_trace_tag) +#define TRACE_ADD0(hlp,fmt) \ + _assuan_debug_add (_assuan_trace_context, &(hlp), fmt) +#define TRACE_ADD1(hlp,fmt,a) \ + _assuan_debug_add (_assuan_trace_context, &(hlp), fmt, (a)) +#define TRACE_ADD2(hlp,fmt,a,b) \ + _assuan_debug_add (_assuan_trace_context, &(hlp), fmt, (a), (b)) +#define TRACE_ADD3(hlp,fmt,a,b,c) \ + _assuan_debug_add (_assuan_trace_context, &(hlp), fmt, (a), (b), (c)) +#define TRACE_END(hlp,fmt) \ + _assuan_debug_add (_assuan_trace_context, &(hlp), fmt); \ + _assuan_debug_end (_assuan_trace_context, &(hlp), _assuan_trace_level) +#define TRACE_ENABLED(hlp) (!!(hlp)) + +#endif /* DEBUG_H */ diff --git a/src/libassuan.def b/src/libassuan.def index a7ca5ee..59fe38c 100644 --- a/src/libassuan.def +++ b/src/libassuan.def @@ -24,64 +24,68 @@ EXPORTS assuan_close_input_fd @3 assuan_close_output_fd @4 assuan_command_parse_fd @5 - assuan_deinit_server @6 - assuan_disconnect @7 - assuan_end_confidential @8 - assuan_get_active_fds @9 - assuan_get_assuan_log_prefix @10 - assuan_get_assuan_log_stream @11 - assuan_get_data_fp @12 - assuan_get_flag @13 - assuan_get_input_fd @14 - assuan_get_output_fd @15 - assuan_get_pid @16 - assuan_get_pointer @17 - assuan_init_pipe_server @18 - assuan_init_socket_server @19 - assuan_init_socket_server_ext @20 - assuan_inquire @21 - assuan_inquire_ext @22 - assuan_pending_line @23 - assuan_pipe_connect @24 - assuan_pipe_connect_ext @25 - assuan_process @26 - assuan_process_done @27 - assuan_process_next @28 - assuan_read_line @29 - assuan_receivefd @30 - assuan_register_bye_notify @31 - assuan_register_cancel_notify @32 - assuan_register_command @33 - assuan_register_input_notify @34 - assuan_register_option_handler @35 - assuan_register_output_notify @36 - assuan_register_post_cmd_notify @37 - assuan_register_reset_notify @38 - assuan_send_data @39 - assuan_sendfd @40 - assuan_set_assuan_err_source @41 - assuan_set_assuan_log_prefix @42 - assuan_set_assuan_log_stream @43 - assuan_set_error @44 - assuan_set_flag @45 - assuan_set_hello_line @46 - assuan_set_io_hooks @47 - assuan_set_io_monitor @48 - assuan_set_log_stream @49 - assuan_set_malloc_hooks @50 - assuan_set_okay_line @51 - assuan_set_pointer @52 - assuan_sock_bind @53 - assuan_sock_check_nonce @54 - assuan_sock_close @55 - assuan_sock_connect @56 - assuan_sock_get_nonce @57 - assuan_sock_new @58 - assuan_socket_connect @59 - assuan_socket_connect_ext @60 - assuan_transact @61 - assuan_write_line @62 - assuan_write_status @63 + assuan_end_confidential @6 + assuan_get_active_fds @7 + assuan_get_assuan_log_prefix @8 + assuan_get_assuan_log_stream @9 + assuan_get_data_fp @10 + assuan_get_flag @11 + assuan_get_gpg_err_source @12 + assuan_get_input_fd @13 + assuan_get_log_cb @14 + assuan_get_malloc_hooks @15 + assuan_get_output_fd @16 + assuan_get_pid @17 + assuan_get_pointer @18 + assuan_init_pipe_server @19 + assuan_init_socket_server @20 + assuan_init_socket_server_ext @21 + assuan_inquire @22 + assuan_inquire_ext @23 + assuan_new @24 + assuan_new_ext @25 + assuan_pending_line @26 + assuan_pipe_connect @27 + assuan_pipe_connect_ext @28 + assuan_process @29 + assuan_process_done @30 + assuan_process_next @31 + assuan_read_line @32 + assuan_receivefd @33 + assuan_register_bye_notify @34 + assuan_register_cancel_notify @35 + assuan_register_command @36 + assuan_register_input_notify @37 + assuan_register_option_handler @38 + assuan_register_output_notify @39 + assuan_register_post_cmd_notify @40 + assuan_register_reset_notify @41 + assuan_release @42 + assuan_send_data @43 + assuan_sendfd @44 + assuan_set_assuan_log_prefix @45 + assuan_set_assuan_log_stream @46 + assuan_set_error @47 + assuan_set_flag @48 + assuan_set_gpg_err_source @49 + assuan_set_hello_line @50 + assuan_set_io_monitor @51 + assuan_set_log_cb @52 + assuan_set_log_stream @53 + assuan_set_malloc_hooks @54 + assuan_set_okay_line @55 + assuan_set_pointer @56 + assuan_sock_bind @57 + assuan_sock_check_nonce @58 + assuan_sock_close @59 + assuan_sock_connect @60 + assuan_sock_get_nonce @61 + assuan_sock_new @62 + assuan_socket_connect @63 + assuan_socket_connect_ext @64 + assuan_transact @65 + assuan_write_line @66 + assuan_write_status @67 ; END diff --git a/src/libassuan.vers b/src/libassuan.vers index b139143..14c0cc7 100644 --- a/src/libassuan.vers +++ b/src/libassuan.vers @@ -27,8 +27,6 @@ LIBASSUAN_1.0 { assuan_close_input_fd; assuan_close_output_fd; assuan_command_parse_fd; - assuan_deinit_server; - assuan_disconnect; assuan_end_confidential; assuan_get_active_fds; assuan_get_assuan_log_prefix; @@ -63,13 +61,11 @@ LIBASSUAN_1.0 { assuan_register_reset_notify; assuan_send_data; assuan_sendfd; - assuan_set_assuan_err_source; assuan_set_assuan_log_prefix; assuan_set_assuan_log_stream; assuan_set_error; assuan_set_flag; assuan_set_hello_line; - assuan_set_io_hooks; assuan_set_io_monitor; assuan_set_log_stream; assuan_set_malloc_hooks; @@ -86,6 +82,16 @@ LIBASSUAN_1.0 { assuan_transact; assuan_write_line; assuan_write_status; + assuan_new; + assuan_release; + assuan_set_gpg_err_source; + assuan_get_gpg_err_source; + assuan_get_malloc_hooks; + assuan_set_log_cb; + assuan_get_log_cb; + assuan_new_ext; + assuan_new; + assuan_release; local: *; diff --git a/src/system.c b/src/system.c new file mode 100644 index 0000000..dd0c079 --- /dev/null +++ b/src/system.c @@ -0,0 +1,72 @@ +/* system.c - System support functions. + Copyright (C) 2009 Free Software Foundation, Inc. + + This file is part of Assuan. + + Assuan is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + Assuan is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> +#include <errno.h> + +#include "assuan-defs.h" +#include "debug.h" + + +/* Manage memory specific to a context. */ + +void * +_assuan_malloc (assuan_context_t ctx, size_t cnt) +{ + return ctx->malloc_hooks.malloc (cnt); +} + +void * +_assuan_realloc (assuan_context_t ctx, void *ptr, size_t cnt) +{ + return ctx->malloc_hooks.realloc (ptr, cnt); +} + +void * +_assuan_calloc (assuan_context_t ctx, size_t cnt, size_t elsize) +{ + void *ptr; + size_t nbytes; + + nbytes = cnt * elsize; + + /* Check for overflow. */ + if (elsize && nbytes / elsize != cnt) + { + errno = ENOMEM; + return NULL; + } + + ptr = ctx->malloc_hooks.malloc (nbytes); + if (ptr) + memset (ptr, 0, nbytes); + return ptr; +} + +void +_assuan_free (assuan_context_t ctx, void *ptr) +{ + if (ptr) + ctx->malloc_hooks.free (ptr); +} diff --git a/tests/fdpassing.c b/tests/fdpassing.c index fa26353..7197ff7 100644 --- a/tests/fdpassing.c +++ b/tests/fdpassing.c @@ -75,7 +75,7 @@ register_commands (assuan_context_t ctx) static struct { const char *name; - int (*handler) (assuan_context_t, char *line); + gpg_error_t (*handler) (assuan_context_t, char *line); } table[] = { { "ECHO", cmd_echo }, @@ -104,7 +104,11 @@ server (void) log_info ("server started\n"); - rc = assuan_init_pipe_server (&ctx, NULL); + rc = assuan_new (&ctx); + if (rc) + log_fatal ("assuan_new failed: %s\n", gpg_strerror (rc)); + + rc = assuan_init_pipe_server (ctx, NULL); if (rc) log_fatal ("assuan_init_pipe_server failed: %s\n", gpg_strerror (rc)); @@ -132,7 +136,7 @@ server (void) log_error ("assuan_process failed: %s\n", gpg_strerror (rc)); } - assuan_deinit_server (ctx); + assuan_release (ctx); } @@ -193,7 +197,7 @@ client (assuan_context_t ctx, const char *fname) /* Give us some time to check with lsof that all descriptors are closed. */ /* sleep (10); */ - assuan_disconnect (ctx); + assuan_release (ctx); return 0; } @@ -210,7 +214,7 @@ main (int argc, char **argv) { int last_argc = -1; assuan_context_t ctx; - int err; + gpg_error_t err; int no_close_fds[2]; const char *arglist[10]; int is_server = 0; @@ -260,7 +264,6 @@ main (int argc, char **argv) assuan_set_assuan_log_prefix (log_prefix); - assuan_set_assuan_log_stream (stderr); if (is_server) { @@ -269,6 +272,8 @@ main (int argc, char **argv) } else { + const char *loc; + no_close_fds[0] = 2; no_close_fds[1] = -1; if (with_exec) @@ -278,8 +283,13 @@ main (int argc, char **argv) arglist[2] = verbose? "--verbose":NULL; arglist[3] = NULL; } - err = assuan_pipe_connect_ext (&ctx, with_exec? "./fdpassing":NULL, - with_exec? arglist :NULL, + + err = assuan_new (&ctx); + if (err) + log_fatal ("assuan_new failed: %s\n", gpg_strerror (err)); + + err = assuan_pipe_connect_ext (ctx, with_exec? "./fdpassing":NULL, + with_exec ? arglist : &loc, no_close_fds, NULL, NULL, 1); if (err) { @@ -287,7 +297,7 @@ main (int argc, char **argv) return 1; } - if (!ctx) + if (!with_exec && loc[0] == 's') { server (); log_info ("server finished\n"); @@ -297,12 +307,12 @@ main (int argc, char **argv) if (client (ctx, fname)) { log_info ("waiting for server to terminate...\n"); - assuan_disconnect (ctx); + assuan_release (ctx); } log_info ("client finished\n"); } } - return errorcount? 1:0; + return errorcount ? 1 : 0; } |