Update to current version.

2006-09-19  Marcus Brinkmann  <marcus@g10code.de>

	* configure.ac: Turn stpcpy into a replacement function.
	Check for unistd.h and add setenv as replacement function.

gpgme/
2006-09-19  Marcus Brinkmann  <marcus@g10code.de>

	* setenv.c: New file.
This commit is contained in:
Marcus Brinkmann 2006-09-19 14:01:54 +00:00
parent 426fd0cc08
commit 9e09d93de8
27 changed files with 2413 additions and 1329 deletions

View File

@ -1,3 +1,8 @@
2006-09-19 Marcus Brinkmann <marcus@g10code.de>
* configure.ac: Turn stpcpy into a replacement function.
Check for unistd.h and add setenv as replacement function.
2006-07-29 Marcus Brinkmann <marcus@g10code.de> 2006-07-29 Marcus Brinkmann <marcus@g10code.de>
* configure.ac: Check for network libraries and set NETLIBS. * configure.ac: Check for network libraries and set NETLIBS.

View File

@ -1,3 +1,171 @@
2006-09-19 Marcus Brinkmann <marcus@g10code.de>
* assuan.h (assuan_init_socket_server_ext)
[_ASSUAN_EXT_SYM_PREFIX]: Fix typo in macro.
2006-09-19 Werner Koch <wk@g10code.com>
* 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 <marcus@g10code.de>
* 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 <wk@g10code.com>
* 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 <wk@g10code.com>
* 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 <wk@g10code.com>
* 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 <wk@g10code.com>
* 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 <wk@g10code.com>
* 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 <wk@g10code.com>
* 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 <wk@g10code.com>
* 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 <wk@g10code.com>
* 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 <marcus@g10code.de>
* 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 <marcus@g10code.de>
* 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 <marcus@g10code.de> 2005-10-01 Marcus Brinkmann <marcus@g10code.de>
* assuan.h (assuan_pipe_connect, assuan_pipe_connect2): Make type * assuan.h (assuan_pipe_connect, assuan_pipe_connect2): Make type

View File

@ -15,7 +15,7 @@
# #
# You should have received a copy of the GNU Lesser General Public # You should have received a copy of the GNU Lesser General Public
# License along with this program; if not, write to the Free Software # 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 ## Process this file with automake to produce Makefile.in
@ -44,12 +44,11 @@ libassuan_la_SOURCES = \
assuan-socket-server.c \ assuan-socket-server.c \
assuan-pipe-connect.c \ assuan-pipe-connect.c \
assuan-socket-connect.c \ assuan-socket-connect.c \
assuan-socket.c \ assuan-uds.c \
funopen.c \ funopen.c \
assuan-io.c \ assuan-io.c \
assuan-domain-connect.c \ assuan-logging.c \
assuan-domain-server.c \ assuan-socket.c
assuan-logging.c
assuan-errors.c : assuan.h assuan-errors.c : assuan.h mkerrors
$(srcdir)/mkerrors < $(srcdir)/assuan.h > assuan-errors.c $(srcdir)/mkerrors < $(srcdir)/assuan.h > assuan-errors.c

View File

@ -15,7 +15,8 @@
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software * 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 <config.h> #include <config.h>
@ -30,8 +31,11 @@
#endif #endif
#include "assuan-defs.h" #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 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) while (length)
{ {
@ -49,9 +53,11 @@ writen (ASSUAN_CONTEXT ctx, const char *buffer, size_t length)
return 0; /* okay */ 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 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) int *r_nread, int *r_eof)
{ {
size_t nleft = buflen; size_t nleft = buflen;
@ -88,8 +94,9 @@ readline (ASSUAN_CONTEXT ctx, char *buf, size_t buflen,
} }
int /* Function returns an Assuan error. */
_assuan_read_line (ASSUAN_CONTEXT ctx) assuan_error_t
_assuan_read_line (assuan_context_t ctx)
{ {
char *line = ctx->inbound.line; char *line = ctx->inbound.line;
int nread, atticlen; int nread, atticlen;
@ -97,7 +104,7 @@ _assuan_read_line (ASSUAN_CONTEXT ctx)
char *endp = 0; char *endp = 0;
if (ctx->inbound.eof) if (ctx->inbound.eof)
return -1; return _assuan_error (-1);
atticlen = ctx->inbound.attic.linelen; atticlen = ctx->inbound.attic.linelen;
if (atticlen) if (atticlen)
@ -128,19 +135,20 @@ _assuan_read_line (ASSUAN_CONTEXT ctx)
if (rc) if (rc)
{ {
if (ctx->log_fp) 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 (), assuan_get_assuan_log_prefix (),
(unsigned int)getpid (), ctx, strerror (errno)); (unsigned int)getpid (), ctx->inbound.fd,
return ASSUAN_Read_Error; strerror (errno));
return _assuan_error (ASSUAN_Read_Error);
} }
if (!nread) if (!nread)
{ {
assert (ctx->inbound.eof); assert (ctx->inbound.eof);
if (ctx->log_fp) 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 (), assuan_get_assuan_log_prefix (),
(unsigned int)getpid (), ctx); (unsigned int)getpid (), ctx->inbound.fd);
return -1; return _assuan_error (-1);
} }
ctx->inbound.attic.pending = 0; ctx->inbound.attic.pending = 0;
@ -170,9 +178,9 @@ _assuan_read_line (ASSUAN_CONTEXT ctx)
ctx->inbound.linelen = endp - line; ctx->inbound.linelen = endp - line;
if (ctx->log_fp) 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 (), assuan_get_assuan_log_prefix (),
(unsigned int)getpid (), ctx); (unsigned int)getpid (), ctx->inbound.fd);
if (ctx->confidential) if (ctx->confidential)
fputs ("[Confidential data not shown]", ctx->log_fp); fputs ("[Confidential data not shown]", ctx->log_fp);
else else
@ -186,13 +194,14 @@ _assuan_read_line (ASSUAN_CONTEXT ctx)
else else
{ {
if (ctx->log_fp) 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 (), assuan_get_assuan_log_prefix (),
(unsigned int)getpid (), ctx); (unsigned int)getpid (), ctx->inbound.fd);
*line = 0; *line = 0;
ctx->inbound.linelen = 0; ctx->inbound.linelen = 0;
return ctx->inbound.eof ? ASSUAN_Line_Not_Terminated return _assuan_error (ctx->inbound.eof
: ASSUAN_Line_Too_Long; ? ASSUAN_Line_Not_Terminated
: ASSUAN_Line_Too_Long);
} }
} }
@ -207,12 +216,12 @@ _assuan_read_line (ASSUAN_CONTEXT ctx)
See also: assuan_pending_line(). See also: assuan_pending_line().
*/ */
assuan_error_t 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; assuan_error_t err;
if (!ctx) if (!ctx)
return ASSUAN_Invalid_Value; return _assuan_error (ASSUAN_Invalid_Value);
err = _assuan_read_line (ctx); err = _assuan_read_line (ctx);
*line = ctx->inbound.line; *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 /* Return true if a full line is buffered (i.e. an entire line may be
read without any I/O). */ read without any I/O). */
int int
assuan_pending_line (ASSUAN_CONTEXT ctx) assuan_pending_line (assuan_context_t ctx)
{ {
return ctx && ctx->inbound.attic.pending; return ctx && ctx->inbound.attic.pending;
} }
@ -234,17 +243,17 @@ assuan_error_t
_assuan_write_line (assuan_context_t ctx, const char *prefix, _assuan_write_line (assuan_context_t ctx, const char *prefix,
const char *line, size_t len) const char *line, size_t len)
{ {
int rc = 0; assuan_error_t rc = 0;
size_t prefixlen = prefix? strlen (prefix):0; size_t prefixlen = prefix? strlen (prefix):0;
/* Make sure that the line is short enough. */ /* Make sure that the line is short enough. */
if (len + prefixlen + 2 > ASSUAN_LINELENGTH) if (len + prefixlen + 2 > ASSUAN_LINELENGTH)
{ {
if (ctx->log_fp) 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", "[supplied line too long -truncated]\n",
assuan_get_assuan_log_prefix (), assuan_get_assuan_log_prefix (),
(unsigned int)getpid (), ctx); (unsigned int)getpid (), ctx->inbound.fd);
if (prefixlen > 5) if (prefixlen > 5)
prefixlen = 5; prefixlen = 5;
if (len > ASSUAN_LINELENGTH - prefixlen - 2) 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. */ /* Fixme: we should do some kind of line buffering. */
if (ctx->log_fp) 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 (), assuan_get_assuan_log_prefix (),
(unsigned int)getpid (), ctx); (unsigned int)getpid (), ctx->inbound.fd);
if (ctx->confidential) if (ctx->confidential)
fputs ("[Confidential data not shown]", ctx->log_fp); fputs ("[Confidential data not shown]", ctx->log_fp);
else 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); putc ('\n', ctx->log_fp);
} }
@ -268,18 +281,18 @@ _assuan_write_line (assuan_context_t ctx, const char *prefix,
{ {
rc = writen (ctx, prefix, prefixlen); rc = writen (ctx, prefix, prefixlen);
if (rc) if (rc)
rc = ASSUAN_Write_Error; rc = _assuan_error (ASSUAN_Write_Error);
} }
if (!rc) if (!rc)
{ {
rc = writen (ctx, line, len); rc = writen (ctx, line, len);
if (rc) if (rc)
rc = ASSUAN_Write_Error; rc = _assuan_error (ASSUAN_Write_Error);
if (!rc) if (!rc)
{ {
rc = writen (ctx, "\n", 1); rc = writen (ctx, "\n", 1);
if (rc) if (rc)
rc = ASSUAN_Write_Error; rc = _assuan_error (ASSUAN_Write_Error);
} }
} }
return rc; return rc;
@ -287,13 +300,13 @@ _assuan_write_line (assuan_context_t ctx, const char *prefix,
assuan_error_t 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; size_t len;
const char *s; const char *s;
if (!ctx) 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 /* Make sure that we never take a LF from the user - this might
violate the protocol. */ violate the protocol. */
@ -301,10 +314,10 @@ assuan_write_line (ASSUAN_CONTEXT ctx, const char *line)
len = s? (s-line) : strlen (line); len = s? (s-line) : strlen (line);
if (ctx->log_fp && s) if (ctx->log_fp && s)
fprintf (ctx->log_fp, "%s[%u.%p] DBG: -> " fprintf (ctx->log_fp, "%s[%u.%d] DBG: -> "
"[supplied line contained a LF -truncated]\n", "[supplied line contained a LF - truncated]\n",
assuan_get_assuan_log_prefix (), assuan_get_assuan_log_prefix (),
(unsigned int)getpid (), ctx); (unsigned int)getpid (), ctx->inbound.fd);
return _assuan_write_line (ctx, NULL, line, len); return _assuan_write_line (ctx, NULL, line, len);
} }
@ -316,7 +329,7 @@ assuan_write_line (ASSUAN_CONTEXT ctx, const char *line)
int int
_assuan_cookie_write_data (void *cookie, const char *buffer, size_t orig_size) _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; size_t size = orig_size;
char *line; char *line;
size_t linelen; size_t linelen;
@ -359,9 +372,9 @@ _assuan_cookie_write_data (void *cookie, const char *buffer, size_t orig_size)
{ {
if (ctx->log_fp) 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 (), assuan_get_assuan_log_prefix (),
(unsigned int)getpid (), ctx); (unsigned int)getpid (), ctx->inbound.fd);
if (ctx->confidential) if (ctx->confidential)
fputs ("[Confidential data not shown]", ctx->log_fp); 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++; linelen++;
if (writen (ctx, ctx->outbound.data.line, 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; return 0;
} }
line = ctx->outbound.data.line; line = ctx->outbound.data.line;
@ -393,7 +406,7 @@ _assuan_cookie_write_data (void *cookie, const char *buffer, size_t orig_size)
int int
_assuan_cookie_write_flush (void *cookie) _assuan_cookie_write_flush (void *cookie)
{ {
ASSUAN_CONTEXT ctx = cookie; assuan_context_t ctx = cookie;
char *line; char *line;
size_t linelen; size_t linelen;
@ -407,9 +420,9 @@ _assuan_cookie_write_flush (void *cookie)
{ {
if (ctx->log_fp) 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 (), assuan_get_assuan_log_prefix (),
(unsigned int)getpid (), ctx); (unsigned int)getpid (), ctx->inbound.fd);
if (ctx->confidential) if (ctx->confidential)
fputs ("[Confidential data not shown]", ctx->log_fp); fputs ("[Confidential data not shown]", ctx->log_fp);
else else
@ -421,7 +434,7 @@ _assuan_cookie_write_flush (void *cookie)
linelen++; linelen++;
if (writen (ctx, ctx->outbound.data.line, 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; return 0;
} }
ctx->outbound.data.linelen = 0; ctx->outbound.data.linelen = 0;
@ -449,12 +462,12 @@ _assuan_cookie_write_flush (void *cookie)
**/ **/
assuan_error_t 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) if (!ctx)
return ASSUAN_Invalid_Value; return _assuan_error (ASSUAN_Invalid_Value);
if (!buffer && length) if (!buffer && length)
return ASSUAN_Invalid_Value; return _assuan_error (ASSUAN_Invalid_Value);
if (!buffer) if (!buffer)
{ /* flush what we have */ { /* flush what we have */
@ -475,7 +488,7 @@ assuan_send_data (ASSUAN_CONTEXT ctx, const void *buffer, size_t length)
} }
assuan_error_t assuan_error_t
assuan_sendfd (ASSUAN_CONTEXT ctx, int fd) assuan_sendfd (assuan_context_t ctx, int fd)
{ {
if (! ctx->io->sendfd) if (! ctx->io->sendfd)
return set_error (ctx, Not_Implemented, return set_error (ctx, Not_Implemented,
@ -485,7 +498,7 @@ assuan_sendfd (ASSUAN_CONTEXT ctx, int fd)
} }
assuan_error_t assuan_error_t
assuan_receivefd (ASSUAN_CONTEXT ctx, int *fd) assuan_receivefd (assuan_context_t ctx, int *fd)
{ {
if (! ctx->io->receivefd) if (! ctx->io->receivefd)
return set_error (ctx, Not_Implemented, return set_error (ctx, Not_Implemented,

View File

@ -15,7 +15,8 @@
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software * 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 <config.h> #include <config.h>
@ -33,7 +34,7 @@
assuan_error_t 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; char *line;
int linelen; int linelen;
@ -103,7 +104,7 @@ _assuan_read_from_server (ASSUAN_CONTEXT ctx, int *okay, int *off)
*off = 3; *off = 3;
} }
else else
rc = ASSUAN_Invalid_Response; rc = _assuan_error (ASSUAN_Invalid_Response);
return rc; return rc;
} }
@ -112,7 +113,7 @@ _assuan_read_from_server (ASSUAN_CONTEXT ctx, int *okay, int *off)
/** /**
* assuan_transact: * assuan_transact:
* @ctx: The Assuan context * @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: Callback function for data lines
* @data_cb_arg: first argument passed to @data_cb * @data_cb_arg: first argument passed to @data_cb
* @inquire_cb: Callback function for a inquire response * @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 * 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 * 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_error_t
assuan_transact (ASSUAN_CONTEXT ctx, assuan_transact (assuan_context_t ctx,
const char *command, 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, void *data_cb_arg,
assuan_error_t (*inquire_cb)(void*, const char *), int (*inquire_cb)(void*, const char *),
void *inquire_cb_arg, void *inquire_cb_arg,
assuan_error_t (*status_cb)(void*, const char *), int (*status_cb)(void*, const char *),
void *status_cb_arg) void *status_cb_arg)
{ {
int rc, okay, off; assuan_error_t rc;
int okay, off;
char *line; char *line;
int linelen; int linelen;
@ -157,14 +161,14 @@ assuan_transact (ASSUAN_CONTEXT ctx,
if (!okay) if (!okay)
{ {
rc = atoi (line); rc = _assuan_error (atoi (line));
if (rc < 100) if (rc < 100)
rc = ASSUAN_Server_Fault; rc = ASSUAN_Server_Fault;
} }
else if (okay == 2) else if (okay == 2)
{ {
if (!data_cb) if (!data_cb)
rc = ASSUAN_No_Data_Callback; rc = _assuan_error (ASSUAN_No_Data_Callback);
else else
{ {
char *s, *d; char *s, *d;
@ -193,7 +197,7 @@ assuan_transact (ASSUAN_CONTEXT ctx,
{ {
assuan_write_line (ctx, "END"); /* get out of inquire mode */ assuan_write_line (ctx, "END"); /* get out of inquire mode */
_assuan_read_from_server (ctx, &okay, &off); /* dummy read */ _assuan_read_from_server (ctx, &okay, &off); /* dummy read */
rc = ASSUAN_No_Inquire_Callback; rc = _assuan_error (ASSUAN_No_Inquire_Callback);
} }
else else
{ {
@ -214,7 +218,7 @@ assuan_transact (ASSUAN_CONTEXT ctx,
else if (okay == 5) else if (okay == 5)
{ {
if (!data_cb) if (!data_cb)
rc = ASSUAN_No_Data_Callback; rc = _assuan_error (ASSUAN_No_Data_Callback);
else else
{ {
rc = data_cb (data_cb_arg, NULL, 0); rc = data_cb (data_cb_arg, NULL, 0);

View File

@ -15,7 +15,8 @@
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software * 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 #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 pid_t
assuan_get_pid (assuan_context_t ctx) assuan_get_pid (assuan_context_t ctx)
{ {
return (ctx && ctx->pid)? ctx->pid : -1; 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;
}

View File

@ -1,5 +1,5 @@
/* assuan-defs.c - Internal definitions to Assuan /* 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. * This file is part of Assuan.
* *
@ -15,7 +15,8 @@
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software * 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 #ifndef ASSUAN_DEFS_H
@ -62,24 +63,30 @@ char * stpcpy (char *dest, const char *src);
#define LINELENGTH ASSUAN_LINELENGTH #define LINELENGTH ASSUAN_LINELENGTH
struct cmdtbl_s struct cmdtbl_s
{ {
const char *name; 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 struct assuan_io
{ {
/* Routine to read from input_fd. */ /* 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. */ /* 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. */ /* Send a file descriptor. */
assuan_error_t (*sendfd) (ASSUAN_CONTEXT, int); assuan_error_t (*sendfd) (assuan_context_t, int);
/* Receive a file descriptor. */ /* 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 struct assuan_context_s
{ {
assuan_error_t err_no; assuan_error_t err_no;
@ -99,7 +106,7 @@ struct assuan_context_s
char *hello_line; char *hello_line;
char *okay_line; /* See assuan_set_okay_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; FILE *log_fp;
@ -109,7 +116,7 @@ struct assuan_context_s
char line[LINELENGTH]; char line[LINELENGTH];
int linelen; /* w/o CR, LF - might not be the same as int linelen; /* w/o CR, LF - might not be the same as
strlen(line) due to embedded nuls. However a nul strlen(line) due to embedded nuls. However a nul
is always written at this pos */ is always written at this pos. */
struct { struct {
char line[LINELENGTH]; char line[LINELENGTH];
int linelen ; int linelen ;
@ -128,43 +135,49 @@ struct assuan_context_s
} outbound; } outbound;
int pipe_mode; /* We are in pipe mode, i.e. we can handle just one int pipe_mode; /* We are in pipe mode, i.e. we can handle just one
connection and must terminate then */ connection and must terminate then. */
pid_t pid; /* The the pid of the peer. */ pid_t pid; /* The pid of the peer. */
int listen_fd; /* The fd we are listening on (used by socket servers) */ int listen_fd; /* The fd we are listening on (used by socket servers) */
int connected_fd; /* helper */ 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. */ /* Used for Unix domain sockets. */
struct sockaddr_un myaddr; struct sockaddr_un myaddr;
struct sockaddr_un serveraddr; 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; /* Structure used for unix domain socket buffering. FIXME: We don't
int pendingfdscount; 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. */
void (*deinit_handler)(ASSUAN_CONTEXT); int pendingfds[5]; /* Array to save received descriptors. */
int (*accept_handler)(ASSUAN_CONTEXT); int pendingfdscount; /* Number of received descriptors. */
int (*finish_handler)(ASSUAN_CONTEXT); } uds;
void (*deinit_handler)(assuan_context_t);
int (*accept_handler)(assuan_context_t);
int (*finish_handler)(assuan_context_t);
struct cmdtbl_s *cmdtbl; struct cmdtbl_s *cmdtbl;
size_t cmdtbl_used; /* used entries */ size_t cmdtbl_used; /* used entries */
size_t cmdtbl_size; /* allocated size of table */ size_t cmdtbl_size; /* allocated size of table */
void (*bye_notify_fnc)(ASSUAN_CONTEXT); void (*bye_notify_fnc)(assuan_context_t);
void (*reset_notify_fnc)(ASSUAN_CONTEXT); void (*reset_notify_fnc)(assuan_context_t);
void (*cancel_notify_fnc)(ASSUAN_CONTEXT); void (*cancel_notify_fnc)(assuan_context_t);
int (*option_handler_fnc)(ASSUAN_CONTEXT,const char*, const char*); int (*option_handler_fnc)(assuan_context_t,const char*, const char*);
void (*input_notify_fnc)(ASSUAN_CONTEXT, const char *); void (*input_notify_fnc)(assuan_context_t, const char *);
void (*output_notify_fnc)(ASSUAN_CONTEXT, const char *); void (*output_notify_fnc)(assuan_context_t, const char *);
int input_fd; /* set by INPUT command */ int input_fd; /* set by INPUT command */
int output_fd; /* set by OUTPUT command */ int output_fd; /* set by OUTPUT command */
@ -174,29 +187,45 @@ struct assuan_context_s
}; };
/*-- assuan-pipe-server.c --*/ /*-- assuan-pipe-server.c --*/
int _assuan_new_context (ASSUAN_CONTEXT *r_ctx); int _assuan_new_context (assuan_context_t *r_ctx);
void _assuan_release_context (ASSUAN_CONTEXT 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 --*/ /*-- assuan-handler.c --*/
int _assuan_register_std_commands (ASSUAN_CONTEXT ctx); int _assuan_register_std_commands (assuan_context_t ctx);
/*-- assuan-buffer.c --*/ /*-- 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_data (void *cookie, const char *buffer, size_t size);
int _assuan_cookie_write_flush (void *cookie); int _assuan_cookie_write_flush (void *cookie);
assuan_error_t _assuan_write_line (assuan_context_t ctx, const char *prefix, assuan_error_t _assuan_write_line (assuan_context_t ctx, const char *prefix,
const char *line, size_t len); const char *line, size_t len);
/*-- assuan-client.c --*/ /*-- 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 --*/ /*-- assuan-util.c --*/
@ -210,10 +239,8 @@ void _assuan_free (void *p);
#define xtryrealloc(a,b) _assuan_realloc((a),(b)) #define xtryrealloc(a,b) _assuan_realloc((a),(b))
#define xfree(a) _assuan_free ((a)) #define xfree(a) _assuan_free ((a))
#define set_error(c,e,t) assuan_set_error ((c), ASSUAN_ ## e, (t)) #define set_error(c,e,t) \
assuan_set_error ((c), _assuan_error (ASSUAN_ ## e), (t))
void _assuan_log_print_buffer (FILE *fp, const void *buffer, size_t length);
void _assuan_log_sanitized_string (const char *string);
#ifdef HAVE_W32_SYSTEM #ifdef HAVE_W32_SYSTEM
const char *_assuan_w32_strerror (int ec); const char *_assuan_w32_strerror (int ec);
@ -229,11 +256,18 @@ void _assuan_log_printf (const char *format, ...)
__attribute__ ((format (printf,1,2))) __attribute__ ((format (printf,1,2)))
#endif #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 --*/ /*-- assuan-io.c --*/
ssize_t _assuan_simple_read (ASSUAN_CONTEXT ctx, void *buffer, size_t size); pid_t _assuan_waitpid (pid_t pid, int *status, int options);
ssize_t _assuan_simple_write (ASSUAN_CONTEXT ctx, const void *buffer,
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); 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 --*/ /*-- assuan-socket.c --*/
int _assuan_close (int fd); 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)) #define funopen(a,r,w,s,c) _assuan_funopen ((a), (r), (w), (s), (c))
#endif /*HAVE_FOPENCOOKIE*/ #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*/

View File

@ -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 <config.h>
#endif
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#ifndef HAVE_W32_SYSTEM
#include <sys/socket.h>
#include <sys/un.h>
#else
#include <windows.h>
#endif
#if HAVE_SYS_UIO_H
#include <sys/uio.h>
#endif
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <assert.h>
#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;
}

View File

@ -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 <config.h>
#endif
#include <unistd.h>
#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;
}

View File

@ -15,7 +15,8 @@
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software * 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 <config.h> #include <config.h>
@ -36,20 +37,20 @@ static int my_strcasecmp (const char *a, const char *b);
static int 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"); return set_error (ctx, Server_Fault, "no handler registered");
} }
static int static int
std_handler_nop (ASSUAN_CONTEXT ctx, char *line) std_handler_nop (assuan_context_t ctx, char *line)
{ {
return 0; /* okay */ return 0; /* okay */
} }
static int static int
std_handler_cancel (ASSUAN_CONTEXT ctx, char *line) std_handler_cancel (assuan_context_t ctx, char *line)
{ {
if (ctx->cancel_notify_fnc) if (ctx->cancel_notify_fnc)
ctx->cancel_notify_fnc (ctx); ctx->cancel_notify_fnc (ctx);
@ -57,7 +58,7 @@ std_handler_cancel (ASSUAN_CONTEXT ctx, char *line)
} }
static int static int
std_handler_option (ASSUAN_CONTEXT ctx, char *line) std_handler_option (assuan_context_t ctx, char *line)
{ {
char *key, *value, *p; char *key, *value, *p;
@ -104,7 +105,7 @@ std_handler_option (ASSUAN_CONTEXT ctx, char *line)
} }
static int static int
std_handler_bye (ASSUAN_CONTEXT ctx, char *line) std_handler_bye (assuan_context_t ctx, char *line)
{ {
if (ctx->bye_notify_fnc) if (ctx->bye_notify_fnc)
ctx->bye_notify_fnc (ctx); ctx->bye_notify_fnc (ctx);
@ -114,33 +115,35 @@ std_handler_bye (ASSUAN_CONTEXT ctx, char *line)
} }
static int 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); return set_error (ctx, Not_Implemented, NULL);
} }
static int static int
std_handler_reset (ASSUAN_CONTEXT ctx, char *line) std_handler_reset (assuan_context_t ctx, char *line)
{ {
if (ctx->reset_notify_fnc) if (ctx->reset_notify_fnc)
ctx->reset_notify_fnc (ctx); ctx->reset_notify_fnc (ctx);
assuan_close_input_fd (ctx); assuan_close_input_fd (ctx);
assuan_close_output_fd (ctx); assuan_close_output_fd (ctx);
_assuan_uds_close_fds (ctx);
return 0; return 0;
} }
static int 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); return set_error (ctx, Not_Implemented, NULL);
} }
assuan_error_t 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; 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[=<n>] expected"); return set_error (ctx, Syntax_Error, "FD[=<n>] expected");
line += 2; line += 2;
if (*line == '=') if (*line == '=')
@ -149,7 +152,7 @@ assuan_command_parse_fd (ASSUAN_CONTEXT ctx, char *line, int *rfd)
if (!digitp (*line)) if (!digitp (*line))
return set_error (ctx, Syntax_Error, "number required"); return set_error (ctx, Syntax_Error, "number required");
*rfd = strtoul (line, &endp, 10); *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)); memset (line, ' ', endp? (endp-line):strlen(line));
if (*rfd == ctx->inbound.fd) if (*rfd == ctx->inbound.fd)
@ -165,7 +168,7 @@ assuan_command_parse_fd (ASSUAN_CONTEXT ctx, char *line, int *rfd)
/* Format is INPUT FD=<n> */ /* Format is INPUT FD=<n> */
static int static int
std_handler_input (ASSUAN_CONTEXT ctx, char *line) std_handler_input (assuan_context_t ctx, char *line)
{ {
int rc, fd; int rc, fd;
@ -180,7 +183,7 @@ std_handler_input (ASSUAN_CONTEXT ctx, char *line)
/* Format is OUTPUT FD=<n> */ /* Format is OUTPUT FD=<n> */
static int static int
std_handler_output (ASSUAN_CONTEXT ctx, char *line) std_handler_output (assuan_context_t ctx, char *line)
{ {
int rc, fd; int rc, fd;
@ -202,7 +205,7 @@ std_handler_output (ASSUAN_CONTEXT ctx, char *line)
with default handlers */ with default handlers */
static struct { static struct {
const char *name; const char *name;
int (*handler)(ASSUAN_CONTEXT, char *line); int (*handler)(assuan_context_t, char *line);
int always; /* always initialize this command */ int always; /* always initialize this command */
} std_cmd_table[] = { } std_cmd_table[] = {
{ "NOP", std_handler_nop, 1 }, { "NOP", std_handler_nop, 1 },
@ -234,9 +237,9 @@ static struct {
* Return value: 0 on success or an error code * Return value: 0 on success or an error code
**/ **/
int int
assuan_register_command (ASSUAN_CONTEXT ctx, assuan_register_command (assuan_context_t ctx,
const char *cmd_name, const char *cmd_name,
int (*handler)(ASSUAN_CONTEXT, char *)) int (*handler)(assuan_context_t, char *))
{ {
int i; int i;
const char *s; const char *s;
@ -245,7 +248,7 @@ assuan_register_command (ASSUAN_CONTEXT ctx,
cmd_name = NULL; cmd_name = NULL;
if (!cmd_name) if (!cmd_name)
return ASSUAN_Invalid_Value; return _assuan_error (ASSUAN_Invalid_Value);
if (!handler) if (!handler)
{ /* find a default handler. */ { /* find a default handler. */
@ -268,7 +271,7 @@ assuan_register_command (ASSUAN_CONTEXT ctx,
ctx->cmdtbl_size = 50; ctx->cmdtbl_size = 50;
ctx->cmdtbl = xtrycalloc ( ctx->cmdtbl_size, sizeof *ctx->cmdtbl); ctx->cmdtbl = xtrycalloc ( ctx->cmdtbl_size, sizeof *ctx->cmdtbl);
if (!ctx->cmdtbl) if (!ctx->cmdtbl)
return ASSUAN_Out_Of_Core; return _assuan_error (ASSUAN_Out_Of_Core);
ctx->cmdtbl_used = 0; ctx->cmdtbl_used = 0;
} }
else if (ctx->cmdtbl_used >= ctx->cmdtbl_size) 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); x = xtryrealloc ( ctx->cmdtbl, (ctx->cmdtbl_size+10) * sizeof *x);
if (!x) if (!x)
return ASSUAN_Out_Of_Core; return _assuan_error (ASSUAN_Out_Of_Core);
ctx->cmdtbl = x; ctx->cmdtbl = x;
ctx->cmdtbl_size += 50; ctx->cmdtbl_size += 50;
} }
@ -289,59 +292,62 @@ assuan_register_command (ASSUAN_CONTEXT ctx,
} }
int 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) if (!ctx)
return ASSUAN_Invalid_Value; return _assuan_error (ASSUAN_Invalid_Value);
ctx->bye_notify_fnc = fnc; ctx->bye_notify_fnc = fnc;
return 0; return 0;
} }
int 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) if (!ctx)
return ASSUAN_Invalid_Value; return _assuan_error (ASSUAN_Invalid_Value);
ctx->reset_notify_fnc = fnc; ctx->reset_notify_fnc = fnc;
return 0; return 0;
} }
int 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) if (!ctx)
return ASSUAN_Invalid_Value; return _assuan_error (ASSUAN_Invalid_Value);
ctx->cancel_notify_fnc = fnc; ctx->cancel_notify_fnc = fnc;
return 0; return 0;
} }
int int
assuan_register_option_handler (ASSUAN_CONTEXT ctx, assuan_register_option_handler (assuan_context_t ctx,
int (*fnc)(ASSUAN_CONTEXT, int (*fnc)(assuan_context_t,
const char*, const char*)) const char*, const char*))
{ {
if (!ctx) if (!ctx)
return ASSUAN_Invalid_Value; return _assuan_error (ASSUAN_Invalid_Value);
ctx->option_handler_fnc = fnc; ctx->option_handler_fnc = fnc;
return 0; return 0;
} }
int int
assuan_register_input_notify (ASSUAN_CONTEXT ctx, assuan_register_input_notify (assuan_context_t ctx,
void (*fnc)(ASSUAN_CONTEXT, const char *)) void (*fnc)(assuan_context_t, const char *))
{ {
if (!ctx) if (!ctx)
return ASSUAN_Invalid_Value; return _assuan_error (ASSUAN_Invalid_Value);
ctx->input_notify_fnc = fnc; ctx->input_notify_fnc = fnc;
return 0; return 0;
} }
int int
assuan_register_output_notify (ASSUAN_CONTEXT ctx, assuan_register_output_notify (assuan_context_t ctx,
void (*fnc)(ASSUAN_CONTEXT, const char *)) void (*fnc)(assuan_context_t, const char *))
{ {
if (!ctx) if (!ctx)
return ASSUAN_Invalid_Value; return _assuan_error (ASSUAN_Invalid_Value);
ctx->output_notify_fnc = fnc; ctx->output_notify_fnc = fnc;
return 0; return 0;
} }
@ -349,7 +355,7 @@ assuan_register_output_notify (ASSUAN_CONTEXT ctx,
/* Helper to register the standards commands */ /* Helper to register the standards commands */
int int
_assuan_register_std_commands (ASSUAN_CONTEXT ctx) _assuan_register_std_commands (assuan_context_t ctx)
{ {
int i, rc; 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 /* Process the special data lines. The "D " has already been removed
from the line. As all handlers this function may modify the line. */ from the line. As all handlers this function may modify the line. */
static int 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); 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 table, remove leading and white spaces from the arguments, call the
handler with the argument line and return the error */ handler with the argument line and return the error */
static int static int
dispatch_command (ASSUAN_CONTEXT ctx, char *line, int linelen) dispatch_command (assuan_context_t ctx, char *line, int linelen)
{ {
char *p; char *p;
const char *s; const char *s;
@ -406,7 +412,7 @@ dispatch_command (ASSUAN_CONTEXT ctx, char *line, int linelen)
for (p=line; *p && *p != ' ' && *p != '\t'; p++) for (p=line; *p && *p != ' ' && *p != '\t'; p++)
; ;
if (p==line) if (p==line)
return set_error (ctx, Invalid_Command, "leading white-space"); return set_error (ctx, Syntax_Error, "leading white-space");
if (*p) if (*p)
{ /* Skip over leading WS after the keyword */ { /* Skip over leading WS after the keyword */
*p++ = 0; *p++ = 0;
@ -441,12 +447,12 @@ dispatch_command (ASSUAN_CONTEXT ctx, char *line, int linelen)
static int static int
process_request (ASSUAN_CONTEXT ctx) process_request (assuan_context_t ctx)
{ {
int rc; int rc;
if (ctx->in_inquire) if (ctx->in_inquire)
return ASSUAN_Nested_Commands; return _assuan_error (ASSUAN_Nested_Commands);
rc = _assuan_read_line (ctx); rc = _assuan_read_line (ctx);
if (rc) if (rc)
@ -477,8 +483,8 @@ process_request (ASSUAN_CONTEXT ctx)
{ {
rc = assuan_write_line (ctx, ctx->okay_line? ctx->okay_line : "OK"); rc = assuan_write_line (ctx, ctx->okay_line? ctx->okay_line : "OK");
} }
else if (rc == -1) else if (err_is_eof (rc))
{ /* No error checking because the peer may have already disconnect */ { /* No error checking because the peer may have already disconnect. */
assuan_write_line (ctx, "OK closing connection"); assuan_write_line (ctx, "OK closing connection");
ctx->finish_handler (ctx); ctx->finish_handler (ctx);
} }
@ -488,7 +494,7 @@ process_request (ASSUAN_CONTEXT ctx)
if (rc < 100) if (rc < 100)
sprintf (errline, "ERR %d server fault (%.50s)", sprintf (errline, "ERR %d server fault (%.50s)",
ASSUAN_Server_Fault, assuan_strerror (rc)); _assuan_error (ASSUAN_Server_Fault), assuan_strerror (rc));
else else
{ {
const char *text = ctx->err_no == rc? ctx->err_str:NULL; 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. strings from libgpg-error without creating a dependency.
They are used for debugging purposes only, so there is no They are used for debugging purposes only, so there is no
problem if they are not available. We need to make sure 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 weak symbol support is available in case GNU ld is not
used. */ used. */
unsigned int source, code; unsigned int source, code;
@ -552,7 +558,7 @@ process_request (ASSUAN_CONTEXT ctx)
* failed. Note, that no error is returned for operational errors. * failed. Note, that no error is returned for operational errors.
**/ **/
int int
assuan_process (ASSUAN_CONTEXT ctx) assuan_process (assuan_context_t ctx)
{ {
int rc; int rc;
@ -560,7 +566,7 @@ assuan_process (ASSUAN_CONTEXT ctx)
rc = process_request (ctx); rc = process_request (ctx);
} while (!rc); } while (!rc);
if (rc == -1) if (err_is_eof (rc))
rc = 0; rc = 0;
return rc; 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 * Return value: -1 for end of server, 0 on success or an error code
**/ **/
int int
assuan_process_next (ASSUAN_CONTEXT ctx) assuan_process_next (assuan_context_t ctx)
{ {
return process_request (ctx); return process_request (ctx);
} }
@ -603,7 +609,7 @@ assuan_process_next (ASSUAN_CONTEXT ctx)
* error which is most likely a too small fdarray. * error which is most likely a too small fdarray.
**/ **/
int 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 *fdarray, int fdarraysize)
{ {
int n = 0; 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 implementaion for systems w/o a glibc, a simple implementation
could use a child process */ could use a child process */
FILE * FILE *
assuan_get_data_fp (ASSUAN_CONTEXT ctx) assuan_get_data_fp (assuan_context_t ctx)
{ {
#if defined (HAVE_FOPENCOOKIE) || defined (HAVE_FUNOPEN) #if defined (HAVE_FOPENCOOKIE) || defined (HAVE_FUNOPEN)
if (ctx->outbound.data.fp) 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 /* Set the text used for the next OK reponse. This string is
automatically reset to NULL after the next command. */ automatically reset to NULL after the next command. */
assuan_error_t 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) if (!ctx)
return ASSUAN_Invalid_Value; return _assuan_error (ASSUAN_Invalid_Value);
if (!line) if (!line)
{ {
xfree (ctx->okay_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 */ we should allocate the entire line in secure memory */
char *buf = xtrymalloc (3+strlen(line)+1); char *buf = xtrymalloc (3+strlen(line)+1);
if (!buf) if (!buf)
return ASSUAN_Out_Of_Core; return _assuan_error (ASSUAN_Out_Of_Core);
strcpy (buf, "OK "); strcpy (buf, "OK ");
strcpy (buf+3, line); strcpy (buf+3, line);
xfree (ctx->okay_line); xfree (ctx->okay_line);
@ -685,7 +691,8 @@ assuan_set_okay_line (ASSUAN_CONTEXT ctx, const char *line)
assuan_error_t 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 buffer[256];
char *helpbuf; char *helpbuf;
@ -693,7 +700,7 @@ assuan_write_status (ASSUAN_CONTEXT ctx, const char *keyword, const char *text)
assuan_error_t ae; assuan_error_t ae;
if ( !ctx || !keyword) if ( !ctx || !keyword)
return ASSUAN_Invalid_Value; return _assuan_error (ASSUAN_Invalid_Value);
if (!text) if (!text)
text = ""; text = "";

View File

@ -15,7 +15,8 @@
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software * 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 <config.h> #include <config.h>
@ -146,14 +147,14 @@ assuan_inquire (assuan_context_t ctx, const char *keyword,
int nodataexpected; int nodataexpected;
if (!ctx || !keyword || (10 + strlen (keyword) >= sizeof (cmdbuf))) if (!ctx || !keyword || (10 + strlen (keyword) >= sizeof (cmdbuf)))
return ASSUAN_Invalid_Value; return _assuan_error (ASSUAN_Invalid_Value);
nodataexpected = !r_buffer && !r_length && !maxlen; nodataexpected = !r_buffer && !r_length && !maxlen;
if (!nodataexpected && (!r_buffer || !r_length)) if (!nodataexpected && (!r_buffer || !r_length))
return ASSUAN_Invalid_Value; return _assuan_error (ASSUAN_Invalid_Value);
if (!ctx->is_server) if (!ctx->is_server)
return ASSUAN_Not_A_Server; return _assuan_error (ASSUAN_Not_A_Server);
if (ctx->in_inquire) if (ctx->in_inquire)
return ASSUAN_Nested_Commands; return _assuan_error (ASSUAN_Nested_Commands);
ctx->in_inquire = 1; ctx->in_inquire = 1;
if (nodataexpected) if (nodataexpected)
@ -182,12 +183,12 @@ assuan_inquire (assuan_context_t ctx, const char *keyword,
break; /* END command received*/ break; /* END command received*/
if (line[0] == 'C' && line[1] == 'A' && line[2] == 'N') if (line[0] == 'C' && line[1] == 'A' && line[2] == 'N')
{ {
rc = ASSUAN_Canceled; rc = _assuan_error (ASSUAN_Canceled);
goto leave; goto leave;
} }
if (line[0] != 'D' || line[1] != ' ' || nodataexpected) if (line[0] != 'D' || line[1] != ' ' || nodataexpected)
{ {
rc = ASSUAN_Unexpected_Command; rc = _assuan_error (ASSUAN_Unexpected_Command);
goto leave; goto leave;
} }
if (linelen < 3) if (linelen < 3)
@ -214,7 +215,7 @@ assuan_inquire (assuan_context_t ctx, const char *keyword,
} }
if (mb.too_large) if (mb.too_large)
{ {
rc = ASSUAN_Too_Much_Data; rc = _assuan_error (ASSUAN_Too_Much_Data);
goto leave; goto leave;
} }
} }
@ -223,7 +224,7 @@ assuan_inquire (assuan_context_t ctx, const char *keyword,
{ {
*r_buffer = get_membuf (&mb, r_length); *r_buffer = get_membuf (&mb, r_length);
if (!*r_buffer) if (!*r_buffer)
rc = ASSUAN_Out_Of_Core; rc = _assuan_error (ASSUAN_Out_Of_Core);
} }
leave: leave:

View File

@ -1,5 +1,5 @@
/* assuan-io.c - Wraps the read and write functions. /* 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. * This file is part of Assuan.
* *
@ -15,30 +15,93 @@
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software * 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 #ifdef HAVE_CONFIG_H
#include <config.h> #include <config.h>
#endif #endif
#include "assuan-defs.h"
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <sys/socket.h>
#ifdef HAVE_W32_SYSTEM #include <sys/wait.h>
#include <windows.h> #if HAVE_SYS_UIO_H
# include <sys/uio.h>
#endif #endif
#include <unistd.h>
#include <errno.h>
#ifdef HAVE_W32_SYSTEM
# include <windows.h>
#else
# include <sys/wait.h>
#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 #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_read (int fd, void *buffer, size_t size);
extern ssize_t pth_write (int fd, const 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 #ifndef HAVE_W32_SYSTEM
#pragma weak pth_waitpid
#pragma weak pth_read #pragma weak pth_read
#pragma weak pth_write #pragma weak pth_write
#pragma weak pth_fdmode
#pragma weak pth_select
#endif #endif
#endif /*!_ASSUAN_NO_PTH*/ #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 ssize_t
_assuan_simple_read (assuan_context_t ctx, void *buffer, size_t size) _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) return pth_read ? pth_read (ctx->inbound.fd, buffer, size)
: recv (ctx->inbound.fd, buffer, size, 0); : recv (ctx->inbound.fd, buffer, size, 0);
# endif # endif
# endif #endif
} }
ssize_t ssize_t
@ -68,3 +131,87 @@ _assuan_simple_write (assuan_context_t ctx, const void *buffer, size_t size)
# endif # endif
#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
}

View File

@ -15,7 +15,8 @@
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software * 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 <config.h> #include <config.h>
@ -23,6 +24,7 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <errno.h>
#include "assuan-defs.h" #include "assuan-defs.h"
@ -30,7 +32,7 @@ assuan_error_t
assuan_set_hello_line (assuan_context_t ctx, const char *line) assuan_set_hello_line (assuan_context_t ctx, const char *line)
{ {
if (!ctx) if (!ctx)
return ASSUAN_Invalid_Value; return _assuan_error (ASSUAN_Invalid_Value);
if (!line) if (!line)
{ {
xfree (ctx->hello_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); char *buf = xtrymalloc (3+strlen(line)+1);
if (!buf) if (!buf)
return ASSUAN_Out_Of_Core; return _assuan_error (ASSUAN_Out_Of_Core);
if (strchr (line, '\n')) if (strchr (line, '\n'))
strcpy (buf, line); strcpy (buf, line);
else else
@ -73,7 +75,7 @@ assuan_accept (assuan_context_t ctx)
const char *p, *pend; const char *p, *pend;
if (!ctx) if (!ctx)
return ASSUAN_Invalid_Value; return _assuan_error (ASSUAN_Invalid_Value);
if (ctx->pipe_mode > 1) if (ctx->pipe_mode > 1)
return -1; /* second invocation for pipemode -> terminate */ return -1; /* second invocation for pipemode -> terminate */
@ -134,7 +136,7 @@ assuan_error_t
assuan_close_input_fd (assuan_context_t ctx) assuan_close_input_fd (assuan_context_t ctx)
{ {
if (!ctx || ctx->input_fd == -1) if (!ctx || ctx->input_fd == -1)
return ASSUAN_Invalid_Value; return _assuan_error (ASSUAN_Invalid_Value);
_assuan_close (ctx->input_fd); _assuan_close (ctx->input_fd);
ctx->input_fd = -1; ctx->input_fd = -1;
return 0; return 0;
@ -146,7 +148,7 @@ assuan_error_t
assuan_close_output_fd (assuan_context_t ctx) assuan_close_output_fd (assuan_context_t ctx)
{ {
if (!ctx || ctx->output_fd == -1) if (!ctx || ctx->output_fd == -1)
return ASSUAN_Invalid_Value; return _assuan_error (ASSUAN_Invalid_Value);
_assuan_close (ctx->output_fd); _assuan_close (ctx->output_fd);
ctx->output_fd = -1; ctx->output_fd = -1;

View File

@ -15,29 +15,37 @@
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software * 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 #ifdef HAVE_CONFIG_H
#include <config.h> #include <config.h>
#endif #endif
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdarg.h> #include <stdarg.h>
#ifdef HAVE_W32_SYSTEM #ifdef HAVE_W32_SYSTEM
#include <windows.h> #include <windows.h>
#endif /*HAVE_W32_SYSTEM*/ #endif /*HAVE_W32_SYSTEM*/
#include <errno.h>
#include <ctype.h>
#include "assuan-defs.h" #include "assuan-defs.h"
static char prefix_buffer[80]; static char prefix_buffer[80];
static FILE *_assuan_log; static FILE *_assuan_log;
static int full_logging;
void void
_assuan_set_default_log_stream (FILE *fp) _assuan_set_default_log_stream (FILE *fp)
{ {
if (!_assuan_log) if (!_assuan_log)
_assuan_log = fp; {
_assuan_log = fp;
full_logging = !!getenv ("ASSUAN_FULL_LOGGING");
}
} }
void void
@ -46,6 +54,22 @@ assuan_set_assuan_log_stream (FILE *fp)
_assuan_log = 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 * FILE *
assuan_get_assuan_log_stream (void) assuan_get_assuan_log_stream (void)
{ {
@ -80,18 +104,123 @@ _assuan_log_printf (const char *format, ...)
va_list arg_ptr; va_list arg_ptr;
FILE *fp; FILE *fp;
const char *prf; const char *prf;
int save_errno = errno;
fp = assuan_get_assuan_log_stream (); fp = assuan_get_assuan_log_stream ();
prf = assuan_get_assuan_log_prefix (); prf = assuan_get_assuan_log_prefix ();
if (*prf) if (*prf)
{ fprintf (fp, "%s[%u]: ", prf, (unsigned int)getpid ());
fputs (prf, fp);
fputs (": ", fp);
}
va_start (arg_ptr, format); va_start (arg_ptr, format);
vfprintf (fp, format, arg_ptr ); vfprintf (fp, format, arg_ptr );
va_end (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
} }

View File

@ -1,5 +1,5 @@
/* assuan-pipe-connect.c - Establish a pipe connection (client) /* 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. * This file is part of Assuan.
* *
@ -15,7 +15,8 @@
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software * 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 #ifdef HAVE_CONFIG_H
@ -38,6 +39,19 @@
#include "assuan-defs.h" #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 #ifdef _POSIX_OPEN_MAX
#define MAX_OPEN_FDS _POSIX_OPEN_MAX #define MAX_OPEN_FDS _POSIX_OPEN_MAX
#else #else
@ -111,6 +125,8 @@ do_finish (assuan_context_t ctx)
if (ctx->inbound.fd != -1) if (ctx->inbound.fd != -1)
{ {
_assuan_close (ctx->inbound.fd); _assuan_close (ctx->inbound.fd);
if (ctx->inbound.fd == ctx->outbound.fd)
ctx->outbound.fd = -1;
ctx->inbound.fd = -1; ctx->inbound.fd = -1;
} }
if (ctx->outbound.fd != -1) if (ctx->outbound.fd != -1)
@ -123,7 +139,7 @@ do_finish (assuan_context_t ctx)
#ifndef HAVE_W32_SYSTEM #ifndef HAVE_W32_SYSTEM
#ifndef _ASSUAN_USE_DOUBLE_FORK #ifndef _ASSUAN_USE_DOUBLE_FORK
if (!ctx->flags.no_waitpid) if (!ctx->flags.no_waitpid)
waitpid (ctx->pid, NULL, 0); _assuan_waitpid (ctx->pid, NULL, 0);
ctx->pid = -1; ctx->pid = -1;
#endif #endif
#endif /*!HAVE_W32_SYSTEM*/ #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 #ifdef HAVE_W32_SYSTEM
/* Build a command line for use with W32's CreateProcess. On success /* Build a command line for use with W32's CreateProcess. On success
CMDLINE gets the address of a newly allocated string. */ 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*/ #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 #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; assuan_error_t err;
int rp[2]; int rp[2];
int wp[2]; int wp[2];
@ -269,7 +676,7 @@ assuan_pipe_connect2 (assuan_context_t *ctx,
HANDLE nullfd = INVALID_HANDLE_VALUE; HANDLE nullfd = INVALID_HANDLE_VALUE;
if (!ctx || !name || !argv || !argv[0]) if (!ctx || !name || !argv || !argv[0])
return ASSUAN_Invalid_Value; return _assuan_error (ASSUAN_Invalid_Value);
fix_signals (); fix_signals ();
@ -277,13 +684,13 @@ assuan_pipe_connect2 (assuan_context_t *ctx,
/* Build the command line. */ /* Build the command line. */
if (build_w32_commandline (argv, &cmdline)) if (build_w32_commandline (argv, &cmdline))
return ASSUAN_Out_Of_Core; return _assuan_error (ASSUAN_Out_Of_Core);
/* Create thew two pipes. */ /* Create thew two pipes. */
if (create_inheritable_pipe (rp, 0)) if (create_inheritable_pipe (rp, 0))
{ {
xfree (cmdline); xfree (cmdline);
return ASSUAN_General_Error; return _assuan_error (ASSUAN_General_Error);
} }
if (create_inheritable_pipe (wp, 1)) 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[0]));
CloseHandle (fd_to_handle (rp[1])); CloseHandle (fd_to_handle (rp[1]));
xfree (cmdline); 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[0]));
CloseHandle (fd_to_handle (wp[1])); CloseHandle (fd_to_handle (wp[1]));
xfree (cmdline); xfree (cmdline);
return ASSUAN_General_Error; return _assuan_error (ASSUAN_General_Error);
} }
(*ctx)->pipe_mode = 1; (*ctx)->pipe_mode = 1;
@ -390,7 +797,7 @@ assuan_pipe_connect2 (assuan_context_t *ctx,
CloseHandle (nullfd); CloseHandle (nullfd);
xfree (cmdline); xfree (cmdline);
_assuan_release_context (*ctx); _assuan_release_context (*ctx);
return ASSUAN_General_Error; return _assuan_error (ASSUAN_General_Error);
} }
xfree (cmdline); xfree (cmdline);
cmdline = NULL; cmdline = NULL;
@ -413,200 +820,11 @@ assuan_pipe_connect2 (assuan_context_t *ctx,
(*ctx)->pid = 0; /* We don't use the PID. */ (*ctx)->pid = 0; /* We don't use the PID. */
CloseHandle (pi.hProcess); /* We don't need to wait for the process. */ CloseHandle (pi.hProcess); /* We don't need to wait for the process. */
#else /*!HAVE_W32_SYSTEM*/ return initial_handshake (ctx);
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;
} }
#endif /*HAVE_W32_SYSTEM*/
/* Connect to a server over a pipe, creating the assuan context and /* Connect to a server over a pipe, creating the assuan context and
returning it in CTX. The server filename is NAME, the argument returning it in CTX. The server filename is NAME, the argument
vector in ARGV. FD_CHILD_LIST is a -1 terminated list of file 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, assuan_pipe_connect (assuan_context_t *ctx, const char *name,
const char *const argv[], int *fd_child_list) 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);
}

View File

@ -15,12 +15,15 @@
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software * 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 <config.h> #include <config.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
#ifdef HAVE_W32_SYSTEM #ifdef HAVE_W32_SYSTEM
#include <windows.h> #include <windows.h>
@ -31,20 +34,20 @@
static void static void
deinit_pipe_server (ASSUAN_CONTEXT ctx) deinit_pipe_server (assuan_context_t ctx)
{ {
/* nothing to do for this simple server */ /* nothing to do for this simple server */
} }
static int static int
accept_connection (ASSUAN_CONTEXT ctx) accept_connection (assuan_context_t ctx)
{ {
/* This is a NOP for a pipe server */ /* This is a NOP for a pipe server */
return 0; return 0;
} }
static int static int
finish_connection (ASSUAN_CONTEXT ctx) finish_connection (assuan_context_t ctx)
{ {
/* This is a NOP for a pipe server */ /* This is a NOP for a pipe server */
return 0; 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 /* 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 */ server/client - this way we don't need extra dummy functions */
int int
_assuan_new_context (ASSUAN_CONTEXT *r_ctx) _assuan_new_context (assuan_context_t *r_ctx)
{ {
static struct assuan_io io = { _assuan_simple_read, static struct assuan_io io = { _assuan_simple_read,
_assuan_simple_write, _assuan_simple_write,
0, 0 }; 0, 0 };
ASSUAN_CONTEXT ctx; assuan_context_t ctx;
int rc; int rc;
*r_ctx = NULL; *r_ctx = NULL;
ctx = xtrycalloc (1, sizeof *ctx); ctx = xtrycalloc (1, sizeof *ctx);
if (!ctx) if (!ctx)
return ASSUAN_Out_Of_Core; return _assuan_error (ASSUAN_Out_Of_Core);
ctx->input_fd = -1; ctx->input_fd = -1;
ctx->output_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 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; int rc;
rc = _assuan_new_context (r_ctx); rc = _assuan_new_context (r_ctx);
if (!rc) if (!rc)
{ {
ASSUAN_CONTEXT ctx = *r_ctx; assuan_context_t ctx = *r_ctx;
const char *s; const char *s;
unsigned long ul; 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->inbound.fd = _get_osfhandle (filedes[0]);
ctx->outbound.fd = _get_osfhandle (filedes[1]); ctx->outbound.fd = _get_osfhandle (filedes[1]);
#else #else
ctx->inbound.fd = filedes[0]; s = getenv ("_assuan_connection_fd");
ctx->outbound.fd = filedes[1]; 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 #endif
ctx->pipe_mode = 1; ctx->pipe_mode = 1;
@ -127,7 +162,7 @@ assuan_init_pipe_server (ASSUAN_CONTEXT *r_ctx, int filedes[2])
void void
_assuan_release_context (ASSUAN_CONTEXT ctx) _assuan_release_context (assuan_context_t ctx)
{ {
if (ctx) if (ctx)
{ {
@ -138,7 +173,7 @@ _assuan_release_context (ASSUAN_CONTEXT ctx)
} }
void void
assuan_deinit_server (ASSUAN_CONTEXT ctx) assuan_deinit_server (assuan_context_t ctx)
{ {
if (ctx) if (ctx)
{ {

View File

@ -15,7 +15,8 @@
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software * 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 <config.h> #include <config.h>
@ -54,7 +55,7 @@
static int static int
do_finish (ASSUAN_CONTEXT ctx) do_finish (assuan_context_t ctx)
{ {
if (ctx->inbound.fd != -1) if (ctx->inbound.fd != -1)
{ {
@ -66,56 +67,70 @@ do_finish (ASSUAN_CONTEXT ctx)
} }
static void static void
do_deinit (ASSUAN_CONTEXT ctx) do_deinit (assuan_context_t ctx)
{ {
do_finish (ctx); do_finish (ctx);
} }
/* Make a connection to the Unix domain socket NAME and return a new /* 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 Assuan context in CTX. SERVER_PID is currently not used but may
become handy in the future. */ become handy in the future. */
assuan_error_t 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) 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, static struct assuan_io io = { _assuan_simple_read,
_assuan_simple_write }; _assuan_simple_write };
assuan_error_t err; assuan_error_t err;
ASSUAN_CONTEXT ctx; assuan_context_t ctx;
int fd; int fd;
struct sockaddr_un srvr_addr; struct sockaddr_un srvr_addr;
size_t len; size_t len;
const char *s; const char *s;
if (!r_ctx || !name) if (!r_ctx || !name)
return ASSUAN_Invalid_Value; return _assuan_error (ASSUAN_Invalid_Value);
*r_ctx = NULL; *r_ctx = NULL;
/* We require that the name starts with a slash, so that we can /* We require that the name starts with a slash, so that we
alter reuse this function for other socket types. To make things eventually can reuse this function for other socket types. To
easier we allow an optional dirver prefix. */ make things easier we allow an optional dirver prefix. */
s = name; s = name;
if (*s && s[1] == ':') if (*s && s[1] == ':')
s += 2; s += 2;
if (*s != DIRSEP_C && *s != '/') if (*s != DIRSEP_C && *s != '/')
return ASSUAN_Invalid_Value; return _assuan_error (ASSUAN_Invalid_Value);
if (strlen (name)+1 >= sizeof srvr_addr.sun_path) if (strlen (name)+1 >= sizeof srvr_addr.sun_path)
return ASSUAN_Invalid_Value; return _assuan_error (ASSUAN_Invalid_Value);
err = _assuan_new_context (&ctx); err = _assuan_new_context (&ctx);
if (err) if (err)
return err; return err;
ctx->deinit_handler = do_deinit; ctx->deinit_handler = ((flags&1))? _assuan_uds_deinit : do_deinit;
ctx->finish_handler = do_finish; ctx->finish_handler = do_finish;
fd = _assuan_sock_new (PF_LOCAL, SOCK_STREAM, 0); fd = _assuan_sock_new (PF_LOCAL, SOCK_STREAM, 0);
if (fd == -1) if (fd == -1)
{ {
_assuan_log_printf ("can't create socket: %s\n", strerror (errno)); _assuan_log_printf ("can't create socket: %s\n", strerror (errno));
_assuan_release_context (ctx); _assuan_release_context (ctx);
return ASSUAN_General_Error; return _assuan_error (ASSUAN_General_Error);
} }
memset (&srvr_addr, 0, sizeof srvr_addr); memset (&srvr_addr, 0, sizeof srvr_addr);
@ -131,12 +146,14 @@ assuan_socket_connect (ASSUAN_CONTEXT *r_ctx,
name, strerror (errno)); name, strerror (errno));
_assuan_release_context (ctx); _assuan_release_context (ctx);
_assuan_close (fd); _assuan_close (fd);
return ASSUAN_Connect_Failed; return _assuan_error (ASSUAN_Connect_Failed);
} }
ctx->inbound.fd = fd; ctx->inbound.fd = fd;
ctx->outbound.fd = fd; ctx->outbound.fd = fd;
ctx->io = &io; ctx->io = &io;
if ((flags&1))
_assuan_init_uds_io (ctx);
/* initial handshake */ /* initial handshake */
{ {
@ -151,7 +168,7 @@ assuan_socket_connect (ASSUAN_CONTEXT *r_ctx,
/*LOG ("can't connect to server: `");*/ /*LOG ("can't connect to server: `");*/
_assuan_log_sanitized_string (ctx->inbound.line); _assuan_log_sanitized_string (ctx->inbound.line);
fprintf (assuan_get_assuan_log_stream (), "'\n"); 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; *r_ctx = ctx;
return 0; return 0;
} }

View File

@ -15,7 +15,8 @@
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software * 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 <config.h> #include <config.h>
@ -33,21 +34,33 @@
#include "assuan-defs.h" #include "assuan-defs.h"
static struct assuan_io io = { _assuan_simple_read,
_assuan_simple_write };
static int static int
accept_connection_bottom (assuan_context_t ctx) accept_connection_bottom (assuan_context_t ctx)
{ {
int fd = ctx->connected_fd; int fd = ctx->connected_fd;
ctx->peercred.valid = 0;
#ifdef HAVE_SO_PEERCRED #ifdef HAVE_SO_PEERCRED
{ {
/* This overrides any already set PID if the function returns a
valid one. */
struct ucred cr; struct ucred cr;
int cl = sizeof cr; socklen_t cl = sizeof cr;
if ( !getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &cr, &cl) if ( !getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &cr, &cl))
&& cr.pid != (pid_t)-1 && cr.pid ) {
ctx->pid = cr.pid; 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 #endif
@ -72,13 +85,13 @@ accept_connection (assuan_context_t ctx)
{ {
int fd; int fd;
struct sockaddr_un clnt_addr; 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 ); fd = accept (ctx->listen_fd, (struct sockaddr*)&clnt_addr, &len );
if (fd == -1) if (fd == -1)
{ {
ctx->os_errno = errno; ctx->os_errno = errno;
return ASSUAN_Accept_Failed; return _assuan_error (ASSUAN_Accept_Failed);
} }
ctx->connected_fd = fd; ctx->connected_fd = fd;
@ -104,47 +117,30 @@ deinit_socket_server (assuan_context_t ctx)
finish_connection (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 /* Initialize a server for the socket LISTEN_FD which has already be
put into listen mode */ put into listen mode */
int int
assuan_init_socket_server (assuan_context_t *r_ctx, int listen_fd) assuan_init_socket_server (assuan_context_t *r_ctx, int listen_fd)
{ {
assuan_context_t ctx; return assuan_init_socket_server_ext (r_ctx, listen_fd, 0);
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;
} }
/* Initialize a server using the already accepted socket FD. */ /* Initialize a server using the already accepted socket FD. This
fucntion is deprecated. */
int int
assuan_init_connected_socket_server (assuan_context_t *r_ctx, int fd) 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; assuan_context_t ctx;
int rc; int rc;
@ -152,23 +148,36 @@ assuan_init_connected_socket_server (assuan_context_t *r_ctx, int fd)
*r_ctx = NULL; *r_ctx = NULL;
ctx = xtrycalloc (1, sizeof *ctx); ctx = xtrycalloc (1, sizeof *ctx);
if (!ctx) if (!ctx)
return ASSUAN_Out_Of_Core; return _assuan_error (ASSUAN_Out_Of_Core);
ctx->is_server = 1; 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->input_fd = -1;
ctx->output_fd = -1; ctx->output_fd = -1;
ctx->inbound.fd = -1; ctx->inbound.fd = -1;
ctx->outbound.fd = -1; ctx->outbound.fd = -1;
ctx->io = &io; if ((flags & 2))
{
ctx->listen_fd = -1; ctx->listen_fd = -1;
ctx->connected_fd = fd; ctx->connected_fd = fd;
ctx->deinit_handler = deinit_socket_server; }
ctx->accept_handler = accept_connection_bottom; 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->finish_handler = finish_connection;
ctx->io = &io;
if ((flags & 1))
_assuan_init_uds_io (ctx);
rc = _assuan_register_std_commands (ctx); rc = _assuan_register_std_commands (ctx);
if (rc) if (rc)
xfree (ctx); xfree (ctx);
@ -176,5 +185,3 @@ assuan_init_connected_socket_server (assuan_context_t *r_ctx, int fd)
*r_ctx = ctx; *r_ctx = ctx;
return rc; return rc;
} }

View File

@ -1,22 +1,24 @@
/* assuan-socket.c /* 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 * Assuan is free software; you can redistribute it and/or modify it
* it under the terms of the GNU General Public License as published by * under the terms of the GNU Lesser General Public License as
* the Free Software Foundation; either version 2 of the License, or * published by the Free Software Foundation; either version 2.1 of
* (at your option) any later version. * the License, or (at your option) any later version.
* *
* GnuPG is distributed in the hope that it will be useful, * Assuan is distributed in the hope that it will be useful, but
* but WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* GNU General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU Lesser General Public
* along with this program; if not, write to the Free Software * 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 <config.h> #include <config.h>
#include <stdio.h> #include <stdio.h>
#ifdef HAVE_W32_SYSTEM #ifdef HAVE_W32_SYSTEM
@ -28,6 +30,18 @@
#endif #endif
#include "assuan-defs.h" #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 int
_assuan_close (int fd) _assuan_close (int fd)
{ {

285
assuan/assuan-uds.c Normal file
View File

@ -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 <config.h>
#endif
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#ifndef HAVE_W32_SYSTEM
#include <sys/socket.h>
#include <sys/un.h>
#else
#include <windows.h>
#endif
#if HAVE_SYS_UIO_H
#include <sys/uio.h>
#endif
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <assert.h>
#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;
}

View File

@ -15,7 +15,8 @@
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software * 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 <config.h> #include <config.h>
@ -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 void
assuan_begin_confidential (assuan_context_t ctx) 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
}

View File

@ -15,7 +15,8 @@
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software * 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 #ifndef ASSUAN_H
@ -26,24 +27,32 @@
#include <unistd.h> #include <unistd.h>
/* To use this file with libraries the following macros are often /* To use this file with libraries the following macros are useful:
useful:
#define _ASSUAN_EXT_SYM_PREFIX _foo_ #define _ASSUAN_EXT_SYM_PREFIX _foo_
This prefixes all external symbols with "_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. ******/ /**** Begin GPGME specific modifications. ******/
#define _ASSUAN_EXT_SYM_PREFIX _gpgme_ #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_socket_server _ASSUAN_PREFIX(assuan_init_socket_server)
#define assuan_init_connected_socket_server \ #define assuan_init_connected_socket_server \
_ASSUAN_PREFIX(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 _ASSUAN_PREFIX(assuan_pipe_connect)
#define assuan_pipe_connect_ext _ASSUAN_PREFIX(assuan_pipe_connect_ext)
#define assuan_socket_connect _ASSUAN_PREFIX(assuan_socket_connect) #define assuan_socket_connect _ASSUAN_PREFIX(assuan_socket_connect)
#define assuan_domain_connect _ASSUAN_PREFIX(assuan_domain_connect) #define assuan_socket_connect_ext _ASSUAN_PREFIX(assuan_socket_connect_ext)
#define assuan_init_domain_server _ASSUAN_PREFIX(assuan_init_domain_server)
#define assuan_disconnect _ASSUAN_PREFIX(assuan_disconnect) #define assuan_disconnect _ASSUAN_PREFIX(assuan_disconnect)
#define assuan_get_pid _ASSUAN_PREFIX(assuan_get_pid) #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_transact _ASSUAN_PREFIX(assuan_transact)
#define assuan_inquire _ASSUAN_PREFIX(assuan_inquire) #define assuan_inquire _ASSUAN_PREFIX(assuan_inquire)
#define assuan_read_line _ASSUAN_PREFIX(assuan_read_line) #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_begin_confidential _ASSUAN_PREFIX(assuan_begin_confidential)
#define assuan_end_confidential _ASSUAN_PREFIX(assuan_end_confidential) #define assuan_end_confidential _ASSUAN_PREFIX(assuan_end_confidential)
#define assuan_strerror _ASSUAN_PREFIX(assuan_strerror) #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 \ #define assuan_set_assuan_log_stream \
_ASSUAN_PREFIX(assuan_set_assuan_log_stream) _ASSUAN_PREFIX(assuan_set_assuan_log_stream)
#define assuan_get_assuan_log_stream \ #define assuan_get_assuan_log_stream \
@ -189,89 +203,121 @@ extern "C"
#endif #endif
typedef enum /* Check for compiler features. */
{ #if __GNUC__
ASSUAN_No_Error = 0, #define _ASSUAN_GCC_VERSION (__GNUC__ * 10000 \
ASSUAN_General_Error = 1, + __GNUC_MINOR__ * 100 \
ASSUAN_Out_Of_Core = 2, + __GNUC_PATCHLEVEL__)
ASSUAN_Invalid_Value = 3,
ASSUAN_Timeout = 4, #if _ASSUAN_GCC_VERSION > 30100
ASSUAN_Read_Error = 5, #define _ASSUAN_DEPRECATED __attribute__ ((__deprecated__))
ASSUAN_Write_Error = 6, #endif
ASSUAN_Problem_Starting_Server = 7, #endif
ASSUAN_Not_A_Server = 8, #ifndef _ASSUAN_DEPRECATED
ASSUAN_Not_A_Client = 9, #define _ASSUAN_DEPRECATED
ASSUAN_Nested_Commands = 10, #endif
ASSUAN_Invalid_Response = 11,
ASSUAN_No_Data_Callback = 12,
ASSUAN_No_Inquire_Callback = 13, /* Assuan error codes. These are only used by old applications or
ASSUAN_Connect_Failed = 14, those applications which won't make use of libgpg-error. */
ASSUAN_Accept_Failed = 15, #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 */ /* Error codes above 99 are meant as status codes */
ASSUAN_Not_Implemented = 100, #define ASSUAN_Not_Implemented 100
ASSUAN_Server_Fault = 101, #define ASSUAN_Server_Fault 101
ASSUAN_Invalid_Command = 102, #ifndef _ASSUAN_IN_LIBASSUAN
ASSUAN_Unknown_Command = 103, #define ASSUAN_Invalid_Command 102
ASSUAN_Syntax_Error = 104, #endif
ASSUAN_Parameter_Error = 105, #define ASSUAN_Unknown_Command 103
ASSUAN_Parameter_Conflict = 106, #define ASSUAN_Syntax_Error 104
ASSUAN_Line_Too_Long = 107, #ifndef _ASSUAN_IN_LIBASSUAN
ASSUAN_Line_Not_Terminated = 108, #define ASSUAN_Parameter_Error 105
ASSUAN_No_Input = 109, #endif
ASSUAN_No_Output = 110, #define ASSUAN_Parameter_Conflict 106
ASSUAN_Canceled = 111, #define ASSUAN_Line_Too_Long 107
ASSUAN_Unsupported_Algorithm = 112, #define ASSUAN_Line_Not_Terminated 108
ASSUAN_Server_Resource_Problem = 113, #ifndef _ASSUAN_IN_LIBASSUAN
ASSUAN_Server_IO_Error = 114, #define ASSUAN_No_Input 109
ASSUAN_Server_Bug = 115, #define ASSUAN_No_Output 110
ASSUAN_No_Data_Available = 116, #endif
ASSUAN_Invalid_Data = 117, #define ASSUAN_Canceled 111
ASSUAN_Unexpected_Command = 118, #ifndef _ASSUAN_IN_LIBASSUAN
ASSUAN_Too_Much_Data = 119, #define ASSUAN_Unsupported_Algorithm 112
ASSUAN_Inquire_Unknown = 120, #define ASSUAN_Server_Resource_Problem 113
ASSUAN_Inquire_Error = 121, #define ASSUAN_Server_IO_Error 114
ASSUAN_Invalid_Option = 122, #define ASSUAN_Server_Bug 115
ASSUAN_Invalid_Index = 123, #define ASSUAN_No_Data_Available 116
ASSUAN_Unexpected_Status = 124, #define ASSUAN_Invalid_Data 117
ASSUAN_Unexpected_Data = 125, #endif
ASSUAN_Invalid_Status = 126, #define ASSUAN_Unexpected_Command 118
ASSUAN_Locale_Problem = 127, #define ASSUAN_Too_Much_Data 119
ASSUAN_Not_Confirmed = 128, #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 rror codes, below they are deprecated. */ /* Warning: Don't use the Error codes, below they are deprecated. */
ASSUAN_Bad_Certificate = 201, #define ASSUAN_Bad_Certificate 201
ASSUAN_Bad_Certificate_Chain = 202, #define ASSUAN_Bad_Certificate_Chain 202
ASSUAN_Missing_Certificate = 203, #define ASSUAN_Missing_Certificate 203
ASSUAN_Bad_Signature = 204, #define ASSUAN_Bad_Signature 204
ASSUAN_No_Agent = 205, #define ASSUAN_No_Agent 205
ASSUAN_Agent_Error = 206, #define ASSUAN_Agent_Error 206
ASSUAN_No_Public_Key = 207, #define ASSUAN_No_Public_Key 207
ASSUAN_No_Secret_Key = 208, #define ASSUAN_No_Secret_Key 208
ASSUAN_Invalid_Name = 209, #define ASSUAN_Invalid_Name 209
ASSUAN_Cert_Revoked = 301, #define ASSUAN_Cert_Revoked 301
ASSUAN_No_CRL_For_Cert = 302, #define ASSUAN_No_CRL_For_Cert 302
ASSUAN_CRL_Too_Old = 303, #define ASSUAN_CRL_Too_Old 303
ASSUAN_Not_Trusted = 304, #define ASSUAN_Not_Trusted 304
ASSUAN_Card_Error = 401, #define ASSUAN_Card_Error 401
ASSUAN_Invalid_Card = 402, #define ASSUAN_Invalid_Card 402
ASSUAN_No_PKCS15_App = 403, #define ASSUAN_No_PKCS15_App 403
ASSUAN_Card_Not_Present = 404, #define ASSUAN_Card_Not_Present 404
ASSUAN_Invalid_Id = 405, #define ASSUAN_Invalid_Id 405
/* Error codes in the range 1000 to 9999 may be used by applications /* Error codes in the range 1000 to 9999 may be used by applications
at their own discretion. */ at their own discretion. */
ASSUAN_USER_ERROR_FIRST = 1000, #define ASSUAN_USER_ERROR_FIRST 1000
ASSUAN_USER_ERROR_LAST = 9999 #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 */ /* 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. */ compatibility reasons. */
typedef enum typedef enum
{ {
@ -290,6 +336,13 @@ typedef enum
} AssuanCommand; } AssuanCommand;
#else /*!_ASSUAN_ONLY_GPG_ERRORS*/
typedef int assuan_error_t;
#endif /*!_ASSUAN_ONLY_GPG_ERRORS*/
/* Definitions of flags for assuan_set_flag(). */ /* Definitions of flags for assuan_set_flag(). */
typedef enum typedef enum
{ {
@ -306,7 +359,9 @@ assuan_flag_t;
struct assuan_context_s; struct assuan_context_s;
typedef struct assuan_context_s *assuan_context_t; 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 --*/ /*-- assuan-handler.c --*/
int assuan_register_command (assuan_context_t ctx, 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 file descriptor via CTX and stores it in *RDF (the CTX must be
capable of passing file descriptors). */ capable of passing file descriptors). */
assuan_error_t assuan_command_parse_fd (assuan_context_t ctx, char *line, assuan_error_t assuan_command_parse_fd (assuan_context_t ctx, char *line,
int *rfd); int *rfd);
/*-- assuan-listen.c --*/ /*-- assuan-listen.c --*/
assuan_error_t assuan_set_hello_line (assuan_context_t ctx, const char *line); 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 --*/ /*-- assuan-socket-server.c --*/
int assuan_init_socket_server (assuan_context_t *r_ctx, int listen_fd); int assuan_init_socket_server (assuan_context_t *r_ctx, 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-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[], const char *const argv[],
int *fd_child_list); 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[], const char *const argv[],
int *fd_child_list, int *fd_child_list,
void (*atfork) (void*, int), 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-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); pid_t server_pid);
assuan_error_t assuan_socket_connect_ext (assuan_context_t *ctx,
/*-- assuan-domain-connect.c --*/ const char *name,
pid_t server_pid,
/* Connect to a Unix domain socket server. RENDEZVOUSFD is unsigned int flags);
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-connect.c --*/ /*-- assuan-connect.c --*/
void assuan_disconnect (assuan_context_t ctx); void assuan_disconnect (assuan_context_t ctx);
pid_t assuan_get_pid (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-client.c --*/
assuan_error_t assuan_error_t
assuan_transact (assuan_context_t ctx, assuan_transact (assuan_context_t ctx,
const char *command, 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, void *data_cb_arg,
assuan_error_t (*inquire_cb)(void*, const char *), int (*inquire_cb)(void*, const char *),
void *inquire_cb_arg, void *inquire_cb_arg,
assuan_error_t (*status_cb)(void*, const char *), int (*status_cb)(void*, const char *),
void *status_cb_arg); void *status_cb_arg);
@ -426,9 +480,8 @@ assuan_error_t assuan_send_data (assuan_context_t ctx,
const void *buffer, size_t length); const void *buffer, size_t length);
/* The file descriptor must be pending before assuan_receivefd is /* The file descriptor must be pending before assuan_receivefd is
call. This means that assuan_sendfd should be called *before* the called. This means that assuan_sendfd should be called *before* the
trigger is sent (normally via assuan_send_data ("I sent you a trigger is sent (normally via assuan_write_line ("INPUT FD")). */
descriptor")). */
assuan_error_t assuan_sendfd (assuan_context_t ctx, int fd); assuan_error_t assuan_sendfd (assuan_context_t ctx, int fd);
assuan_error_t assuan_receivefd (assuan_context_t ctx, int *fd); assuan_error_t assuan_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); 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); 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 --*/ /*-- assuan-logging.c --*/

View File

@ -1,21 +1,22 @@
/* funopen.c - Replacement for funopen. /* 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 * Assuan is free software; you can redistribute it and/or modify it
* it under the terms of the GNU General Public License as published by * under the terms of the GNU Lesser General Public License as
* the Free Software Foundation; either version 2 of the License, or * published by the Free Software Foundation; either version 2.1 of
* (at your option) any later version. * the License, or (at your option) any later version.
* *
* GnuPG is distributed in the hope that it will be useful, * Assuan is distributed in the hope that it will be useful, but
* but WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* GNU General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU Lesser General Public
* along with this program; if not, write to the Free Software * 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 #ifdef HAVE_CONFIG_H
@ -54,7 +55,7 @@ _assuan_funopen(void *cookie,
io.seek = seekfn; io.seek = seekfn;
io.close = closefn; io.close = closefn;
return fopencookie (cookie, return fopencookie (cookie,
readfn ? ( writefn ? "rw" : "r" ) readfn ? ( writefn ? "rw" : "r" )
: ( writefn ? "w" : ""), io); : ( writefn ? "w" : ""), io);
} }

View File

@ -1,7 +1,7 @@
#!/bin/sh #!/bin/sh
# mkerrors - Extract error strings from assuan.h # mkerrors - Extract error strings from assuan.h
# and create C source for assuan_strerror # 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. # This file is part of Assuan.
# #
@ -17,19 +17,118 @@
# #
# You should have received a copy of the GNU Lesser General Public # You should have received a copy of the GNU Lesser General Public
# License along with this program; if not, write to the Free Software # 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 <<EOF cat <<EOF
/* Generated automatically by mkerrors */ /* Generated automatically by mkerrors */
/* Do not edit! */ /* Do not edit! See mkerrors for copyright notice. */
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include <config.h> #include <config.h>
#endif #endif
#include <stdio.h> #include <stdio.h>
#include <assert.h>
#include <errno.h>
#undef _ASSUAN_IN_LIBASSUAN /* undef to get all error codes. */
#include "assuan.h" #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: * assuan_strerror:
* @err: Error code * @err: Error code
@ -41,7 +140,7 @@ cat <<EOF
* Return value: String with the error description. * Return value: String with the error description.
**/ **/
const char * const char *
assuan_strerror (AssuanError err) assuan_strerror (assuan_error_t err)
{ {
const char *s; const char *s;
static char buf[50]; static char buf[50];
@ -51,10 +150,10 @@ assuan_strerror (AssuanError err)
EOF EOF
awk ' awk '
/ASSUAN_No_Error/ { okay=1 } /ASSUAN_No_Error/ { okay=1 }
!okay {next} !okay {next}
/}/ { exit 0 } /^#define[ ]+ASSUAN_[A-Za-z_]*/ { print_code($2) }
/ASSUAN_[A-Za-z_]*/ { print_code($1) } /ASSUAN_USER_ERROR_LAST/ { exit 0 }
function print_code( s ) function print_code( s )
@ -66,18 +165,59 @@ printf "%s\"; break;\n", tolower(substr(s,8));
' '
cat <<EOF cat <<EOF
case -1: s = "EOF (-1)"; break;
default: default:
{ {
unsigned int source, code; unsigned int source, code, n;
source = ((err >> 24) & 0xff); source = ((err >> 24) & 0xff);
code = (err & 0x00ffffff); code = (err & 0x00ffffff);
if (source) /* Assume this is an libgpg-error. */ if (source)
sprintf (buf, "ec=%u.%u", source, code ); {
/* 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 else
sprintf (buf, "ec=%d", err ); {
s=buf; break; sprintf (buf, "ec=%d", err );
s=buf;
}
} }
break;
} }
return s; return s;

View File

@ -202,8 +202,6 @@ AC_SUBST(NETLIBS)
# Checks for library functions. # Checks for library functions.
AC_FUNC_FSEEKO AC_FUNC_FSEEKO
AC_CHECK_FUNCS(stpcpy)
AC_REPLACE_FUNCS(vasprintf) AC_REPLACE_FUNCS(vasprintf)
if test "$ac_cv_func_vasprintf" != yes; then if test "$ac_cv_func_vasprintf" != yes; then
GNUPG_CHECK_VA_COPY GNUPG_CHECK_VA_COPY
@ -462,6 +460,10 @@ fi
AC_REPLACE_FUNCS(isascii) AC_REPLACE_FUNCS(isascii)
AC_REPLACE_FUNCS(putc_unlocked) AC_REPLACE_FUNCS(putc_unlocked)
AC_REPLACE_FUNCS(memrchr) 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. # More assuan checks.
AC_CHECK_HEADERS([sys/uio.h]) AC_CHECK_HEADERS([sys/uio.h])

View File

@ -72,7 +72,7 @@ extern "C" {
AM_PATH_GPGME macro) check that this header matches the installed AM_PATH_GPGME macro) check that this header matches the installed
library. Warning: Do not edit the next line. configure will do library. Warning: Do not edit the next line. configure will do
that for you! */ that for you! */
#define GPGME_VERSION "1.1.1-cvs1150" #define GPGME_VERSION "1.1.3-cvs1179"

352
gpgme/setenv.c Normal file
View File

@ -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 <config.h>
#endif
#include "assuan-defs.h"
#define __builtin_expect(cond,val) (cond)
#include <errno.h>
#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 <stdlib.h>
#endif
#if _LIBC || HAVE_STRING_H
# include <string.h>
#endif
#if _LIBC || HAVE_UNISTD_H
# include <unistd.h>
#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 <bits/libc-lock.h>
__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 <search.h>
/* 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