diff --git a/ChangeLog b/ChangeLog index 40966da0..fecb981c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2009-03-06 Marcus Brinkmann + + * assuan/: Update to libassuan SVN 2009-03-06. + 2009-01-26 Werner Koch * configure.ac (AC_CONFIG_FILES): Add tests/opassuan/Makefile. diff --git a/assuan/ChangeLog b/assuan/ChangeLog index e620d205..3d875fb6 100644 --- a/assuan/ChangeLog +++ b/assuan/ChangeLog @@ -3,68 +3,262 @@ * assuan-buffer.c (assuan_send_data): Add hack to optionally send a final "CAN". -2008-11-03 Marcus Brinkmann +2008-11-03 Marcus Brinkmann - * Makefile.am (INCLUDES): Replace gpgme path with src. + * assuan-handler.c (std_handler_help): Make I unsigned to silence + gcc -W warning. + * assuan-logging.c (_assuan_log_print_buffer): Likewise for N. + * funopen.c (_assuan_funopen): Remove initializer to silence gcc + -W warning. + * assuan-handler.c (std_cmd_table): Add missing initializer to + silence gcc -W warning. + * assuan-socket-server.c (io): Likewise. + * assuan-socket-connect.c (assuan_socket_connect_ext): Likewise. -2008-10-30 Marcus Brinkmann +2008-10-29 Marcus Brinkmann - * assuan-pipe-connect.c: Fix prototype for _gpgme_io_spawn. Cast - second argument in its invocation to silence gcc warning. + * assuan.h (assuan_error_t) (_ASSUAN_ONLY_GPG_ERRORS): Make + unsigned int. + (assuan_transact): Change return type of callback handlers to + assuan_error_t. -2008-06-25 Marcus Brinkmann +2008-10-15 Werner Koch - * assuan-pipe-connect.c (struct spawn_fd_item_s): Add new members. - (HANDLE_TRANSLATION): New macro. - (pipe_connect_gpgme): Adjust caller of _gpgme_io_spawn. - [HANDLE_TRANSLATION]: Return translated handles. + * assuan-logging.c (_assuan_log_printf): Flush if the format + string ends with a LF. -2008-02-14 Werner Koch +2008-09-01 Werner Koch - * assuan-pipe-connect.c (_gpgme_io_spawn): Adjust prototype. - (pipe_connect_gpgme, pipe_connect_gpgme): Adjust call. + * assuan-io.c: Include time.h. Fixes bug#951. + (_assuan_usleep): Use nanosleep only is available. -2008-01-04 Marcus Brinkmann +2008-03-25 Marcus Brinkmann - * assuan-pipe-connect.c (_gpgme_io_pipe) - (_gpgme_io_spawn) [_ASSUAN_IN_GPGME_BUILD_ASSUAN]: Add prototypes - to silence compiler warning. Reported by Alon Bar-Lev. + * assuan-inquire.c (assuan_inquire): Loop over _assuan_read_line + for EAGAIN. + +2008-03-21 Marcus Brinkmann + + * assuan-defs.h (_assuan_usleep): New prototype. + * assuan-io.c (_assuan_usleep): New function. + * assuan-io-pth.c (_assuan_usleep): New function. + * mkerrors: Do not incude , but assuan-defs.h. + (_assuan_error_is_eagain): Call _assuan_usleep. + + * mkerrors [HAVE_W32_SYSTEM]: Include + (_assuan_error_is_eagain) [HAVE_W32_SYSTEM]: Wait the tenth of a + second. + +2007-11-23 Marcus Brinkmann + + * assuan-inquire.c (_assuan_inquire_ext_cb): Pass through return + value from callback function. + Suggested by Ben Kibbey . + +2007-11-14 Werner Koch + + * assuan-pipe-connect.c (pipe_connect_unix): Add dummy arg FLAGS. + (pipe_connect_w32): Add arg FLAGS and start process detached if + requested. Changed callers to pass 0. + (assuan_pipe_connect_ext): Pass FLAG. + +2007-11-12 Marcus Brinkmann + + * assuan-inquire.c (_assuan_inquire_ext_cb): Clear + CTX->inquire_membuf after deallocating it. + +2007-10-18 Marcus Brinkmann + + * assuan-handler.c (std_handler_help): New function. + (std_cmd_table): Add new command HELP. + +2007-10-08 Werner Koch + + * assuan-util.c (assuan_set_io_hooks): New. + * assuan.h (struct assuan_io_hooks): New. + (assuan_set_io_hooks, _assuan_io_hooks): Add prefix macros. + * assuan-defs.h (_assuan_io_hooks): New. + * assuan-io.c (do_io_read): Take all code from _assuan_io_read. + (_assuan_io_read, _assuan_simple_read): Add hook feature. + (do_io_write): Take all code from _assuan_io_write. + (_assuan_io_write, _assuan_simple_write): Add hook feature. + * assuan-io-pth.c (_assuan_simple_read, _assuan_simple_write) + (_assuan_io_read, _assuan_io_write): Add hook feature. + +2007-10-05 Marcus Brinkmann + + * assuan.h (_assuan_error_is_eagain): Add prefix macro. + + * assuan-defs.h (_assuan_error_is_eagain): New prototype. + * mkerrors (_assuan_error_is_eagain): New function. + * assuan-handler.c (process_next): Leave on EAGAIN. + * assuan-handler.c (process_request), + assuan-client.c (_assuan_read_from_server), + assuan-buffer.c (assuan_read_line): Busy loop over EAGAIN. + +2007-10-05 Werner Koch + + * assuan-socket.c (_assuan_sock_wsa2errno): Map WSANOTINITIALISED. + (_assuan_sock_new): Use assuan_fd_t. + * assuan.h (_assuan_sock_wsa2errno): Add prefix macro. + +2007-10-05 Marcus Brinkmann + + * assuan-defs.h (_assuan_sock_wsa2errno) [HAVE_W32_SYSTEM]: Add prototype. + * assuan-uds.c (wsa2errno) [HAVE_W32_SYSTEM]: Move and rename to ... + * assuan-socket.c (_assuan_sock_wsa2errno) [HAVE_W32_SYSTEM]: ... this. + (_assuan_close, _assuan_sock_new, _assuan_sock_connect, _assuan_sock_bind): + Always set errno on error. + + * assuan-uds.c (wsa2errno) [HAVE_W32_SYSTEM]: New function. + (uds_reader, uds_writer) [HAVE_W32_SYSTEM]: Set errno. + +2007-10-04 Werner Koch + + * mkerrors: Map EAGAIN to GPG_ERR_EAGAIN for read and write + errors. + +2007-10-02 Werner Koch + + * assuan-io.c (_assuan_io_read) [W32]: Map WSAEWOULDBLOCK to EAGAIN. + * assuan-socket.c (_assuan_sock_check_nonce): N needs to be signed. + + * assuan-defs.h (struct assuan_context_s): Add LISTEN_NONCE. + * assuan-socket-server.c (assuan_set_sock_nonce): New. + (accept_connection): Check the nonce. + +2007-10-01 Werner Koch + + * assuan.h (ASSUAN_INT2FD, ASSUAN_FD2INT): New. + + * assuan-socket.c: Rewritten. + (assuan_sock_new, assuan_sock_connect, assuan_sock_bind) + (assuan_sock_get_nonce, assuan_sock_check_nonce): New APIs. + + * assuan-io.c (_assuan_simple_read, _assuan_simple_write): + Factored code out to ... + (_assuan_io_read, _assuan_io_write): .. new. + * assuan-io-pth.c (_assuan_io_read, _assuan_io_write): New. 2007-09-25 Werner Koch * assuan.h (_assuan_gpg_strerror_r, _assuan_gpg_strsource): Add - new wrappers. + wrappers for these new internal functions. + +2007-09-24 Marcus Brinkmann + + * assuan-uds.c (uds_reader) [HAVE_W32_SYSTEM]: Do not touch the + UDS structure in the context. Reported by Frank Osterfeld. + (uds_writer): Clarify code. + +2007-09-14 Marcus Brinkmann + + * assuan-pipe-connect.c (do_finish) [HAVE_W32_SYSTEM]: Close + ctx->pid as handle. + (pipe_connect_w32): Save the spawned processes handle. + +2007-09-13 Werner Koch + + * assuan-socket.c (_assuan_close): Add inactive debug outputs. + +2007-09-11 Marcus Brinkmann + + * assuan.h: Use _WIN32 instead of HAVE_W32_SYSTEM. + +2007-09-07 Marcus Brinkmann + + * assuan-inquire.c (assuan_inquire_ext): If MAXLEN is 0, still + initialize MEMBUF. + + * assuan-inquire.c (_assuan_inquire_ext_cb): Clear CTX->in_inquire + before invoking callback and returning. + +2007-09-05 Marcus Brinkmann + + * assuan-handler.c (dispatch_command): Return non-critical errors + with PROCESS_DONE (). 2007-09-03 Marcus Brinkmann * assuan.h [_ASSUAN_EXT_SYM_PREFIX]: Add missing symbol renames with _ASSUAN_PREFIX. -2007-08-02 Werner Koch +2007-09-03 Marcus Brinkmann - * assuan-pipe-connect.c (pipe_connect_w32): A bit more debug output. - (pipe_connect_w32): Use DETACHED_PROCESS flag. - * assuan-logging.c (log_level): New. Use this to disable logging. - (assuan_set_assuan_log_level): New. - * assuan.h: Add prototype. + * assuan.h [_ASSUAN_EXT_SYM_PREFIX]: Add missing symbol renames + with _ASSUAN_PREFIX. + * assuan.h (assuan_inquire_ext): Move buffer and buffer_length + arguments callback in prototype. + * assuan-defs.h (struct assuan_context_s): Remove members + inquire_r_buffer and inquire_r_buffer_len. Add buffer and buffer + length arguments to inquire_cb. + * assuan-inquire.c (_assuan_inquire_ext_cb): Return buffer and + buffer length via callback. + (assuan_inquire_ext): Move buffer and buffer length arguments to + callback. + +2007-08-24 Werner Koch + + Switched license to back to LGPLv2.1. + +2007-08-09 Marcus Brinkmann + + * assuan.h (assuan_process_done, assuan_inquire_ext): New + prototypes. + * assuan-defs.h (struct assuan_context_s): New members + in_process_next, in_command, inquire_cb, inquire_cb_data, + inquire_r_buffer, inquire_r_buffer_len, inquire_membuf. + (_assuan_inquire_ext_cb, _assuan_inquire_release): New prototypes. + * assuan-handler.c (PROCESS_DONE): New macro. + (dummy_handler, std_handler_nop, std_handler_cancel) + (std_handler_option, std_handler_bye, std_handler_auth) + (std_handler_reset, std_handler_end): Use PROCESS_DONE to + optionally call assuan_process_done if CTX->in_process_next is + true. + (assuan_process_done, process_next): New functions. + (assuan_process_next): Rewritten to support external event + handling. + * mkerrors: Do not clear high bits of -1 for old style EOF. + * assuan-inquire.c (_assuan_inquire_release) + (_assuan_inquire_ext_cb, assuan_inquire_ext): New functions. + * assuan-pipe-server.c (_assuan_release_context): Call + _assuan_inquire_release. + 2007-07-12 Werner Koch - * assuan-handler.c (assuan_get_active_fds): Use get_osfhandle for - the data fp. - * assuan-socket.c (_assuan_close) [W32]: Use CloseHandle and not close. - - * assuan-io.c (_assuan_simple_write, _assuan_simple_read): Map - ERROR_BROKEN_PIPE to EPIPE. + * assuan.h (assuan_fd_t): New. + (ASSUAN_INVALID_FD): New. Use it everywhere. + * assuan-defs.h (SOCKET2HANDLE, HANDLE2SOCKET) [W32]: New. Use + them to cast descriptors for socket fucntions. + * assuan-pipe-connect.c (fd_to_handle, handle_to_fd): Remove + definition and all uses. + (pid_to_handle, handle_to_pid): Remove as they are ununsed. + * assuan-io.c (_assuan_simple_write, _assuan_simple_read) [W32]: + Make use of HANDLE2SOCKET. + * assuan-socket.c (_assuan_close) [W32]: Use CloseHandle and not + close. + * assuan-handler.c (assuan_get_active_fds) [W32]: Use + _get_osfhandle for the data fp. + * assuan-io.c (_assuan_simple_write): Return EPIPE on a closed pipe. + (_assuan_simple_read): Likewise + 2007-07-08 Marcus Brinkmann - * assuan-defs.h (struct assuan_context_s): Have partial peercred - structure even if HAVE_W32_SYSTEM, and have full peercred - structure only if HAVE_SO_PEERCRED. + * assuan-defs.h (struct assuan_context_s): Have full peercred + structure for HAVE_SO_PEERCRED. * assuan-connect.c (assuan_get_peercred) [!HAVE_SO_PEERCRED]: Do not try to set PID, UID and GID. +2007-07-05 Werner Koch + + * assuan-defs.h (struct assuan_context_s): Have peercred.valid + even for Windows. This makes some other code cleaner. + + * assuan.h (ASSUAN_CONFIDENTIAL): New flag. + * assuan-util.c (assuan_set_flag, assuan_get_flag): Support flag. + 2007-07-04 Marcus Brinkmann Change _WIN32 to HAVE_W32_SYSTEM for consistency. @@ -382,28 +576,63 @@ to silence gcc warning. * assuan-inquire.c (assuan_inquire): Likewise. -2005-08-19 Werner Koch +2005-09-08 Marcus Brinkmann - * funopen.c, assuan-socket.c: Copied from libassuan CVS. * assuan-pipe-connect.c (assuan_pipe_connect2): Add missing declaration of PID. 2005-08-09 Werner Koch - * README.1st: Adjusted to cope with changes done in upstream Assuan. + * mkerrors: Include config.h into assuan-errors.c. This is + required so that assuan.h knows about the W32 macro. - Merged changes for W32 support from libassuan. - * assuan.h [_ASSUAN_EXT_SYM_PREFIX]: New. * assuan-io.c [_ASSUAN_NO_PTH]: New. * assuan-pipe-connect.c (fix_signals) [_ASSUAN_NO_FIXED_SIGNALS]: New. (assuan_pipe_connect2) [_ASSUAN_USE_DOUBLE_FORK]: Use double fork. (fix_signals) [_ASSUAN_USE_DOUBLE_FORK]: Do not wait.. - * assuan-logging.c, assuan-io.c: Include config.h - Replaced all usages of _WIN32 by the new HAVE_W32_SYSTEM because - there is nothing winning in this API. - * assuan-pipe-connect.c (assuan_pipe_connect2) [_WIN32]: Return - error Not Imlemented. + +2005-05-21 Werner Koch + + * assuan-util.c (assuan_set_flag, assuan_get_flag): New. + * assuan-defs.h (struct assuan_context_s): New field flags. + * assuan.h (assuan_flag_t): New with one flag value + ASSUAN_NO_WAITPID for now. + * assuan-pipe-connect.c (do_finish): Take care of the no_waitpid + flag. + +2005-04-04 Werner Koch + + * assuan-util.c (_assuan_calloc): Avoid integer overflow. + +2005-03-22 Werner Koch + + * assuan-defs.h (struct assuan_io): Renamed elements READ and + WRITE to READFNC and WRITEFNC to avoid problems with read defined + as macros. Changed callers. Noted by Ville Skyttä. + +2005-02-24 Werner Koch + + * assuan-client.c (assuan_transact): Handle empty and comment + commands correctly. + +2004-12-20 Werner Koch + + * assuan-socket-connect.c (assuan_socket_connect) [W32]: Allow for + a drive letter in the path. + +2004-12-19 Werner Koch + + * assuan-pipe-server.c (assuan_init_pipe_server) [W32]: Map file + descriptors using _get_osfhandle. + +2004-12-19 Moritz Schulte + + * assuan-pipe-connect.c (assuan_pipe_connect2): Removed "`" + character at beginning of line 532. + +2004-12-18 Werner Koch + * assuan-logging.c (_assuan_w32_strerror): New. * assuan-defs.h (w32_strerror): new. * assuan-pipe-connect.c (assuan_pipe_connect2, fix_signals): @@ -411,57 +640,95 @@ (build_w32_commandline, create_inheritable_pipe): New. Taken from gnupg 1.9. (assuan_pipe_connect2) [W32]: Implemented for W32. - * assuan-pipe-server.c (assuan_init_pipe_server) [W32]: Map file - descriptors using _get_osfhandle. - * assuan-socket-connect.c (assuan_socket_connect) [W32]: Allow for - a drive letter in the path. - * assuan-client.c (assuan_transact): Handle empty and comment - commands correctly. - * assuan-util.c (_assuan_calloc): Avoid integer overflow. - * assuan-util.c (assuan_set_flag, assuan_get_flag): New. - * assuan-defs.h (struct assuan_context_s): New field flags. - * assuan.h (assuan_flag_t): New with one flag value - ASSUAN_NO_WAITPID for now. - * assuan-pipe-connect.c (do_finish): Take care of the no_waitpid - flag. - * mkerrors: Include config.h into assuan-errors.c. This is - required so that assuan.h knows about the W32 macro. -2005-08-09 Timo Schulz (ported from libassuan by wk) +2004-12-14 Werner Koch + + * assuan-socket-connect.c (assuan_socket_connect): Always allow + NAME to start with a froward slash. + +2004-12-07 Werner Koch + + * assuan-logging.c, assuan-io.c: Include config.h + + Replaced all usages of _WIN32 by the new HAVE_W32_SYSTEM because + there is nothing winning in this API. + + * assuan-pipe-connect.c (assuan_pipe_connect2) [_WIN32]: Return + error Not Imlemented. + +2004-11-27 Werner Koch + + * assuan-socket.c: Include sys/types.h. Noted by Michael + Nottebrock. + +2004-11-26 Werner Koch + + * assuan-io.c [_WIN32]: Avoid warnings about unknown pragmas. + +2004-11-24 Werner Koch + + * assuan-logging.c (_assuan_log_printf): New. + * assuan-domain-connect.c (LOG): Removed and replaced all callers + by _assuan_log_printf. This is needed for C89 and gcc 2.95 which + both don't have C99 style variable arg macros. + * assuan-pipe-connect.c (LOG): Ditto. + * assuan-socket-connect.c (LOG): Ditto. + + * assuan-socket.c[!_WIN32]: Fixed includes. + +2004-11-23 Timo Schulz + + * assuan-socket.c (_assuan_sock_connect): Get local port from + the sun_path[] file. + (_assuan_sock_bind): Write local port to the sun_path[] file. + * assuan-socket-connect.c (assuan_socket_connect): Use DIRSEP_C + for a better portability. + (assuan-defs.h): Define DIRSEP_C. +2004-11-19 Werner Koch + + * assuan-handler.c (assuan_write_status): Return an error code. + +2004-11-22 Timo Schulz + * assuan-io.c (_assuan_simple_read, _assuan_simple_write): W32 support. * assuan-socket.c (_assuan_close): New. (_assuan_sock_new): New. (_assuan_sock_bind): New. + +2004-11-16 Werner Koch -2005-03-22 Werner Koch + * assuan-socket-connect.c (LOG): Fixed macro to print not only the + prefix. + * assuan-domain-connect.c, assuan-socket-connect.c (LOG): Ditto. - * assuan-defs.h (struct assuan_io): Renamed elements READ and - WRITE to READFNC and WRITEFNC to avoid problems with read defined - as macro. Changed callers. Noted by Ville Skyttä. +2004-10-02 Werner Koch -2004-12-16 Marcus Brinkmann - - * assuan-pipe-connect.c (do_finish): Do not wait for child to finish. - (assuan_pipe_connect): Use double-fork approach. - * assuan-connect.c (assuan_disconnect): Do not write BYE to the - status line. - -2004-12-07 Marcus Brinkmann - - * README.1st: Add copyright notice. + * assuan-socket-connect.c: Define SUN_LEN, AF_LOCAL and PF_LOCAL + if they are not available. + * assuan-domain-connect.c: Define PF_LOCAL and AF_LOCAL if needed. 2004-06-23 Marcus Brinkmann * assuan-domain-connect.c [HAVE_SYS_UIO_H]: Include . - * assuan-handler.c: Include . +2004-05-11 Werner Koch -2004-06-08 Marcus Brinkmann + * assuan-listen.c (assuan_set_hello_line, assuan_accept): Allow + for multi line hello strings. - * assuan-buffer.c (assuan_write_line): If the line is longer than - the maximum line length, bail out early. + * assuan-buffer.c (_assuan_write_line): New with parts of .. + (assuan_write_line): .. factored out. + +2004-04-29 Werner Koch + + * assuan-socket-connect.c: Include string.h. + * assuan-logging.c: Ditto. + +2004-04-22 Marcus Brinkmann + + * libassuan.m4: Quote first argument to AC_DEFUN. 2004-04-21 Werner Koch @@ -1039,7 +1306,7 @@ * assuan-defs.h: Add space in the context for this. - Copyright 2001, 2002, 2006 Free Software Foundation, Inc. + Copyright 2001, 2002, 2006, 2007 Free Software Foundation, Inc. This file is free software; as a special exception the author gives unlimited permission to copy and/or distribute it, with or without diff --git a/assuan/assuan-buffer.c b/assuan/assuan-buffer.c index 31f33945..b9e35721 100644 --- a/assuan/assuan-buffer.c +++ b/assuan/assuan-buffer.c @@ -14,9 +14,7 @@ * 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. + * License along with this program; if not, see . */ #include @@ -53,9 +51,10 @@ writen (assuan_context_t ctx, const char *buffer, size_t length) return 0; /* okay */ } -/* Read an entire line. Returns 0 on success or -1 and ERRNo on +/* Read an entire line. Returns 0 on success or -1 and ERRNO on failure. EOF is indictated by setting the integer at address - R_EOF. */ + R_EOF. Note: BUF, R_NREAD and R_EOF contain a valid result even if + an error is returned. */ static int readline (assuan_context_t ctx, char *buf, size_t buflen, int *r_nread, int *r_eof) @@ -94,7 +93,7 @@ readline (assuan_context_t ctx, char *buf, size_t buflen, } -/* Function returns an Assuan error. */ +/* Function returns an Assuan error. */ assuan_error_t _assuan_read_line (assuan_context_t ctx) { @@ -134,11 +133,23 @@ _assuan_read_line (assuan_context_t ctx) &nread, &ctx->inbound.eof); if (rc) { + int saved_errno = errno; + if (ctx->log_fp) - fprintf (ctx->log_fp, "%s[%u.%d] DBG: <- [Error: %s (%d)]\n", - assuan_get_assuan_log_prefix (), - (unsigned int)getpid (), ctx->inbound.fd, - strerror (errno), errno); + fprintf (ctx->log_fp, "%s[%u.%d] DBG: <- [Error: %s]\n", + assuan_get_assuan_log_prefix (), + (unsigned int)getpid (), (int)ctx->inbound.fd, + strerror (errno)); + + if (saved_errno == EAGAIN) + { + /* We have to save a partial line. */ + memcpy (ctx->inbound.attic.line, line, atticlen + nread); + ctx->inbound.attic.pending = 0; + ctx->inbound.attic.linelen = atticlen + nread; + } + + errno = saved_errno; return _assuan_error (ASSUAN_Read_Error); } if (!nread) @@ -147,7 +158,7 @@ _assuan_read_line (assuan_context_t ctx) if (ctx->log_fp) fprintf (ctx->log_fp, "%s[%u.%d] DBG: <- [EOF]\n", assuan_get_assuan_log_prefix (), - (unsigned int)getpid (), ctx->inbound.fd); + (unsigned int)getpid (), (int)ctx->inbound.fd); return _assuan_error (-1); } @@ -191,7 +202,7 @@ _assuan_read_line (assuan_context_t ctx) { fprintf (ctx->log_fp, "%s[%u.%d] DBG: <- ", assuan_get_assuan_log_prefix (), - (unsigned int)getpid (), ctx->inbound.fd); + (unsigned int)getpid (), (int)ctx->inbound.fd); if (ctx->confidential) fputs ("[Confidential data not shown]", ctx->log_fp); else @@ -207,7 +218,7 @@ _assuan_read_line (assuan_context_t ctx) if (ctx->log_fp) fprintf (ctx->log_fp, "%s[%u.%d] DBG: <- [Invalid line]\n", assuan_get_assuan_log_prefix (), - (unsigned int)getpid (), ctx->inbound.fd); + (unsigned int)getpid (), (int)ctx->inbound.fd); *line = 0; ctx->inbound.linelen = 0; return _assuan_error (ctx->inbound.eof @@ -234,7 +245,12 @@ assuan_read_line (assuan_context_t ctx, char **line, size_t *linelen) if (!ctx) return _assuan_error (ASSUAN_Invalid_Value); - err = _assuan_read_line (ctx); + do + { + err = _assuan_read_line (ctx); + } + while (_assuan_error_is_eagain (err)); + *line = ctx->inbound.line; *linelen = ctx->inbound.linelen; return err; @@ -265,7 +281,7 @@ _assuan_write_line (assuan_context_t ctx, const char *prefix, fprintf (ctx->log_fp, "%s[%u.%d] DBG: -> " "[supplied line too long -truncated]\n", assuan_get_assuan_log_prefix (), - (unsigned int)getpid (), ctx->inbound.fd); + (unsigned int)getpid (), (int)ctx->inbound.fd); if (prefixlen > 5) prefixlen = 5; if (len > ASSUAN_LINELENGTH - prefixlen - 2) @@ -281,7 +297,7 @@ _assuan_write_line (assuan_context_t ctx, const char *prefix, { fprintf (ctx->log_fp, "%s[%u.%d] DBG: -> ", assuan_get_assuan_log_prefix (), - (unsigned int)getpid (), ctx->inbound.fd); + (unsigned int)getpid (), (int)ctx->inbound.fd); if (ctx->confidential) fputs ("[Confidential data not shown]", ctx->log_fp); else @@ -333,7 +349,7 @@ assuan_write_line (assuan_context_t ctx, const char *line) fprintf (ctx->log_fp, "%s[%u.%d] DBG: -> " "[supplied line contained a LF - truncated]\n", assuan_get_assuan_log_prefix (), - (unsigned int)getpid (), ctx->inbound.fd); + (unsigned int)getpid (), (int)ctx->inbound.fd); return _assuan_write_line (ctx, NULL, line, len); } @@ -398,7 +414,7 @@ _assuan_cookie_write_data (void *cookie, const char *buffer, size_t orig_size) { fprintf (ctx->log_fp, "%s[%u.%d] DBG: -> ", assuan_get_assuan_log_prefix (), - (unsigned int)getpid (), ctx->inbound.fd); + (unsigned int)getpid (), (int)ctx->inbound.fd); if (ctx->confidential) fputs ("[Confidential data not shown]", ctx->log_fp); @@ -454,7 +470,7 @@ _assuan_cookie_write_flush (void *cookie) { fprintf (ctx->log_fp, "%s[%u.%d] DBG: -> ", assuan_get_assuan_log_prefix (), - (unsigned int)getpid (), ctx->inbound.fd); + (unsigned int)getpid (), (int)ctx->inbound.fd); if (ctx->confidential) fputs ("[Confidential data not shown]", ctx->log_fp); else @@ -524,11 +540,11 @@ assuan_send_data (assuan_context_t ctx, const void *buffer, size_t length) } assuan_error_t -assuan_sendfd (assuan_context_t ctx, int fd) +assuan_sendfd (assuan_context_t ctx, assuan_fd_t fd) { /* It is explicitly allowed to use (NULL, -1) as a runtime test to check whether descriptor passing is available. */ - if (!ctx && fd == -1) + if (!ctx && fd == ASSUAN_INVALID_FD) #ifdef USE_DESCRIPTOR_PASSING return 0; #else @@ -543,7 +559,7 @@ assuan_sendfd (assuan_context_t ctx, int fd) } assuan_error_t -assuan_receivefd (assuan_context_t ctx, int *fd) +assuan_receivefd (assuan_context_t ctx, assuan_fd_t *fd) { if (! ctx->io->receivefd) return set_error (ctx, Not_Implemented, diff --git a/assuan/assuan-client.c b/assuan/assuan-client.c index 7b3d2662..15f4f1cd 100644 --- a/assuan/assuan-client.c +++ b/assuan/assuan-client.c @@ -14,9 +14,7 @@ * 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. + * License along with this program; if not, see . */ #include @@ -44,7 +42,11 @@ _assuan_read_from_server (assuan_context_t ctx, int *okay, int *off) *off = 0; do { - rc = _assuan_read_line (ctx); + do + { + rc = _assuan_read_line (ctx); + } + while (_assuan_error_is_eagain (rc)); if (rc) return rc; line = ctx->inbound.line; diff --git a/assuan/assuan-connect.c b/assuan/assuan-connect.c index b50b17bd..2106ac30 100644 --- a/assuan/assuan-connect.c +++ b/assuan/assuan-connect.c @@ -14,9 +14,7 @@ * 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. + * License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H @@ -60,8 +58,8 @@ assuan_get_pid (assuan_context_t ctx) #ifndef HAVE_W32_SYSTEM -/* Return user credentials. PID, UID and GID amy be gived as NULL if - you are not interested in this value. For getting the pid of the +/* Return user credentials. PID, UID and GID may be given as NULL if + you are not interested in a value. For getting the pid of the peer the assuan_get_pid is usually better suited. */ assuan_error_t assuan_get_peercred (assuan_context_t ctx, pid_t *pid, uid_t *uid, gid_t *gid) diff --git a/assuan/assuan-defs.h b/assuan/assuan-defs.h index b1d9f3ef..e2d0f52b 100644 --- a/assuan/assuan-defs.h +++ b/assuan/assuan-defs.h @@ -1,5 +1,5 @@ /* assuan-defs.c - Internal definitions to Assuan - * Copyright (C) 2001, 2002, 2004, 2005 Free Software Foundation, Inc. + * Copyright (C) 2001, 2002, 2004, 2005, 2007, 2008 Free Software Foundation, Inc. * * This file is part of Assuan. * @@ -40,17 +40,6 @@ #endif #ifdef HAVE_W32_SYSTEM -#define AF_LOCAL AF_UNIX -/* We need to prefix the structure with a sockaddr_in header so we can - use it later for sendto and recvfrom. */ -struct sockaddr_un -{ - short sun_family; - unsigned short sun_port; - struct in_addr sun_addr; - char sun_path[108-2-4]; /* Path name. */ -}; - /* Not needed anymore because the current mingw32 defines this in sys/types.h */ /* typedef int ssize_t; */ @@ -80,12 +69,16 @@ struct assuan_io /* Routine to write to output_fd. */ ssize_t (*writefnc) (assuan_context_t, const void *, size_t); /* Send a file descriptor. */ - assuan_error_t (*sendfd) (assuan_context_t, int); + assuan_error_t (*sendfd) (assuan_context_t, assuan_fd_t); /* Receive a file descriptor. */ - assuan_error_t (*receivefd) (assuan_context_t, int *); + assuan_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 { @@ -103,6 +96,14 @@ struct assuan_context_s int confidential; 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); + void *inquire_cb_data; + void *inquire_membuf; + char *hello_line; char *okay_line; /* See assuan_set_okay_line() */ @@ -111,7 +112,7 @@ struct assuan_context_s FILE *log_fp; struct { - int fd; + assuan_fd_t fd; int eof; char line[LINELENGTH]; int linelen; /* w/o CR, LF - might not be the same as @@ -125,7 +126,7 @@ struct assuan_context_s } inbound; struct { - int fd; + assuan_fd_t fd; struct { FILE *fp; char line[LINELENGTH]; @@ -137,8 +138,10 @@ struct assuan_context_s int pipe_mode; /* We are in pipe mode, i.e. we can handle just one connection and must terminate then. */ pid_t pid; /* The pid of the peer. */ - int listen_fd; /* The fd we are listening on (used by socket servers) */ - int connected_fd; /* helper */ + assuan_fd_t listen_fd; /* The fd we are listening on (used by + socket servers) */ + assuan_sock_nonce_t listen_nonce; /* Used with LISTEN_FD. */ + assuan_fd_t connected_fd; /* helper */ struct { int valid; /* Whether this structure has valid information. */ @@ -162,7 +165,7 @@ struct assuan_context_s int bufferoffset; /* Offset of start of buffer. */ int buffersize; /* Bytes buffered. */ - int pendingfds[5]; /* Array to save received descriptors. */ + assuan_fd_t pendingfds[5]; /* Array to save received descriptors. */ int pendingfdscount; /* Number of received descriptors. */ } uds; @@ -188,15 +191,15 @@ struct assuan_context_s /* 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 will be suppressed. With bit 1 set, the entire - line will be ignored. */ + 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); - int input_fd; /* set by INPUT command */ - int output_fd; /* set by OUTPUT command */ + 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; @@ -228,17 +231,22 @@ assuan_error_t _assuan_read_from_server (assuan_context_t ctx, /*-- assuan-error.c --*/ +/*-- assuan-inquire.c --*/ +int _assuan_inquire_ext_cb (assuan_context_t ctx); +void _assuan_inquire_release (assuan_context_t ctx); -/* Map error codes as used in this implementaion to the libgpg-error +/* Map error codes as used in this implementation to the libgpg-error codes. */ assuan_error_t _assuan_error (int oldcode); +/* Check if ERR means EAGAIN. */ +int _assuan_error_is_eagain (assuan_error_t err); -/* Extrac the erro code from A. This works for both the old and the - new style error codes. This needs to be whenever an error code is - compared. */ +/* Extract the error code from A. This works for both the old and the + new style error codes. This needs to be used whenever an error + code is compared. */ #define err_code(a) ((a) & 0x00ffffff) -/* Check whether A is the erro code for EOF. We allow forold and new +/* Check whether A is the erro code for EOF. We allow for old and new style EOF error codes here. */ #define err_is_eof(a) ((a) == (-1) || err_code (a) == 16383) @@ -284,6 +292,8 @@ pid_t _assuan_waitpid (pid_t pid, int *status, int options); ssize_t _assuan_simple_read (assuan_context_t ctx, void *buffer, size_t size); ssize_t _assuan_simple_write (assuan_context_t ctx, const void *buffer, size_t size); +ssize_t _assuan_io_read (assuan_fd_t fd, void *buffer, size_t size); +ssize_t _assuan_io_write (assuan_fd_t fd, const void *buffer, size_t size); #ifdef HAVE_W32_SYSTEM int _assuan_simple_sendmsg (assuan_context_t ctx, void *msg); int _assuan_simple_recvmsg (assuan_context_t ctx, void *msg); @@ -292,11 +302,21 @@ ssize_t _assuan_simple_sendmsg (assuan_context_t ctx, struct msghdr *msg); ssize_t _assuan_simple_recvmsg (assuan_context_t ctx, struct msghdr *msg); #endif +void _assuan_usleep (unsigned int usec); + + /*-- assuan-socket.c --*/ -int _assuan_close (int fd); -int _assuan_sock_new (int domain, int type, int proto); -int _assuan_sock_bind (int sockfd, struct sockaddr *addr, int addrlen); -int _assuan_sock_connect (int sockfd, struct sockaddr *addr, int addrlen); +int _assuan_close (assuan_fd_t fd); +assuan_fd_t _assuan_sock_new (int domain, int type, int proto); +int _assuan_sock_connect (assuan_fd_t sockfd, + struct sockaddr *addr, int addrlen); +int _assuan_sock_bind (assuan_fd_t sockfd, struct sockaddr *addr, int addrlen); +int _assuan_sock_get_nonce (struct sockaddr *addr, int addrlen, + assuan_sock_nonce_t *nonce); +int _assuan_sock_check_nonce (assuan_fd_t fd, assuan_sock_nonce_t *nonce); +#ifdef HAVE_W32_SYSTEM +int _assuan_sock_wsa2errno (int err); +#endif #ifdef HAVE_FOPENCOOKIE /* We have to implement funopen in terms of glibc's fopencookie. */ @@ -329,4 +349,13 @@ int putc_unlocked (int c, FILE *stream); #define DIMof(type,member) DIM(((type *)0)->member) +#if HAVE_W32_SYSTEM +#define SOCKET2HANDLE(s) ((void *)(s)) +#define HANDLE2SOCKET(h) ((unsigned int)(h)) +#else +#define SOCKET2HANDLE(s) (s) +#define HANDLE2SOCKET(h) (h) +#endif + + #endif /*ASSUAN_DEFS_H*/ diff --git a/assuan/assuan-handler.c b/assuan/assuan-handler.c index d1b29cff..b940bfd4 100644 --- a/assuan/assuan-handler.c +++ b/assuan/assuan-handler.c @@ -1,5 +1,5 @@ /* assuan-handler.c - dispatch commands - * Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc. + * Copyright (C) 2001, 2002, 2003, 2007 Free Software Foundation, Inc. * * This file is part of Assuan. * @@ -14,9 +14,7 @@ * 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. + * License along with this program; if not, see . */ #include @@ -35,18 +33,21 @@ static int my_strcasecmp (const char *a, const char *b); +#define PROCESS_DONE(ctx, rc) \ + ((ctx)->in_process_next ? assuan_process_done ((ctx), (rc)) : (rc)) static int dummy_handler (assuan_context_t ctx, char *line) { - return set_error (ctx, Server_Fault, "no handler registered"); + return + PROCESS_DONE (ctx, set_error (ctx, Server_Fault, "no handler registered")); } static int std_handler_nop (assuan_context_t ctx, char *line) { - return 0; /* okay */ + return PROCESS_DONE (ctx, 0); /* okay */ } static int @@ -54,7 +55,7 @@ std_handler_cancel (assuan_context_t ctx, char *line) { if (ctx->cancel_notify_fnc) ctx->cancel_notify_fnc (ctx); - return set_error (ctx, Not_Implemented, NULL); + return PROCESS_DONE (ctx, set_error (ctx, Not_Implemented, NULL)); } static int @@ -65,9 +66,12 @@ std_handler_option (assuan_context_t ctx, char *line) for (key=line; spacep (key); key++) ; if (!*key) - return set_error (ctx, Syntax_Error, "argument required"); + return + PROCESS_DONE (ctx, set_error (ctx, Syntax_Error, "argument required")); if (*key == '=') - return set_error (ctx, Syntax_Error, "no option name given"); + return + PROCESS_DONE (ctx, set_error (ctx, Syntax_Error, + "no option name given")); for (value=key; *value && !spacep (value) && *value != '='; value++) ; if (*value) @@ -82,7 +86,9 @@ std_handler_option (assuan_context_t ctx, char *line) for (; spacep (value); value++) ; if (!*value) - return set_error (ctx, Syntax_Error, "option argument expected"); + return + PROCESS_DONE (ctx, set_error (ctx, Syntax_Error, + "option argument expected")); } if (*value) { @@ -96,12 +102,13 @@ std_handler_option (assuan_context_t ctx, char *line) if (*key == '-' && key[1] == '-' && key[2]) key += 2; /* the double dashes are optional */ if (*key == '-') - return set_error (ctx, Syntax_Error, - "option should not begin with one dash"); + return PROCESS_DONE (ctx, + set_error (ctx, Syntax_Error, + "option should not begin with one dash")); if (ctx->option_handler_fnc) - return ctx->option_handler_fnc (ctx, key, value); - return 0; + return PROCESS_DONE (ctx, ctx->option_handler_fnc (ctx, key, value)); + return PROCESS_DONE (ctx, 0); } static int @@ -111,13 +118,13 @@ std_handler_bye (assuan_context_t ctx, char *line) ctx->bye_notify_fnc (ctx); assuan_close_input_fd (ctx); assuan_close_output_fd (ctx); - return -1; /* pretty simple :-) */ + return PROCESS_DONE (ctx, _assuan_error (-1)); /* pretty simple :-) */ } static int std_handler_auth (assuan_context_t ctx, char *line) { - return set_error (ctx, Not_Implemented, NULL); + return PROCESS_DONE (ctx, set_error (ctx, Not_Implemented, NULL)); } static int @@ -128,17 +135,35 @@ std_handler_reset (assuan_context_t ctx, char *line) assuan_close_input_fd (ctx); assuan_close_output_fd (ctx); _assuan_uds_close_fds (ctx); - return 0; + return PROCESS_DONE (ctx, 0); } static int -std_handler_end (assuan_context_t ctx, char *line) +std_handler_help (assuan_context_t ctx, char *line) { - return set_error (ctx, Not_Implemented, NULL); + unsigned int i; + char buf[ASSUAN_LINELENGTH]; + + for (i = 0; i < ctx->cmdtbl_used; i++) + { + snprintf (buf, sizeof (buf), "# %s", ctx->cmdtbl[i].name); + buf[ASSUAN_LINELENGTH - 1] = '\0'; + assuan_write_line (ctx, buf); + } + + return PROCESS_DONE (ctx, 0); } + +static int +std_handler_end (assuan_context_t ctx, char *line) +{ + return PROCESS_DONE (ctx, set_error (ctx, Not_Implemented, NULL)); +} + + assuan_error_t -assuan_command_parse_fd (assuan_context_t ctx, char *line, int *rfd) +assuan_command_parse_fd (assuan_context_t ctx, char *line, assuan_fd_t *rfd) { char *endp; @@ -151,7 +176,13 @@ assuan_command_parse_fd (assuan_context_t ctx, char *line, int *rfd) line ++; if (!digitp (*line)) return set_error (ctx, Syntax_Error, "number required"); +#ifdef HAVE_W32_SYSTEM + /* Fixme: For a W32/64bit system we will need to change the cast + and the conversion fucntion. */ + *rfd = (void*)strtoul (line, &endp, 10); +#else *rfd = strtoul (line, &endp, 10); +#endif /* Remove that argument so that a notify handler won't see it. */ memset (line, ' ', endp? (endp-line):strlen(line)); @@ -166,34 +197,37 @@ assuan_command_parse_fd (assuan_context_t ctx, char *line, int *rfd) return assuan_receivefd (ctx, rfd); } + /* Format is INPUT FD= */ static int std_handler_input (assuan_context_t ctx, char *line) { - int rc, fd; + int rc; + assuan_fd_t fd; rc = assuan_command_parse_fd (ctx, line, &fd); if (rc) - return rc; + return PROCESS_DONE (ctx, rc); ctx->input_fd = fd; if (ctx->input_notify_fnc) ctx->input_notify_fnc (ctx, line); - return 0; + return PROCESS_DONE (ctx, 0); } /* Format is OUTPUT FD= */ static int std_handler_output (assuan_context_t ctx, char *line) { - int rc, fd; + int rc; + assuan_fd_t fd; rc = assuan_command_parse_fd (ctx, line, &fd); if (rc) - return rc; + return PROCESS_DONE (ctx, rc); ctx->output_fd = fd; if (ctx->output_notify_fnc) ctx->output_notify_fnc (ctx, line); - return 0; + return PROCESS_DONE (ctx, 0); } @@ -215,11 +249,12 @@ static struct { { "AUTH", std_handler_auth, 1 }, { "RESET", std_handler_reset, 1 }, { "END", std_handler_end, 1 }, + { "HELP", std_handler_help, 1 }, - { "INPUT", std_handler_input }, - { "OUTPUT", std_handler_output }, + { "INPUT", std_handler_input, 0 }, + { "OUTPUT", std_handler_output, 0 }, { "OPTION", std_handler_option, 1 }, - { NULL } + { NULL, NULL, 0 } }; @@ -406,9 +441,10 @@ my_strcasecmp (const char *a, const char *b) return *a == *b? 0 : (((*a >= 'a' && *a <= 'z')? (*a&~0x20):*a) - *b); } + /* Parse the line, break out the command, find it in the command table, remove leading and white spaces from the arguments, call the - handler with the argument line and return the error */ + handler with the argument line and return the error. */ static int dispatch_command (assuan_context_t ctx, char *line, int linelen) { @@ -416,13 +452,21 @@ dispatch_command (assuan_context_t ctx, char *line, int linelen) const char *s; int shift, i; + /* Note that as this function is invoked by assuan_process_next as + well, we need to hide non-critical errors with PROCESS_DONE. */ + if (*line == 'D' && line[1] == ' ') /* divert to special handler */ - return handle_data_line (ctx, line+2, linelen-2); + /* FIXME: Depending on the final implementation of + handle_data_line, this may be wrong here. For example, if a + user callback is invoked, and that callback is responsible for + calling assuan_process_done, then this is wrong. */ + return PROCESS_DONE (ctx, handle_data_line (ctx, line+2, linelen-2)); for (p=line; *p && *p != ' ' && *p != '\t'; p++) ; if (p==line) - return set_error (ctx, Syntax_Error, "leading white-space"); + return PROCESS_DONE + (ctx, set_error (ctx, Syntax_Error, "leading white-space")); if (*p) { /* Skip over leading WS after the keyword */ *p++ = 0; @@ -445,7 +489,7 @@ dispatch_command (assuan_context_t ctx, char *line, int linelen) } } if (!s) - return set_error (ctx, Unknown_Command, NULL); + return PROCESS_DONE (ctx, set_error (ctx, Unknown_Command, NULL)); line += shift; linelen -= shift; @@ -453,42 +497,34 @@ dispatch_command (assuan_context_t ctx, char *line, int linelen) return ctx->cmdtbl[i].handler (ctx, line); } - - -static int -process_request (assuan_context_t ctx) +/* Call this to acknowledge the current command. */ +int +assuan_process_done (assuan_context_t ctx, int rc) { - int rc; + if (!ctx->in_command) + return _assuan_error (ASSUAN_General_Error); - if (ctx->in_inquire) - return _assuan_error (ASSUAN_Nested_Commands); + ctx->in_command = 0; - rc = _assuan_read_line (ctx); - if (rc) - return rc; - if (*ctx->inbound.line == '#' || !ctx->inbound.linelen) - return 0; /* comment line - ignore */ - - ctx->outbound.data.error = 0; - ctx->outbound.data.linelen = 0; - /* dispatch command and return reply */ - rc = dispatch_command (ctx, ctx->inbound.line, ctx->inbound.linelen); - /* check from data write errors */ + /* Check for data write errors. */ if (ctx->outbound.data.fp) - { /* Flush the data lines */ + { + /* Flush the data lines. */ fclose (ctx->outbound.data.fp); ctx->outbound.data.fp = NULL; if (!rc && ctx->outbound.data.error) - rc = ctx->outbound.data.error; + rc = ctx->outbound.data.error; } - else /* flush any data send w/o using the data fp */ + else { + /* Flush any data send without using the data FP. */ assuan_send_data (ctx, NULL, 0); if (!rc && ctx->outbound.data.error) - rc = ctx->outbound.data.error; + rc = ctx->outbound.data.error; } - /* Error handling */ + + /* Error handling. */ if (!rc) { rc = assuan_write_line (ctx, ctx->okay_line? ctx->okay_line : "OK"); @@ -501,26 +537,26 @@ process_request (assuan_context_t ctx) else { char errline[300]; - + if (rc < 100) sprintf (errline, "ERR %d server fault (%.50s)", _assuan_error (ASSUAN_Server_Fault), assuan_strerror (rc)); else { const char *text = ctx->err_no == rc? ctx->err_str:NULL; - + #if defined(HAVE_W32_SYSTEM) unsigned int source, code; char ebuf[50]; const char *esrc; - + source = ((rc >> 24) & 0xff); code = (rc & 0x00ffffff); if (source && !_assuan_gpg_strerror_r (rc, ebuf, sizeof ebuf) && (esrc=_assuan_gpg_strsource (rc))) { - /* Assume this is an libgpg-error. */ + /* Assume this is an libgpg-error. */ sprintf (errline, "ERR %d %.50s <%.30s>%s%.100s", rc, ebuf, esrc, text? " - ":"", text?text:""); @@ -554,7 +590,7 @@ process_request (assuan_context_t ctx) { /* Assume this is an libgpg-error. */ char ebuf[50]; - + gpg_strerror_r (rc, ebuf, sizeof ebuf ); sprintf (errline, "ERR %d %.50s <%.30s>%s%.100s", rc, @@ -569,19 +605,123 @@ process_request (assuan_context_t ctx) } rc = assuan_write_line (ctx, errline); } - + if (ctx->post_cmd_notify_fnc) ctx->post_cmd_notify_fnc (ctx, rc); - + ctx->confidential = 0; if (ctx->okay_line) { xfree (ctx->okay_line); ctx->okay_line = NULL; } + return rc; } + +static int +process_next (assuan_context_t ctx) +{ + int rc; + + /* What the next thing to do is depends on the current state. + However, we will always first read the next line. The client is + required to write full lines without blocking long after starting + a partial line. */ + rc = _assuan_read_line (ctx); + if (_assuan_error_is_eagain (rc)) + return 0; + if (rc) + return rc; + if (*ctx->inbound.line == '#' || !ctx->inbound.linelen) + /* Comment lines are ignored. */ + return 0; + + /* Now we have a line that really means something. It could be one + of the following things: First, if we are not in a command + already, it is the next command to dispatch. Second, if we are + in a command, it can only be the response to an INQUIRE + reply. */ + + if (!ctx->in_command) + { + ctx->in_command = 1; + + ctx->outbound.data.error = 0; + ctx->outbound.data.linelen = 0; + /* Dispatch command and return reply. */ + ctx->in_process_next = 1; + rc = dispatch_command (ctx, ctx->inbound.line, ctx->inbound.linelen); + ctx->in_process_next = 0; + } + else if (ctx->in_inquire) + { + /* FIXME: Pick up the continuation. */ + rc = _assuan_inquire_ext_cb (ctx); + } + else + { + /* Should not happen. The client is sending data while we are + in a command and not waiting for an inquire. We log an error + and discard it. */ + _assuan_log_printf ("unexpected client data\n"); + rc = 0; + } + + return rc; +} + + +/* This function should be invoked when the assuan connected FD is + ready for reading. If the equivalent to EWOULDBLOCK is returned + (this should be done by the command handler), assuan_process_next + should be invoked the next time the connected FD is readable. + Eventually, the caller will finish by invoking + assuan_process_done. */ +int +assuan_process_next (assuan_context_t ctx) +{ + int rc; + + do + { + rc = process_next (ctx); + } + while (!rc && assuan_pending_line (ctx)); + + return rc; +} + + + +static int +process_request (assuan_context_t ctx) +{ + int rc; + + if (ctx->in_inquire) + return _assuan_error (ASSUAN_Nested_Commands); + + do + { + rc = _assuan_read_line (ctx); + } + while (_assuan_error_is_eagain (rc)); + if (rc) + return rc; + if (*ctx->inbound.line == '#' || !ctx->inbound.linelen) + return 0; /* comment line - ignore */ + + ctx->in_command = 1; + ctx->outbound.data.error = 0; + ctx->outbound.data.linelen = 0; + /* dispatch command and return reply */ + rc = dispatch_command (ctx, ctx->inbound.line, ctx->inbound.linelen); + + return assuan_process_done (ctx, rc); +} + /** * assuan_process: * @ctx: assuan context @@ -609,24 +749,6 @@ assuan_process (assuan_context_t ctx) } -/** - * assuan_process_next: - * @ctx: Assuan context - * - * Same as assuan_process() but the user has to provide the outer - * loop. He should loop as long as the return code is zero and stop - * otherwise; -1 is regular end. - * - * See also: assuan_get_active_fds() - * Return value: -1 for end of server, 0 on success or an error code - **/ -int -assuan_process_next (assuan_context_t ctx) -{ - return process_request (ctx); -} - - /** * assuan_get_active_fds: * @ctx: Assuan context @@ -646,7 +768,7 @@ assuan_process_next (assuan_context_t ctx) **/ int assuan_get_active_fds (assuan_context_t ctx, int what, - int *fdarray, int fdarraysize) + assuan_fd_t *fdarray, int fdarraysize) { int n = 0; @@ -655,16 +777,16 @@ assuan_get_active_fds (assuan_context_t ctx, int what, if (!what) { - if (ctx->inbound.fd != -1) + if (ctx->inbound.fd != ASSUAN_INVALID_FD) fdarray[n++] = ctx->inbound.fd; } else { - if (ctx->outbound.fd != -1) + if (ctx->outbound.fd != ASSUAN_INVALID_FD) fdarray[n++] = ctx->outbound.fd; if (ctx->outbound.data.fp) #ifdef HAVE_W32_SYSTEM - fdarray[n++] = _get_osfhandle (fileno (ctx->outbound.data.fp)); + fdarray[n++] = (void*)_get_osfhandle (fileno (ctx->outbound.data.fp)); #else fdarray[n++] = fileno (ctx->outbound.data.fp); #endif diff --git a/assuan/assuan-inquire.c b/assuan/assuan-inquire.c index d8c52d09..58b9f029 100644 --- a/assuan/assuan-inquire.c +++ b/assuan/assuan-inquire.c @@ -1,5 +1,5 @@ /* assuan-inquire.c - handle inquire stuff - * Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc. + * Copyright (C) 2001, 2002, 2003, 2005, 2007 Free Software Foundation, Inc. * * This file is part of Assuan. * @@ -14,9 +14,7 @@ * 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. + * License along with this program; if not, see . */ #include @@ -44,7 +42,7 @@ struct membuf -/* A simple implemnation of a dynamic buffer. Use init_membuf() to +/* A simple implementation of a dynamic buffer. Use init_membuf() to create a buffer, put_membuf to append bytes and get_membuf to release and return the buffer. Allocation errors are detected but only returned at the final get_membuf(), this helps not to clutter @@ -171,7 +169,9 @@ assuan_inquire (assuan_context_t ctx, const char *keyword, { do { - rc = _assuan_read_line (ctx); + do + rc = _assuan_read_line (ctx); + while (_assuan_error_is_eagain (rc)); if (rc) goto leave; line = (unsigned char *) ctx->inbound.line; @@ -234,8 +234,154 @@ assuan_inquire (assuan_context_t ctx, const char *keyword, return rc; } + +void +_assuan_inquire_release (assuan_context_t ctx) +{ + if (ctx->in_inquire) + { + if (ctx->inquire_membuf) + { + free_membuf (ctx->inquire_membuf); + free (ctx->inquire_membuf); + } + ctx->in_inquire = 0; + } +} +int +_assuan_inquire_ext_cb (assuan_context_t ctx) +{ + int rc; + unsigned char *line; + int linelen; + struct membuf *mb; + unsigned char *p; + line = (unsigned char *) ctx->inbound.line; + linelen = ctx->inbound.linelen; + mb = ctx->inquire_membuf; + if (line[0] == 'C' && line[1] == 'A' && line[2] == 'N') + { + rc = _assuan_error (ASSUAN_Canceled); + goto leave; + } + if (line[0] == 'E' && line[1] == 'N' && line[2] == 'D' + && (!line[3] || line[3] == ' ')) + { + rc = 0; + goto leave; + } + if (line[0] != 'D' || line[1] != ' ' || mb == NULL) + { + rc = _assuan_error (ASSUAN_Unexpected_Command); + goto leave; + } + + if (linelen < 3) + return 0; + line += 2; + linelen -= 2; + + p = line; + while (linelen) + { + for (;linelen && *p != '%'; linelen--, p++) + ; + put_membuf (mb, line, p-line); + if (linelen > 2) + { /* handle escaping */ + unsigned char tmp[1]; + p++; + *tmp = xtoi_2 (p); + p += 2; + linelen -= 3; + put_membuf (mb, tmp, 1); + } + line = p; + } + if (mb->too_large) + { + rc = _assuan_error (ASSUAN_Too_Much_Data); + goto leave; + } + + return 0; + + leave: + { + size_t buf_len = 0; + unsigned char *buf = NULL; + + if (mb) + { + buf = get_membuf (mb, &buf_len); + if (!buf) + rc = _assuan_error (ASSUAN_Out_Of_Core); + free_membuf (mb); + free (mb); + ctx->inquire_membuf = NULL; + } + ctx->in_inquire = 0; + rc = (ctx->inquire_cb) (ctx->inquire_cb_data, rc, buf, buf_len); + } + return rc; +} + +/** + * assuan_inquire_ext: + * @ctx: An assuan context + * @keyword: The keyword used for the inquire + * @maxlen: If not 0, the size limit of the inquired data. + * @cb: A callback handler which is invoked after the operation completed. + * @cb_data: A user-provided value passed to the callback handler. + * + * A Server may use this to Send an inquire. r_buffer, r_length and + * maxlen may all be NULL/0 to indicate that no real data is expected. + * When this function returns, + * + * Return value: 0 on success or an ASSUAN error code + **/ +assuan_error_t +assuan_inquire_ext (assuan_context_t ctx, const char *keyword, size_t maxlen, + int (*cb) (void *cb_data, int rc, unsigned char *buf, + size_t len), + void *cb_data) +{ + assuan_error_t rc; + struct membuf *mb = NULL; + char cmdbuf[LINELENGTH-10]; /* (10 = strlen ("INQUIRE ")+CR,LF) */ + + if (!ctx || !keyword || (10 + strlen (keyword) >= sizeof (cmdbuf))) + return _assuan_error (ASSUAN_Invalid_Value); + if (!ctx->is_server) + return _assuan_error (ASSUAN_Not_A_Server); + if (ctx->in_inquire) + return _assuan_error (ASSUAN_Nested_Commands); + + mb = malloc (sizeof (struct membuf)); + if (!mb) + return _assuan_error (ASSUAN_Out_Of_Core); + init_membuf (mb, maxlen ? maxlen : 1024, maxlen); + + strcpy (stpcpy (cmdbuf, "INQUIRE "), keyword); + rc = assuan_write_line (ctx, cmdbuf); + if (rc) + { + free_membuf (mb); + free (mb); + return rc; + } + + ctx->in_inquire = 1; + + /* Set up the continuation. */ + ctx->inquire_cb = cb; + ctx->inquire_cb_data = cb_data; + ctx->inquire_membuf = mb; + + return 0; +} diff --git a/assuan/assuan-io.c b/assuan/assuan-io.c index a7f84492..8d4cbb8e 100644 --- a/assuan/assuan-io.c +++ b/assuan/assuan-io.c @@ -1,5 +1,5 @@ /* assuan-io.c - Wraps the read and write functions. - * Copyright (C) 2002, 2004, 2006 Free Software Foundation, Inc. + * Copyright (C) 2002, 2004, 2006, 2007, 2008 Free Software Foundation, Inc. * * This file is part of Assuan. * @@ -14,15 +14,14 @@ * 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. + * License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include #endif +#include #include #include #ifdef HAVE_SYS_SOCKET_H @@ -48,8 +47,8 @@ _assuan_waitpid (pid_t pid, int *status, int options) #endif -ssize_t -_assuan_simple_read (assuan_context_t ctx, void *buffer, size_t size) +static ssize_t +do_io_read (assuan_fd_t fd, void *buffer, size_t size) { #if defined(HAVE_W32_SYSTEM) && !defined(_ASSUAN_IN_GPGME_BUILD_ASSUAN) /* Due to the peculiarities of the W32 API we can't use read for a @@ -57,32 +56,71 @@ _assuan_simple_read (assuan_context_t ctx, void *buffer, size_t size) read if recv detects that it is not a network socket. */ int n; - n = recv (ctx->inbound.fd, buffer, size, 0); - if (n == -1 && WSAGetLastError () == WSAENOTSOCK) + n = recv (HANDLE2SOCKET(fd), buffer, size, 0); + if (n == -1) { - DWORD nread = 0; - - n = ReadFile ((HANDLE)ctx->inbound.fd, buffer, size, &nread, NULL); - if (!n) + switch (WSAGetLastError ()) { - switch (GetLastError()) - { - case ERROR_BROKEN_PIPE: errno = EPIPE; break; - default: errno = EIO; - } - n = -1; + case WSAENOTSOCK: + { + DWORD nread = 0; + + n = ReadFile (fd, buffer, size, &nread, NULL); + if (!n) + { + switch (GetLastError()) + { + case ERROR_BROKEN_PIPE: errno = EPIPE; break; + default: errno = EIO; + } + n = -1; + } + else + n = (int)nread; + } + break; + + case WSAEWOULDBLOCK: errno = EAGAIN; break; + case ERROR_BROKEN_PIPE: errno = EPIPE; break; + default: errno = EIO; break; } - else - n = (int)nread; } return n; #else /*!HAVE_W32_SYSTEM*/ - return read (ctx->inbound.fd, buffer, size); + return read (fd, buffer, size); #endif /*!HAVE_W32_SYSTEM*/ } + ssize_t -_assuan_simple_write (assuan_context_t ctx, const void *buffer, size_t size) +_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); +} + + + +static ssize_t +do_io_write (assuan_fd_t fd, const void *buffer, size_t size) { #if defined(HAVE_W32_SYSTEM) && !defined(_ASSUAN_IN_GPGME_BUILD_ASSUAN) /* Due to the peculiarities of the W32 API we can't use write for a @@ -90,12 +128,12 @@ _assuan_simple_write (assuan_context_t ctx, const void *buffer, size_t size) write if send detects that it is not a network socket. */ int n; - n = send (ctx->outbound.fd, buffer, size, 0); + n = send (HANDLE2SOCKET(fd), buffer, size, 0); if (n == -1 && WSAGetLastError () == WSAENOTSOCK) { DWORD nwrite; - n = WriteFile ((HANDLE)ctx->outbound.fd, buffer, size, &nwrite, NULL); + n = WriteFile (fd, buffer, size, &nwrite, NULL); if (!n) { switch (GetLastError ()) @@ -111,10 +149,34 @@ _assuan_simple_write (assuan_context_t ctx, const void *buffer, size_t size) } return n; #else /*!HAVE_W32_SYSTEM*/ - return write (ctx->outbound.fd, buffer, size); + return write (fd, buffer, size); #endif /*!HAVE_W32_SYSTEM*/ } +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); +} + #ifdef HAVE_W32_SYSTEM int @@ -152,3 +214,32 @@ _assuan_simple_recvmsg (assuan_context_t ctx, struct msghdr *msg) return ret; #endif } + + +void +_assuan_usleep (unsigned int usec) +{ + if (usec) + { +#ifdef HAVE_NANOSLEEP + struct timespec req; + struct timespec rem; + + req.tv_sec = 0; + req.tv_nsec = usec * 1000; + + while (nanosleep (&req, &rem) < 0 && errno == EINTR) + req = rem; + +#elif defined(HAVE_W32_SYSTEM) + Sleep (usec / 1000); +#else + struct timeval tv; + + tv.tv_sec = usec / 1000000; + tv.tv_usec = usec % 1000000; + select (0, NULL, NULL, NULL, &tv); +#endif + } +} + diff --git a/assuan/assuan-listen.c b/assuan/assuan-listen.c index 04db68ce..2ef93340 100644 --- a/assuan/assuan-listen.c +++ b/assuan/assuan-listen.c @@ -14,9 +14,7 @@ * 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. + * License along with this program; if not, see . */ #include @@ -116,17 +114,17 @@ assuan_accept (assuan_context_t ctx) -int +assuan_fd_t assuan_get_input_fd (assuan_context_t ctx) { - return ctx? ctx->input_fd : -1; + return ctx? ctx->input_fd : ASSUAN_INVALID_FD; } -int +assuan_fd_t assuan_get_output_fd (assuan_context_t ctx) { - return ctx? ctx->output_fd : -1; + return ctx? ctx->output_fd : ASSUAN_INVALID_FD; } @@ -135,10 +133,10 @@ assuan_get_output_fd (assuan_context_t ctx) assuan_error_t assuan_close_input_fd (assuan_context_t ctx) { - if (!ctx || ctx->input_fd == -1) + if (!ctx || ctx->input_fd == ASSUAN_INVALID_FD) return _assuan_error (ASSUAN_Invalid_Value); _assuan_close (ctx->input_fd); - ctx->input_fd = -1; + ctx->input_fd = ASSUAN_INVALID_FD; return 0; } @@ -147,11 +145,11 @@ assuan_close_input_fd (assuan_context_t ctx) assuan_error_t assuan_close_output_fd (assuan_context_t ctx) { - if (!ctx || ctx->output_fd == -1) + if (!ctx || ctx->output_fd == ASSUAN_INVALID_FD) return _assuan_error (ASSUAN_Invalid_Value); _assuan_close (ctx->output_fd); - ctx->output_fd = -1; + ctx->output_fd = ASSUAN_INVALID_FD; return 0; } diff --git a/assuan/assuan-logging.c b/assuan/assuan-logging.c index 41ada915..2ebd6678 100644 --- a/assuan/assuan-logging.c +++ b/assuan/assuan-logging.c @@ -14,9 +14,7 @@ * 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. + * License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H @@ -37,23 +35,6 @@ static char prefix_buffer[80]; static FILE *_assuan_log; static int full_logging; -static int log_level = 1; /* Defaults to logging enabled. */ - - -/* Set the log level for general assuan commands. 0 is no logging at - all, 1 is the standard logging and the default. Higher leveles may - be defined in the future. Passing a level of -1 will not change - the current log level. Returns previosu log level. */ -int -assuan_set_assuan_log_level (int level) -{ - int old = log_level; - - if (level != -1) - log_level = level; - return old; -} - void _assuan_set_default_log_stream (FILE *fp) @@ -122,9 +103,6 @@ _assuan_log_printf (const char *format, ...) FILE *fp; const char *prf; int save_errno = errno; - - if (!log_level) - return; fp = assuan_get_assuan_log_stream (); prf = assuan_get_assuan_log_prefix (); @@ -134,29 +112,31 @@ _assuan_log_printf (const char *format, ...) va_start (arg_ptr, format); vfprintf (fp, format, arg_ptr ); va_end (arg_ptr); + /* 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') + fflush (fp); errno = save_errno; } /* Dump a possibly binary string (used for debugging). Distinguish ascii text from binary and print it accordingly. This function - takes FILE pointer arg becuase logging may be enabled on a per - context basis. */ + takes FILE pointer arg because logging may be enabled on a per + context basis. */ void _assuan_log_print_buffer (FILE *fp, const void *buffer, size_t length) { const unsigned char *s; - int n; + unsigned int n; - if (!log_level) - return; - - for (n=length,s=buffer; n; n--, s++) - if ((!isascii (*s) || iscntrl (*s) || !isprint (*s)) && !(*s >= 0x80)) + for (n = length, s = buffer; n; n--, s++) + if ((! isascii (*s) || iscntrl (*s) || ! isprint (*s)) && !(*s >= 0x80)) break; s = buffer; - if (!n && *s != '[') + if (! n && *s != '[') fwrite (buffer, length, 1, fp); else { @@ -164,15 +144,15 @@ _assuan_log_print_buffer (FILE *fp, const void *buffer, size_t length) flockfile (fp); #endif putc_unlocked ('[', fp); - if ( length > 16 && !full_logging) + if (length > 16 && ! full_logging) { - for (n=0; n < 12; n++, s++) + for (n = 0; n < 12; n++, s++) fprintf (fp, " %02x", *s); - fprintf (fp, " ...(%d bytes skipped)", (int)length - 12); + fprintf (fp, " ...(%d bytes skipped)", (int) length - 12); } else { - for (n=0; n < length; n++, s++) + for (n = 0; n < length; n++, s++) fprintf (fp, " %02x", *s); } putc_unlocked (' ', fp); @@ -189,16 +169,11 @@ void _assuan_log_sanitized_string (const char *string) { const unsigned char *s = (const unsigned char *) string; - FILE *fp; + FILE *fp = assuan_get_assuan_log_stream (); - if (!log_level) + if (! *s) return; - if (!*s) - return; - - fp = assuan_get_assuan_log_stream (); - #ifdef HAVE_FLOCKFILE flockfile (fp); #endif diff --git a/assuan/assuan-pipe-connect.c b/assuan/assuan-pipe-connect.c index e3555325..7fdfe74f 100644 --- a/assuan/assuan-pipe-connect.c +++ b/assuan/assuan-pipe-connect.c @@ -1,5 +1,6 @@ /* assuan-pipe-connect.c - Establish a pipe connection (client) - * Copyright (C) 2001, 2002, 2003, 2005, 2006 Free Software Foundation, Inc. + * Copyright (C) 2001, 2002, 2003, 2005, 2006, + * 2007 Free Software Foundation, Inc. * * This file is part of Assuan. * @@ -14,9 +15,7 @@ * 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. + * License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H @@ -75,17 +74,6 @@ int _gpgme_io_spawn (const char *path, char *const argv[], #define MAX_OPEN_FDS 20 #endif -#ifdef HAVE_W32_SYSTEM -/* We assume that a HANDLE can be represented by an int which should - be true for all i386 systems (HANDLE is defined as void *) and - these are the only systems for which Windows is available. Further - we assume that -1 denotes an invalid handle. */ -#define fd_to_handle(a) ((HANDLE)(a)) -#define handle_to_fd(a) ((int)(a)) -#define pid_to_handle(a) ((HANDLE)(a)) -#define handle_to_pid(a) ((int)(a)) -#endif /*HAVE_W32_SYSTEM*/ - /* This should be called to make sure that SIGPIPE gets ignored. */ static void @@ -139,31 +127,35 @@ writen (int fd, const char *buffer, size_t length) static int do_finish (assuan_context_t ctx) { - if (ctx->inbound.fd != -1) + if (ctx->inbound.fd != ASSUAN_INVALID_FD) { _assuan_close (ctx->inbound.fd); if (ctx->inbound.fd == ctx->outbound.fd) - ctx->outbound.fd = -1; - ctx->inbound.fd = -1; + ctx->outbound.fd = ASSUAN_INVALID_FD; + ctx->inbound.fd = ASSUAN_INVALID_FD; } - if (ctx->outbound.fd != -1) + if (ctx->outbound.fd != ASSUAN_INVALID_FD) { _assuan_close (ctx->outbound.fd); - ctx->outbound.fd = -1; + ctx->outbound.fd = ASSUAN_INVALID_FD; } - if (ctx->pid != -1 && ctx->pid) + if (ctx->pid != (pid_t)(-1) && ctx->pid) { #ifndef HAVE_W32_SYSTEM #ifndef _ASSUAN_USE_DOUBLE_FORK if (!ctx->flags.no_waitpid) _assuan_waitpid (ctx->pid, NULL, 0); - ctx->pid = -1; + ctx->pid =(pid_t)(-1); #endif -#endif /*!HAVE_W32_SYSTEM*/ +#else /*!HAVE_W32_SYSTEM*/ + CloseHandle ((HANDLE) ctx->pid); + ctx->pid = (pid_t) INVALID_HANDLE_VALUE; +#endif /*HAVE_W32_SYSTEM*/ } return 0; } + static void do_deinit (assuan_context_t ctx) { @@ -209,13 +201,15 @@ 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) + void *atforkvalue, unsigned int flags) { assuan_error_t err; int rp[2]; int wp[2]; char mypidstr[50]; + (void)flags; + if (!ctx || !name || !argv || !argv[0]) return _assuan_error (ASSUAN_Invalid_Value); @@ -581,7 +575,7 @@ pipe_connect_gpgme (assuan_context_t *ctx, const char *name, const char *const argv[], int *fd_child_list, void (*atfork) (void *opaque, int reserved), - void *atforkvalue) + void *atforkvalue, unsigned int flags) { assuan_error_t err; int res; @@ -744,9 +738,9 @@ build_w32_commandline (const char * const *argv, char **cmdline) #ifdef HAVE_W32_SYSTEM -/* Create pipe where one end is inheritable. */ +/* Create pipe where one end end is inheritable. */ static int -create_inheritable_pipe (int filedes[2], int for_write) +create_inheritable_pipe (assuan_fd_t filedes[2], int for_write) { HANDLE r, w, h; SECURITY_ATTRIBUTES sec_attr; @@ -781,14 +775,12 @@ create_inheritable_pipe (int filedes[2], int for_write) w = h; } - _assuan_log_printf ("created pipe: read=%p%s, write=%p%s\n", - r, for_write? " (inherit)":"", - w, for_write? "":" (inherit)"); - filedes[0] = handle_to_fd (r); - filedes[1] = handle_to_fd (w); + filedes[0] = r; + filedes[1] = w; return 0; } -#endif /* HAVE_W32_SYSTEM */ +#endif /*HAVE_W32_SYSTEM*/ + #ifdef HAVE_W32_SYSTEM #define pipe_connect pipe_connect_w32 @@ -798,11 +790,11 @@ pipe_connect_w32 (assuan_context_t *ctx, const char *name, const char *const argv[], int *fd_child_list, void (*atfork) (void *opaque, int reserved), - void *atforkvalue) + void *atforkvalue, unsigned int flags) { assuan_error_t err; - int rp[2]; - int wp[2]; + assuan_fd_t rp[2]; + assuan_fd_t wp[2]; char mypidstr[50]; char *cmdline; SECURITY_ATTRIBUTES sec_attr; @@ -837,8 +829,8 @@ pipe_connect_w32 (assuan_context_t *ctx, if (create_inheritable_pipe (wp, 1)) { - CloseHandle (fd_to_handle (rp[0])); - CloseHandle (fd_to_handle (rp[1])); + CloseHandle (rp[0]); + CloseHandle (rp[1]); xfree (cmdline); return _assuan_error (ASSUAN_General_Error); } @@ -847,10 +839,10 @@ pipe_connect_w32 (assuan_context_t *ctx, err = _assuan_new_context (ctx); if (err) { - CloseHandle (fd_to_handle (rp[0])); - CloseHandle (fd_to_handle (rp[1])); - CloseHandle (fd_to_handle (wp[0])); - CloseHandle (fd_to_handle (wp[1])); + CloseHandle (rp[0]); + CloseHandle (rp[1]); + CloseHandle (wp[0]); + CloseHandle (wp[1]); xfree (cmdline); return _assuan_error (ASSUAN_General_Error); } @@ -877,8 +869,8 @@ pipe_connect_w32 (assuan_context_t *ctx, memset (&si, 0, sizeof si); si.cb = sizeof (si); si.dwFlags = STARTF_USESTDHANDLES; - si.hStdInput = fd_to_handle (wp[0]); - si.hStdOutput = fd_to_handle (rp[1]); + si.hStdInput = wp[0]; + si.hStdOutput = rp[1]; /* Dup stderr to /dev/null unless it is in the list of FDs to be passed to the child. */ @@ -894,14 +886,13 @@ pipe_connect_w32 (assuan_context_t *ctx, nullfd = CreateFile ("nul", GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); - _assuan_log_printf ("created nul device, hd=%p\n", nullfd); if (nullfd == INVALID_HANDLE_VALUE) { _assuan_log_printf ("can't open `nul': %s\n", w32_strerror (-1)); - CloseHandle (fd_to_handle (rp[0])); - CloseHandle (fd_to_handle (rp[1])); - CloseHandle (fd_to_handle (wp[0])); - CloseHandle (fd_to_handle (wp[1])); + CloseHandle (rp[0]); + CloseHandle (rp[1]); + CloseHandle (wp[0]); + CloseHandle (wp[1]); xfree (cmdline); _assuan_release_context (*ctx); return -1; @@ -909,23 +900,21 @@ pipe_connect_w32 (assuan_context_t *ctx, si.hStdError = nullfd; } else - si.hStdError = fd_to_handle (_get_osfhandle (fd)); + si.hStdError = (void*)_get_osfhandle (fd); /* Note: We inherit all handles flagged as inheritable. This seems to be a security flaw but there seems to be no way of selecting handles to inherit. */ - _assuan_log_printf ("CreateProcess, path=`%s' cmdline=`%s'\n", - name, cmdline); - _assuan_log_printf (" stdin=%p stdout=%p stderr=%p\n", - si.hStdInput, si.hStdOutput, si.hStdError); + /* _assuan_log_printf ("CreateProcess, path=`%s' cmdline=`%s'\n", */ + /* name, cmdline); */ if (!CreateProcess (name, /* Program to start. */ cmdline, /* Command line arguments. */ &sec_attr, /* Process security attributes. */ &sec_attr, /* Thread security attributes. */ TRUE, /* Inherit handles. */ (CREATE_DEFAULT_ERROR_MODE - | DETACHED_PROCESS + | ((flags & 128)? DETACHED_PROCESS : 0) | GetPriorityClass (GetCurrentProcess ()) | CREATE_SUSPENDED), /* Creation flags. */ NULL, /* Environment. */ @@ -935,10 +924,10 @@ pipe_connect_w32 (assuan_context_t *ctx, )) { _assuan_log_printf ("CreateProcess failed: %s\n", w32_strerror (-1)); - CloseHandle (fd_to_handle (rp[0])); - CloseHandle (fd_to_handle (rp[1])); - CloseHandle (fd_to_handle (wp[0])); - CloseHandle (fd_to_handle (wp[1])); + CloseHandle (rp[0]); + CloseHandle (rp[1]); + CloseHandle (wp[0]); + CloseHandle (wp[1]); if (nullfd != INVALID_HANDLE_VALUE) CloseHandle (nullfd); xfree (cmdline); @@ -953,20 +942,17 @@ pipe_connect_w32 (assuan_context_t *ctx, nullfd = INVALID_HANDLE_VALUE; } - _assuan_log_printf ("closing handles %p and %p\n", - fd_to_handle (rp[1]), fd_to_handle (wp[0]) ); - CloseHandle (fd_to_handle (rp[1])); - CloseHandle (fd_to_handle (wp[0])); + CloseHandle (rp[1]); + CloseHandle (wp[0]); - _assuan_log_printf ("CreateProcess ready: hProcess=%p hThread=%p" - " dwProcessID=%d dwThreadId=%d\n", - pi.hProcess, pi.hThread, - (int) pi.dwProcessId, (int) pi.dwThreadId); + /* _assuan_log_printf ("CreateProcess ready: hProcess=%p hThread=%p" */ + /* " dwProcessID=%d dwThreadId=%d\n", */ + /* pi.hProcess, pi.hThread, */ + /* (int) pi.dwProcessId, (int) pi.dwThreadId); */ ResumeThread (pi.hThread); CloseHandle (pi.hThread); - (*ctx)->pid = 0; /* We don't use the PID. */ - CloseHandle (pi.hProcess); /* We don't need to wait for the process. */ + (*ctx)->pid = (pid_t) pi.hProcess; return initial_handshake (ctx); } @@ -982,7 +968,7 @@ assuan_error_t assuan_pipe_connect (assuan_context_t *ctx, const char *name, const char *const argv[], int *fd_child_list) { - return pipe_connect (ctx, name, argv, fd_child_list, NULL, NULL); + return pipe_connect (ctx, name, argv, fd_child_list, NULL, NULL, 0); } @@ -994,7 +980,7 @@ assuan_pipe_connect2 (assuan_context_t *ctx, void (*atfork) (void *opaque, int reserved), void *atforkvalue) { - return pipe_connect (ctx, name, argv, fd_child_list, atfork, atforkvalue); + return pipe_connect (ctx, name, argv, fd_child_list, atfork, atforkvalue, 0); } @@ -1007,9 +993,19 @@ assuan_pipe_connect2 (assuan_context_t *ctx, as the second argument. The ATFORK function should only act if the second value is 0. - For now FLAGS may either take the value 0 to behave like - assuan_pipe_connect2 or 1 to enable the described full-duplex - socket behaviour. + FLAGS is a bit vector and controls how the function acts: + Bit 0: If cleared a simple pipe based server is expected and the + function behaves similar to `assuan_pipe_connect'. + + If set a server based on full-duplex pipes is expected. Such + pipes are usually created using the `socketpair' function. + It also enables features only available with such servers. + + Bit 7: If set and there is a need to start ther server it will be + started as a background process. This flag is useful under + W32 systems, so that no new console is created and pops up a + 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 @@ -1033,6 +1029,7 @@ assuan_pipe_connect_ext (assuan_context_t *ctx, #endif } else - return pipe_connect (ctx, name, argv, fd_child_list, atfork, atforkvalue); + return pipe_connect (ctx, name, argv, fd_child_list, atfork, atforkvalue, + flags); } diff --git a/assuan/assuan-pipe-server.c b/assuan/assuan-pipe-server.c index 1b47def5..70404144 100644 --- a/assuan/assuan-pipe-server.c +++ b/assuan/assuan-pipe-server.c @@ -14,9 +14,7 @@ * 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. + * License along with this program; if not, see . */ #include @@ -69,14 +67,14 @@ _assuan_new_context (assuan_context_t *r_ctx) ctx = xtrycalloc (1, sizeof *ctx); if (!ctx) return _assuan_error (ASSUAN_Out_Of_Core); - ctx->input_fd = -1; - ctx->output_fd = -1; + ctx->input_fd = ASSUAN_INVALID_FD; + ctx->output_fd = ASSUAN_INVALID_FD; - ctx->inbound.fd = -1; - ctx->outbound.fd = -1; + ctx->inbound.fd = ASSUAN_INVALID_FD; + ctx->outbound.fd = ASSUAN_INVALID_FD; ctx->io = &io; - ctx->listen_fd = -1; + 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; @@ -121,11 +119,11 @@ assuan_init_pipe_server (assuan_context_t *r_ctx, int filedes[2]) #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 fiel descriptos are in binary mode. */ + make sure that the file descriptors are in binary mode. */ setmode (filedes[0], O_BINARY); setmode (filedes[1], O_BINARY); - ctx->inbound.fd = _get_osfhandle (filedes[0]); - ctx->outbound.fd = _get_osfhandle (filedes[1]); + ctx->inbound.fd = (void*)_get_osfhandle (filedes[0]); + ctx->outbound.fd = (void*)_get_osfhandle (filedes[1]); #else s = getenv ("_assuan_connection_fd"); if (s && *s && is_valid_socket (s) ) @@ -137,7 +135,8 @@ assuan_init_pipe_server (assuan_context_t *r_ctx, int filedes[2]) _assuan_init_uds_io (ctx); ctx->deinit_handler = _assuan_uds_deinit; } - else if (filedes && filedes[0] != -1 && filedes[1] != -1 ) + else if (filedes && filedes[0] != ASSUAN_INVALID_FD + && filedes[1] != ASSUAN_INVALID_FD ) { /* Standard pipe server. */ ctx->inbound.fd = filedes[0]; @@ -168,6 +167,7 @@ _assuan_release_context (assuan_context_t ctx) { if (ctx) { + _assuan_inquire_release (ctx); xfree (ctx->hello_line); xfree (ctx->okay_line); xfree (ctx->cmdtbl); diff --git a/assuan/assuan-socket-connect.c b/assuan/assuan-socket-connect.c index 5953f1c3..8eb6d828 100644 --- a/assuan/assuan-socket-connect.c +++ b/assuan/assuan-socket-connect.c @@ -14,9 +14,7 @@ * 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. + * License along with this program; if not, see . */ #include @@ -57,12 +55,12 @@ static int do_finish (assuan_context_t ctx) { - if (ctx->inbound.fd != -1) + if (ctx->inbound.fd != ASSUAN_INVALID_FD) { _assuan_close (ctx->inbound.fd); } - ctx->inbound.fd = -1; - ctx->outbound.fd = -1; + ctx->inbound.fd = ASSUAN_INVALID_FD; + ctx->outbound.fd = ASSUAN_INVALID_FD; return 0; } @@ -87,18 +85,17 @@ assuan_socket_connect (assuan_context_t *r_ctx, /* Make a connection to the Unix domain socket NAME and return a new Assuan context in CTX. SERVER_PID is currently not used but may become handy in the future. With flags set to 1 sendmsg and - recvmesg are used. */ + recvmsg are used. */ assuan_error_t assuan_socket_connect_ext (assuan_context_t *r_ctx, const char *name, pid_t server_pid, unsigned int flags) { - static struct assuan_io io = { _assuan_simple_read, - _assuan_simple_write }; - + static struct assuan_io io = { _assuan_simple_read, _assuan_simple_write, + NULL, NULL }; assuan_error_t err; assuan_context_t ctx; - int fd; + assuan_fd_t fd; struct sockaddr_un srvr_addr; size_t len; const char *s; @@ -109,7 +106,7 @@ assuan_socket_connect_ext (assuan_context_t *r_ctx, /* We require that the name starts with a slash, so that we eventually can reuse this function for other socket types. To - make things easier we allow an optional dirver prefix. */ + make things easier we allow an optional driver prefix. */ s = name; if (*s && s[1] == ':') s += 2; @@ -126,7 +123,7 @@ assuan_socket_connect_ext (assuan_context_t *r_ctx, ctx->finish_handler = do_finish; fd = _assuan_sock_new (PF_LOCAL, SOCK_STREAM, 0); - if (fd == -1) + if (fd == ASSUAN_INVALID_FD) { _assuan_log_printf ("can't create socket: %s\n", strerror (errno)); _assuan_release_context (ctx); @@ -139,8 +136,7 @@ assuan_socket_connect_ext (assuan_context_t *r_ctx, srvr_addr.sun_path[sizeof (srvr_addr.sun_path) - 1] = 0; len = SUN_LEN (&srvr_addr); - - if (_assuan_sock_connect (fd, (struct sockaddr *) &srvr_addr, len) == -1) + if ( _assuan_sock_connect (fd, (struct sockaddr *) &srvr_addr, len) == -1 ) { _assuan_log_printf ("can't connect to `%s': %s\n", name, strerror (errno)); diff --git a/assuan/assuan-socket-server.c b/assuan/assuan-socket-server.c index 5c461644..c536dba4 100644 --- a/assuan/assuan-socket-server.c +++ b/assuan/assuan-socket-server.c @@ -1,5 +1,5 @@ /* assuan-socket-server.c - Assuan socket based server - * Copyright (C) 2002 Free Software Foundation, Inc. + * Copyright (C) 2002, 2007 Free Software Foundation, Inc. * * This file is part of Assuan. * @@ -14,9 +14,7 @@ * 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. + * License along with this program; if not, see . */ #include @@ -40,14 +38,13 @@ #include "assuan-defs.h" -static struct assuan_io io = { _assuan_simple_read, - _assuan_simple_write }; - +static struct assuan_io io = { _assuan_simple_read, _assuan_simple_write, + NULL, NULL }; static int accept_connection_bottom (assuan_context_t ctx) { - int fd = ctx->connected_fd; + assuan_fd_t fd = ctx->connected_fd; ctx->peercred.valid = 0; #ifdef HAVE_SO_PEERCRED @@ -89,16 +86,23 @@ accept_connection_bottom (assuan_context_t ctx) static int accept_connection (assuan_context_t ctx) { - int fd; + assuan_fd_t fd; struct sockaddr_un clnt_addr; socklen_t len = sizeof clnt_addr; - fd = accept (ctx->listen_fd, (struct sockaddr*)&clnt_addr, &len ); - if (fd == -1) + fd = SOCKET2HANDLE(accept (HANDLE2SOCKET(ctx->listen_fd), + (struct sockaddr*)&clnt_addr, &len )); + if (fd == ASSUAN_INVALID_FD) { ctx->os_errno = errno; return _assuan_error (ASSUAN_Accept_Failed); } + if (_assuan_sock_check_nonce (fd, &ctx->listen_nonce)) + { + _assuan_close (fd); + ctx->os_errno = EACCES; + return _assuan_error (ASSUAN_Accept_Failed); + } ctx->connected_fd = fd; return accept_connection_bottom (ctx); @@ -107,12 +111,12 @@ accept_connection (assuan_context_t ctx) static int finish_connection (assuan_context_t ctx) { - if (ctx->inbound.fd != -1) + if (ctx->inbound.fd != ASSUAN_INVALID_FD) { _assuan_close (ctx->inbound.fd); } - ctx->inbound.fd = -1; - ctx->outbound.fd = -1; + ctx->inbound.fd = ASSUAN_INVALID_FD; + ctx->outbound.fd = ASSUAN_INVALID_FD; return 0; } @@ -126,15 +130,15 @@ deinit_socket_server (assuan_context_t ctx) /* Initialize a server for the socket LISTEN_FD which has already be put into listen mode */ int -assuan_init_socket_server (assuan_context_t *r_ctx, int listen_fd) +assuan_init_socket_server (assuan_context_t *r_ctx, assuan_fd_t listen_fd) { return assuan_init_socket_server_ext (r_ctx, listen_fd, 0); } /* Initialize a server using the already accepted socket FD. This - fucntion is deprecated. */ + function is deprecated. */ int -assuan_init_connected_socket_server (assuan_context_t *r_ctx, int fd) +assuan_init_connected_socket_server (assuan_context_t *r_ctx, assuan_fd_t fd) { return assuan_init_socket_server_ext (r_ctx, fd, 2); } @@ -145,7 +149,7 @@ assuan_init_connected_socket_server (assuan_context_t *r_ctx, int fd) 1 - FD has already been accepted. */ int -assuan_init_socket_server_ext (assuan_context_t *r_ctx, int fd, +assuan_init_socket_server_ext (assuan_context_t *r_ctx, assuan_fd_t fd, unsigned int flags) { assuan_context_t ctx; @@ -158,21 +162,21 @@ assuan_init_socket_server_ext (assuan_context_t *r_ctx, int fd, ctx->is_server = 1; if ((flags & 2)) ctx->pipe_mode = 1; /* We want a second accept to indicate EOF. */ - ctx->input_fd = -1; - ctx->output_fd = -1; + ctx->input_fd = ASSUAN_INVALID_FD; + ctx->output_fd = ASSUAN_INVALID_FD; - ctx->inbound.fd = -1; - ctx->outbound.fd = -1; + ctx->inbound.fd = ASSUAN_INVALID_FD; + ctx->outbound.fd = ASSUAN_INVALID_FD; if ((flags & 2)) { - ctx->listen_fd = -1; + ctx->listen_fd = ASSUAN_INVALID_FD; ctx->connected_fd = fd; } else { ctx->listen_fd = fd; - ctx->connected_fd = -1; + ctx->connected_fd = ASSUAN_INVALID_FD; } ctx->deinit_handler = (flags & 1)? _assuan_uds_deinit:deinit_socket_server; ctx->accept_handler = ((flags & 2) @@ -191,3 +195,14 @@ assuan_init_socket_server_ext (assuan_context_t *r_ctx, int fd, *r_ctx = ctx; return rc; } + + +/* Save a copy of NONCE in context CTX. This should be used to + register the server's nonce with an context established by + assuan_init_socket_server. */ +void +assuan_set_sock_nonce (assuan_context_t ctx, assuan_sock_nonce_t *nonce) +{ + if (ctx && nonce) + ctx->listen_nonce = *nonce; +} diff --git a/assuan/assuan-socket.c b/assuan/assuan-socket.c index 5566fdea..02a62253 100644 --- a/assuan/assuan-socket.c +++ b/assuan/assuan-socket.c @@ -14,20 +14,26 @@ * 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. + * License along with this program; if not, see . */ #include #include +#include #ifdef HAVE_W32_SYSTEM +#define WIN32_LEAN_AND_MEAN #include +#include #include #else #include #include #endif +#include +#include +#include +#include + #include "assuan-defs.h" /* Hacks for Slowaris. */ @@ -42,13 +48,114 @@ # define AF_LOCAL AF_UNIX #endif +#ifdef HAVE_W32_SYSTEM +#ifndef S_IRGRP +# define S_IRGRP 0 +# define S_IWGRP 0 +#endif +#endif + + +#ifdef HAVE_W32_SYSTEM int -_assuan_close (int fd) +_assuan_sock_wsa2errno (int err) +{ + switch (err) + { + case WSAENOTSOCK: + return EINVAL; + case WSAEWOULDBLOCK: + return EAGAIN; + case ERROR_BROKEN_PIPE: + return EPIPE; + case WSANOTINITIALISED: + return ENOSYS; + default: + return EIO; + } +} + + +/* W32: Fill BUFFER with LENGTH bytes of random. Returns -1 on + failure, 0 on success. Sets errno on failure. */ +static int +get_nonce (char *buffer, size_t nbytes) +{ + HCRYPTPROV prov; + int ret = -1; + + if (!CryptAcquireContext (&prov, NULL, NULL, PROV_RSA_FULL, + (CRYPT_VERIFYCONTEXT|CRYPT_SILENT)) ) + errno = ENODEV; + else + { + if (!CryptGenRandom (prov, nbytes, buffer)) + errno = ENODEV; + else + ret = 0; + CryptReleaseContext (prov, 0); + } + return ret; +} + + +/* W32: The buffer for NONCE needs to be at least 16 bytes. Returns 0 on + success and sets errno on failure. */ +static int +read_port_and_nonce (const char *fname, unsigned short *port, char *nonce) +{ + FILE *fp; + char buffer[50], *p; + size_t nread; + int aval; + + fp = fopen (fname, "rb"); + if (!fp) + return -1; + nread = fread (buffer, 1, sizeof buffer - 1, fp); + fclose (fp); + if (!nread) + { + errno = ENOFILE; + return -1; + } + buffer[nread] = 0; + aval = atoi (buffer); + if (aval < 1 || aval > 65535) + { + errno = EINVAL; + return -1; + } + *port = (unsigned int)aval; + for (p=buffer; nread && *p != '\n'; p++, nread--) + ; + if (*p != '\n' || nread != 17) + { + errno = EINVAL; + return -1; + } + p++; nread--; + memcpy (nonce, p, 16); + return 0; +} +#endif /*HAVE_W32_SYSTEM*/ + + + +int +_assuan_close (assuan_fd_t fd) { #if defined (HAVE_W32_SYSTEM) && !defined(_ASSUAN_IN_GPGME_BUILD_ASSUAN) - int rc = closesocket (fd); + int rc = closesocket (HANDLE2SOCKET(fd)); + if (rc) + errno = _assuan_sock_wsa2errno (WSAGetLastError ()); if (rc && WSAGetLastError () == WSAENOTSOCK) - rc = CloseHandle (fd); + { + rc = CloseHandle (fd); + if (rc) + /* FIXME. */ + errno = EIO; + } return rc; #else return close (fd); @@ -56,93 +163,277 @@ _assuan_close (int fd) } -int +/* Return a new socket. Note that under W32 we consider a socket the + same as an System Handle; all functions using such a handle know + about this dual use and act accordingly. */ +assuan_fd_t _assuan_sock_new (int domain, int type, int proto) { -#ifndef HAVE_W32_SYSTEM - return socket (domain, type, proto); -#else +#ifdef HAVE_W32_SYSTEM + assuan_fd_t res; if (domain == AF_UNIX || domain == AF_LOCAL) domain = AF_INET; + res = SOCKET2HANDLE(socket (domain, type, proto)); + if (res == ASSUAN_INVALID_FD) + errno = _assuan_sock_wsa2errno (WSAGetLastError ()); + return res; +#else return socket (domain, type, proto); #endif } int -_assuan_sock_connect (int sockfd, struct sockaddr * addr, int addrlen) +_assuan_sock_connect (assuan_fd_t sockfd, struct sockaddr *addr, int addrlen) { -#ifndef HAVE_W32_SYSTEM - return connect (sockfd, addr, addrlen); -#else - struct sockaddr_in myaddr; - struct sockaddr_un * unaddr; - FILE * fp; - int port = 0; - - unaddr = (struct sockaddr_un *)addr; - fp = fopen (unaddr->sun_path, "rb"); - if (!fp) - return -1; - fscanf (fp, "%d", &port); - fclose (fp); - /* XXX: set errno in this case */ - if (port < 0 || port > 65535) - return -1; - - myaddr.sin_family = AF_INET; - myaddr.sin_port = port; - myaddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); - - /* we need this later. */ - unaddr->sun_family = myaddr.sin_family; - unaddr->sun_port = myaddr.sin_port; - unaddr->sun_addr.s_addr = myaddr.sin_addr.s_addr; - - return connect (sockfd, (struct sockaddr *)&myaddr, sizeof myaddr); -#endif -} - - -int -_assuan_sock_bind (int sockfd, struct sockaddr * addr, int addrlen) -{ -#ifndef HAVE_W32_SYSTEM - return bind (sockfd, addr, addrlen); -#else +#ifdef HAVE_W32_SYSTEM if (addr->sa_family == AF_LOCAL || addr->sa_family == AF_UNIX) { struct sockaddr_in myaddr; - struct sockaddr_un * unaddr; - FILE * fp; + struct sockaddr_un *unaddr; + unsigned short port; + char nonce[16]; + int ret; + + unaddr = (struct sockaddr_un *)addr; + if (read_port_and_nonce (unaddr->sun_path, &port, nonce)) + return -1; + + myaddr.sin_family = AF_INET; + myaddr.sin_port = htons (port); + myaddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); + + /* Set return values. */ + unaddr->sun_family = myaddr.sin_family; + unaddr->sun_port = myaddr.sin_port; + unaddr->sun_addr.s_addr = myaddr.sin_addr.s_addr; + + ret = connect (HANDLE2SOCKET(sockfd), + (struct sockaddr *)&myaddr, sizeof myaddr); + if (!ret) + { + /* Send the nonce. */ + ret = _assuan_io_write (sockfd, nonce, 16); + if (ret >= 0 && ret != 16) + { + errno = EIO; + ret = -1; + } + } + return ret; + } + else + { + int res; + res = connect (HANDLE2SOCKET (sockfd), addr, addrlen); + if (res < 0) + errno = _assuan_sock_wsa2errno (WSAGetLastError ()); + return res; + } +#else + return connect (sockfd, addr, addrlen); +#endif +} + + +int +_assuan_sock_bind (assuan_fd_t sockfd, struct sockaddr *addr, int addrlen) +{ +#ifdef HAVE_W32_SYSTEM + if (addr->sa_family == AF_LOCAL || addr->sa_family == AF_UNIX) + { + struct sockaddr_in myaddr; + struct sockaddr_un *unaddr; + int filefd; + FILE *fp; int len = sizeof myaddr; int rc; + char nonce[16]; + + if (get_nonce (nonce, 16)) + return -1; + + unaddr = (struct sockaddr_un *)addr; myaddr.sin_port = 0; myaddr.sin_family = AF_INET; myaddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); - rc = bind (sockfd, (struct sockaddr *)&myaddr, len); - if (rc) - return rc; - rc = getsockname (sockfd, (struct sockaddr *)&myaddr, &len); - if (rc) - return rc; - unaddr = (struct sockaddr_un *)addr; - fp = fopen (unaddr->sun_path, "wb"); + filefd = open (unaddr->sun_path, + (O_WRONLY|O_CREAT|O_EXCL|O_BINARY), + (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP)); + if (filefd == -1) + { + if (errno == EEXIST) + errno = WSAEADDRINUSE; + return -1; + } + fp = fdopen (filefd, "wb"); if (!fp) - return -1; - fprintf (fp, "%d", myaddr.sin_port); + { + int save_e = errno; + close (filefd); + errno = save_e; + return -1; + } + + rc = bind (HANDLE2SOCKET (sockfd), (struct sockaddr *)&myaddr, len); + if (!rc) + rc = getsockname (HANDLE2SOCKET (sockfd), + (struct sockaddr *)&myaddr, &len); + if (rc) + { + int save_e = errno; + fclose (fp); + remove (unaddr->sun_path); + errno = save_e; + return rc; + } + fprintf (fp, "%d\n", ntohs (myaddr.sin_port)); + fwrite (nonce, 16, 1, fp); fclose (fp); - /* we need this later. */ - unaddr->sun_family = myaddr.sin_family; - unaddr->sun_port = myaddr.sin_port; - unaddr->sun_addr.s_addr = myaddr.sin_addr.s_addr; - return 0; } + else + { + int res = bind (HANDLE2SOCKET(sockfd), addr, addrlen); + if (res < 0) + errno = _assuan_sock_wsa2errno (WSAGetLastError ()); + return res; + } +#else return bind (sockfd, addr, addrlen); #endif } + +int +_assuan_sock_get_nonce (struct sockaddr *addr, int addrlen, + assuan_sock_nonce_t *nonce) +{ +#ifdef HAVE_W32_SYSTEM + if (addr->sa_family == AF_LOCAL || addr->sa_family == AF_UNIX) + { + struct sockaddr_un *unaddr; + unsigned short port; + + if (sizeof nonce->nonce != 16) + { + errno = EINVAL; + return -1; + } + nonce->length = 16; + unaddr = (struct sockaddr_un *)addr; + if (read_port_and_nonce (unaddr->sun_path, &port, nonce->nonce)) + return -1; + } + else + { + nonce->length = 42; /* Arbitrary valuie to detect unitialized nonce. */ + nonce->nonce[0] = 42; + } +#else + (void)addr; + (void)addrlen; + nonce->length = 0; +#endif + return 0; +} + + +int +_assuan_sock_check_nonce (assuan_fd_t fd, assuan_sock_nonce_t *nonce) +{ +#ifdef HAVE_W32_SYSTEM + char buffer[16], *p; + size_t nleft; + int n; + + if (sizeof nonce->nonce != 16) + { + errno = EINVAL; + return -1; + } + + if (nonce->length == 42 && nonce->nonce[0] == 42) + return 0; /* Not a Unix domain socket. */ + + if (nonce->length != 16) + { + errno = EINVAL; + return -1; + } + + p = buffer; + nleft = 16; + while (nleft) + { + n = _assuan_io_read (SOCKET2HANDLE(fd), p, nleft); + if (n < 0 && errno == EINTR) + ; + else if (n < 0 && errno == EAGAIN) + Sleep (100); + else if (n < 0) + return -1; + else if (!n) + { + errno = EIO; + return -1; + } + else + { + p += n; + nleft -= n; + } + } + if (memcmp (buffer, nonce->nonce, 16)) + { + errno = EACCES; + return -1; + } +#else + (void)fd; + (void)nonce; +#endif + return 0; +} + + +/* Public API. */ +int +assuan_sock_close (assuan_fd_t fd) +{ + return _assuan_close (fd); +} + +assuan_fd_t +assuan_sock_new (int domain, int type, int proto) +{ + return _assuan_sock_new (domain, type, proto); +} + +int +assuan_sock_connect (assuan_fd_t sockfd, struct sockaddr *addr, int addrlen) +{ + return _assuan_sock_connect (sockfd, addr, addrlen); +} + +int +assuan_sock_bind (assuan_fd_t sockfd, struct sockaddr *addr, int addrlen) +{ + return _assuan_sock_bind (sockfd, addr, addrlen); +} + +int +assuan_sock_get_nonce (struct sockaddr *addr, int addrlen, + assuan_sock_nonce_t *nonce) +{ + return _assuan_sock_get_nonce (addr, addrlen, nonce); +} + +int +assuan_sock_check_nonce (assuan_fd_t fd, assuan_sock_nonce_t *nonce) +{ + return _assuan_sock_check_nonce (fd, nonce); +} diff --git a/assuan/assuan-uds.c b/assuan/assuan-uds.c index 70ec8ccc..02f77a52 100644 --- a/assuan/assuan-uds.c +++ b/assuan/assuan-uds.c @@ -14,9 +14,7 @@ * 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. + * License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H @@ -72,9 +70,9 @@ static ssize_t uds_reader (assuan_context_t ctx, void *buf, size_t buflen) { +#ifndef HAVE_W32_SYSTEM int len = ctx->uds.buffersize; -#ifndef HAVE_W32_SYSTEM if (!ctx->uds.bufferallocated) { ctx->uds.buffer = xtrymalloc (2048); @@ -141,12 +139,6 @@ uds_reader (assuan_context_t ctx, void *buf, size_t buflen) #endif /*USE_DESCRIPTOR_PASSING*/ } -#else /*HAVE_W32_SYSTEM*/ - - len = recvfrom (ctx->inbound.fd, buf, buflen, 0, NULL, NULL); - -#endif /*HAVE_W32_SYSTEM*/ - /* Return some data to the user. */ if (len > buflen) /* We have more than the user requested. */ @@ -159,6 +151,12 @@ uds_reader (assuan_context_t ctx, void *buf, size_t buflen) assert (ctx->uds.bufferoffset <= ctx->uds.bufferallocated); return len; +#else /*HAVE_W32_SYSTEM*/ + int res = recvfrom (HANDLE2SOCKET(ctx->inbound.fd), buf, buflen, 0, NULL, NULL); + if (res < 0) + errno = _assuan_sock_wsa2errno (WSAGetLastError ()); + return res; +#endif /*HAVE_W32_SYSTEM*/ } @@ -181,19 +179,21 @@ uds_writer (assuan_context_t ctx, const void *buf, size_t buflen) iovec.iov_len = buflen; len = _assuan_simple_sendmsg (ctx, &msg); -#else /*HAVE_W32_SYSTEM*/ - int len; - - len = sendto (ctx->outbound.fd, buf, buflen, 0, - (struct sockaddr *)&ctx->serveraddr, - sizeof (struct sockaddr_in)); -#endif /*HAVE_W32_SYSTEM*/ + return len; +#else /*HAVE_W32_SYSTEM*/ + int res = sendto (HANDLE2SOCKET(ctx->outbound.fd), buf, buflen, 0, + (struct sockaddr *)&ctx->serveraddr, + sizeof (struct sockaddr_in)); + if (res < 0) + errno = _assuan_sock_wsa2errno (WSAGetLastError ()); + return res; +#endif /*HAVE_W32_SYSTEM*/ } static assuan_error_t -uds_sendfd (assuan_context_t ctx, int fd) +uds_sendfd (assuan_context_t ctx, assuan_fd_t fd) { #ifdef USE_DESCRIPTOR_PASSING struct msghdr msg; @@ -243,7 +243,7 @@ uds_sendfd (assuan_context_t ctx, int fd) static assuan_error_t -uds_receivefd (assuan_context_t ctx, int *fd) +uds_receivefd (assuan_context_t ctx, assuan_fd_t *fd) { #ifdef USE_DESCRIPTOR_PASSING int i; diff --git a/assuan/assuan-util.c b/assuan/assuan-util.c index d12277fc..cefefcb2 100644 --- a/assuan/assuan-util.c +++ b/assuan/assuan-util.c @@ -14,9 +14,7 @@ * 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. + * License along with this program; if not, see . */ #include @@ -32,6 +30,10 @@ 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), @@ -42,6 +44,20 @@ assuan_set_malloc_hooks ( void *(*new_alloc_func)(size_t n), 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) { @@ -152,6 +168,7 @@ assuan_set_flag (assuan_context_t ctx, assuan_flag_t flag, int value) switch (flag) { case ASSUAN_NO_WAITPID: ctx->flags.no_waitpid = value; break; + case ASSUAN_CONFIDENTIAL: ctx->confidential = value; break; } } @@ -164,8 +181,8 @@ assuan_get_flag (assuan_context_t ctx, assuan_flag_t flag) switch (flag) { case ASSUAN_NO_WAITPID: return ctx->flags.no_waitpid; + case ASSUAN_CONFIDENTIAL: return ctx->confidential; } return 0; } - diff --git a/assuan/assuan.h b/assuan/assuan.h index 6df01667..0e5c7413 100644 --- a/assuan/assuan.h +++ b/assuan/assuan.h @@ -1,5 +1,6 @@ /* assuan.h - Definitions for the Assuan IPC library - * Copyright (C) 2001, 2002, 2003, 2005, 2007 Free Software Foundation, Inc. + * Copyright (C) 2001, 2002, 2003, 2005, 2007, + * 2008 Free Software Foundation, Inc. * * This file is part of Assuan. * @@ -14,9 +15,7 @@ * 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. + * License along with this program; if not, see . */ #ifndef ASSUAN_H @@ -25,18 +24,28 @@ #include #include #include - +#ifndef _ASSUAN_NO_SOCKET_WRAPPER +#ifdef _WIN32 +#include +#else +#include +#endif +#endif /*!_ASSUAN_NO_SOCKET_WRAPPER*/ /* To use this file with libraries the following macros are useful: #define _ASSUAN_EXT_SYM_PREFIX _foo_ - This prefixes all external symbols with "_foo_". + This prefixes all external symbols with "_foo_". #define _ASSUAN_ONLY_GPG_ERRORS - If this is defined all old-style Assuan error codes are made - inactive as well as other dereacted stuff. + If this is defined all old-style Assuan error codes are made + inactive as well as other deprecated stuff. + + #define _ASSUAN_NO_SOCKET_WRAPPER + + Do not include the definitions for the socket wrapper feature. The follwing macros are used internally in the implementation of libassuan: @@ -69,6 +78,8 @@ int _gpgme_io_write (int fd, const void *buffer, size_t count); int _gpgme_io_sendmsg (int sock, const struct msghdr *msg, int flags); int _gpgme_io_recvmsg (int sock, struct msghdr *msg, int flags); +#define _assuan_funopen _gpgme_funopen + #define close _gpgme_io_close #define read _gpgme_io_read #define write _gpgme_io_write @@ -103,6 +114,7 @@ int _gpgme_io_recvmsg (int sock, struct msghdr *msg, int flags); _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) @@ -130,6 +142,7 @@ int _gpgme_io_recvmsg (int sock, struct msghdr *msg, int flags); #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) @@ -137,7 +150,7 @@ int _gpgme_io_recvmsg (int sock, struct msghdr *msg, int flags); #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_assuan_log_level _ASSUAN_PREFIX(assuan_set_assuan_log_level) +#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) @@ -159,6 +172,13 @@ int _gpgme_io_recvmsg (int sock, struct msghdr *msg, int flags); #define assuan_pipe_connect2 _ASSUAN_PREFIX(assuan_pipe_connect2) #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) @@ -170,8 +190,9 @@ int _gpgme_io_recvmsg (int sock, struct msghdr *msg, int flags); _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_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) @@ -188,19 +209,22 @@ int _gpgme_io_recvmsg (int sock, struct msghdr *msg, int flags); #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_close _ASSUAN_PREFIX(_assuan_close) -#define _assuan_sock_new _ASSUAN_PREFIX(_assuan_sock_new) -#define _assuan_sock_bind _ASSUAN_PREFIX(_assuan_sock_bind) -#define _assuan_sock_connect _ASSUAN_PREFIX(_assuan_sock_connect) #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) -#define _assuan_funopen _gpgme_funopen #endif /*_ASSUAN_EXT_SYM_PREFIX*/ @@ -350,7 +374,8 @@ typedef enum #else /*!_ASSUAN_ONLY_GPG_ERRORS*/ -typedef int assuan_error_t; +/* Choose a type compatible with gpg_error_t. */ +typedef unsigned int assuan_error_t; #endif /*!_ASSUAN_ONLY_GPG_ERRORS*/ @@ -363,7 +388,11 @@ typedef enum this is not desirable. By setting this flag, the waitpid will be skipped and the caller is responsible to cleanup a forked process. */ - ASSUAN_NO_WAITPID = 1 + ASSUAN_NO_WAITPID = 1, + /* This flag indicates whether Assuan logging is in confidential + mode. Use assuan_{begin,end}_condidential to change the + mode. */ + ASSUAN_CONFIDENTIAL = 2 } assuan_flag_t; @@ -375,6 +404,66 @@ typedef struct assuan_context_s *assuan_context_t; typedef struct assuan_context_s *ASSUAN_CONTEXT _ASSUAN_DEPRECATED; #endif /*_ASSUAN_ONLY_GPG_ERRORS*/ +/* Because we use system handles and not libc low level file + descriptors on W32, we need to declare them as HANDLE (which + actually is a plain pointer). This is required to eventually + support 64 bit Windows systems. */ +#ifdef _WIN32 +typedef void *assuan_fd_t; +#define ASSUAN_INVALID_FD ((void*)(-1)) +#define ASSUAN_INT2FD(s) ((void *)(s)) +#define ASSUAN_FD2INT(h) ((unsigned int)(h)) +#else +typedef int assuan_fd_t; +#define ASSUAN_INVALID_FD (-1) +#define ASSUAN_INT2FD(s) ((s)) +#define ASSUAN_FD2INT(h) ((h)) +#endif + + +/* Assuan features an emulation of Unix domain sockets based on a + local TCP connections. To implement access permissions based on + file permissions a nonce is used which is expected by th server as + the first bytes received. This structure is used by the server to + save the nonce created initially by bind. On POSIX systems this is + a dummy operation. */ +struct assuan_sock_nonce_s +{ + size_t length; +#ifdef _WIN32 + char nonce[16]; +#endif +}; +typedef struct assuan_sock_nonce_s assuan_sock_nonce_t; + +/* Define the Unix domain socket structure for Windows. */ +#if defined(_WIN32) && !defined(_ASSUAN_NO_SOCKET_WRAPPER) +#ifndef AF_LOCAL +#define AF_LOCAL AF_UNIX +#endif +#define EADDRINUSE WSAEADDRINUSE +struct sockaddr_un +{ + short sun_family; + unsigned short sun_port; + struct in_addr sun_addr; + char sun_path[108-2-4]; +}; +#endif + + +/* Definition of hook functions used to conditionally replace the + default I/O functions. */ +struct assuan_io_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 *); +}; +typedef struct assuan_io_hooks *assuan_io_hooks_t; + + + /*-- assuan-handler.c --*/ int assuan_register_command (assuan_context_t ctx, const char *cmd_string, @@ -398,8 +487,9 @@ int assuan_register_option_handler (assuan_context_t ctx, int assuan_process (assuan_context_t ctx); int assuan_process_next (assuan_context_t ctx); +int assuan_process_done (assuan_context_t ctx, int rc); int assuan_get_active_fds (assuan_context_t ctx, int what, - int *fdarray, int fdarraysize); + assuan_fd_t *fdarray, int fdarraysize); FILE *assuan_get_data_fp (assuan_context_t ctx); @@ -410,15 +500,17 @@ assuan_error_t assuan_write_status (assuan_context_t ctx, /* Negotiate a file descriptor. If LINE contains "FD=N", returns N assuming a local file descriptor. If LINE contains "FD" reads a file descriptor via CTX and stores it in *RDF (the CTX must be - capable of passing file descriptors). */ + capable of passing file descriptors). Under W32 the returned FD is + a libc-type one. */ assuan_error_t assuan_command_parse_fd (assuan_context_t ctx, char *line, - int *rfd); + assuan_fd_t *rfd); + /*-- assuan-listen.c --*/ assuan_error_t assuan_set_hello_line (assuan_context_t ctx, const char *line); assuan_error_t assuan_accept (assuan_context_t ctx); -int assuan_get_input_fd (assuan_context_t ctx); -int assuan_get_output_fd (assuan_context_t ctx); +assuan_fd_t assuan_get_input_fd (assuan_context_t ctx); +assuan_fd_t assuan_get_output_fd (assuan_context_t ctx); assuan_error_t assuan_close_input_fd (assuan_context_t ctx); assuan_error_t assuan_close_output_fd (assuan_context_t ctx); @@ -428,11 +520,12 @@ int assuan_init_pipe_server (assuan_context_t *r_ctx, int filedes[2]); void assuan_deinit_server (assuan_context_t ctx); /*-- assuan-socket-server.c --*/ -int assuan_init_socket_server (assuan_context_t *r_ctx, int listen_fd); +int assuan_init_socket_server (assuan_context_t *r_ctx, assuan_fd_t listen_fd); int assuan_init_connected_socket_server (assuan_context_t *r_ctx, - int fd) _ASSUAN_DEPRECATED; -int assuan_init_socket_server_ext (assuan_context_t *r_ctx, int fd, + assuan_fd_t fd) _ASSUAN_DEPRECATED; +int assuan_init_socket_server_ext (assuan_context_t *r_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 --*/ assuan_error_t assuan_pipe_connect (assuan_context_t *ctx, @@ -465,7 +558,7 @@ assuan_error_t assuan_socket_connect_ext (assuan_context_t *ctx, /*-- assuan-connect.c --*/ void assuan_disconnect (assuan_context_t ctx); pid_t assuan_get_pid (assuan_context_t ctx); -#ifndef HAVE_W32_SYSTEM +#ifndef _WIN32 assuan_error_t assuan_get_peercred (assuan_context_t ctx, pid_t *pid, uid_t *uid, gid_t *gid); #endif @@ -474,11 +567,11 @@ assuan_error_t assuan_get_peercred (assuan_context_t ctx, assuan_error_t assuan_transact (assuan_context_t ctx, const char *command, - int (*data_cb)(void *, const void *, size_t), + assuan_error_t (*data_cb)(void *, const void *, size_t), void *data_cb_arg, - int (*inquire_cb)(void*, const char *), + assuan_error_t (*inquire_cb)(void*, const char *), void *inquire_cb_arg, - int (*status_cb)(void*, const char *), + assuan_error_t (*status_cb)(void*, const char *), void *status_cb_arg); @@ -486,7 +579,12 @@ assuan_transact (assuan_context_t ctx, assuan_error_t assuan_inquire (assuan_context_t ctx, const char *keyword, unsigned char **r_buffer, size_t *r_length, size_t maxlen); - +assuan_error_t assuan_inquire_ext (assuan_context_t ctx, const char *keyword, + size_t maxlen, + int (*cb) (void *cb_data, int rc, + unsigned char *buf, + size_t buf_len), + void *cb_data); /*-- assuan-buffer.c --*/ assuan_error_t assuan_read_line (assuan_context_t ctx, char **line, size_t *linelen); @@ -498,13 +596,15 @@ assuan_error_t assuan_send_data (assuan_context_t ctx, /* The file descriptor must be pending before assuan_receivefd is called. This means that assuan_sendfd should be called *before* the trigger is sent (normally via assuan_write_line ("INPUT FD")). */ -assuan_error_t assuan_sendfd (assuan_context_t ctx, int fd); -assuan_error_t assuan_receivefd (assuan_context_t ctx, int *fd); +assuan_error_t assuan_sendfd (assuan_context_t ctx, assuan_fd_t fd); +assuan_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); int assuan_set_error (assuan_context_t ctx, int err, const char *text); void assuan_set_pointer (assuan_context_t ctx, void *pointer); @@ -545,14 +645,6 @@ void assuan_set_assuan_err_source (int errsource); /*-- assuan-logging.c --*/ -/* Set the log level for general assuan commands. 0 is no logging at - all, 1 is the standard logging and the default. Higher leveles may - be defined in the future. Passing a level of -1 will not change - the current log level. Returns previous log level. Note, that - this function is not thread-safe and should in general be used - right at startup. */ -int assuan_set_assuan_log_level (int level); - /* 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 @@ -574,6 +666,21 @@ void assuan_set_assuan_log_prefix (const char *text); string, i.e. "" */ const char *assuan_get_assuan_log_prefix (void); + +/*-- assuan-socket.c --*/ + +/* These are socket wrapper functions to support an emulation of Unix + domain sockets on Windows W32. */ +int assuan_sock_close (assuan_fd_t fd); +assuan_fd_t assuan_sock_new (int domain, int type, int proto); +int assuan_sock_connect (assuan_fd_t sockfd, + struct sockaddr *addr, int addrlen); +int assuan_sock_bind (assuan_fd_t sockfd, struct sockaddr *addr, int addrlen); +int assuan_sock_get_nonce (struct sockaddr *addr, int addrlen, + assuan_sock_nonce_t *nonce); +int assuan_sock_check_nonce (assuan_fd_t fd, assuan_sock_nonce_t *nonce); + + #ifdef __cplusplus } #endif diff --git a/assuan/mkerrors b/assuan/mkerrors index 28451f63..79ac23b6 100755 --- a/assuan/mkerrors +++ b/assuan/mkerrors @@ -31,6 +31,7 @@ cat < 0 && errno < 4096) - { - n = (EAGAIN | (1 << 15)); - break; - } + n = (6 | (1 << 15)); + break; default: n = 270; /*GPG_ERR_ASS_READ_ERROR*/ break; } break; @@ -108,11 +106,8 @@ _assuan_error (int oldcode) { case 0: n = 16381; /*GPG_ERR_MISSING_ERRNO*/ break; case EAGAIN: - if (errno > 0 && errno < 4096) - { - n = (EAGAIN | (1 << 15)); - break; - } + n = (6 | (1 << 15)); + break; default: n = 271; /*GPG_ERR_ASS_WRITE_ERROR*/ break; } break; @@ -127,11 +122,8 @@ _assuan_error (int oldcode) n = 16381; /*GPG_ERR_MISSING_ERRNO*/ break; case ENOMEM: - if (errno > 0 && errno < 4096) - { - n = (ENOMEM | (1 << 15)); - break; - } + n = (86 | (1 << 15)); + break; default: n = 16382; /*GPG_ERR_UNKNOWN_ERRNO*/ break; @@ -150,6 +142,23 @@ _assuan_error (int oldcode) } +/* A small helper function to treat EAGAIN transparently to the + caller. */ +int +_assuan_error_is_eagain (assuan_error_t err) +{ + if ((!err_source && err == ASSUAN_Read_Error && errno == EAGAIN) + || (err_source && (err & ((1 << 24) - 1)) == (6 | (1 << 15)))) + { + /* Avoid spinning by sleeping for one tenth of a second. */ + _assuan_usleep (100000); + return 1; + } + else + return 0; +} + + /** * assuan_strerror: * @err: Error code diff --git a/src/debug.c b/src/debug.c index bf1ca18c..d529653a 100644 --- a/src/debug.c +++ b/src/debug.c @@ -145,8 +145,7 @@ debug_init (void) fprintf (errfp, "gpgme_debug: level=%d\n", debug_level); #ifdef HAVE_ASSUAN_H assuan_set_assuan_log_prefix ("gpgme-assuan"); - assuan_set_assuan_log_stream (errfp); - assuan_set_assuan_log_level (debug_level >= 0? debug_level:0); + assuan_set_assuan_log_stream (debug_level > 0 ? errfp : NULL); #endif /* HAVE_ASSUAN_H*/ } UNLOCK (debug_lock); diff --git a/src/version.c b/src/version.c index 879e2f3e..03d9e9ae 100644 --- a/src/version.c +++ b/src/version.c @@ -56,7 +56,6 @@ do_subsystem_inits (void) _gpgme_sema_subsystem_init (); #ifdef HAVE_ASSUAN_H - assuan_set_assuan_log_level (0); assuan_set_assuan_err_source (GPG_ERR_SOURCE_GPGME); #endif /*HAVE_ASSUAN_H*/ _gpgme_debug_subsystem_init ();