From 9e09d93de83fe1160689acb36b082c02ccb52716 Mon Sep 17 00:00:00 2001 From: Marcus Brinkmann Date: Tue, 19 Sep 2006 14:01:54 +0000 Subject: [PATCH] assuan/ Update to current version. 2006-09-19 Marcus Brinkmann * configure.ac: Turn stpcpy into a replacement function. Check for unistd.h and add setenv as replacement function. gpgme/ 2006-09-19 Marcus Brinkmann * setenv.c: New file. --- ChangeLog | 5 + assuan/ChangeLog | 168 ++++++++ assuan/Makefile.am | 11 +- assuan/assuan-buffer.c | 111 +++--- assuan/assuan-client.c | 32 +- assuan/assuan-connect.c | 25 +- assuan/assuan-defs.h | 172 +++++--- assuan/assuan-domain-connect.c | 504 ----------------------- assuan/assuan-domain-server.c | 46 --- assuan/assuan-handler.c | 117 +++--- assuan/assuan-inquire.c | 19 +- assuan/assuan-io.c | 157 +++++++- assuan/assuan-listen.c | 14 +- assuan/assuan-logging.c | 143 ++++++- assuan/assuan-pipe-connect.c | 702 +++++++++++++++++++++++---------- assuan/assuan-pipe-server.c | 61 ++- assuan/assuan-socket-connect.c | 53 ++- assuan/assuan-socket-server.c | 111 +++--- assuan/assuan-socket.c | 40 +- assuan/assuan-uds.c | 285 +++++++++++++ assuan/assuan-util.c | 110 +----- assuan/assuan.h | 307 ++++++++------ assuan/funopen.c | 29 +- assuan/mkerrors | 168 +++++++- configure.ac | 6 +- gpgme/gpgme.h | 2 +- gpgme/setenv.c | 352 +++++++++++++++++ 27 files changed, 2417 insertions(+), 1333 deletions(-) create mode 100644 assuan/assuan-uds.c create mode 100644 gpgme/setenv.c diff --git a/ChangeLog b/ChangeLog index 1e9c68b..a91322d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2006-09-19 Marcus Brinkmann + + * configure.ac: Turn stpcpy into a replacement function. + Check for unistd.h and add setenv as replacement function. + 2006-07-29 Marcus Brinkmann * configure.ac: Check for network libraries and set NETLIBS. diff --git a/assuan/ChangeLog b/assuan/ChangeLog index 3aef839..d9519c1 100644 --- a/assuan/ChangeLog +++ b/assuan/ChangeLog @@ -1,3 +1,171 @@ +2006-09-19 Marcus Brinkmann + + * assuan.h (assuan_init_socket_server_ext) + [_ASSUAN_EXT_SYM_PREFIX]: Fix typo in macro. + +2006-09-19 Werner Koch + + * assuan-defs.h (putc_unlocked): Add prototype. + + * assuan-socket-server.c (accept_connection): Made LEN a socklen_t. + + * assuan.h: Replaced assuan error code enum by simple defines and + made assuan_error_t an int. + * mkerrors: Changed parser accordingly. + +2006-09-19 Marcus Brinkmann + + * assuan-pipe-connect.c: Add hacks for Slowaris. + * assuan-socket.c: Likewise here. + + * assuan.h (enum): Avoid trailing comma in enumerator list. Ugh. + + * mkerrors (_assuan_error): Change return type to assuan_error_t. + * assuan-buffer.c (_assuan_read_line): Change return type to + assuan_error_t. Map returned value of -1. + (_assuan_write_line): Change type of RC to assuan_error_t. + * assuan-defs.h (_assuan_read_line, _assuan_error): Likewise for + prototypes. + + * assuan-defs.h (unsetenv): Define correctly. + +2006-09-14 Werner Koch + + * assuan-io.c (_assuan_waitpid): New. Changed all waitpid calls + to this. + + * assuan.h (_ASSUAN_DEPRECATED): New internal macro. + (assuan_pipe_connect2): Declare deprecated. + (assuan_init_connected_socket_server): Declare deprecated. + + * assuan-connect.c (assuan_get_peercred): New. + * assuan-socket-server.c (accept_connection_bottom): Save uid and gid. + +2006-09-13 Werner Koch + + * assuan-client.c (assuan_transact): Need to map the error code. + * mkerrors: Need to map ASSUAN_No_Secret_Key. + + * assuan-pipe-server.c (is_valid_socket): New. + (assuan_init_pipe_server): Use UDS with the environmet variable is + set and a valid descriptor is given. Ignore FILEDES in this case. + + * assuan-socket-server.c (assuan_init_socket_server_ext): New. + Changed other init fucntions to make use of it. + + * assuan-handler.c (assuan_command_parse_fd): Allow for lowercase + "fd". + (std_handler_reset): Close pending fds. + * assuan-uds.c (uds_receivefd): Fixed. + (_assuan_uds_close_fds): New. + + * assuan-socket-connect.c (assuan_socket_connect_ext): New. Takes + all code of assuan_socket_connect plus an option to use sendmsg. + * assuan-pipe-connect.c (assuan_pipe_connect_ext): New arg FLAGS. + +2006-09-12 Werner Koch + + * assuan-buffer.c (_assuan_write_line): Also log the prefix. + + * assuan-defs.h (DIM, DIMof): New. + + * assuan-domain-server.c: Removed. + * assuan-domain-connect.c: Renamed to .. + * assuan-uds.c: this. + (domain_reader, domain_writer, domain_sendfd, domain_receivefd) + (assuan_domain_connect, _assuan_domain_init): Removed. + (uds_reader, uds_writer, uds_sendfd, uds_receivefd) + (_assuan_init_uds_io): New. + (_assuan_uds_deinit): New. + + * assuan-io.c (_assuan_simple_sendmsg, _assuan_simple_recvmsg): New. + (my_pth_fdmode, my_pth_select): New. + +2006-09-11 Werner Koch + + * assuan-pipe-server.c (assuan_init_pipe_server): Allow for + FILEDES to be NULL and try to start as a socketpair server in this + case. + + * assuan-pipe-connect.c (assuan_pipe_connect2): Split up into two + functions (unix and w32) for clarity. + (pipe_connect_unix): This is the new fucntion. Add USE_CMSG flag. + (pipe_connect_w32): Ditto. + (initial_handshake): Factored out code. + (socketpair_connect): New. + (assuan_pipe_connect_ext): New. + (do_finish): Handle case if outbound and inbound fd are the same. + This is to support socketpairs. + +2006-09-10 Werner Koch + + * assuan-util.c (_assuan_log_print_buffer) + (_assuan_log_sanitized_string,assuan_set_log_stream): Moved to .. + * assuan-logging.c: .. here. + (_assuan_log_print_buffer): Only print the leading bytes in hex + log mode unless the new env variable ASSUAN_FULL_LOGGING has been + set. + (_assuan_set_default_log_stream): Test this env variable. + +2006-09-06 Werner Koch + + * assuan.h (_ASSUAN_ONLY_GPG_ERRORS): New. + + * assuan-handler.c (dispatch_command): Use Syntax_Error instead of + Invalid_Command. + + * assuan-domain-connect.c: Changed alloc malloc/free/realloc to + xtrymalloc et al. + (read_int, write_int): Make args void pointers. + (domain_receivefd): Take care of realloc shrinking failure. + + * assuan-buffer.c (_assuan_read_line, _assuan_write_line) + (assuan_write_line, _assuan_cookie_write_data) + (_assuan_cookie_write_flush): Print the inbound fd instead of the + address of the context when logging I/0. This makes it more + readable. + +2006-09-05 Werner Koch + + * assuan-defs.h (err_code, err_is_eof): New. + + * mkerrors (_assuan_error): New. Wrapped all error code + assignments in a call to this. + (assuan_strerror): Map gpg-style error codes back. Also print a + string for the old EOF code. + (assuan_set_assuan_err_source): New. + + * assuan-logging.c (_assuan_log_printf): Do not change ERRNO and + print the pid. + + * assuan-domain-connect.c (domain_reader): Replaced plain printf + by assuan_log function. + +2005-10-24 Werner Koch + + * putc_unlocked.c, memrchr.c, isascii.c, funopen.c: Changed + distribution terms to LGPL. This are small and trivial files so + there are no obstacles of doing so. + * assuan-socket.c: Likewise, the stated GPL was not intended. + +2005-10-08 Marcus Brinkmann + + * assuan-defs.h (setenv, unsetenv, clearenv) [!HAVE_SETENV]: + Define to _assuan_*. + * setenv.c: Include "assuan-defs.h". + (__add_to_environ): Make static. + +2005-10-07 Marcus Brinkmann + + * assuan-defs.h (memrchr) [!HAVE_MEMRCHR]: New prototype. + (stpcpy) [!HAVE_STPCPY]: Likewise. + * stpcpy.c: New LGPL'ed file from the GNU C Library. + * setenv.c: New file. + * assuan-domain-connect.c (read_int): New function. + (write_int): New function. + (domain_reader): Use read_int. + (domain_sendfd): Use write_int. + 2005-10-01 Marcus Brinkmann * assuan.h (assuan_pipe_connect, assuan_pipe_connect2): Make type diff --git a/assuan/Makefile.am b/assuan/Makefile.am index b88b7dc..e19a356 100644 --- a/assuan/Makefile.am +++ b/assuan/Makefile.am @@ -15,7 +15,7 @@ # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA ## Process this file with automake to produce Makefile.in @@ -44,12 +44,11 @@ libassuan_la_SOURCES = \ assuan-socket-server.c \ assuan-pipe-connect.c \ assuan-socket-connect.c \ - assuan-socket.c \ + assuan-uds.c \ funopen.c \ assuan-io.c \ - assuan-domain-connect.c \ - assuan-domain-server.c \ - assuan-logging.c + assuan-logging.c \ + assuan-socket.c -assuan-errors.c : assuan.h +assuan-errors.c : assuan.h mkerrors $(srcdir)/mkerrors < $(srcdir)/assuan.h > assuan-errors.c diff --git a/assuan/assuan-buffer.c b/assuan/assuan-buffer.c index 99ea72e..5580392 100644 --- a/assuan/assuan-buffer.c +++ b/assuan/assuan-buffer.c @@ -15,7 +15,8 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include @@ -30,8 +31,11 @@ #endif #include "assuan-defs.h" + +/* Extended version of write(2) to guarantee that all bytes are + written. Returns 0 on success or -1 and ERRNO on failure. */ static int -writen (ASSUAN_CONTEXT ctx, const char *buffer, size_t length) +writen (assuan_context_t ctx, const char *buffer, size_t length) { while (length) { @@ -49,9 +53,11 @@ writen (ASSUAN_CONTEXT ctx, const char *buffer, size_t length) return 0; /* okay */ } -/* Read an entire line. */ +/* 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. */ static int -readline (ASSUAN_CONTEXT ctx, char *buf, size_t buflen, +readline (assuan_context_t ctx, char *buf, size_t buflen, int *r_nread, int *r_eof) { size_t nleft = buflen; @@ -88,8 +94,9 @@ readline (ASSUAN_CONTEXT ctx, char *buf, size_t buflen, } -int -_assuan_read_line (ASSUAN_CONTEXT ctx) +/* Function returns an Assuan error. */ +assuan_error_t +_assuan_read_line (assuan_context_t ctx) { char *line = ctx->inbound.line; int nread, atticlen; @@ -97,7 +104,7 @@ _assuan_read_line (ASSUAN_CONTEXT ctx) char *endp = 0; if (ctx->inbound.eof) - return -1; + return _assuan_error (-1); atticlen = ctx->inbound.attic.linelen; if (atticlen) @@ -128,19 +135,20 @@ _assuan_read_line (ASSUAN_CONTEXT ctx) if (rc) { if (ctx->log_fp) - fprintf (ctx->log_fp, "%s[%u.%p] DBG: <- [Error: %s]\n", + fprintf (ctx->log_fp, "%s[%u.%d] DBG: <- [Error: %s]\n", assuan_get_assuan_log_prefix (), - (unsigned int)getpid (), ctx, strerror (errno)); - return ASSUAN_Read_Error; + (unsigned int)getpid (), ctx->inbound.fd, + strerror (errno)); + return _assuan_error (ASSUAN_Read_Error); } if (!nread) { assert (ctx->inbound.eof); if (ctx->log_fp) - fprintf (ctx->log_fp, "%s[%u.%p] DBG: <- [EOF]\n", + fprintf (ctx->log_fp, "%s[%u.%d] DBG: <- [EOF]\n", assuan_get_assuan_log_prefix (), - (unsigned int)getpid (), ctx); - return -1; + (unsigned int)getpid (), ctx->inbound.fd); + return _assuan_error (-1); } ctx->inbound.attic.pending = 0; @@ -170,9 +178,9 @@ _assuan_read_line (ASSUAN_CONTEXT ctx) ctx->inbound.linelen = endp - line; if (ctx->log_fp) { - fprintf (ctx->log_fp, "%s[%u.%p] DBG: <- ", + fprintf (ctx->log_fp, "%s[%u.%d] DBG: <- ", assuan_get_assuan_log_prefix (), - (unsigned int)getpid (), ctx); + (unsigned int)getpid (), ctx->inbound.fd); if (ctx->confidential) fputs ("[Confidential data not shown]", ctx->log_fp); else @@ -186,13 +194,14 @@ _assuan_read_line (ASSUAN_CONTEXT ctx) else { if (ctx->log_fp) - fprintf (ctx->log_fp, "%s[%u.%p] DBG: <- [Invalid line]\n", + fprintf (ctx->log_fp, "%s[%u.%d] DBG: <- [Invalid line]\n", assuan_get_assuan_log_prefix (), - (unsigned int)getpid (), ctx); + (unsigned int)getpid (), ctx->inbound.fd); *line = 0; ctx->inbound.linelen = 0; - return ctx->inbound.eof ? ASSUAN_Line_Not_Terminated - : ASSUAN_Line_Too_Long; + return _assuan_error (ctx->inbound.eof + ? ASSUAN_Line_Not_Terminated + : ASSUAN_Line_Too_Long); } } @@ -207,12 +216,12 @@ _assuan_read_line (ASSUAN_CONTEXT ctx) See also: assuan_pending_line(). */ assuan_error_t -assuan_read_line (ASSUAN_CONTEXT ctx, char **line, size_t *linelen) +assuan_read_line (assuan_context_t ctx, char **line, size_t *linelen) { assuan_error_t err; if (!ctx) - return ASSUAN_Invalid_Value; + return _assuan_error (ASSUAN_Invalid_Value); err = _assuan_read_line (ctx); *line = ctx->inbound.line; @@ -224,7 +233,7 @@ assuan_read_line (ASSUAN_CONTEXT ctx, char **line, size_t *linelen) /* Return true if a full line is buffered (i.e. an entire line may be read without any I/O). */ int -assuan_pending_line (ASSUAN_CONTEXT ctx) +assuan_pending_line (assuan_context_t ctx) { return ctx && ctx->inbound.attic.pending; } @@ -234,17 +243,17 @@ assuan_error_t _assuan_write_line (assuan_context_t ctx, const char *prefix, const char *line, size_t len) { - int rc = 0; + assuan_error_t rc = 0; size_t prefixlen = prefix? strlen (prefix):0; /* Make sure that the line is short enough. */ if (len + prefixlen + 2 > ASSUAN_LINELENGTH) { if (ctx->log_fp) - fprintf (ctx->log_fp, "%s[%u.%p] DBG: -> " + fprintf (ctx->log_fp, "%s[%u.%d] DBG: -> " "[supplied line too long -truncated]\n", assuan_get_assuan_log_prefix (), - (unsigned int)getpid (), ctx); + (unsigned int)getpid (), ctx->inbound.fd); if (prefixlen > 5) prefixlen = 5; if (len > ASSUAN_LINELENGTH - prefixlen - 2) @@ -254,13 +263,17 @@ _assuan_write_line (assuan_context_t ctx, const char *prefix, /* Fixme: we should do some kind of line buffering. */ if (ctx->log_fp) { - fprintf (ctx->log_fp, "%s[%u.%p] DBG: -> ", + fprintf (ctx->log_fp, "%s[%u.%d] DBG: -> ", assuan_get_assuan_log_prefix (), - (unsigned int)getpid (), ctx); + (unsigned int)getpid (), ctx->inbound.fd); if (ctx->confidential) fputs ("[Confidential data not shown]", ctx->log_fp); else - _assuan_log_print_buffer (ctx->log_fp, line, len); + { + if (prefixlen) + _assuan_log_print_buffer (ctx->log_fp, prefix, prefixlen); + _assuan_log_print_buffer (ctx->log_fp, line, len); + } putc ('\n', ctx->log_fp); } @@ -268,18 +281,18 @@ _assuan_write_line (assuan_context_t ctx, const char *prefix, { rc = writen (ctx, prefix, prefixlen); if (rc) - rc = ASSUAN_Write_Error; + rc = _assuan_error (ASSUAN_Write_Error); } if (!rc) { rc = writen (ctx, line, len); if (rc) - rc = ASSUAN_Write_Error; + rc = _assuan_error (ASSUAN_Write_Error); if (!rc) { rc = writen (ctx, "\n", 1); if (rc) - rc = ASSUAN_Write_Error; + rc = _assuan_error (ASSUAN_Write_Error); } } return rc; @@ -287,13 +300,13 @@ _assuan_write_line (assuan_context_t ctx, const char *prefix, assuan_error_t -assuan_write_line (ASSUAN_CONTEXT ctx, const char *line) +assuan_write_line (assuan_context_t ctx, const char *line) { size_t len; const char *s; if (!ctx) - return ASSUAN_Invalid_Value; + return _assuan_error (ASSUAN_Invalid_Value); /* Make sure that we never take a LF from the user - this might violate the protocol. */ @@ -301,10 +314,10 @@ assuan_write_line (ASSUAN_CONTEXT ctx, const char *line) len = s? (s-line) : strlen (line); if (ctx->log_fp && s) - fprintf (ctx->log_fp, "%s[%u.%p] DBG: -> " - "[supplied line contained a LF -truncated]\n", + fprintf (ctx->log_fp, "%s[%u.%d] DBG: -> " + "[supplied line contained a LF - truncated]\n", assuan_get_assuan_log_prefix (), - (unsigned int)getpid (), ctx); + (unsigned int)getpid (), ctx->inbound.fd); return _assuan_write_line (ctx, NULL, line, len); } @@ -316,7 +329,7 @@ assuan_write_line (ASSUAN_CONTEXT ctx, const char *line) int _assuan_cookie_write_data (void *cookie, const char *buffer, size_t orig_size) { - ASSUAN_CONTEXT ctx = cookie; + assuan_context_t ctx = cookie; size_t size = orig_size; char *line; size_t linelen; @@ -359,9 +372,9 @@ _assuan_cookie_write_data (void *cookie, const char *buffer, size_t orig_size) { if (ctx->log_fp) { - fprintf (ctx->log_fp, "%s[%u.%p] DBG: -> ", + fprintf (ctx->log_fp, "%s[%u.%d] DBG: -> ", assuan_get_assuan_log_prefix (), - (unsigned int)getpid (), ctx); + (unsigned int)getpid (), ctx->inbound.fd); if (ctx->confidential) fputs ("[Confidential data not shown]", ctx->log_fp); @@ -375,7 +388,7 @@ _assuan_cookie_write_data (void *cookie, const char *buffer, size_t orig_size) linelen++; if (writen (ctx, ctx->outbound.data.line, linelen)) { - ctx->outbound.data.error = ASSUAN_Write_Error; + ctx->outbound.data.error = _assuan_error (ASSUAN_Write_Error); return 0; } line = ctx->outbound.data.line; @@ -393,7 +406,7 @@ _assuan_cookie_write_data (void *cookie, const char *buffer, size_t orig_size) int _assuan_cookie_write_flush (void *cookie) { - ASSUAN_CONTEXT ctx = cookie; + assuan_context_t ctx = cookie; char *line; size_t linelen; @@ -407,9 +420,9 @@ _assuan_cookie_write_flush (void *cookie) { if (ctx->log_fp) { - fprintf (ctx->log_fp, "%s[%u.%p] DBG: -> ", + fprintf (ctx->log_fp, "%s[%u.%d] DBG: -> ", assuan_get_assuan_log_prefix (), - (unsigned int)getpid (), ctx); + (unsigned int)getpid (), ctx->inbound.fd); if (ctx->confidential) fputs ("[Confidential data not shown]", ctx->log_fp); else @@ -421,7 +434,7 @@ _assuan_cookie_write_flush (void *cookie) linelen++; if (writen (ctx, ctx->outbound.data.line, linelen)) { - ctx->outbound.data.error = ASSUAN_Write_Error; + ctx->outbound.data.error = _assuan_error (ASSUAN_Write_Error); return 0; } ctx->outbound.data.linelen = 0; @@ -449,12 +462,12 @@ _assuan_cookie_write_flush (void *cookie) **/ assuan_error_t -assuan_send_data (ASSUAN_CONTEXT ctx, const void *buffer, size_t length) +assuan_send_data (assuan_context_t ctx, const void *buffer, size_t length) { if (!ctx) - return ASSUAN_Invalid_Value; + return _assuan_error (ASSUAN_Invalid_Value); if (!buffer && length) - return ASSUAN_Invalid_Value; + return _assuan_error (ASSUAN_Invalid_Value); if (!buffer) { /* flush what we have */ @@ -475,7 +488,7 @@ assuan_send_data (ASSUAN_CONTEXT ctx, const void *buffer, size_t length) } assuan_error_t -assuan_sendfd (ASSUAN_CONTEXT ctx, int fd) +assuan_sendfd (assuan_context_t ctx, int fd) { if (! ctx->io->sendfd) return set_error (ctx, Not_Implemented, @@ -485,7 +498,7 @@ assuan_sendfd (ASSUAN_CONTEXT ctx, int fd) } assuan_error_t -assuan_receivefd (ASSUAN_CONTEXT ctx, int *fd) +assuan_receivefd (assuan_context_t ctx, int *fd) { if (! ctx->io->receivefd) return set_error (ctx, Not_Implemented, diff --git a/assuan/assuan-client.c b/assuan/assuan-client.c index 2f78d0c..06e3966 100644 --- a/assuan/assuan-client.c +++ b/assuan/assuan-client.c @@ -15,7 +15,8 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include @@ -33,7 +34,7 @@ assuan_error_t -_assuan_read_from_server (ASSUAN_CONTEXT ctx, int *okay, int *off) +_assuan_read_from_server (assuan_context_t ctx, int *okay, int *off) { char *line; int linelen; @@ -103,7 +104,7 @@ _assuan_read_from_server (ASSUAN_CONTEXT ctx, int *okay, int *off) *off = 3; } else - rc = ASSUAN_Invalid_Response; + rc = _assuan_error (ASSUAN_Invalid_Response); return rc; } @@ -112,7 +113,7 @@ _assuan_read_from_server (ASSUAN_CONTEXT ctx, int *okay, int *off) /** * assuan_transact: * @ctx: The Assuan context - * @command: Coimmand line to be send to server + * @command: Command line to be send to the server * @data_cb: Callback function for data lines * @data_cb_arg: first argument passed to @data_cb * @inquire_cb: Callback function for a inquire response @@ -124,19 +125,22 @@ _assuan_read_from_server (ASSUAN_CONTEXT ctx, int *okay, int *off) * * Return value: 0 on success or error code. The error code may be * the one one returned by the server in error lines or from the - * callback functions. + * callback functions. Take care: When a callback returns an error + * this function returns immediately with an error and thus the caller + * will altter return an Assuan error (write erro in most cases). **/ assuan_error_t -assuan_transact (ASSUAN_CONTEXT ctx, +assuan_transact (assuan_context_t ctx, const char *command, - assuan_error_t (*data_cb)(void *, const void *, size_t), + int (*data_cb)(void *, const void *, size_t), void *data_cb_arg, - assuan_error_t (*inquire_cb)(void*, const char *), + int (*inquire_cb)(void*, const char *), void *inquire_cb_arg, - assuan_error_t (*status_cb)(void*, const char *), + int (*status_cb)(void*, const char *), void *status_cb_arg) { - int rc, okay, off; + assuan_error_t rc; + int okay, off; char *line; int linelen; @@ -157,14 +161,14 @@ assuan_transact (ASSUAN_CONTEXT ctx, if (!okay) { - rc = atoi (line); + rc = _assuan_error (atoi (line)); if (rc < 100) rc = ASSUAN_Server_Fault; } else if (okay == 2) { if (!data_cb) - rc = ASSUAN_No_Data_Callback; + rc = _assuan_error (ASSUAN_No_Data_Callback); else { char *s, *d; @@ -193,7 +197,7 @@ assuan_transact (ASSUAN_CONTEXT ctx, { assuan_write_line (ctx, "END"); /* get out of inquire mode */ _assuan_read_from_server (ctx, &okay, &off); /* dummy read */ - rc = ASSUAN_No_Inquire_Callback; + rc = _assuan_error (ASSUAN_No_Inquire_Callback); } else { @@ -214,7 +218,7 @@ assuan_transact (ASSUAN_CONTEXT ctx, else if (okay == 5) { if (!data_cb) - rc = ASSUAN_No_Data_Callback; + rc = _assuan_error (ASSUAN_No_Data_Callback); else { rc = data_cb (data_cb_arg, NULL, 0); diff --git a/assuan/assuan-connect.c b/assuan/assuan-connect.c index ff1f6ff..92995d8 100644 --- a/assuan/assuan-connect.c +++ b/assuan/assuan-connect.c @@ -15,7 +15,8 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #ifdef HAVE_CONFIG_H @@ -49,10 +50,30 @@ assuan_disconnect (assuan_context_t ctx) } } -/* Return the PID of the peer or -1 if not known. */ +/* Return the PID of the peer or -1 if not known. This function works + in some situations where assuan_get_ucred fails. */ pid_t assuan_get_pid (assuan_context_t ctx) { return (ctx && ctx->pid)? ctx->pid : -1; } + +/* 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 + 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) +{ + if (!ctx) + return _assuan_error (ASSUAN_Invalid_Value); + if (!ctx->peercred.valid) + return _assuan_error (ASSUAN_General_Error); + if (pid) + *pid = ctx->peercred.pid; + if (uid) + *uid = ctx->peercred.uid; + if (gid) + *gid = ctx->peercred.gid; + return 0; +} diff --git a/assuan/assuan-defs.h b/assuan/assuan-defs.h index 2917fe8..7a96c0f 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 Free Software Foundation, Inc. + * Copyright (C) 2001, 2002, 2004, 2005 Free Software Foundation, Inc. * * This file is part of Assuan. * @@ -15,7 +15,8 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #ifndef ASSUAN_DEFS_H @@ -62,24 +63,30 @@ char * stpcpy (char *dest, const char *src); #define LINELENGTH ASSUAN_LINELENGTH + struct cmdtbl_s { const char *name; - int (*handler)(ASSUAN_CONTEXT, char *line); + int (*handler)(assuan_context_t, char *line); }; + +/* A structure to dispatch I/O functions. All these functions need to + return 0 on success and set ERRNO on failure. */ struct assuan_io { /* Routine to read from input_fd. */ - ssize_t (*readfnc) (ASSUAN_CONTEXT, void *, size_t); + ssize_t (*readfnc) (assuan_context_t, void *, size_t); /* Routine to write to output_fd. */ - ssize_t (*writefnc) (ASSUAN_CONTEXT, const void *, size_t); + ssize_t (*writefnc) (assuan_context_t, const void *, size_t); /* Send a file descriptor. */ - assuan_error_t (*sendfd) (ASSUAN_CONTEXT, int); + assuan_error_t (*sendfd) (assuan_context_t, int); /* Receive a file descriptor. */ - assuan_error_t (*receivefd) (ASSUAN_CONTEXT, int *); -}; + assuan_error_t (*receivefd) (assuan_context_t, int *); +}; + +/* The context we use with most functions. */ struct assuan_context_s { assuan_error_t err_no; @@ -88,18 +95,18 @@ struct assuan_context_s error codes. */ /* Context specific flags (cf. assuan_flag_t). */ - struct + struct { unsigned int no_waitpid:1; /* See ASSUAN_NO_WAITPID. */ - } flags; + } flags; int confidential; int is_server; /* Set if this is context belongs to a server */ int in_inquire; char *hello_line; char *okay_line; /* See assuan_set_okay_line() */ - - void *user_pointer; /* For assuan_get_pointer and assuan-set_pointer (). */ + + void *user_pointer; /* For assuan_get_pointer and assuan_set_pointer (). */ FILE *log_fp; @@ -109,7 +116,7 @@ struct assuan_context_s char line[LINELENGTH]; int linelen; /* w/o CR, LF - might not be the same as strlen(line) due to embedded nuls. However a nul - is always written at this pos */ + is always written at this pos. */ struct { char line[LINELENGTH]; int linelen ; @@ -122,49 +129,55 @@ struct assuan_context_s struct { FILE *fp; char line[LINELENGTH]; - int linelen; + int linelen; int error; - } data; + } data; } outbound; int pipe_mode; /* We are in pipe mode, i.e. we can handle just one - connection and must terminate then */ - pid_t pid; /* The the pid of the peer. */ + 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 */ + struct { + int valid; /* Whether this structure has valid information. */ + pid_t pid; /* The pid of the peer. */ + uid_t uid; /* The uid of the peer. */ + gid_t gid; /* The gid of the peer. */ + } peercred; /* Used for Unix domain sockets. */ struct sockaddr_un myaddr; struct sockaddr_un serveraddr; - /* When reading from datagram sockets, we must read an entire - message at a time. This means that we have to do our own - buffering to be able to get the semantics of read. */ - void *domainbuffer; - /* Offset of start of buffer. */ - int domainbufferoffset; - /* Bytes buffered. */ - int domainbuffersize; - /* Memory allocated. */ - int domainbufferallocated; - - int *pendingfds; - int pendingfdscount; - - void (*deinit_handler)(ASSUAN_CONTEXT); - int (*accept_handler)(ASSUAN_CONTEXT); - int (*finish_handler)(ASSUAN_CONTEXT); + + /* Structure used for unix domain socket buffering. FIXME: We don't + use datagrams anymore thus we could get away with a simpler + buffering approach. */ + struct { + void *buffer; /* Malloced buffer. */ + int bufferallocated; /* Memory allocated. */ + int bufferoffset; /* Offset of start of buffer. */ + int buffersize; /* Bytes buffered. */ + + int pendingfds[5]; /* Array to save received descriptors. */ + int pendingfdscount; /* Number of received descriptors. */ + } uds; + + void (*deinit_handler)(assuan_context_t); + int (*accept_handler)(assuan_context_t); + int (*finish_handler)(assuan_context_t); struct cmdtbl_s *cmdtbl; size_t cmdtbl_used; /* used entries */ size_t cmdtbl_size; /* allocated size of table */ - void (*bye_notify_fnc)(ASSUAN_CONTEXT); - void (*reset_notify_fnc)(ASSUAN_CONTEXT); - void (*cancel_notify_fnc)(ASSUAN_CONTEXT); - int (*option_handler_fnc)(ASSUAN_CONTEXT,const char*, const char*); - void (*input_notify_fnc)(ASSUAN_CONTEXT, const char *); - void (*output_notify_fnc)(ASSUAN_CONTEXT, const char *); + void (*bye_notify_fnc)(assuan_context_t); + void (*reset_notify_fnc)(assuan_context_t); + void (*cancel_notify_fnc)(assuan_context_t); + int (*option_handler_fnc)(assuan_context_t,const char*, const char*); + void (*input_notify_fnc)(assuan_context_t, const char *); + void (*output_notify_fnc)(assuan_context_t, const char *); int input_fd; /* set by INPUT command */ int output_fd; /* set by OUTPUT command */ @@ -174,29 +187,45 @@ struct assuan_context_s }; /*-- assuan-pipe-server.c --*/ -int _assuan_new_context (ASSUAN_CONTEXT *r_ctx); -void _assuan_release_context (ASSUAN_CONTEXT ctx); +int _assuan_new_context (assuan_context_t *r_ctx); +void _assuan_release_context (assuan_context_t ctx); + +/*-- assuan-uds.c --*/ +void _assuan_uds_close_fds (assuan_context_t ctx); +void _assuan_uds_deinit (assuan_context_t ctx); +void _assuan_init_uds_io (assuan_context_t ctx); -/*-- assuan-domain-connect.c --*/ -/* 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. */ -assuan_error_t _assuan_domain_init (ASSUAN_CONTEXT *r_ctx, - int rendezvousfd, - pid_t peer); /*-- assuan-handler.c --*/ -int _assuan_register_std_commands (ASSUAN_CONTEXT ctx); +int _assuan_register_std_commands (assuan_context_t ctx); /*-- assuan-buffer.c --*/ -int _assuan_read_line (ASSUAN_CONTEXT ctx); +assuan_error_t _assuan_read_line (assuan_context_t ctx); int _assuan_cookie_write_data (void *cookie, const char *buffer, size_t size); int _assuan_cookie_write_flush (void *cookie); assuan_error_t _assuan_write_line (assuan_context_t ctx, const char *prefix, const char *line, size_t len); /*-- assuan-client.c --*/ -assuan_error_t _assuan_read_from_server (ASSUAN_CONTEXT ctx, int *okay, int *off); +assuan_error_t _assuan_read_from_server (assuan_context_t ctx, + int *okay, int *off); + +/*-- assuan-error.c --*/ + + +/* Map error codes as used in this implementaion to the libgpg-error + codes. */ +assuan_error_t _assuan_error (int oldcode); + +/* 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. */ +#define err_code(a) ((a) & 0x00ffffff) + +/* Check whether A is the erro code for EOF. We allow forold and new + style EOF error codes here. */ +#define err_is_eof(a) ((a) == (-1) || err_code (a) == 16383) + /*-- assuan-util.c --*/ @@ -210,10 +239,8 @@ void _assuan_free (void *p); #define xtryrealloc(a,b) _assuan_realloc((a),(b)) #define xfree(a) _assuan_free ((a)) -#define set_error(c,e,t) assuan_set_error ((c), ASSUAN_ ## e, (t)) - -void _assuan_log_print_buffer (FILE *fp, const void *buffer, size_t length); -void _assuan_log_sanitized_string (const char *string); +#define set_error(c,e,t) \ + assuan_set_error ((c), _assuan_error (ASSUAN_ ## e), (t)) #ifdef HAVE_W32_SYSTEM const char *_assuan_w32_strerror (int ec); @@ -229,11 +256,18 @@ void _assuan_log_printf (const char *format, ...) __attribute__ ((format (printf,1,2))) #endif ; +void _assuan_log_print_buffer (FILE *fp, const void *buffer, size_t length); +void _assuan_log_sanitized_string (const char *string); + /*-- assuan-io.c --*/ -ssize_t _assuan_simple_read (ASSUAN_CONTEXT ctx, void *buffer, size_t size); -ssize_t _assuan_simple_write (ASSUAN_CONTEXT ctx, const void *buffer, +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_simple_sendmsg (assuan_context_t ctx, struct msghdr *msg); +ssize_t _assuan_simple_recvmsg (assuan_context_t ctx, struct msghdr *msg); /*-- assuan-socket.c --*/ int _assuan_close (int fd); @@ -251,5 +285,25 @@ FILE *_assuan_funopen(void *cookie, #define funopen(a,r,w,s,c) _assuan_funopen ((a), (r), (w), (s), (c)) #endif /*HAVE_FOPENCOOKIE*/ -#endif /*ASSUAN_DEFS_H*/ +/* Prototypes for replacement functions. */ +#ifndef HAVE_MEMRCHR +void *memrchr (const void *block, int c, size_t size); +#endif +#ifndef HAVE_STPCPY +char *stpcpy (char *dest, const char *src); +#endif +#ifndef HAVE_SETENV +#define setenv _assuan_setenv +#define unsetenv _assuan_unsetenv +#define clearenv _assuan_clearenv +int setenv (const char *name, const char *value, int replace); +#endif +#ifndef HAVE_PUTC_UNLOCKED +int putc_unlocked (int c, FILE *stream) +#endif +#define DIM(v) (sizeof(v)/sizeof((v)[0])) +#define DIMof(type,member) DIM(((type *)0)->member) + + +#endif /*ASSUAN_DEFS_H*/ diff --git a/assuan/assuan-domain-connect.c b/assuan/assuan-domain-connect.c index b55e9c3..e69de29 100644 --- a/assuan/assuan-domain-connect.c +++ b/assuan/assuan-domain-connect.c @@ -1,504 +0,0 @@ -/* assuan-domain-connect.c - Assuan unix domain socket based client - * Copyright (C) 2002, 2003 Free Software Foundation, Inc. - * - * This file is part of Assuan. - * - * Assuan is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * Assuan is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#ifndef HAVE_W32_SYSTEM -#include -#include -#else -#include -#endif -#if HAVE_SYS_UIO_H -#include -#endif -#include -#include -#include -#include - -#include "assuan-defs.h" - -#ifndef PF_LOCAL -# ifdef PF_UNIX -# define PF_LOCAL PF_UNIX -# else -# define PF_LOCAL AF_UNIX -# endif -# ifndef AF_LOCAL -# define AF_LOCAL AF_UNIX -# endif -#endif - - -static void -do_deinit (assuan_context_t ctx) -{ - if (ctx->inbound.fd != -1) - _assuan_close (ctx->inbound.fd); - ctx->inbound.fd = -1; - ctx->outbound.fd = -1; - - if (ctx->domainbuffer) - { - assert (ctx->domainbufferallocated); - free (ctx->domainbuffer); - } - - if (ctx->pendingfds) - { - int i; - - assert (ctx->pendingfdscount > 0); - for (i = 0; i < ctx->pendingfdscount; i ++) - _assuan_close (ctx->pendingfds[i]); - - free (ctx->pendingfds); - } - - unlink (ctx->myaddr.sun_path); -} - - -/* Read from the socket server. */ -static ssize_t -domain_reader (assuan_context_t ctx, void *buf, size_t buflen) -{ - int len = ctx->domainbuffersize; - -#ifndef HAVE_W32_SYSTEM - start: - if (len == 0) - /* No data is buffered. */ - { - struct msghdr msg; - struct iovec iovec; - struct sockaddr_un sender; - struct - { - struct cmsghdr hdr; - int fd; - } - cmsg; - - memset (&msg, 0, sizeof (msg)); - - for (;;) - { - msg.msg_name = &sender; - msg.msg_namelen = sizeof (struct sockaddr_un); - msg.msg_iov = &iovec; - msg.msg_iovlen = 1; - iovec.iov_base = ctx->domainbuffer; - iovec.iov_len = ctx->domainbufferallocated; - msg.msg_control = &cmsg; - msg.msg_controllen = sizeof cmsg; - - /* Peek first: if the buffer we have is too small then it - will be truncated. */ - len = recvmsg (ctx->inbound.fd, &msg, MSG_PEEK); - if (len < 0) - { - printf ("domain_reader: %m\n"); - return -1; - } - - if (strcmp (ctx->serveraddr.sun_path, - ((struct sockaddr_un *) msg.msg_name)->sun_path) != 0) - { - /* XXX: Arg. Not from whom we expected! What do we - want to do? Should we just ignore it? Either way, - we still need to consume the message. */ - break; - } - - if (msg.msg_flags & MSG_TRUNC) - /* Enlarge the buffer and try again. */ - { - int size = ctx->domainbufferallocated; - void *tmp; - - if (size == 0) - size = 4 * 1024; - else - size *= 2; - - tmp = malloc (size); - if (! tmp) - return -1; - - free (ctx->domainbuffer); - ctx->domainbuffer = tmp; - ctx->domainbufferallocated = size; - } - else - /* We have enough space! */ - break; - } - - /* Now we have to actually consume it (remember, we only - peeked). */ - msg.msg_name = &sender; - msg.msg_namelen = sizeof (struct sockaddr_un); - msg.msg_iov = &iovec; - msg.msg_iovlen = 1; - iovec.iov_base = ctx->domainbuffer; - iovec.iov_len = ctx->domainbufferallocated; - msg.msg_control = &cmsg; - msg.msg_controllen = sizeof cmsg; - - if (strcmp (ctx->serveraddr.sun_path, - ((struct sockaddr_un *) msg.msg_name)->sun_path) != 0) - { - /* XXX: Arg. Not from whom we expected! What do we want to - do? Should we just ignore it? We shall do the latter - for the moment. */ - _assuan_log_printf ("not setup to receive messages from `%s'\n", - ((struct sockaddr_un *) msg.msg_name)->sun_path); - goto start; - } - - len = recvmsg (ctx->inbound.fd, &msg, 0); - if (len < 0) - { - _assuan_log_printf ("domain_reader: %s\n", strerror (errno)); - return -1; - } - - ctx->domainbuffersize = len; - ctx->domainbufferoffset = 0; - - if (sizeof (cmsg) == msg.msg_controllen) - /* We received a file descriptor. */ - { - void *tmp; - - tmp = realloc (ctx->pendingfds, - sizeof (int) * (ctx->pendingfdscount + 1)); - if (! tmp) - { - _assuan_log_printf ("domain_reader: %s\n", strerror (errno)); - return -1; - } - - ctx->pendingfds = tmp; - ctx->pendingfds[ctx->pendingfdscount++] - = *(int *) CMSG_DATA (&cmsg.hdr); - - _assuan_log_printf ("received file descriptor %d from peer\n", - ctx->pendingfds[ctx->pendingfdscount - 1]); - } - - if (len == 0) - goto start; - } -#else - len = recvfrom (ctx->inbound.fd, buf, buflen, 0, NULL, NULL); -#endif - - /* Return some data to the user. */ - - if (len > buflen) - /* We have more than the user requested. */ - len = buflen; - - memcpy (buf, ctx->domainbuffer + ctx->domainbufferoffset, len); - ctx->domainbuffersize -= len; - assert (ctx->domainbuffersize >= 0); - ctx->domainbufferoffset += len; - assert (ctx->domainbufferoffset <= ctx->domainbufferallocated); - - return len; -} - -/* Write to the domain server. */ -static ssize_t -domain_writer (assuan_context_t ctx, const void *buf, size_t buflen) -{ -#ifndef HAVE_W32_SYSTEM - struct msghdr msg; - struct iovec iovec; - ssize_t len; - - memset (&msg, 0, sizeof (msg)); - - msg.msg_name = &ctx->serveraddr; - msg.msg_namelen = offsetof (struct sockaddr_un, sun_path) - + strlen (ctx->serveraddr.sun_path) + 1; - - msg.msg_iovlen = 1; - msg.msg_iov = &iovec; - iovec.iov_base = (void *) buf; - iovec.iov_len = buflen; - msg.msg_control = 0; - msg.msg_controllen = 0; - - len = sendmsg (ctx->outbound.fd, &msg, 0); - if (len < 0) - _assuan_log_printf ("domain_writer: %s\n", strerror (errno)); -#else - int len; - - len = sendto (ctx->outbound.fd, buf, buflen, 0, - (struct sockaddr *)&ctx->serveraddr, - sizeof (struct sockaddr_in)); -#endif - return len; -} - -static assuan_error_t -domain_sendfd (assuan_context_t ctx, int fd) -{ -#ifndef HAVE_W32_SYSTEM - struct msghdr msg; - struct - { - struct cmsghdr hdr; - int fd; - } - cmsg; - int len; - - memset (&msg, 0, sizeof (msg)); - - msg.msg_name = &ctx->serveraddr; - msg.msg_namelen = offsetof (struct sockaddr_un, sun_path) - + strlen (ctx->serveraddr.sun_path) + 1; - - msg.msg_iovlen = 0; - msg.msg_iov = 0; - - cmsg.hdr.cmsg_level = SOL_SOCKET; - cmsg.hdr.cmsg_type = SCM_RIGHTS; - cmsg.hdr.cmsg_len = sizeof (cmsg); - - msg.msg_control = &cmsg; - msg.msg_controllen = sizeof (cmsg); - - *(int *) CMSG_DATA (&cmsg.hdr) = fd; - - len = sendmsg (ctx->outbound.fd, &msg, 0); - if (len < 0) - { - _assuan_log_printf ("domain_sendfd: %s\n", strerror (errno)); - return ASSUAN_General_Error; - } - else - return 0; -#else - return 0; -#endif -} - -static assuan_error_t -domain_receivefd (assuan_context_t ctx, int *fd) -{ -#ifndef HAVE_W32_SYSTEM - if (ctx->pendingfds == 0) - { - _assuan_log_printf ("no pending file descriptors!\n"); - return ASSUAN_General_Error; - } - - *fd = ctx->pendingfds[0]; - if (-- ctx->pendingfdscount == 0) - { - free (ctx->pendingfds); - ctx->pendingfds = 0; - } - else - /* Fix the array. */ - { - memmove (ctx->pendingfds, ctx->pendingfds + 1, - ctx->pendingfdscount * sizeof (int)); - ctx->pendingfds = realloc (ctx->pendingfds, - ctx->pendingfdscount * sizeof (int)); - } -#endif - return 0; -} - - - -/* 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. */ -assuan_error_t -_assuan_domain_init (assuan_context_t *r_ctx, int rendezvousfd, pid_t peer) -{ - static struct assuan_io io = { domain_reader, domain_writer, - domain_sendfd, domain_receivefd }; - - assuan_error_t err; - assuan_context_t ctx; - int fd; - size_t len; - int tries; - - if (!r_ctx) - return ASSUAN_Invalid_Value; - *r_ctx = NULL; - - err = _assuan_new_context (&ctx); - if (err) - return err; - - /* Save it in case we need it later. */ - ctx->pid = peer; - - /* Override the default (NOP) handlers. */ - ctx->deinit_handler = do_deinit; - - /* Setup the socket. */ - - fd = _assuan_sock_new (PF_LOCAL, SOCK_DGRAM, 0); - if (fd == -1) - { - _assuan_log_printf ("can't create socket: %s\n", strerror (errno)); - _assuan_release_context (ctx); - return ASSUAN_General_Error; - } - - ctx->inbound.fd = fd; - ctx->outbound.fd = fd; - - /* And the io buffers. */ - - ctx->io = &io; - ctx->domainbuffer = 0; - ctx->domainbufferoffset = 0; - ctx->domainbuffersize = 0; - ctx->domainbufferallocated = 0; - ctx->pendingfds = 0; - ctx->pendingfdscount = 0; - - /* Get usable name and bind to it. */ - - for (tries = 0; tries < TMP_MAX; tries ++) - { - char *p; - char buf[L_tmpnam]; - - /* XXX: L_tmpnam must be shorter than sizeof (sun_path)! */ - assert (L_tmpnam < sizeof (ctx->myaddr.sun_path)); - - /* XXX: W32 tmpnam is broken */ - p = tmpnam (buf); - if (! p) - { - _assuan_log_printf ("cannot determine an appropriate temporary file " - "name. DoS in progress?\n"); - _assuan_release_context (ctx); - _assuan_close (fd); - return ASSUAN_General_Error; - } - - memset (&ctx->myaddr, 0, sizeof ctx->myaddr); - ctx->myaddr.sun_family = AF_LOCAL; - len = strlen (buf) + 1; - memcpy (ctx->myaddr.sun_path, buf, len); - len += offsetof (struct sockaddr_un, sun_path); - - err = _assuan_sock_bind (fd, (struct sockaddr *) &ctx->myaddr, len); - if (! err) - break; - } - - if (err) - { - _assuan_log_printf ("can't bind to `%s': %s\n", ctx->myaddr.sun_path, - strerror (errno)); - _assuan_release_context (ctx); - _assuan_close (fd); - return ASSUAN_Connect_Failed; - } - - /* Rendezvous with our peer. */ - { - FILE *fp; - char *p; - - fp = fdopen (rendezvousfd, "w+"); - if (! fp) - { - _assuan_log_printf ("can't open rendezvous port: %s\n", strerror (errno)); - return ASSUAN_Connect_Failed; - } - - /* Send our address. */ - fprintf (fp, "%s\n", ctx->myaddr.sun_path); - fflush (fp); - - /* And receive our peer's. */ - memset (&ctx->serveraddr, 0, sizeof ctx->serveraddr); - for (p = ctx->serveraddr.sun_path; - p < (ctx->serveraddr.sun_path - + sizeof ctx->serveraddr.sun_path - 1); - p ++) - { - *p = fgetc (fp); - if (*p == '\n') - break; - } - *p = '\0'; - fclose (fp); - - ctx->serveraddr.sun_family = AF_LOCAL; - } - - *r_ctx = ctx; - return 0; -} - -assuan_error_t -assuan_domain_connect (assuan_context_t * r_ctx, int rendezvousfd, pid_t peer) -{ - assuan_error_t aerr; - int okay, off; - - aerr = _assuan_domain_init (r_ctx, rendezvousfd, peer); - if (aerr) - return aerr; - - /* Initial handshake. */ - aerr = _assuan_read_from_server (*r_ctx, &okay, &off); - if (aerr) - _assuan_log_printf ("can't connect to server: %s\n", - assuan_strerror (aerr)); - else if (okay != 1) - { - _assuan_log_printf ("can't connect to server: `"); - _assuan_log_sanitized_string ((*r_ctx)->inbound.line); - fprintf (assuan_get_assuan_log_stream (), "'\n"); - aerr = ASSUAN_Connect_Failed; - } - - if (aerr) - assuan_disconnect (*r_ctx); - - return aerr; -} diff --git a/assuan/assuan-domain-server.c b/assuan/assuan-domain-server.c index 45d53c2..e69de29 100644 --- a/assuan/assuan-domain-server.c +++ b/assuan/assuan-domain-server.c @@ -1,46 +0,0 @@ -/* assuan-socket-server.c - Assuan socket based server - * Copyright (C) 2002 Free Software Foundation, Inc. - * - * This file is part of Assuan. - * - * Assuan is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * Assuan is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include "assuan-defs.h" - -/* Initialize a server. */ -assuan_error_t -assuan_init_domain_server (ASSUAN_CONTEXT *r_ctx, - int rendezvousfd, - pid_t peer) -{ - assuan_error_t err; - - err = _assuan_domain_init (r_ctx, rendezvousfd, peer); - if (err) - return err; - - (*r_ctx)->is_server = 1; - /* A domain server can only be used once. */ - (*r_ctx)->pipe_mode = 1; - - return 0; -} diff --git a/assuan/assuan-handler.c b/assuan/assuan-handler.c index 21501a3..bf00d1a 100644 --- a/assuan/assuan-handler.c +++ b/assuan/assuan-handler.c @@ -15,7 +15,8 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include @@ -36,20 +37,20 @@ static int my_strcasecmp (const char *a, const char *b); static int -dummy_handler (ASSUAN_CONTEXT ctx, char *line) +dummy_handler (assuan_context_t ctx, char *line) { return set_error (ctx, Server_Fault, "no handler registered"); } static int -std_handler_nop (ASSUAN_CONTEXT ctx, char *line) +std_handler_nop (assuan_context_t ctx, char *line) { return 0; /* okay */ } static int -std_handler_cancel (ASSUAN_CONTEXT ctx, char *line) +std_handler_cancel (assuan_context_t ctx, char *line) { if (ctx->cancel_notify_fnc) ctx->cancel_notify_fnc (ctx); @@ -57,7 +58,7 @@ std_handler_cancel (ASSUAN_CONTEXT ctx, char *line) } static int -std_handler_option (ASSUAN_CONTEXT ctx, char *line) +std_handler_option (assuan_context_t ctx, char *line) { char *key, *value, *p; @@ -104,7 +105,7 @@ std_handler_option (ASSUAN_CONTEXT ctx, char *line) } static int -std_handler_bye (ASSUAN_CONTEXT ctx, char *line) +std_handler_bye (assuan_context_t ctx, char *line) { if (ctx->bye_notify_fnc) ctx->bye_notify_fnc (ctx); @@ -114,33 +115,35 @@ std_handler_bye (ASSUAN_CONTEXT ctx, char *line) } static int -std_handler_auth (ASSUAN_CONTEXT ctx, char *line) +std_handler_auth (assuan_context_t ctx, char *line) { return set_error (ctx, Not_Implemented, NULL); } static int -std_handler_reset (ASSUAN_CONTEXT ctx, char *line) +std_handler_reset (assuan_context_t ctx, char *line) { if (ctx->reset_notify_fnc) ctx->reset_notify_fnc (ctx); assuan_close_input_fd (ctx); assuan_close_output_fd (ctx); + _assuan_uds_close_fds (ctx); return 0; } static int -std_handler_end (ASSUAN_CONTEXT ctx, char *line) +std_handler_end (assuan_context_t ctx, char *line) { return set_error (ctx, Not_Implemented, NULL); } assuan_error_t -assuan_command_parse_fd (ASSUAN_CONTEXT ctx, char *line, int *rfd) +assuan_command_parse_fd (assuan_context_t ctx, char *line, int *rfd) { char *endp; - if (strncmp (line, "FD", 2) != 0 || (line[2] != '=' && line[2] != '\0')) + if ( (strncmp (line, "FD", 2) && strncmp (line, "fd", 2)) + || (line[2] != '=' && line[2] != '\0')) return set_error (ctx, Syntax_Error, "FD[=] expected"); line += 2; if (*line == '=') @@ -149,7 +152,7 @@ assuan_command_parse_fd (ASSUAN_CONTEXT ctx, char *line, int *rfd) if (!digitp (*line)) return set_error (ctx, Syntax_Error, "number required"); *rfd = strtoul (line, &endp, 10); - /* remove that argument so that a notify handler won't see it */ + /* Remove that argument so that a notify handler won't see it. */ memset (line, ' ', endp? (endp-line):strlen(line)); if (*rfd == ctx->inbound.fd) @@ -165,7 +168,7 @@ assuan_command_parse_fd (ASSUAN_CONTEXT ctx, char *line, int *rfd) /* Format is INPUT FD= */ static int -std_handler_input (ASSUAN_CONTEXT ctx, char *line) +std_handler_input (assuan_context_t ctx, char *line) { int rc, fd; @@ -180,7 +183,7 @@ std_handler_input (ASSUAN_CONTEXT ctx, char *line) /* Format is OUTPUT FD= */ static int -std_handler_output (ASSUAN_CONTEXT ctx, char *line) +std_handler_output (assuan_context_t ctx, char *line) { int rc, fd; @@ -202,7 +205,7 @@ std_handler_output (ASSUAN_CONTEXT ctx, char *line) with default handlers */ static struct { const char *name; - int (*handler)(ASSUAN_CONTEXT, char *line); + int (*handler)(assuan_context_t, char *line); int always; /* always initialize this command */ } std_cmd_table[] = { { "NOP", std_handler_nop, 1 }, @@ -234,9 +237,9 @@ static struct { * Return value: 0 on success or an error code **/ int -assuan_register_command (ASSUAN_CONTEXT ctx, +assuan_register_command (assuan_context_t ctx, const char *cmd_name, - int (*handler)(ASSUAN_CONTEXT, char *)) + int (*handler)(assuan_context_t, char *)) { int i; const char *s; @@ -245,7 +248,7 @@ assuan_register_command (ASSUAN_CONTEXT ctx, cmd_name = NULL; if (!cmd_name) - return ASSUAN_Invalid_Value; + return _assuan_error (ASSUAN_Invalid_Value); if (!handler) { /* find a default handler. */ @@ -268,7 +271,7 @@ assuan_register_command (ASSUAN_CONTEXT ctx, ctx->cmdtbl_size = 50; ctx->cmdtbl = xtrycalloc ( ctx->cmdtbl_size, sizeof *ctx->cmdtbl); if (!ctx->cmdtbl) - return ASSUAN_Out_Of_Core; + return _assuan_error (ASSUAN_Out_Of_Core); ctx->cmdtbl_used = 0; } else if (ctx->cmdtbl_used >= ctx->cmdtbl_size) @@ -277,7 +280,7 @@ assuan_register_command (ASSUAN_CONTEXT ctx, x = xtryrealloc ( ctx->cmdtbl, (ctx->cmdtbl_size+10) * sizeof *x); if (!x) - return ASSUAN_Out_Of_Core; + return _assuan_error (ASSUAN_Out_Of_Core); ctx->cmdtbl = x; ctx->cmdtbl_size += 50; } @@ -289,59 +292,62 @@ assuan_register_command (ASSUAN_CONTEXT ctx, } int -assuan_register_bye_notify (ASSUAN_CONTEXT ctx, void (*fnc)(ASSUAN_CONTEXT)) +assuan_register_bye_notify (assuan_context_t ctx, + void (*fnc)(assuan_context_t)) { if (!ctx) - return ASSUAN_Invalid_Value; + return _assuan_error (ASSUAN_Invalid_Value); ctx->bye_notify_fnc = fnc; return 0; } int -assuan_register_reset_notify (ASSUAN_CONTEXT ctx, void (*fnc)(ASSUAN_CONTEXT)) +assuan_register_reset_notify (assuan_context_t ctx, + void (*fnc)(assuan_context_t)) { if (!ctx) - return ASSUAN_Invalid_Value; + return _assuan_error (ASSUAN_Invalid_Value); ctx->reset_notify_fnc = fnc; return 0; } int -assuan_register_cancel_notify (ASSUAN_CONTEXT ctx, void (*fnc)(ASSUAN_CONTEXT)) +assuan_register_cancel_notify (assuan_context_t ctx, + void (*fnc)(assuan_context_t)) { if (!ctx) - return ASSUAN_Invalid_Value; + return _assuan_error (ASSUAN_Invalid_Value); ctx->cancel_notify_fnc = fnc; return 0; } int -assuan_register_option_handler (ASSUAN_CONTEXT ctx, - int (*fnc)(ASSUAN_CONTEXT, +assuan_register_option_handler (assuan_context_t ctx, + int (*fnc)(assuan_context_t, const char*, const char*)) { if (!ctx) - return ASSUAN_Invalid_Value; + return _assuan_error (ASSUAN_Invalid_Value); ctx->option_handler_fnc = fnc; return 0; } int -assuan_register_input_notify (ASSUAN_CONTEXT ctx, - void (*fnc)(ASSUAN_CONTEXT, const char *)) +assuan_register_input_notify (assuan_context_t ctx, + void (*fnc)(assuan_context_t, const char *)) { if (!ctx) - return ASSUAN_Invalid_Value; + return _assuan_error (ASSUAN_Invalid_Value); ctx->input_notify_fnc = fnc; return 0; } int -assuan_register_output_notify (ASSUAN_CONTEXT ctx, - void (*fnc)(ASSUAN_CONTEXT, const char *)) +assuan_register_output_notify (assuan_context_t ctx, + void (*fnc)(assuan_context_t, const char *)) { if (!ctx) - return ASSUAN_Invalid_Value; + return _assuan_error (ASSUAN_Invalid_Value); ctx->output_notify_fnc = fnc; return 0; } @@ -349,7 +355,7 @@ assuan_register_output_notify (ASSUAN_CONTEXT ctx, /* Helper to register the standards commands */ int -_assuan_register_std_commands (ASSUAN_CONTEXT ctx) +_assuan_register_std_commands (assuan_context_t ctx) { int i, rc; @@ -370,7 +376,7 @@ _assuan_register_std_commands (ASSUAN_CONTEXT ctx) /* Process the special data lines. The "D " has already been removed from the line. As all handlers this function may modify the line. */ static int -handle_data_line (ASSUAN_CONTEXT ctx, char *line, int linelen) +handle_data_line (assuan_context_t ctx, char *line, int linelen) { return set_error (ctx, Not_Implemented, NULL); } @@ -394,7 +400,7 @@ my_strcasecmp (const char *a, const char *b) table, remove leading and white spaces from the arguments, call the handler with the argument line and return the error */ static int -dispatch_command (ASSUAN_CONTEXT ctx, char *line, int linelen) +dispatch_command (assuan_context_t ctx, char *line, int linelen) { char *p; const char *s; @@ -406,7 +412,7 @@ dispatch_command (ASSUAN_CONTEXT ctx, char *line, int linelen) for (p=line; *p && *p != ' ' && *p != '\t'; p++) ; if (p==line) - return set_error (ctx, Invalid_Command, "leading white-space"); + return set_error (ctx, Syntax_Error, "leading white-space"); if (*p) { /* Skip over leading WS after the keyword */ *p++ = 0; @@ -441,12 +447,12 @@ dispatch_command (ASSUAN_CONTEXT ctx, char *line, int linelen) static int -process_request (ASSUAN_CONTEXT ctx) +process_request (assuan_context_t ctx) { int rc; if (ctx->in_inquire) - return ASSUAN_Nested_Commands; + return _assuan_error (ASSUAN_Nested_Commands); rc = _assuan_read_line (ctx); if (rc) @@ -477,8 +483,8 @@ process_request (ASSUAN_CONTEXT ctx) { rc = assuan_write_line (ctx, ctx->okay_line? ctx->okay_line : "OK"); } - else if (rc == -1) - { /* No error checking because the peer may have already disconnect */ + else if (err_is_eof (rc)) + { /* No error checking because the peer may have already disconnect. */ assuan_write_line (ctx, "OK closing connection"); ctx->finish_handler (ctx); } @@ -488,7 +494,7 @@ process_request (ASSUAN_CONTEXT ctx) if (rc < 100) sprintf (errline, "ERR %d server fault (%.50s)", - ASSUAN_Server_Fault, assuan_strerror (rc)); + _assuan_error (ASSUAN_Server_Fault), assuan_strerror (rc)); else { const char *text = ctx->err_no == rc? ctx->err_str:NULL; @@ -498,7 +504,7 @@ process_request (ASSUAN_CONTEXT ctx) strings from libgpg-error without creating a dependency. They are used for debugging purposes only, so there is no problem if they are not available. We need to make sure - that we are using elf because only this guarantees that + that we are using ELF because only this guarantees that weak symbol support is available in case GNU ld is not used. */ unsigned int source, code; @@ -552,7 +558,7 @@ process_request (ASSUAN_CONTEXT ctx) * failed. Note, that no error is returned for operational errors. **/ int -assuan_process (ASSUAN_CONTEXT ctx) +assuan_process (assuan_context_t ctx) { int rc; @@ -560,7 +566,7 @@ assuan_process (ASSUAN_CONTEXT ctx) rc = process_request (ctx); } while (!rc); - if (rc == -1) + if (err_is_eof (rc)) rc = 0; return rc; @@ -579,7 +585,7 @@ assuan_process (ASSUAN_CONTEXT ctx) * Return value: -1 for end of server, 0 on success or an error code **/ int -assuan_process_next (ASSUAN_CONTEXT ctx) +assuan_process_next (assuan_context_t ctx) { return process_request (ctx); } @@ -603,7 +609,7 @@ assuan_process_next (ASSUAN_CONTEXT ctx) * error which is most likely a too small fdarray. **/ int -assuan_get_active_fds (ASSUAN_CONTEXT ctx, int what, +assuan_get_active_fds (assuan_context_t ctx, int what, int *fdarray, int fdarraysize) { int n = 0; @@ -636,7 +642,7 @@ assuan_get_active_fds (ASSUAN_CONTEXT ctx, int what, implementaion for systems w/o a glibc, a simple implementation could use a child process */ FILE * -assuan_get_data_fp (ASSUAN_CONTEXT ctx) +assuan_get_data_fp (assuan_context_t ctx) { #if defined (HAVE_FOPENCOOKIE) || defined (HAVE_FUNOPEN) if (ctx->outbound.data.fp) @@ -658,10 +664,10 @@ assuan_get_data_fp (ASSUAN_CONTEXT ctx) /* Set the text used for the next OK reponse. This string is automatically reset to NULL after the next command. */ assuan_error_t -assuan_set_okay_line (ASSUAN_CONTEXT ctx, const char *line) +assuan_set_okay_line (assuan_context_t ctx, const char *line) { if (!ctx) - return ASSUAN_Invalid_Value; + return _assuan_error (ASSUAN_Invalid_Value); if (!line) { xfree (ctx->okay_line); @@ -673,7 +679,7 @@ assuan_set_okay_line (ASSUAN_CONTEXT ctx, const char *line) we should allocate the entire line in secure memory */ char *buf = xtrymalloc (3+strlen(line)+1); if (!buf) - return ASSUAN_Out_Of_Core; + return _assuan_error (ASSUAN_Out_Of_Core); strcpy (buf, "OK "); strcpy (buf+3, line); xfree (ctx->okay_line); @@ -685,7 +691,8 @@ assuan_set_okay_line (ASSUAN_CONTEXT ctx, const char *line) assuan_error_t -assuan_write_status (ASSUAN_CONTEXT ctx, const char *keyword, const char *text) +assuan_write_status (assuan_context_t ctx, + const char *keyword, const char *text) { char buffer[256]; char *helpbuf; @@ -693,7 +700,7 @@ assuan_write_status (ASSUAN_CONTEXT ctx, const char *keyword, const char *text) assuan_error_t ae; if ( !ctx || !keyword) - return ASSUAN_Invalid_Value; + return _assuan_error (ASSUAN_Invalid_Value); if (!text) text = ""; diff --git a/assuan/assuan-inquire.c b/assuan/assuan-inquire.c index 0547aae..d8c52d0 100644 --- a/assuan/assuan-inquire.c +++ b/assuan/assuan-inquire.c @@ -15,7 +15,8 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include @@ -146,14 +147,14 @@ assuan_inquire (assuan_context_t ctx, const char *keyword, int nodataexpected; if (!ctx || !keyword || (10 + strlen (keyword) >= sizeof (cmdbuf))) - return ASSUAN_Invalid_Value; + return _assuan_error (ASSUAN_Invalid_Value); nodataexpected = !r_buffer && !r_length && !maxlen; if (!nodataexpected && (!r_buffer || !r_length)) - return ASSUAN_Invalid_Value; + return _assuan_error (ASSUAN_Invalid_Value); if (!ctx->is_server) - return ASSUAN_Not_A_Server; + return _assuan_error (ASSUAN_Not_A_Server); if (ctx->in_inquire) - return ASSUAN_Nested_Commands; + return _assuan_error (ASSUAN_Nested_Commands); ctx->in_inquire = 1; if (nodataexpected) @@ -182,12 +183,12 @@ assuan_inquire (assuan_context_t ctx, const char *keyword, break; /* END command received*/ if (line[0] == 'C' && line[1] == 'A' && line[2] == 'N') { - rc = ASSUAN_Canceled; + rc = _assuan_error (ASSUAN_Canceled); goto leave; } if (line[0] != 'D' || line[1] != ' ' || nodataexpected) { - rc = ASSUAN_Unexpected_Command; + rc = _assuan_error (ASSUAN_Unexpected_Command); goto leave; } if (linelen < 3) @@ -214,7 +215,7 @@ assuan_inquire (assuan_context_t ctx, const char *keyword, } if (mb.too_large) { - rc = ASSUAN_Too_Much_Data; + rc = _assuan_error (ASSUAN_Too_Much_Data); goto leave; } } @@ -223,7 +224,7 @@ assuan_inquire (assuan_context_t ctx, const char *keyword, { *r_buffer = get_membuf (&mb, r_length); if (!*r_buffer) - rc = ASSUAN_Out_Of_Core; + rc = _assuan_error (ASSUAN_Out_Of_Core); } leave: diff --git a/assuan/assuan-io.c b/assuan/assuan-io.c index 321f2ba..0fe48b7 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 Free Software Foundation, Inc. + * Copyright (C) 2002, 2004, 2006 Free Software Foundation, Inc. * * This file is part of Assuan. * @@ -15,30 +15,93 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #ifdef HAVE_CONFIG_H #include #endif -#include "assuan-defs.h" #include +#include +#include +#if HAVE_SYS_UIO_H +# include +#endif #include +#include #ifdef HAVE_W32_SYSTEM -#include +# include +#else +# include #endif +#include "assuan-defs.h" + +/* We can't include pth.h and we are not sure whether other headers + already included it. This we define macros with the same + values. */ +#define MY_PTH_FDMODE_ERROR (-1) +#define MY_PTH_FDMODE_POLL 0 +#define MY_PTH_FDMODE_BLOCK 1 +#define MY_PTH_FDMODE_NONBLOCK 2 + + #ifndef _ASSUAN_NO_PTH +extern pid_t pth_waitpid (pid_t pid, int *status, int options); extern ssize_t pth_read (int fd, void *buffer, size_t size); extern ssize_t pth_write (int fd, const void *buffer, size_t size); +extern int pth_fdmode (int, int); +extern int pth_select(int, fd_set*, fd_set*, fd_set*, struct timeval*); #ifndef HAVE_W32_SYSTEM +#pragma weak pth_waitpid #pragma weak pth_read #pragma weak pth_write +#pragma weak pth_fdmode +#pragma weak pth_select #endif #endif /*!_ASSUAN_NO_PTH*/ +#ifndef _ASSUAN_NO_PTH +/* Wrapper around pth_fdmode. */ +static int +my_pth_fdmode (int fd, int mode) +{ + if (pth_fdmode) + return pth_fdmode (fd, mode); + else + return MY_PTH_FDMODE_NONBLOCK; /* This is okay, given the way we use it. */ +} +#endif /*_ASSUAN_NO_PTH*/ + +#ifndef _ASSUAN_NO_PTH +/* Wrapper around pth_select. */ +static int +my_pth_select (int nfd, fd_set *rfds, fd_set *wfds, fd_set *efds, + struct timeval *timeout) +{ + if (pth_select) + return pth_select (nfd, rfds, wfds, efds, timeout); + else + return 1; /* Fake one fd ready; this is okay, given the way we use it. */ +} +#endif /*_ASSUAN_NO_PTH*/ + +#ifndef HAVE_W32_SYSTEM +pid_t +_assuan_waitpid (pid_t pid, int *status, int options) +{ +#ifdef _ASSUAN_NO_PTH + return waitpid (pid, status, options); +#else + return (pth_waitpid ? pth_waitpid : waitpid) (pid, status, options); +#endif +} +#endif + + ssize_t _assuan_simple_read (assuan_context_t ctx, void *buffer, size_t size) { @@ -51,7 +114,7 @@ _assuan_simple_read (assuan_context_t ctx, void *buffer, size_t size) return pth_read ? pth_read (ctx->inbound.fd, buffer, size) : recv (ctx->inbound.fd, buffer, size, 0); # endif -# endif +#endif } ssize_t @@ -68,3 +131,87 @@ _assuan_simple_write (assuan_context_t ctx, const void *buffer, size_t size) # endif #endif } + + +ssize_t +_assuan_simple_sendmsg (assuan_context_t ctx, struct msghdr *msg) +{ +#if defined(HAVE_W32_SYSTEM) + return _assuan_error (ASSUAN_Not_Implemented); +#elif defined(_ASSUAN_NO_PTH) + int ret; + while ( (ret = sendmsg (ctx->outbound.fd, msg, 0)) == -1 && errno == EINTR) + ; + return ret; +#else + /* Pth does not provide a sendmsg function. Thus we implement it here. */ + int ret; + int fd = ctx->outbound.fd; + int fdmode; + + fdmode = my_pth_fdmode (fd, MY_PTH_FDMODE_POLL); + if (fdmode == MY_PTH_FDMODE_ERROR) + { + errno = EBADF; + return -1; + } + if (fdmode == MY_PTH_FDMODE_BLOCK) + { + fd_set fds; + + FD_ZERO (&fds); + FD_SET (fd, &fds); + while ( (ret = my_pth_select (fd+1, NULL, &fds, NULL, NULL)) < 0 + && errno == EINTR) + ; + if (ret < 0) + return -1; + } + + while ((ret = sendmsg (fd, msg, 0)) == -1 && errno == EINTR) + ; + return ret; +#endif +} + + +ssize_t +_assuan_simple_recvmsg (assuan_context_t ctx, struct msghdr *msg) +{ +#if defined(HAVE_W32_SYSTEM) + return _assuan_error (ASSUAN_Not_Implemented); +#elif defined(_ASSUAN_NO_PTH) + int ret; + while ( (ret = recvmsg (ctx->inbound.fd, msg, 0)) == -1 && errno == EINTR) + ; + return ret; +#else + /* Pth does not provide a recvmsg function. Thus we implement it here. */ + int ret; + int fd = ctx->inbound.fd; + int fdmode; + + fdmode = my_pth_fdmode (fd, MY_PTH_FDMODE_POLL); + if (fdmode == MY_PTH_FDMODE_ERROR) + { + errno = EBADF; + return -1; + } + if (fdmode == MY_PTH_FDMODE_BLOCK) + { + fd_set fds; + + FD_ZERO (&fds); + FD_SET (fd, &fds); + while ( (ret = my_pth_select (fd+1, &fds, NULL, NULL, NULL)) < 0 + && errno == EINTR) + ; + if (ret < 0) + return -1; + } + + while ((ret = recvmsg (fd, msg, 0)) == -1 && errno == EINTR) + ; + return ret; +#endif +} diff --git a/assuan/assuan-listen.c b/assuan/assuan-listen.c index 04f138e..04db68c 100644 --- a/assuan/assuan-listen.c +++ b/assuan/assuan-listen.c @@ -15,7 +15,8 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include @@ -23,6 +24,7 @@ #include #include #include +#include #include "assuan-defs.h" @@ -30,7 +32,7 @@ assuan_error_t assuan_set_hello_line (assuan_context_t ctx, const char *line) { if (!ctx) - return ASSUAN_Invalid_Value; + return _assuan_error (ASSUAN_Invalid_Value); if (!line) { xfree (ctx->hello_line); @@ -40,7 +42,7 @@ assuan_set_hello_line (assuan_context_t ctx, const char *line) { char *buf = xtrymalloc (3+strlen(line)+1); if (!buf) - return ASSUAN_Out_Of_Core; + return _assuan_error (ASSUAN_Out_Of_Core); if (strchr (line, '\n')) strcpy (buf, line); else @@ -73,7 +75,7 @@ assuan_accept (assuan_context_t ctx) const char *p, *pend; if (!ctx) - return ASSUAN_Invalid_Value; + return _assuan_error (ASSUAN_Invalid_Value); if (ctx->pipe_mode > 1) return -1; /* second invocation for pipemode -> terminate */ @@ -134,7 +136,7 @@ assuan_error_t assuan_close_input_fd (assuan_context_t ctx) { if (!ctx || ctx->input_fd == -1) - return ASSUAN_Invalid_Value; + return _assuan_error (ASSUAN_Invalid_Value); _assuan_close (ctx->input_fd); ctx->input_fd = -1; return 0; @@ -146,7 +148,7 @@ assuan_error_t assuan_close_output_fd (assuan_context_t ctx) { if (!ctx || ctx->output_fd == -1) - return ASSUAN_Invalid_Value; + return _assuan_error (ASSUAN_Invalid_Value); _assuan_close (ctx->output_fd); ctx->output_fd = -1; diff --git a/assuan/assuan-logging.c b/assuan/assuan-logging.c index 7c65d57..cfc3d84 100644 --- a/assuan/assuan-logging.c +++ b/assuan/assuan-logging.c @@ -15,29 +15,37 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #ifdef HAVE_CONFIG_H #include #endif #include +#include #include #include #ifdef HAVE_W32_SYSTEM #include #endif /*HAVE_W32_SYSTEM*/ +#include +#include #include "assuan-defs.h" static char prefix_buffer[80]; static FILE *_assuan_log; +static int full_logging; void _assuan_set_default_log_stream (FILE *fp) { if (!_assuan_log) - _assuan_log = fp; + { + _assuan_log = fp; + full_logging = !!getenv ("ASSUAN_FULL_LOGGING"); + } } void @@ -46,6 +54,22 @@ assuan_set_assuan_log_stream (FILE *fp) _assuan_log = fp; } + +/* Set the per context log stream. Also enable the default log stream + if it has not been set. */ +void +assuan_set_log_stream (assuan_context_t ctx, FILE *fp) +{ + if (ctx) + { + if (ctx->log_fp) + fflush (ctx->log_fp); + ctx->log_fp = fp; + _assuan_set_default_log_stream (fp); + } +} + + FILE * assuan_get_assuan_log_stream (void) { @@ -80,18 +104,123 @@ _assuan_log_printf (const char *format, ...) va_list arg_ptr; FILE *fp; const char *prf; - + int save_errno = errno; + fp = assuan_get_assuan_log_stream (); prf = assuan_get_assuan_log_prefix (); if (*prf) - { - fputs (prf, fp); - fputs (": ", fp); - } + fprintf (fp, "%s[%u]: ", prf, (unsigned int)getpid ()); va_start (arg_ptr, format); vfprintf (fp, format, arg_ptr ); va_end (arg_ptr); + 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. */ +void +_assuan_log_print_buffer (FILE *fp, const void *buffer, size_t length) +{ + const unsigned char *s; + int n; + + for (n=length,s=buffer; n; n--, s++) + if ((!isascii (*s) || iscntrl (*s) || !isprint (*s)) && !(*s >= 0x80)) + break; + + s = buffer; + if (!n && *s != '[') + fwrite (buffer, length, 1, fp); + else + { +#ifdef HAVE_FLOCKFILE + flockfile (fp); +#endif + putc_unlocked ('[', fp); + if ( length > 16 && !full_logging) + { + for (n=0; n < 12; n++, s++) + fprintf (fp, " %02x", *s); + fprintf (fp, " ...(%d bytes skipped)", (int)length - 12); + } + else + { + for (n=0; n < length; n++, s++) + fprintf (fp, " %02x", *s); + } + putc_unlocked (' ', fp); + putc_unlocked (']', fp); +#ifdef HAVE_FUNLOCKFILE + funlockfile (fp); +#endif + } +} + +/* Log a user supplied string. Escapes non-printable before + printing. */ +void +_assuan_log_sanitized_string (const char *string) +{ + const unsigned char *s = (const unsigned char *) string; + FILE *fp = assuan_get_assuan_log_stream (); + + if (! *s) + return; + +#ifdef HAVE_FLOCKFILE + flockfile (fp); +#endif + + for (; *s; s++) + { + int c = 0; + + switch (*s) + { + case '\r': + c = 'r'; + break; + + case '\n': + c = 'n'; + break; + + case '\f': + c = 'f'; + break; + + case '\v': + c = 'v'; + break; + + case '\b': + c = 'b'; + break; + + default: + if ((isascii (*s) && isprint (*s)) || (*s >= 0x80)) + putc_unlocked (*s, fp); + else + { + putc_unlocked ('\\', fp); + fprintf (fp, "x%02x", *s); + } + } + + if (c) + { + putc_unlocked ('\\', fp); + putc_unlocked (c, fp); + } + } + +#ifdef HAVE_FUNLOCKFILE + funlockfile (fp); +#endif } diff --git a/assuan/assuan-pipe-connect.c b/assuan/assuan-pipe-connect.c index ecedb16..8ee9c74 100644 --- a/assuan/assuan-pipe-connect.c +++ b/assuan/assuan-pipe-connect.c @@ -1,5 +1,5 @@ /* assuan-pipe-connect.c - Establish a pipe connection (client) - * Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc. + * Copyright (C) 2001, 2002, 2003, 2005, 2006 Free Software Foundation, Inc. * * This file is part of Assuan. * @@ -15,7 +15,8 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #ifdef HAVE_CONFIG_H @@ -38,6 +39,19 @@ #include "assuan-defs.h" +/* Hacks for Slowaris. */ +#ifndef PF_LOCAL +# ifdef PF_UNIX +# define PF_LOCAL PF_UNIX +# else +# define PF_LOCAL AF_UNIX +# endif +#endif +#ifndef AF_LOCAL +# define AF_LOCAL AF_UNIX +#endif + + #ifdef _POSIX_OPEN_MAX #define MAX_OPEN_FDS _POSIX_OPEN_MAX #else @@ -111,6 +125,8 @@ do_finish (assuan_context_t ctx) if (ctx->inbound.fd != -1) { _assuan_close (ctx->inbound.fd); + if (ctx->inbound.fd == ctx->outbound.fd) + ctx->outbound.fd = -1; ctx->inbound.fd = -1; } if (ctx->outbound.fd != -1) @@ -123,7 +139,7 @@ do_finish (assuan_context_t ctx) #ifndef HAVE_W32_SYSTEM #ifndef _ASSUAN_USE_DOUBLE_FORK if (!ctx->flags.no_waitpid) - waitpid (ctx->pid, NULL, 0); + _assuan_waitpid (ctx->pid, NULL, 0); ctx->pid = -1; #endif #endif /*!HAVE_W32_SYSTEM*/ @@ -138,6 +154,402 @@ do_deinit (assuan_context_t ctx) } +/* Helper for pipe_connect. */ +static assuan_error_t +initial_handshake (assuan_context_t *ctx) +{ + int okay, off; + assuan_error_t err; + + err = _assuan_read_from_server (*ctx, &okay, &off); + if (err) + _assuan_log_printf ("can't connect server: %s\n", + assuan_strerror (err)); + else if (okay != 1) + { + _assuan_log_printf ("can't connect server: `%s'\n", + (*ctx)->inbound.line); + err = _assuan_error (ASSUAN_Connect_Failed); + } + + if (err) + { + assuan_disconnect (*ctx); + *ctx = NULL; + } + return err; +} + + +#ifndef HAVE_W32_SYSTEM +#define pipe_connect pipe_connect_unix +/* Unix version of the pipe connection code. We use an extra macro to + make ChangeLog entries easier. */ +static assuan_error_t +pipe_connect_unix (assuan_context_t *ctx, + const char *name, const char *const argv[], + int *fd_child_list, + void (*atfork) (void *opaque, int reserved), + void *atforkvalue) +{ + assuan_error_t err; + int rp[2]; + int wp[2]; + char mypidstr[50]; + + if (!ctx || !name || !argv || !argv[0]) + return _assuan_error (ASSUAN_Invalid_Value); + + fix_signals (); + + sprintf (mypidstr, "%lu", (unsigned long)getpid ()); + + if (pipe (rp) < 0) + return _assuan_error (ASSUAN_General_Error); + + if (pipe (wp) < 0) + { + close (rp[0]); + close (rp[1]); + return _assuan_error (ASSUAN_General_Error); + } + + err = _assuan_new_context (ctx); + if (err) + { + close (rp[0]); + close (rp[1]); + close (wp[0]); + close (wp[1]); + return err; + } + (*ctx)->pipe_mode = 1; + (*ctx)->inbound.fd = rp[0]; /* Our inbound is read end of read pipe. */ + (*ctx)->outbound.fd = wp[1]; /* Our outbound is write end of write pipe. */ + (*ctx)->deinit_handler = do_deinit; + (*ctx)->finish_handler = do_finish; + + /* FIXME: For GPGME we should better use _gpgme_io_spawn. The PID + stored here is actually soon useless. */ + (*ctx)->pid = fork (); + if ((*ctx)->pid < 0) + { + close (rp[0]); + close (rp[1]); + close (wp[0]); + close (wp[1]); + _assuan_release_context (*ctx); + return _assuan_error (ASSUAN_General_Error); + } + + if ((*ctx)->pid == 0) + { +#ifdef _ASSUAN_USE_DOUBLE_FORK + pid_t pid; + + if ((pid = fork ()) == 0) +#endif + { + int i, n; + char errbuf[512]; + int *fdp; + + if (atfork) + atfork (atforkvalue, 0); + + /* Dup handles to stdin/stdout. */ + if (rp[1] != STDOUT_FILENO) + { + if (dup2 (rp[1], STDOUT_FILENO) == -1) + { + _assuan_log_printf ("dup2 failed in child: %s\n", + strerror (errno)); + _exit (4); + } + } + if (wp[0] != STDIN_FILENO) + { + if (dup2 (wp[0], STDIN_FILENO) == -1) + { + _assuan_log_printf ("dup2 failed in child: %s\n", + strerror (errno)); + _exit (4); + } + } + + /* Dup stderr to /dev/null unless it is in the list of FDs to be + passed to the child. */ + fdp = fd_child_list; + if (fdp) + { + for (; *fdp != -1 && *fdp != STDERR_FILENO; fdp++) + ; + } + if (!fdp || *fdp == -1) + { + int fd = open ("/dev/null", O_WRONLY); + if (fd == -1) + { + _assuan_log_printf ("can't open `/dev/null': %s\n", + strerror (errno)); + _exit (4); + } + if (dup2 (fd, STDERR_FILENO) == -1) + { + _assuan_log_printf ("dup2(dev/null, 2) failed: %s\n", + strerror (errno)); + _exit (4); + } + } + + + /* Close all files which will not be duped and are not in the + fd_child_list. */ + n = sysconf (_SC_OPEN_MAX); + if (n < 0) + n = MAX_OPEN_FDS; + for (i=0; i < n; i++) + { + if ( i == STDIN_FILENO || i == STDOUT_FILENO + || i == STDERR_FILENO) + continue; + fdp = fd_child_list; + if (fdp) + { + while (*fdp != -1 && *fdp != i) + fdp++; + } + + if (!(fdp && *fdp != -1)) + close(i); + } + errno = 0; + + /* We store our parents pid in the environment so that the + execed assuan server is able to read the actual pid of the + client. The server can't use getppid because it might have + been double forked before the assuan server has been + initialized. */ + setenv ("_assuan_pipe_connect_pid", mypidstr, 1); + + /* Make sure that we never pass a connection fd variable + when using a simple pipe. */ + unsetenv ("_assuan_connection_fd"); + + execv (name, (char *const *) argv); + /* oops - use the pipe to tell the parent about it */ + snprintf (errbuf, sizeof(errbuf)-1, + "ERR %d can't exec `%s': %.50s\n", + _assuan_error (ASSUAN_Problem_Starting_Server), + name, strerror (errno)); + errbuf[sizeof(errbuf)-1] = 0; + writen (1, errbuf, strlen (errbuf)); + _exit (4); + } +#ifdef _ASSUAN_USE_DOUBLE_FORK + if (pid == -1) + _exit (1); + else + _exit (0); +#endif + } + +#ifdef _ASSUAN_USE_DOUBLE_FORK + _assuan_waitpid ((*ctx)->pid, NULL, 0); + (*ctx)->pid = -1; +#endif + + close (rp[1]); + close (wp[0]); + + return initial_handshake (ctx); +} +#endif /*!HAVE_W32_SYSTEM*/ + + +#ifndef HAVE_W32_SYSTEM +/* This function is similar to pipe_connect but uses a socketpair and + sets the I/O up to use sendmsg/recvmsg. */ +static assuan_error_t +socketpair_connect (assuan_context_t *ctx, + const char *name, const char *const argv[], + int *fd_child_list, + void (*atfork) (void *opaque, int reserved), + void *atforkvalue) +{ + assuan_error_t err; + int fds[2]; + char mypidstr[50]; + + if (!ctx + || (name && (!argv || !argv[0])) + || (!name && argv)) + return _assuan_error (ASSUAN_Invalid_Value); + + fix_signals (); + + sprintf (mypidstr, "%lu", (unsigned long)getpid ()); + + if ( socketpair (AF_LOCAL, SOCK_STREAM, 0, fds) ) + { + _assuan_log_printf ("socketpair failed: %s\n", strerror (errno)); + return _assuan_error (ASSUAN_General_Error); + } + + err = _assuan_new_context (ctx); + if (err) + { + close (fds[0]); + close (fds[1]); + return err; + } + (*ctx)->pipe_mode = 1; + (*ctx)->inbound.fd = fds[0]; + (*ctx)->outbound.fd = fds[0]; + _assuan_init_uds_io (*ctx); + (*ctx)->deinit_handler = _assuan_uds_deinit; + (*ctx)->finish_handler = do_finish; + + (*ctx)->pid = fork (); + if ((*ctx)->pid < 0) + { + close (fds[0]); + close (fds[1]); + _assuan_release_context (*ctx); + *ctx = NULL; + return _assuan_error (ASSUAN_General_Error); + } + + if ((*ctx)->pid == 0) + { +#ifdef _ASSUAN_USE_DOUBLE_FORK + pid_t pid; + + if ((pid = fork ()) == 0) +#endif + { + int fd, i, n; + char errbuf[512]; + int *fdp; + + if (atfork) + atfork (atforkvalue, 0); + + /* Connect stdin and stdout to /dev/null. */ + fd = open ("/dev/null", O_RDONLY); + if (fd == -1 || dup2 (fd, STDIN_FILENO) == -1) + { + _assuan_log_printf ("dup2(dev/null) failed: %s\n", + strerror (errno)); + _exit (4); + } + fd = open ("/dev/null", O_WRONLY); + if (fd == -1 || dup2 (fd, STDOUT_FILENO) == -1) + { + _assuan_log_printf ("dup2(dev/null) failed: %s\n", + strerror (errno)); + _exit (4); + } + + /* Dup stderr to /dev/null unless it is in the list of FDs to be + passed to the child. */ + fdp = fd_child_list; + if (fdp) + { + for (; *fdp != -1 && *fdp != STDERR_FILENO; fdp++) + ; + } + if (!fdp || *fdp == -1) + { + fd = open ("/dev/null", O_WRONLY); + if (fd == -1 || dup2 (fd, STDERR_FILENO) == -1) + { + _assuan_log_printf ("dup2(dev/null) failed: %s\n", + strerror (errno)); + _exit (4); + } + } + + + /* Close all files which will not be duped, are not in the + fd_child_list and are not the connection fd. */ + n = sysconf (_SC_OPEN_MAX); + if (n < 0) + n = MAX_OPEN_FDS; + for (i=0; i < n; i++) + { + if ( i == STDIN_FILENO || i == STDOUT_FILENO + || i == STDERR_FILENO || i == fds[1]) + continue; + fdp = fd_child_list; + if (fdp) + { + while (*fdp != -1 && *fdp != i) + fdp++; + } + + if (!(fdp && *fdp != -1)) + close(i); + } + errno = 0; + + /* We store our parents pid in the environment so that the + execed assuan server is able to read the actual pid of the + client. The server can't use getppid becuase it might have + been double forked before the assuan server has been + initialized. */ + setenv ("_assuan_pipe_connect_pid", mypidstr, 1); + + /* Now set the environment variable used to convey the + connection's file descriptor. */ + sprintf (mypidstr, "%d", fds[1]); + if (setenv ("_assuan_connection_fd", mypidstr, 1)) + { + _assuan_log_printf ("setenv failed: %s\n", strerror (errno)); + _exit (4); + } + + if (!name && !argv) + { + /* No name and no args given, thus we don't do an exec + but continue the forked process. */ + _assuan_release_context (*ctx); + *ctx = NULL; + return 0; + } + + execv (name, (char *const *) argv); + /* oops - use the pipe to tell the parent about it */ + snprintf (errbuf, sizeof(errbuf)-1, + "ERR %d can't exec `%s': %.50s\n", + _assuan_error (ASSUAN_Problem_Starting_Server), + name, strerror (errno)); + errbuf[sizeof(errbuf)-1] = 0; + writen (fds[1], errbuf, strlen (errbuf)); + _exit (4); + } +#ifdef _ASSUAN_USE_DOUBLE_FORK + if (pid == -1) + _exit (1); + else + _exit (0); +#endif + } + + +#ifdef _ASSUAN_USE_DOUBLE_FORK + _assuan_waitpid ((*ctx)->pid, NULL, 0); + (*ctx)->pid = -1; +#endif + + close (fds[1]); + + return initial_handshake (ctx); +} +#endif /*!HAVE_W32_SYSTEM*/ + + + #ifdef HAVE_W32_SYSTEM /* Build a command line for use with W32's CreateProcess. On success CMDLINE gets the address of a newly allocated string. */ @@ -236,21 +648,16 @@ create_inheritable_pipe (int filedes[2], int for_write) #endif /*HAVE_W32_SYSTEM*/ -/* Connect to a server over a pipe, creating the assuan context and - returning it in CTX. The server filename is NAME, the argument - vector in ARGV. FD_CHILD_LIST is a -1 terminated list of file - descriptors not to close in the child. ATFORK is called in the - child right after the fork; ATFORKVALUE is passed as the first - argument and 0 is passed as the second argument. The ATFORK - function should only act if the second value is 0. */ -assuan_error_t -assuan_pipe_connect2 (assuan_context_t *ctx, - const char *name, const char *const argv[], - int *fd_child_list, - void (*atfork) (void *opaque, int reserved), - void *atforkvalue) -{ #ifdef HAVE_W32_SYSTEM +#define pipe_connect pipe_connect_w32 +/* W32 version of the pipe connection code. */ +static assuan_error_t +pipe_connect_w32 (assuan_context_t *ctx, + const char *name, const char *const argv[], + int *fd_child_list, + void (*atfork) (void *opaque, int reserved), + void *atforkvalue) +{ assuan_error_t err; int rp[2]; int wp[2]; @@ -269,7 +676,7 @@ assuan_pipe_connect2 (assuan_context_t *ctx, HANDLE nullfd = INVALID_HANDLE_VALUE; if (!ctx || !name || !argv || !argv[0]) - return ASSUAN_Invalid_Value; + return _assuan_error (ASSUAN_Invalid_Value); fix_signals (); @@ -277,13 +684,13 @@ assuan_pipe_connect2 (assuan_context_t *ctx, /* Build the command line. */ if (build_w32_commandline (argv, &cmdline)) - return ASSUAN_Out_Of_Core; + return _assuan_error (ASSUAN_Out_Of_Core); /* Create thew two pipes. */ if (create_inheritable_pipe (rp, 0)) { xfree (cmdline); - return ASSUAN_General_Error; + return _assuan_error (ASSUAN_General_Error); } if (create_inheritable_pipe (wp, 1)) @@ -291,7 +698,7 @@ assuan_pipe_connect2 (assuan_context_t *ctx, CloseHandle (fd_to_handle (rp[0])); CloseHandle (fd_to_handle (rp[1])); xfree (cmdline); - return ASSUAN_General_Error; + return _assuan_error (ASSUAN_General_Error); } @@ -303,7 +710,7 @@ assuan_pipe_connect2 (assuan_context_t *ctx, CloseHandle (fd_to_handle (wp[0])); CloseHandle (fd_to_handle (wp[1])); xfree (cmdline); - return ASSUAN_General_Error; + return _assuan_error (ASSUAN_General_Error); } (*ctx)->pipe_mode = 1; @@ -390,7 +797,7 @@ assuan_pipe_connect2 (assuan_context_t *ctx, CloseHandle (nullfd); xfree (cmdline); _assuan_release_context (*ctx); - return ASSUAN_General_Error; + return _assuan_error (ASSUAN_General_Error); } xfree (cmdline); cmdline = NULL; @@ -413,200 +820,11 @@ assuan_pipe_connect2 (assuan_context_t *ctx, (*ctx)->pid = 0; /* We don't use the PID. */ CloseHandle (pi.hProcess); /* We don't need to wait for the process. */ -#else /*!HAVE_W32_SYSTEM*/ - assuan_error_t err; - int rp[2]; - int wp[2]; - char mypidstr[50]; - - if (!ctx || !name || !argv || !argv[0]) - return ASSUAN_Invalid_Value; - - fix_signals (); - - sprintf (mypidstr, "%lu", (unsigned long)getpid ()); - - if (pipe (rp) < 0) - return ASSUAN_General_Error; - - if (pipe (wp) < 0) - { - close (rp[0]); - close (rp[1]); - return ASSUAN_General_Error; - } - - err = _assuan_new_context (ctx); - if (err) - { - close (rp[0]); - close (rp[1]); - close (wp[0]); - close (wp[1]); - return err; - } - (*ctx)->pipe_mode = 1; - (*ctx)->inbound.fd = rp[0]; /* Our inbound is read end of read pipe. */ - (*ctx)->outbound.fd = wp[1]; /* Our outbound is write end of write pipe. */ - (*ctx)->deinit_handler = do_deinit; - (*ctx)->finish_handler = do_finish; - - /* FIXME: For GPGME we should better use _gpgme_io_spawn. The PID - stored here is actually soon useless. */ - (*ctx)->pid = fork (); - if ((*ctx)->pid < 0) - { - close (rp[0]); - close (rp[1]); - close (wp[0]); - close (wp[1]); - _assuan_release_context (*ctx); - return ASSUAN_General_Error; - } - - if ((*ctx)->pid == 0) - { -#ifdef _ASSUAN_USE_DOUBLE_FORK - pid_t pid; - - if ((pid = fork ()) == 0) -#endif - { - int i, n; - char errbuf[512]; - int *fdp; - - if (atfork) - atfork (atforkvalue, 0); - - /* Dup handles to stdin/stdout. */ - if (rp[1] != STDOUT_FILENO) - { - if (dup2 (rp[1], STDOUT_FILENO) == -1) - { - _assuan_log_printf ("dup2 failed in child: %s\n", - strerror (errno)); - _exit (4); - } - } - if (wp[0] != STDIN_FILENO) - { - if (dup2 (wp[0], STDIN_FILENO) == -1) - { - _assuan_log_printf ("dup2 failed in child: %s\n", - strerror (errno)); - _exit (4); - } - } - - /* Dup stderr to /dev/null unless it is in the list of FDs to be - passed to the child. */ - fdp = fd_child_list; - if (fdp) - { - for (; *fdp != -1 && *fdp != STDERR_FILENO; fdp++) - ; - } - if (!fdp || *fdp == -1) - { - int fd = open ("/dev/null", O_WRONLY); - if (fd == -1) - { - _assuan_log_printf ("can't open `/dev/null': %s\n", - strerror (errno)); - _exit (4); - } - if (dup2 (fd, STDERR_FILENO) == -1) - { - _assuan_log_printf ("dup2(dev/null, 2) failed: %s\n", - strerror (errno)); - _exit (4); - } - } - - - /* Close all files which will not be duped and are not in the - fd_child_list. */ - n = sysconf (_SC_OPEN_MAX); - if (n < 0) - n = MAX_OPEN_FDS; - for (i=0; i < n; i++) - { - if ( i == STDIN_FILENO || i == STDOUT_FILENO - || i == STDERR_FILENO) - continue; - fdp = fd_child_list; - if (fdp) - { - while (*fdp != -1 && *fdp != i) - fdp++; - } - - if (!(fdp && *fdp != -1)) - close(i); - } - errno = 0; - - /* We store our parents pid in the environment so that the - execed assuan server is able to read the actual pid of the - client. The server can't use getppid becuase it might have - been double forked before the assuan server has been - initialized. */ - setenv ("_assuan_pipe_connect_pid", mypidstr, 1); - - execv (name, (char *const *) argv); - /* oops - use the pipe to tell the parent about it */ - snprintf (errbuf, sizeof(errbuf)-1, - "ERR %d can't exec `%s': %.50s\n", - ASSUAN_Problem_Starting_Server, name, strerror (errno)); - errbuf[sizeof(errbuf)-1] = 0; - writen (1, errbuf, strlen (errbuf)); - _exit (4); - } -#ifdef _ASSUAN_USE_DOUBLE_FORK - if (pid == -1) - _exit (1); - else - _exit (0); -#endif - } - -#ifdef _ASSUAN_USE_DOUBLE_FORK - waitpid ((*ctx)->pid, NULL, 0); - (*ctx)->pid = -1; -#endif - - close (rp[1]); - close (wp[0]); - -#endif /*!HAVE_W32_SYSTEM*/ - - /* initial handshake */ - { - int okay, off; - - err = _assuan_read_from_server (*ctx, &okay, &off); - if (err) - _assuan_log_printf ("can't connect server: %s\n", - assuan_strerror (err)); - else if (okay != 1) - { - _assuan_log_printf ("can't connect server: `%s'\n", - (*ctx)->inbound.line); - err = ASSUAN_Connect_Failed; - } - } - - if (err) - { - assuan_disconnect (*ctx); - *ctx = NULL; - } - - return err; + return initial_handshake (ctx); } +#endif /*HAVE_W32_SYSTEM*/ - + /* Connect to a server over a pipe, creating the assuan context and returning it in CTX. The server filename is NAME, the argument vector in ARGV. FD_CHILD_LIST is a -1 terminated list of file @@ -615,5 +833,57 @@ assuan_error_t assuan_pipe_connect (assuan_context_t *ctx, const char *name, const char *const argv[], int *fd_child_list) { - return assuan_pipe_connect2 (ctx, name, argv, fd_child_list, NULL, NULL); + return pipe_connect (ctx, name, argv, fd_child_list, NULL, NULL); +} + + + +assuan_error_t +assuan_pipe_connect2 (assuan_context_t *ctx, + const char *name, const char *const argv[], + int *fd_child_list, + void (*atfork) (void *opaque, int reserved), + void *atforkvalue) +{ + return pipe_connect (ctx, name, argv, fd_child_list, atfork, atforkvalue); +} + + +/* Connect to a server over a full-duplex socket (i.e. created by + socketpair), creating the assuan context and returning it in CTX. + The server filename is NAME, the argument vector in ARGV. + FD_CHILD_LIST is a -1 terminated list of file descriptors not to + close in the child. ATFORK is called in the child right after the + fork; ATFORKVALUE is passed as the first argument and 0 is passed + 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. + + If NAME as well as ARGV are NULL, no exec is done but the same + process is continued. However all file descriptors are closed and + some special environment variables are set. To let the caller + detect whether the child or the parent continues, the child returns + a CTX of NULL. */ +assuan_error_t +assuan_pipe_connect_ext (assuan_context_t *ctx, + const char *name, const char *const argv[], + int *fd_child_list, + void (*atfork) (void *opaque, int reserved), + void *atforkvalue, unsigned int flags) +{ + if ((flags & 1)) + { +#ifdef HAVE_W32_SYSTEM + return _assuan_error (ASSUAN_Not_Implemented); +#else + return socketpair_connect (ctx, name, argv, fd_child_list, + atfork, atforkvalue); +#endif + } + else + return pipe_connect (ctx, name, argv, fd_child_list, atfork, atforkvalue); } + diff --git a/assuan/assuan-pipe-server.c b/assuan/assuan-pipe-server.c index beff9a3..a19c88e 100644 --- a/assuan/assuan-pipe-server.c +++ b/assuan/assuan-pipe-server.c @@ -15,12 +15,15 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include #include #include +#include +#include #include #ifdef HAVE_W32_SYSTEM #include @@ -31,20 +34,20 @@ static void -deinit_pipe_server (ASSUAN_CONTEXT ctx) +deinit_pipe_server (assuan_context_t ctx) { /* nothing to do for this simple server */ } static int -accept_connection (ASSUAN_CONTEXT ctx) +accept_connection (assuan_context_t ctx) { /* This is a NOP for a pipe server */ return 0; } static int -finish_connection (ASSUAN_CONTEXT ctx) +finish_connection (assuan_context_t ctx) { /* This is a NOP for a pipe server */ return 0; @@ -53,19 +56,19 @@ finish_connection (ASSUAN_CONTEXT ctx) /* Create a new context. Note that the handlers are set up for a pipe server/client - this way we don't need extra dummy functions */ int -_assuan_new_context (ASSUAN_CONTEXT *r_ctx) +_assuan_new_context (assuan_context_t *r_ctx) { static struct assuan_io io = { _assuan_simple_read, _assuan_simple_write, 0, 0 }; - ASSUAN_CONTEXT ctx; + assuan_context_t ctx; int rc; *r_ctx = NULL; ctx = xtrycalloc (1, sizeof *ctx); if (!ctx) - return ASSUAN_Out_Of_Core; + return _assuan_error (ASSUAN_Out_Of_Core); ctx->input_fd = -1; ctx->output_fd = -1; @@ -88,15 +91,27 @@ _assuan_new_context (ASSUAN_CONTEXT *r_ctx) } +/* Returns true if atoi(S) denotes a valid socket. */ +static int +is_valid_socket (const char *s) +{ + struct stat buf; + + if ( fstat (atoi (s), &buf ) ) + return 0; + return S_ISSOCK (buf.st_mode); +} + + int -assuan_init_pipe_server (ASSUAN_CONTEXT *r_ctx, int filedes[2]) +assuan_init_pipe_server (assuan_context_t *r_ctx, int filedes[2]) { int rc; rc = _assuan_new_context (r_ctx); if (!rc) { - ASSUAN_CONTEXT ctx = *r_ctx; + assuan_context_t ctx = *r_ctx; const char *s; unsigned long ul; @@ -110,8 +125,28 @@ assuan_init_pipe_server (ASSUAN_CONTEXT *r_ctx, int filedes[2]) ctx->inbound.fd = _get_osfhandle (filedes[0]); ctx->outbound.fd = _get_osfhandle (filedes[1]); #else - ctx->inbound.fd = filedes[0]; - ctx->outbound.fd = filedes[1]; + s = getenv ("_assuan_connection_fd"); + if (s && *s && is_valid_socket (s) ) + { + /* Well, we are called with an bi-directional file + descriptor. Prepare for using sendmsg/recvmsg. In this + case we ignore the passed file descriptors. */ + ctx->inbound.fd = ctx->outbound.fd = atoi (s); + _assuan_init_uds_io (ctx); + ctx->deinit_handler = _assuan_uds_deinit; + } + else if (filedes && filedes[0] != -1 && filedes[1] != -1 ) + { + /* Standard pipe server. */ + ctx->inbound.fd = filedes[0]; + ctx->outbound.fd = filedes[1]; + } + else + { + _assuan_release_context (*r_ctx); + *r_ctx = NULL; + return ASSUAN_Problem_Starting_Server; + } #endif ctx->pipe_mode = 1; @@ -127,7 +162,7 @@ assuan_init_pipe_server (ASSUAN_CONTEXT *r_ctx, int filedes[2]) void -_assuan_release_context (ASSUAN_CONTEXT ctx) +_assuan_release_context (assuan_context_t ctx) { if (ctx) { @@ -138,7 +173,7 @@ _assuan_release_context (ASSUAN_CONTEXT ctx) } void -assuan_deinit_server (ASSUAN_CONTEXT ctx) +assuan_deinit_server (assuan_context_t ctx) { if (ctx) { diff --git a/assuan/assuan-socket-connect.c b/assuan/assuan-socket-connect.c index 9937c7a..5953f1c 100644 --- a/assuan/assuan-socket-connect.c +++ b/assuan/assuan-socket-connect.c @@ -15,7 +15,8 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include @@ -54,7 +55,7 @@ static int -do_finish (ASSUAN_CONTEXT ctx) +do_finish (assuan_context_t ctx) { if (ctx->inbound.fd != -1) { @@ -66,56 +67,70 @@ do_finish (ASSUAN_CONTEXT ctx) } static void -do_deinit (ASSUAN_CONTEXT ctx) +do_deinit (assuan_context_t ctx) { do_finish (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. */ assuan_error_t -assuan_socket_connect (ASSUAN_CONTEXT *r_ctx, +assuan_socket_connect (assuan_context_t *r_ctx, const char *name, pid_t server_pid) +{ + return assuan_socket_connect_ext (r_ctx, name, server_pid, 0); +} + + +/* 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. */ +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 }; assuan_error_t err; - ASSUAN_CONTEXT ctx; + assuan_context_t ctx; int fd; struct sockaddr_un srvr_addr; size_t len; const char *s; if (!r_ctx || !name) - return ASSUAN_Invalid_Value; + return _assuan_error (ASSUAN_Invalid_Value); *r_ctx = NULL; - /* We require that the name starts with a slash, so that we can - alter reuse this function for other socket types. To make things - easier we allow an optional dirver prefix. */ + /* 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. */ s = name; if (*s && s[1] == ':') s += 2; if (*s != DIRSEP_C && *s != '/') - return ASSUAN_Invalid_Value; + return _assuan_error (ASSUAN_Invalid_Value); if (strlen (name)+1 >= sizeof srvr_addr.sun_path) - return ASSUAN_Invalid_Value; + return _assuan_error (ASSUAN_Invalid_Value); err = _assuan_new_context (&ctx); if (err) return err; - ctx->deinit_handler = do_deinit; + ctx->deinit_handler = ((flags&1))? _assuan_uds_deinit : do_deinit; ctx->finish_handler = do_finish; - fd = _assuan_sock_new (PF_LOCAL, SOCK_STREAM, 0); if (fd == -1) { _assuan_log_printf ("can't create socket: %s\n", strerror (errno)); _assuan_release_context (ctx); - return ASSUAN_General_Error; + return _assuan_error (ASSUAN_General_Error); } memset (&srvr_addr, 0, sizeof srvr_addr); @@ -131,13 +146,15 @@ assuan_socket_connect (ASSUAN_CONTEXT *r_ctx, name, strerror (errno)); _assuan_release_context (ctx); _assuan_close (fd); - return ASSUAN_Connect_Failed; + return _assuan_error (ASSUAN_Connect_Failed); } ctx->inbound.fd = fd; ctx->outbound.fd = fd; ctx->io = &io; - + if ((flags&1)) + _assuan_init_uds_io (ctx); + /* initial handshake */ { int okay, off; @@ -151,7 +168,7 @@ assuan_socket_connect (ASSUAN_CONTEXT *r_ctx, /*LOG ("can't connect to server: `");*/ _assuan_log_sanitized_string (ctx->inbound.line); fprintf (assuan_get_assuan_log_stream (), "'\n"); - err = ASSUAN_Connect_Failed; + err = _assuan_error (ASSUAN_Connect_Failed); } } @@ -163,3 +180,5 @@ assuan_socket_connect (ASSUAN_CONTEXT *r_ctx, *r_ctx = ctx; return 0; } + + diff --git a/assuan/assuan-socket-server.c b/assuan/assuan-socket-server.c index 275af42..45c227d 100644 --- a/assuan/assuan-socket-server.c +++ b/assuan/assuan-socket-server.c @@ -15,7 +15,8 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include @@ -33,21 +34,33 @@ #include "assuan-defs.h" +static struct assuan_io io = { _assuan_simple_read, + _assuan_simple_write }; + + static int accept_connection_bottom (assuan_context_t ctx) { int fd = ctx->connected_fd; + ctx->peercred.valid = 0; #ifdef HAVE_SO_PEERCRED { - /* This overrides any already set PID if the function returns a - valid one. */ struct ucred cr; - int cl = sizeof cr; - - if ( !getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &cr, &cl) - && cr.pid != (pid_t)-1 && cr.pid ) - ctx->pid = cr.pid; + socklen_t cl = sizeof cr; + + if ( !getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &cr, &cl)) + { + ctx->peercred.pid = cr.pid; + ctx->peercred.uid = cr.uid; + ctx->peercred.gid = cr.gid; + ctx->peercred.valid = 1; + + /* This overrides any already set PID if the function returns + a valid one. */ + if (cr.pid != (pid_t)-1 && cr.pid) + ctx->pid = cr.pid; + } } #endif @@ -72,13 +85,13 @@ accept_connection (assuan_context_t ctx) { int fd; struct sockaddr_un clnt_addr; - size_t len = sizeof clnt_addr; + socklen_t len = sizeof clnt_addr; fd = accept (ctx->listen_fd, (struct sockaddr*)&clnt_addr, &len ); if (fd == -1) { ctx->os_errno = errno; - return ASSUAN_Accept_Failed; + return _assuan_error (ASSUAN_Accept_Failed); } ctx->connected_fd = fd; @@ -104,47 +117,30 @@ deinit_socket_server (assuan_context_t ctx) finish_connection (ctx); } -static struct assuan_io io = { _assuan_simple_read, - _assuan_simple_write }; - /* 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_context_t ctx; - int rc; - - *r_ctx = NULL; - ctx = xtrycalloc (1, sizeof *ctx); - if (!ctx) - return ASSUAN_Out_Of_Core; - ctx->is_server = 1; - ctx->input_fd = -1; - ctx->output_fd = -1; - - ctx->inbound.fd = -1; - ctx->outbound.fd = -1; - - ctx->listen_fd = listen_fd; - ctx->connected_fd = -1; - ctx->deinit_handler = deinit_socket_server; - ctx->accept_handler = accept_connection; - ctx->finish_handler = finish_connection; - - ctx->io = &io; - - rc = _assuan_register_std_commands (ctx); - if (rc) - xfree (ctx); - else - *r_ctx = ctx; - return rc; + return assuan_init_socket_server_ext (r_ctx, listen_fd, 0); } -/* Initialize a server using the already accepted socket FD. */ +/* Initialize a server using the already accepted socket FD. This + fucntion is deprecated. */ int assuan_init_connected_socket_server (assuan_context_t *r_ctx, int fd) +{ + return assuan_init_socket_server_ext (r_ctx, fd, 2); +} + + +/* + Flag bits: 0 - use sendmsg/recvmsg to allow descriptor passing + 1 - FD has already been accepted. +*/ +int +assuan_init_socket_server_ext (assuan_context_t *r_ctx, int fd, + unsigned int flags) { assuan_context_t ctx; int rc; @@ -152,23 +148,36 @@ assuan_init_connected_socket_server (assuan_context_t *r_ctx, int fd) *r_ctx = NULL; ctx = xtrycalloc (1, sizeof *ctx); if (!ctx) - return ASSUAN_Out_Of_Core; + return _assuan_error (ASSUAN_Out_Of_Core); ctx->is_server = 1; - ctx->pipe_mode = 1; /* we want a second accept to indicate EOF */ + if ((flags & 2)) + ctx->pipe_mode = 1; /* We want a second accept to indicate EOF. */ ctx->input_fd = -1; ctx->output_fd = -1; ctx->inbound.fd = -1; ctx->outbound.fd = -1; - ctx->io = &io; - - ctx->listen_fd = -1; - ctx->connected_fd = fd; - ctx->deinit_handler = deinit_socket_server; - ctx->accept_handler = accept_connection_bottom; + if ((flags & 2)) + { + ctx->listen_fd = -1; + ctx->connected_fd = fd; + } + else + { + ctx->listen_fd = fd; + ctx->connected_fd = -1; + } + ctx->deinit_handler = (flags & 1)? _assuan_uds_deinit:deinit_socket_server; + ctx->accept_handler = ((flags & 2) + ? accept_connection_bottom + : accept_connection); ctx->finish_handler = finish_connection; + ctx->io = &io; + if ((flags & 1)) + _assuan_init_uds_io (ctx); + rc = _assuan_register_std_commands (ctx); if (rc) xfree (ctx); @@ -176,5 +185,3 @@ assuan_init_connected_socket_server (assuan_context_t *r_ctx, int fd) *r_ctx = ctx; return rc; } - - diff --git a/assuan/assuan-socket.c b/assuan/assuan-socket.c index 005f730..6aa5708 100644 --- a/assuan/assuan-socket.c +++ b/assuan/assuan-socket.c @@ -1,22 +1,24 @@ /* assuan-socket.c - * Copyright (C) 2004 Free Software Foundation, Inc. + * Copyright (C) 2004, 2005 Free Software Foundation, Inc. * - * This file is part of GnuPG. + * This file is part of Assuan. * - * GnuPG is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * Assuan is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. * - * GnuPG is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Assuan is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * 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. */ + #include #include #ifdef HAVE_W32_SYSTEM @@ -28,6 +30,18 @@ #endif #include "assuan-defs.h" +/* Hacks for Slowaris. */ +#ifndef PF_LOCAL +# ifdef PF_UNIX +# define PF_LOCAL PF_UNIX +# else +# define PF_LOCAL AF_UNIX +# endif +#endif +#ifndef AF_LOCAL +# define AF_LOCAL AF_UNIX +#endif + int _assuan_close (int fd) { diff --git a/assuan/assuan-uds.c b/assuan/assuan-uds.c new file mode 100644 index 0000000..c725392 --- /dev/null +++ b/assuan/assuan-uds.c @@ -0,0 +1,285 @@ +/* assuan-uds.c - Assuan unix domain socket utilities + * Copyright (C) 2006 Free Software Foundation, Inc. + * + * This file is part of Assuan. + * + * Assuan is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Assuan is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#ifndef HAVE_W32_SYSTEM +#include +#include +#else +#include +#endif +#if HAVE_SYS_UIO_H +#include +#endif +#include +#include +#include +#include + +#include "assuan-defs.h" + + +/* Read from a unix domain socket using sendmsg. + + FIXME: We don't need the buffering. It is a leftover from the time + when we used datagrams. */ +static ssize_t +uds_reader (assuan_context_t ctx, void *buf, size_t buflen) +{ + int len = ctx->uds.buffersize; + +#ifndef HAVE_W32_SYSTEM + + if (!ctx->uds.bufferallocated) + { + ctx->uds.buffer = xtrymalloc (2048); + if (!ctx->uds.buffer) + return _assuan_error (ASSUAN_Out_Of_Core); + ctx->uds.bufferallocated = 2048; + } + + while (!len) /* No data is buffered. */ + { + struct msghdr msg; + struct iovec iovec; + union { + struct cmsghdr cm; + char control[CMSG_SPACE(sizeof (int))]; + } control_u; + struct cmsghdr *cmptr; + + memset (&msg, 0, sizeof (msg)); + + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &iovec; + msg.msg_iovlen = 1; + iovec.iov_base = ctx->uds.buffer; + iovec.iov_len = ctx->uds.bufferallocated; + msg.msg_control = control_u.control; + msg.msg_controllen = sizeof (control_u.control); + + len = _assuan_simple_recvmsg (ctx, &msg); + if (len < 0) + return -1; + + ctx->uds.buffersize = len; + ctx->uds.bufferoffset = 0; + + cmptr = CMSG_FIRSTHDR (&msg); + if (cmptr && cmptr->cmsg_len == CMSG_LEN (sizeof(int))) + { + if (cmptr->cmsg_level != SOL_SOCKET + || cmptr->cmsg_type != SCM_RIGHTS) + _assuan_log_printf ("unexpected ancillary data received\n"); + else + { + int fd = *((int*)CMSG_DATA (cmptr)); + + if (ctx->uds.pendingfdscount >= DIM (ctx->uds.pendingfds)) + { + _assuan_log_printf ("too many descriptors pending - " + "closing received descriptor %d\n", fd); + _assuan_close (fd); + } + else + ctx->uds.pendingfds[ctx->uds.pendingfdscount++] = fd; + } + } + } +#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. */ + len = buflen; + + memcpy (buf, ctx->uds.buffer + ctx->uds.bufferoffset, len); + ctx->uds.buffersize -= len; + assert (ctx->uds.buffersize >= 0); + ctx->uds.bufferoffset += len; + assert (ctx->uds.bufferoffset <= ctx->uds.bufferallocated); + + return len; +} + + +/* Write to the domain server. */ +static ssize_t +uds_writer (assuan_context_t ctx, const void *buf, size_t buflen) +{ +#ifndef HAVE_W32_SYSTEM + struct msghdr msg; + struct iovec iovec; + ssize_t len; + + memset (&msg, 0, sizeof (msg)); + + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iovlen = 1; + msg.msg_iov = &iovec; + iovec.iov_base = (void*)buf; + iovec.iov_len = buflen; + msg.msg_control = 0; + msg.msg_controllen = 0; + + 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; +} + + +static assuan_error_t +uds_sendfd (assuan_context_t ctx, int fd) +{ +#ifndef HAVE_W32_SYSTEM + struct msghdr msg; + struct iovec iovec; + union { + struct cmsghdr cm; + char control[CMSG_SPACE(sizeof (int))]; + } control_u; + struct cmsghdr *cmptr; + int len; + char buffer[80]; + + /* We need to send some real data so that a read won't return 0 + which will be taken as an EOF. It also helps with debugging. */ + snprintf (buffer, sizeof(buffer)-1, "# descriptor %d is in flight\n", fd); + buffer[sizeof(buffer)-1] = 0; + + memset (&msg, 0, sizeof (msg)); + + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iovlen = 1; + msg.msg_iov = &iovec; + iovec.iov_base = buffer; + iovec.iov_len = strlen (buffer); + + msg.msg_control = control_u.control; + msg.msg_controllen = sizeof (control_u.control); + cmptr = CMSG_FIRSTHDR (&msg); + cmptr->cmsg_len = CMSG_LEN(sizeof(int)); + cmptr->cmsg_level = SOL_SOCKET; + cmptr->cmsg_type = SCM_RIGHTS; + *((int*)CMSG_DATA (cmptr)) = fd; + + len = _assuan_simple_sendmsg (ctx, &msg); + if (len < 0) + { + _assuan_log_printf ("uds_sendfd: %s\n", strerror (errno)); + return _assuan_error (ASSUAN_Write_Error); + } + else + return 0; +#else + return _assuan_error (ASSUAN_Not_Implemented); +#endif +} + + +static assuan_error_t +uds_receivefd (assuan_context_t ctx, int *fd) +{ +#ifndef HAVE_W32_SYSTEM + int i; + + if (!ctx->uds.pendingfdscount) + { + _assuan_log_printf ("no pending file descriptors!\n"); + return _assuan_error (ASSUAN_General_Error); + } + assert (ctx->uds.pendingfdscount <= DIM(ctx->uds.pendingfds)); + + *fd = ctx->uds.pendingfds[0]; + for (i=1; i < ctx->uds.pendingfdscount; i++) + ctx->uds.pendingfds[i-1] = ctx->uds.pendingfds[i]; + ctx->uds.pendingfdscount--; + + return 0; +#else + return _assuan_error (ASSUAN_Not_Implemented); +#endif +} + + +/* Close all pending fds. */ +void +_assuan_uds_close_fds (assuan_context_t ctx) +{ + int i; + + for (i = 0; i < ctx->uds.pendingfdscount; i++) + _assuan_close (ctx->uds.pendingfds[i]); + ctx->uds.pendingfdscount = 0; +} + +/* Deinitialize the unix domain socket I/O functions. */ +void +_assuan_uds_deinit (assuan_context_t ctx) +{ + /* First call the finish_handler which should close descriptors etc. */ + ctx->finish_handler (ctx); + + if (ctx->uds.buffer) + { + assert (ctx->uds.bufferallocated); + ctx->uds.bufferallocated = 0; + xfree (ctx->uds.buffer); + } + + _assuan_uds_close_fds (ctx); +} + + +/* Helper function to initialize a context for domain I/O. */ +void +_assuan_init_uds_io (assuan_context_t ctx) +{ + static struct assuan_io io = { uds_reader, uds_writer, + uds_sendfd, uds_receivefd }; + + ctx->io = &io; + ctx->uds.buffer = 0; + ctx->uds.bufferoffset = 0; + ctx->uds.buffersize = 0; + ctx->uds.bufferallocated = 0; + ctx->uds.pendingfdscount = 0; +} + diff --git a/assuan/assuan-util.c b/assuan/assuan-util.c index 2c2f744..3e627fc 100644 --- a/assuan/assuan-util.c +++ b/assuan/assuan-util.c @@ -15,7 +15,8 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include @@ -105,19 +106,6 @@ assuan_get_pointer (assuan_context_t ctx) } -void -assuan_set_log_stream (assuan_context_t ctx, FILE *fp) -{ - if (ctx) - { - if (ctx->log_fp) - fflush (ctx->log_fp); - ctx->log_fp = fp; - _assuan_set_default_log_stream (fp); - } -} - - void assuan_begin_confidential (assuan_context_t ctx) { @@ -166,97 +154,3 @@ assuan_get_flag (assuan_context_t ctx, assuan_flag_t flag) } -/* Dump a possibly binary string (used for debugging). Distinguish - ascii text from binary and print it accordingly. */ -void -_assuan_log_print_buffer (FILE *fp, const void *buffer, size_t length) -{ - const unsigned char *s; - int n; - - for (n=length,s=buffer; n; n--, s++) - if ((!isascii (*s) || iscntrl (*s) || !isprint (*s)) && !(*s >= 0x80)) - break; - - s = buffer; - if (!n && *s != '[') - fwrite (buffer, length, 1, fp); - else - { -#ifdef HAVE_FLOCKFILE - flockfile (fp); -#endif - putc_unlocked ('[', fp); - for (n=0; n < length; n++, s++) - fprintf (fp, " %02x", *s); - putc_unlocked (' ', fp); - putc_unlocked (']', fp); -#ifdef HAVE_FUNLOCKFILE - funlockfile (fp); -#endif - } -} - -/* Log a user supplied string. Escapes non-printable before - printing. */ -void -_assuan_log_sanitized_string (const char *string) -{ - const unsigned char *s = (const unsigned char *) string; - FILE *fp = assuan_get_assuan_log_stream (); - - if (! *s) - return; - -#ifdef HAVE_FLOCKFILE - flockfile (fp); -#endif - - for (; *s; s++) - { - int c = 0; - - switch (*s) - { - case '\r': - c = 'r'; - break; - - case '\n': - c = 'n'; - break; - - case '\f': - c = 'f'; - break; - - case '\v': - c = 'v'; - break; - - case '\b': - c = 'b'; - break; - - default: - if ((isascii (*s) && isprint (*s)) || (*s >= 0x80)) - putc_unlocked (*s, fp); - else - { - putc_unlocked ('\\', fp); - fprintf (fp, "x%02x", *s); - } - } - - if (c) - { - putc_unlocked ('\\', fp); - putc_unlocked (c, fp); - } - } - -#ifdef HAVE_FUNLOCKFILE - funlockfile (fp); -#endif -} - diff --git a/assuan/assuan.h b/assuan/assuan.h index b2641b2..0f36cdd 100644 --- a/assuan/assuan.h +++ b/assuan/assuan.h @@ -15,7 +15,8 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #ifndef ASSUAN_H @@ -26,24 +27,32 @@ #include -/* To use this file with libraries the following macros are often - useful: +/* To use this file with libraries the following macros are useful: - #define _ASSUAN_EXT_SYM_PREFIX _foo_ + #define _ASSUAN_EXT_SYM_PREFIX _foo_ This prefixes all external symbols with "_foo_". - #define _ASSUAN_NO_PTH + #define _ASSUAN_ONLY_GPG_ERRORS - This avoids inclusion of special GNU Pth hacks. + If this is defined all old-style Assuan error codes are made + inactive as well as other dereacted stuff. - #define _ASSUAN_NO_FIXED_SIGNALS + The follwing macros are used internally in the implementation of + libassuan: - This disables changing of certain signal handler; i.e. SIGPIPE. + #define _ASSUAN_NO_PTH - #define _ASSUAN_USE_DOUBLE_FORK + This avoids inclusion of special GNU Pth hacks. - Use a double fork approach when connecting to a server through a pipe. + #define _ASSUAN_NO_FIXED_SIGNALS + + This disables changing of certain signal handler; i.e. SIGPIPE. + + #define _ASSUAN_USE_DOUBLE_FORK + + Use a double fork approach when connecting to a server through + a pipe. */ /**** Begin GPGME specific modifications. ******/ #define _ASSUAN_EXT_SYM_PREFIX _gpgme_ @@ -115,12 +124,15 @@ int _gpgme_ath_recvmsg (int s, struct msghdr *msg, int flags); #define assuan_init_socket_server _ASSUAN_PREFIX(assuan_init_socket_server) #define assuan_init_connected_socket_server \ _ASSUAN_PREFIX(assuan_init_connected_socket_server) +#define assuan_init_socket_server_ext \ + _ASSUAN_PREFIX(assuan_init_socket_server_ext) #define assuan_pipe_connect _ASSUAN_PREFIX(assuan_pipe_connect) +#define assuan_pipe_connect_ext _ASSUAN_PREFIX(assuan_pipe_connect_ext) #define assuan_socket_connect _ASSUAN_PREFIX(assuan_socket_connect) -#define assuan_domain_connect _ASSUAN_PREFIX(assuan_domain_connect) -#define assuan_init_domain_server _ASSUAN_PREFIX(assuan_init_domain_server) +#define assuan_socket_connect_ext _ASSUAN_PREFIX(assuan_socket_connect_ext) #define assuan_disconnect _ASSUAN_PREFIX(assuan_disconnect) #define assuan_get_pid _ASSUAN_PREFIX(assuan_get_pid) +#define assuan_get_peercred _ASSUAN_PREFIX(assuan_get_peercred) #define assuan_transact _ASSUAN_PREFIX(assuan_transact) #define assuan_inquire _ASSUAN_PREFIX(assuan_inquire) #define assuan_read_line _ASSUAN_PREFIX(assuan_read_line) @@ -137,6 +149,8 @@ int _gpgme_ath_recvmsg (int s, struct msghdr *msg, int flags); #define assuan_begin_confidential _ASSUAN_PREFIX(assuan_begin_confidential) #define assuan_end_confidential _ASSUAN_PREFIX(assuan_end_confidential) #define assuan_strerror _ASSUAN_PREFIX(assuan_strerror) +#define assuan_set_assuan_err_source \ + _ASSUAN_PREFIX(assuan_set_assuan_err_source) #define assuan_set_assuan_log_stream \ _ASSUAN_PREFIX(assuan_set_assuan_log_stream) #define assuan_get_assuan_log_stream \ @@ -189,89 +203,121 @@ extern "C" #endif -typedef enum -{ - ASSUAN_No_Error = 0, - ASSUAN_General_Error = 1, - ASSUAN_Out_Of_Core = 2, - ASSUAN_Invalid_Value = 3, - ASSUAN_Timeout = 4, - ASSUAN_Read_Error = 5, - ASSUAN_Write_Error = 6, - ASSUAN_Problem_Starting_Server = 7, - ASSUAN_Not_A_Server = 8, - ASSUAN_Not_A_Client = 9, - ASSUAN_Nested_Commands = 10, - ASSUAN_Invalid_Response = 11, - ASSUAN_No_Data_Callback = 12, - ASSUAN_No_Inquire_Callback = 13, - ASSUAN_Connect_Failed = 14, - ASSUAN_Accept_Failed = 15, +/* Check for compiler features. */ +#if __GNUC__ +#define _ASSUAN_GCC_VERSION (__GNUC__ * 10000 \ + + __GNUC_MINOR__ * 100 \ + + __GNUC_PATCHLEVEL__) + +#if _ASSUAN_GCC_VERSION > 30100 +#define _ASSUAN_DEPRECATED __attribute__ ((__deprecated__)) +#endif +#endif +#ifndef _ASSUAN_DEPRECATED +#define _ASSUAN_DEPRECATED +#endif + + +/* Assuan error codes. These are only used by old applications or + those applications which won't make use of libgpg-error. */ +#ifndef _ASSUAN_ONLY_GPG_ERRORS +#ifndef _ASSUAN_IN_LIBASSUAN +#define ASSUAN_No_Error 0 +#endif +#define ASSUAN_General_Error 1 +#define ASSUAN_Out_Of_Core 2 +#define ASSUAN_Invalid_Value 3 +#ifndef _ASSUAN_IN_LIBASSUAN +#define ASSUAN_Timeout 4 +#endif +#define ASSUAN_Read_Error 5 +#define ASSUAN_Write_Error 6 +#define ASSUAN_Problem_Starting_Server 7 +#define ASSUAN_Not_A_Server 8 +#ifndef _ASSUAN_IN_LIBASSUAN +#define ASSUAN_Not_A_Client 9 +#endif +#define ASSUAN_Nested_Commands 10 +#define ASSUAN_Invalid_Response 11 +#define ASSUAN_No_Data_Callback 12 +#define ASSUAN_No_Inquire_Callback 13 +#define ASSUAN_Connect_Failed 14 +#define ASSUAN_Accept_Failed 15 /* Error codes above 99 are meant as status codes */ - ASSUAN_Not_Implemented = 100, - ASSUAN_Server_Fault = 101, - ASSUAN_Invalid_Command = 102, - ASSUAN_Unknown_Command = 103, - ASSUAN_Syntax_Error = 104, - ASSUAN_Parameter_Error = 105, - ASSUAN_Parameter_Conflict = 106, - ASSUAN_Line_Too_Long = 107, - ASSUAN_Line_Not_Terminated = 108, - ASSUAN_No_Input = 109, - ASSUAN_No_Output = 110, - ASSUAN_Canceled = 111, - ASSUAN_Unsupported_Algorithm = 112, - ASSUAN_Server_Resource_Problem = 113, - ASSUAN_Server_IO_Error = 114, - ASSUAN_Server_Bug = 115, - ASSUAN_No_Data_Available = 116, - ASSUAN_Invalid_Data = 117, - ASSUAN_Unexpected_Command = 118, - ASSUAN_Too_Much_Data = 119, - ASSUAN_Inquire_Unknown = 120, - ASSUAN_Inquire_Error = 121, - ASSUAN_Invalid_Option = 122, - ASSUAN_Invalid_Index = 123, - ASSUAN_Unexpected_Status = 124, - ASSUAN_Unexpected_Data = 125, - ASSUAN_Invalid_Status = 126, - ASSUAN_Locale_Problem = 127, - ASSUAN_Not_Confirmed = 128, - - /* Warning: Don't use the rror codes, below they are deprecated. */ - ASSUAN_Bad_Certificate = 201, - ASSUAN_Bad_Certificate_Chain = 202, - ASSUAN_Missing_Certificate = 203, - ASSUAN_Bad_Signature = 204, - ASSUAN_No_Agent = 205, - ASSUAN_Agent_Error = 206, - ASSUAN_No_Public_Key = 207, - ASSUAN_No_Secret_Key = 208, - ASSUAN_Invalid_Name = 209, - - ASSUAN_Cert_Revoked = 301, - ASSUAN_No_CRL_For_Cert = 302, - ASSUAN_CRL_Too_Old = 303, - ASSUAN_Not_Trusted = 304, - - ASSUAN_Card_Error = 401, - ASSUAN_Invalid_Card = 402, - ASSUAN_No_PKCS15_App = 403, - ASSUAN_Card_Not_Present = 404, - ASSUAN_Invalid_Id = 405, +#define ASSUAN_Not_Implemented 100 +#define ASSUAN_Server_Fault 101 +#ifndef _ASSUAN_IN_LIBASSUAN +#define ASSUAN_Invalid_Command 102 +#endif +#define ASSUAN_Unknown_Command 103 +#define ASSUAN_Syntax_Error 104 +#ifndef _ASSUAN_IN_LIBASSUAN +#define ASSUAN_Parameter_Error 105 +#endif +#define ASSUAN_Parameter_Conflict 106 +#define ASSUAN_Line_Too_Long 107 +#define ASSUAN_Line_Not_Terminated 108 +#ifndef _ASSUAN_IN_LIBASSUAN +#define ASSUAN_No_Input 109 +#define ASSUAN_No_Output 110 +#endif +#define ASSUAN_Canceled 111 +#ifndef _ASSUAN_IN_LIBASSUAN +#define ASSUAN_Unsupported_Algorithm 112 +#define ASSUAN_Server_Resource_Problem 113 +#define ASSUAN_Server_IO_Error 114 +#define ASSUAN_Server_Bug 115 +#define ASSUAN_No_Data_Available 116 +#define ASSUAN_Invalid_Data 117 +#endif +#define ASSUAN_Unexpected_Command 118 +#define ASSUAN_Too_Much_Data 119 +#ifndef _ASSUAN_IN_LIBASSUAN +#define ASSUAN_Inquire_Unknown 120 +#define ASSUAN_Inquire_Error 121 +#define ASSUAN_Invalid_Option 122 +#define ASSUAN_Invalid_Index 123 +#define ASSUAN_Unexpected_Status 124 +#define ASSUAN_Unexpected_Data 125 +#define ASSUAN_Invalid_Status 126 +#define ASSUAN_Locale_Problem 127 +#define ASSUAN_Not_Confirmed 128 + + /* Warning: Don't use the Error codes, below they are deprecated. */ +#define ASSUAN_Bad_Certificate 201 +#define ASSUAN_Bad_Certificate_Chain 202 +#define ASSUAN_Missing_Certificate 203 +#define ASSUAN_Bad_Signature 204 +#define ASSUAN_No_Agent 205 +#define ASSUAN_Agent_Error 206 +#define ASSUAN_No_Public_Key 207 +#define ASSUAN_No_Secret_Key 208 +#define ASSUAN_Invalid_Name 209 + +#define ASSUAN_Cert_Revoked 301 +#define ASSUAN_No_CRL_For_Cert 302 +#define ASSUAN_CRL_Too_Old 303 +#define ASSUAN_Not_Trusted 304 + +#define ASSUAN_Card_Error 401 +#define ASSUAN_Invalid_Card 402 +#define ASSUAN_No_PKCS15_App 403 +#define ASSUAN_Card_Not_Present 404 +#define ASSUAN_Invalid_Id 405 /* Error codes in the range 1000 to 9999 may be used by applications at their own discretion. */ - ASSUAN_USER_ERROR_FIRST = 1000, - ASSUAN_USER_ERROR_LAST = 9999 +#define ASSUAN_USER_ERROR_FIRST 1000 +#define ASSUAN_USER_ERROR_LAST 9999 +#endif -} assuan_error_t; +typedef int assuan_error_t; -typedef assuan_error_t AssuanError; /* Deprecated. */ +typedef assuan_error_t AssuanError _ASSUAN_DEPRECATED; /* This is a list of pre-registered ASSUAN commands */ -/* NOTE, these command IDs are now deprectated and solely exists for +/* Note, these command IDs are now deprectated and solely exists for compatibility reasons. */ typedef enum { @@ -290,6 +336,13 @@ typedef enum } AssuanCommand; +#else /*!_ASSUAN_ONLY_GPG_ERRORS*/ + +typedef int assuan_error_t; + +#endif /*!_ASSUAN_ONLY_GPG_ERRORS*/ + + /* Definitions of flags for assuan_set_flag(). */ typedef enum { @@ -306,7 +359,9 @@ assuan_flag_t; struct assuan_context_s; typedef struct assuan_context_s *assuan_context_t; -typedef struct assuan_context_s *ASSUAN_CONTEXT; +#ifndef _ASSUAN_ONLY_GPG_ERRORS +typedef struct assuan_context_s *ASSUAN_CONTEXT _ASSUAN_DEPRECATED; +#endif /*_ASSUAN_ONLY_GPG_ERRORS*/ /*-- assuan-handler.c --*/ int assuan_register_command (assuan_context_t ctx, @@ -343,7 +398,7 @@ assuan_error_t assuan_write_status (assuan_context_t ctx, file descriptor via CTX and stores it in *RDF (the CTX must be capable of passing file descriptors). */ assuan_error_t assuan_command_parse_fd (assuan_context_t ctx, char *line, - int *rfd); + int *rfd); /*-- assuan-listen.c --*/ assuan_error_t assuan_set_hello_line (assuan_context_t ctx, const char *line); @@ -360,55 +415,54 @@ 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_connected_socket_server (assuan_context_t *r_ctx, int 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, + unsigned int flags); /*-- assuan-pipe-connect.c --*/ -assuan_error_t assuan_pipe_connect (assuan_context_t *ctx, const char *name, +assuan_error_t assuan_pipe_connect (assuan_context_t *ctx, + const char *name, const char *const argv[], int *fd_child_list); -assuan_error_t assuan_pipe_connect2 (assuan_context_t *ctx, const char *name, +assuan_error_t assuan_pipe_connect2 (assuan_context_t *ctx, + const char *name, const char *const argv[], int *fd_child_list, void (*atfork) (void*, int), - void *atforkvalue); + void *atforkvalue) _ASSUAN_DEPRECATED; +assuan_error_t assuan_pipe_connect_ext (assuan_context_t *ctx, + const char *name, + const char *const argv[], + int *fd_child_list, + void (*atfork) (void *, int), + void *atforkvalue, + unsigned int flags); + /*-- assuan-socket-connect.c --*/ -assuan_error_t assuan_socket_connect (assuan_context_t *ctx, const char *name, +assuan_error_t assuan_socket_connect (assuan_context_t *ctx, + const char *name, pid_t server_pid); - -/*-- assuan-domain-connect.c --*/ - -/* Connect to a Unix domain socket server. RENDEZVOUSFD is - bidirectional file descriptor (normally returned via socketpair) - which the client can use to rendezvous with the server. SERVER s - the server's pid. */ -assuan_error_t assuan_domain_connect (assuan_context_t *r_ctx, - int rendezvousfd, - pid_t server); - -/*-- assuan-domain-server.c --*/ - -/* RENDEZVOUSFD is a bidirectional file descriptor (normally returned - via socketpair) that the domain server can use to rendezvous with - the client. CLIENT is the client's pid. */ -assuan_error_t assuan_init_domain_server (assuan_context_t *r_ctx, - int rendezvousfd, - pid_t client); - +assuan_error_t assuan_socket_connect_ext (assuan_context_t *ctx, + const char *name, + pid_t server_pid, + unsigned int flags); /*-- assuan-connect.c --*/ void assuan_disconnect (assuan_context_t ctx); pid_t assuan_get_pid (assuan_context_t ctx); +assuan_error_t assuan_get_peercred (assuan_context_t ctx, + pid_t *pid, uid_t *uid, gid_t *gid); /*-- assuan-client.c --*/ assuan_error_t assuan_transact (assuan_context_t ctx, const char *command, - assuan_error_t (*data_cb)(void *, const void *, size_t), + int (*data_cb)(void *, const void *, size_t), void *data_cb_arg, - assuan_error_t (*inquire_cb)(void*, const char *), + int (*inquire_cb)(void*, const char *), void *inquire_cb_arg, - assuan_error_t (*status_cb)(void*, const char *), + int (*status_cb)(void*, const char *), void *status_cb_arg); @@ -426,9 +480,8 @@ assuan_error_t assuan_send_data (assuan_context_t ctx, const void *buffer, size_t length); /* The file descriptor must be pending before assuan_receivefd is - call. This means that assuan_sendfd should be called *before* the - trigger is sent (normally via assuan_send_data ("I sent you a - descriptor")). */ + 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); @@ -453,8 +506,20 @@ void assuan_set_flag (assuan_context_t ctx, assuan_flag_t flag, int value); int assuan_get_flag (assuan_context_t ctx, assuan_flag_t flag); -/*-- assuan-errors.c (built) --*/ +/*-- assuan-errors.c --*/ + +#ifndef _ASSUAN_ONLY_GPG_ERRORS +/* Return a string describing the assuan error. The use of this + function is deprecated; it is better to call + assuan_set_assuan_err_source once and then make use libgpg-error. */ const char *assuan_strerror (assuan_error_t err); +#endif /*_ASSUAN_ONLY_GPG_ERRORS*/ + +/* Enable gpg-error style error codes. ERRSOURCE is one of gpg-error + sources. Note, that this function is not thread-safe and should be + used right at startup. Switching back to the old style mode is not + supported. */ +void assuan_set_assuan_err_source (int errsource); /*-- assuan-logging.c --*/ diff --git a/assuan/funopen.c b/assuan/funopen.c index 47f3370..ac31007 100644 --- a/assuan/funopen.c +++ b/assuan/funopen.c @@ -1,21 +1,22 @@ /* funopen.c - Replacement for funopen. - * Copyright (C) 2003 Free Software Foundation, Inc. + * Copyright (C) 2003, 2005 Free Software Foundation, Inc. * - * This file is part of GnuPG. + * This file is part of Assuan. * - * GnuPG is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * Assuan is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. * - * GnuPG is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Assuan is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * 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. */ #ifdef HAVE_CONFIG_H @@ -54,7 +55,7 @@ _assuan_funopen(void *cookie, io.seek = seekfn; io.close = closefn; - return fopencookie (cookie, + return fopencookie (cookie, readfn ? ( writefn ? "rw" : "r" ) : ( writefn ? "w" : ""), io); } diff --git a/assuan/mkerrors b/assuan/mkerrors index e00011b..ded7ba3 100755 --- a/assuan/mkerrors +++ b/assuan/mkerrors @@ -1,7 +1,7 @@ #!/bin/sh # mkerrors - Extract error strings from assuan.h # and create C source for assuan_strerror -# Copyright (C) 2001, 2002 Free Software Foundation, Inc. +# Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. # # This file is part of Assuan. # @@ -17,19 +17,118 @@ # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA cat < #endif #include +#include +#include + +#undef _ASSUAN_IN_LIBASSUAN /* undef to get all error codes. */ #include "assuan.h" +/* If true the modern gpg-error style error codes are used in the + API. */ +static unsigned int err_source; + +/* Enable gpg-error style error codes. ERRSOURCE is one of gpg-error + sources. Note, that this function is not thread-safe and should be + used right at startup. Switching back to the old style mode is not + supported. */ +void +assuan_set_assuan_err_source (int errsource) +{ + errsource &= 0xff; + err_source = errsource? errsource : 31 /*GPG_ERR_SOURCE_ANY*/; +} + + +/* Helper to map old style Assuan error codes to gpg-error codes. + This is used internally to keep an compatible ABI. */ +assuan_error_t +_assuan_error (int oldcode) +{ + unsigned int n; + + if (!err_source) + return (oldcode & 0x00ffffff); /* Make sure that the gpg-error + source part is cleared. */ + + switch (oldcode) + { + case ASSUAN_General_Error: n = 257; break; + case ASSUAN_Accept_Failed: n = 258; break; + case ASSUAN_Connect_Failed: n = 259; break; + case ASSUAN_Invalid_Response: n = 260; break; + case ASSUAN_Invalid_Value: n = 261; break; + case ASSUAN_Line_Not_Terminated: n = 262; break; + case ASSUAN_Line_Too_Long: n = 263; break; + case ASSUAN_Nested_Commands: n = 264; break; + case ASSUAN_No_Data_Callback: n = 265; break; + case ASSUAN_No_Inquire_Callback: n = 266; break; + case ASSUAN_Not_A_Server: n = 267; break; + case ASSUAN_Not_Implemented: n = 69; break; + case ASSUAN_Parameter_Conflict: n = 280; break; + case ASSUAN_Problem_Starting_Server: n = 269; break; + case ASSUAN_Server_Fault: n = 80; break; + case ASSUAN_Syntax_Error: n = 276; break; + case ASSUAN_Too_Much_Data: n = 273; break; + case ASSUAN_Unexpected_Command: n = 274; break; + case ASSUAN_Unknown_Command: n = 275; break; + case ASSUAN_Canceled: n = 277; break; + case ASSUAN_No_Secret_Key: n = 17; break; + + case ASSUAN_Read_Error: + switch (errno) + { + case 0: n = 16381; /*GPG_ERR_MISSING_ERRNO*/ break; + default: n = 270; /*GPG_ERR_ASS_READ_ERROR*/ break; + } + break; + + case ASSUAN_Write_Error: + switch (errno) + { + case 0: n = 16381; /*GPG_ERR_MISSING_ERRNO*/ break; + default: n = 271; /*GPG_ERR_ASS_WRITE_ERROR*/ break; + } + break; + + case ASSUAN_Out_Of_Core: + switch (errno) + { + case 0: /* Should not happen but a user might have provided + an incomplete implemented malloc function. Give + him a chance to correct this fault but make sure + an error is indeed returned. */ + n = 16381; /*GPG_ERR_MISSING_ERRNO*/ + break; + case ENOMEM: n = (1 << 15) | 86; break; + default: + n = 16382; /*GPG_ERR_UNKNOWN_ERRNO*/ + break; + } + break; + + case -1: n = 16383 /*GPG_ERR_EOF*/; break; + + default: + n = 257; + break; + } + + return ((err_source << 24) | (n & 0x00ffffff)); + +} + + /** * assuan_strerror: * @err: Error code @@ -41,7 +140,7 @@ cat <> 24) & 0xff); code = (err & 0x00ffffff); - if (source) /* Assume this is an libgpg-error. */ - sprintf (buf, "ec=%u.%u", source, code ); + if (source) + { + /* Assume this is an libgpg-error and try to map the codes + back. */ + switch (code) + { + case 257: n = ASSUAN_General_Error ; break; + case 258: n = ASSUAN_Accept_Failed ; break; + case 259: n = ASSUAN_Connect_Failed ; break; + case 260: n = ASSUAN_Invalid_Response ; break; + case 261: n = ASSUAN_Invalid_Value ; break; + case 262: n = ASSUAN_Line_Not_Terminated ; break; + case 263: n = ASSUAN_Line_Too_Long ; break; + case 264: n = ASSUAN_Nested_Commands ; break; + case 265: n = ASSUAN_No_Data_Callback ; break; + case 266: n = ASSUAN_No_Inquire_Callback ; break; + case 267: n = ASSUAN_Not_A_Server ; break; + case 69: n = ASSUAN_Not_Implemented ; break; + case 280: n = ASSUAN_Parameter_Conflict ; break; + case 269: n = ASSUAN_Problem_Starting_Server; break; + case 270: n = ASSUAN_Read_Error ; break; + case 271: n = ASSUAN_Write_Error ; break; + case 80: n = ASSUAN_Server_Fault ; break; + case 276: n = ASSUAN_Syntax_Error ; break; + case 273: n = ASSUAN_Too_Much_Data ; break; + case 274: n = ASSUAN_Unexpected_Command ; break; + case 275: n = ASSUAN_Unknown_Command ; break; + case 277: n = ASSUAN_Canceled ; break; + case ((1<<15)|86): n = ASSUAN_Out_Of_Core ; break; + default: n = 0; break; + } + if (n) + s = assuan_strerror (n); + else + { + sprintf (buf, "ec=%u.%u", source, code ); + s=buf; + } + } else - sprintf (buf, "ec=%d", err ); - s=buf; break; + { + sprintf (buf, "ec=%d", err ); + s=buf; + } } + break; } return s; } -EOF \ No newline at end of file +EOF diff --git a/configure.ac b/configure.ac index d40fc32..45f295a 100644 --- a/configure.ac +++ b/configure.ac @@ -202,8 +202,6 @@ AC_SUBST(NETLIBS) # Checks for library functions. AC_FUNC_FSEEKO -AC_CHECK_FUNCS(stpcpy) - AC_REPLACE_FUNCS(vasprintf) if test "$ac_cv_func_vasprintf" != yes; then GNUPG_CHECK_VA_COPY @@ -462,6 +460,10 @@ fi AC_REPLACE_FUNCS(isascii) AC_REPLACE_FUNCS(putc_unlocked) AC_REPLACE_FUNCS(memrchr) +AC_REPLACE_FUNCS(stpcpy) +# Check for unistd.h for setenv replacement function. +AC_CHECK_HEADERS(unistd.h) +AC_REPLACE_FUNCS(setenv) # More assuan checks. AC_CHECK_HEADERS([sys/uio.h]) diff --git a/gpgme/gpgme.h b/gpgme/gpgme.h index f0fee7c..ac66242 100644 --- a/gpgme/gpgme.h +++ b/gpgme/gpgme.h @@ -72,7 +72,7 @@ extern "C" { AM_PATH_GPGME macro) check that this header matches the installed library. Warning: Do not edit the next line. configure will do that for you! */ -#define GPGME_VERSION "1.1.1-cvs1150" +#define GPGME_VERSION "1.1.3-cvs1179" diff --git a/gpgme/setenv.c b/gpgme/setenv.c new file mode 100644 index 0000000..3c803b0 --- /dev/null +++ b/gpgme/setenv.c @@ -0,0 +1,352 @@ +/* Copyright (C) 1992,1995-2001,2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02110-1301 USA. */ + +#if HAVE_CONFIG_H +# include +#endif + +#include "assuan-defs.h" + +#define __builtin_expect(cond,val) (cond) + +#include +#if !_LIBC +# if !defined errno && !defined HAVE_ERRNO_DECL +extern int errno; +# endif +# define __set_errno(ev) ((errno) = (ev)) +#endif + +#if _LIBC || HAVE_STDLIB_H +# include +#endif +#if _LIBC || HAVE_STRING_H +# include +#endif +#if _LIBC || HAVE_UNISTD_H +# include +#endif + +#if !_LIBC +# define __environ environ +# ifndef HAVE_ENVIRON_DECL +extern char **environ; +# endif +#endif + +#if _LIBC +/* This lock protects against simultaneous modifications of `environ'. */ +# include +__libc_lock_define_initialized (static, envlock) +# define LOCK __libc_lock_lock (envlock) +# define UNLOCK __libc_lock_unlock (envlock) +#else +# define LOCK +# define UNLOCK +#endif + +/* In the GNU C library we must keep the namespace clean. */ +#ifdef _LIBC +# define setenv __setenv +# define unsetenv __unsetenv +# define clearenv __clearenv +# define tfind __tfind +# define tsearch __tsearch +#endif + +/* In the GNU C library implementation we try to be more clever and + allow arbitrarily many changes of the environment given that the used + values are from a small set. Outside glibc this will eat up all + memory after a while. */ +#if defined _LIBC || (defined HAVE_SEARCH_H && defined HAVE_TSEARCH \ + && defined __GNUC__) +# define USE_TSEARCH 1 +# include + +/* This is a pointer to the root of the search tree with the known + values. */ +static void *known_values; + +# define KNOWN_VALUE(Str) \ + ({ \ + void *value = tfind (Str, &known_values, (__compar_fn_t) strcmp); \ + value != NULL ? *(char **) value : NULL; \ + }) +# define STORE_VALUE(Str) \ + tsearch (Str, &known_values, (__compar_fn_t) strcmp) + +#else +# undef USE_TSEARCH + +# define KNOWN_VALUE(Str) NULL +# define STORE_VALUE(Str) do { } while (0) + +#endif + + +/* If this variable is not a null pointer we allocated the current + environment. */ +static char **last_environ; + + +/* This function is used by `setenv' and `putenv'. The difference between + the two functions is that for the former must create a new string which + is then placed in the environment, while the argument of `putenv' + must be used directly. This is all complicated by the fact that we try + to reuse values once generated for a `setenv' call since we can never + free the strings. */ +static int +__add_to_environ (const char *name, const char *value, const char *combined, + int replace) +{ + register char **ep; + register size_t size; + const size_t namelen = strlen (name); + const size_t vallen = value != NULL ? strlen (value) + 1 : 0; + + LOCK; + + /* We have to get the pointer now that we have the lock and not earlier + since another thread might have created a new environment. */ + ep = __environ; + + size = 0; + if (ep != NULL) + { + for (; *ep != NULL; ++ep) + if (!strncmp (*ep, name, namelen) && (*ep)[namelen] == '=') + break; + else + ++size; + } + + if (ep == NULL || __builtin_expect (*ep == NULL, 1)) + { + char **new_environ; + + /* We allocated this space; we can extend it. */ + new_environ = (char **) realloc (last_environ, + (size + 2) * sizeof (char *)); + if (new_environ == NULL) + { + UNLOCK; + return -1; + } + + /* If the whole entry is given add it. */ + if (combined != NULL) + /* We must not add the string to the search tree since it belongs + to the user. */ + new_environ[size] = (char *) combined; + else + { + /* See whether the value is already known. */ +#ifdef USE_TSEARCH +# ifdef __GNUC__ + char new_value[namelen + 1 + vallen]; +# else + char *new_value = (char *) alloca (namelen + 1 + vallen); +# endif +# ifdef _LIBC + __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1), + value, vallen); +# else + memcpy (new_value, name, namelen); + new_value[namelen] = '='; + memcpy (&new_value[namelen + 1], value, vallen); +# endif + + new_environ[size] = KNOWN_VALUE (new_value); + if (__builtin_expect (new_environ[size] == NULL, 1)) +#endif + { + new_environ[size] = (char *) malloc (namelen + 1 + vallen); + if (__builtin_expect (new_environ[size] == NULL, 0)) + { + __set_errno (ENOMEM); + UNLOCK; + return -1; + } + +#ifdef USE_TSEARCH + memcpy (new_environ[size], new_value, namelen + 1 + vallen); +#else + memcpy (new_environ[size], name, namelen); + new_environ[size][namelen] = '='; + memcpy (&new_environ[size][namelen + 1], value, vallen); +#endif + /* And save the value now. We cannot do this when we remove + the string since then we cannot decide whether it is a + user string or not. */ + STORE_VALUE (new_environ[size]); + } + } + + if (__environ != last_environ) + memcpy ((char *) new_environ, (char *) __environ, + size * sizeof (char *)); + + new_environ[size + 1] = NULL; + + last_environ = __environ = new_environ; + } + else if (replace) + { + char *np; + + /* Use the user string if given. */ + if (combined != NULL) + np = (char *) combined; + else + { +#ifdef USE_TSEARCH +# ifdef __GNUC__ + char new_value[namelen + 1 + vallen]; +# else + char *new_value = (char *) alloca (namelen + 1 + vallen); +# endif +# ifdef _LIBC + __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1), + value, vallen); +# else + memcpy (new_value, name, namelen); + new_value[namelen] = '='; + memcpy (&new_value[namelen + 1], value, vallen); +# endif + + np = KNOWN_VALUE (new_value); + if (__builtin_expect (np == NULL, 1)) +#endif + { + np = malloc (namelen + 1 + vallen); + if (__builtin_expect (np == NULL, 0)) + { + UNLOCK; + return -1; + } + +#ifdef USE_TSEARCH + memcpy (np, new_value, namelen + 1 + vallen); +#else + memcpy (np, name, namelen); + np[namelen] = '='; + memcpy (&np[namelen + 1], value, vallen); +#endif + /* And remember the value. */ + STORE_VALUE (np); + } + } + + *ep = np; + } + + UNLOCK; + + return 0; +} + +int +setenv (const char *name, const char *value, int replace) +{ + if (name == NULL || *name == '\0' || strchr (name, '=') != NULL) + { + __set_errno (EINVAL); + return -1; + } + + return __add_to_environ (name, value, NULL, replace); +} + +int +unsetenv (const char *name) +{ + size_t len; + char **ep; + + if (name == NULL || *name == '\0' || strchr (name, '=') != NULL) + { + __set_errno (EINVAL); + return -1; + } + + len = strlen (name); + + LOCK; + + ep = __environ; + while (*ep != NULL) + if (!strncmp (*ep, name, len) && (*ep)[len] == '=') + { + /* Found it. Remove this pointer by moving later ones back. */ + char **dp = ep; + + do + dp[0] = dp[1]; + while (*dp++); + /* Continue the loop in case NAME appears again. */ + } + else + ++ep; + + UNLOCK; + + return 0; +} + +/* The `clearenv' was planned to be added to POSIX.1 but probably + never made it. Nevertheless the POSIX.9 standard (POSIX bindings + for Fortran 77) requires this function. */ +int +clearenv (void) +{ + LOCK; + + if (__environ == last_environ && __environ != NULL) + { + /* We allocated this environment so we can free it. */ + free (__environ); + last_environ = NULL; + } + + /* Clear the environment pointer removes the whole environment. */ + __environ = NULL; + + UNLOCK; + + return 0; +} +#ifdef _LIBC +libc_freeres_fn (free_mem) +{ + /* Remove all traces. */ + clearenv (); + + /* Now remove the search tree. */ + __tdestroy (known_values, free); + known_values = NULL; +} + +# undef setenv +# undef unsetenv +# undef clearenv +weak_alias (__setenv, setenv) +weak_alias (__unsetenv, unsetenv) +weak_alias (__clearenv, clearenv) +#endif + + -- 2.26.2