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.
+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>
* configure.ac: Check for network libraries and set NETLIBS.
+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>
* assuan.h (assuan_pipe_connect, assuan_pipe_connect2): Make type
#
# You should have received a copy of the GNU Lesser General Public
# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
## Process this file with automake to produce Makefile.in
assuan-socket-server.c \
assuan-pipe-connect.c \
assuan-socket-connect.c \
- assuan-socket.c \
+ assuan-uds.c \
funopen.c \
assuan-io.c \
- assuan-domain-connect.c \
- assuan-domain-server.c \
- assuan-logging.c
+ assuan-logging.c \
+ assuan-socket.c
-assuan-errors.c : assuan.h
+assuan-errors.c : assuan.h mkerrors
$(srcdir)/mkerrors < $(srcdir)/assuan.h > assuan-errors.c
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
*/
#include <config.h>
#endif
#include "assuan-defs.h"
+
+/* Extended version of write(2) to guarantee that all bytes are
+ written. Returns 0 on success or -1 and ERRNO on failure. */
static int
-writen (ASSUAN_CONTEXT ctx, const char *buffer, size_t length)
+writen (assuan_context_t ctx, const char *buffer, size_t length)
{
while (length)
{
return 0; /* okay */
}
-/* Read an entire line. */
+/* Read an entire line. Returns 0 on success or -1 and ERRNo on
+ failure. EOF is indictated by setting the integer at address
+ R_EOF. */
static int
-readline (ASSUAN_CONTEXT ctx, char *buf, size_t buflen,
+readline (assuan_context_t ctx, char *buf, size_t buflen,
int *r_nread, int *r_eof)
{
size_t nleft = buflen;
}
-int
-_assuan_read_line (ASSUAN_CONTEXT ctx)
+/* Function returns an Assuan error. */
+assuan_error_t
+_assuan_read_line (assuan_context_t ctx)
{
char *line = ctx->inbound.line;
int nread, atticlen;
char *endp = 0;
if (ctx->inbound.eof)
- return -1;
+ return _assuan_error (-1);
atticlen = ctx->inbound.attic.linelen;
if (atticlen)
if (rc)
{
if (ctx->log_fp)
- fprintf (ctx->log_fp, "%s[%u.%p] DBG: <- [Error: %s]\n",
+ fprintf (ctx->log_fp, "%s[%u.%d] DBG: <- [Error: %s]\n",
assuan_get_assuan_log_prefix (),
- (unsigned int)getpid (), ctx, strerror (errno));
- return ASSUAN_Read_Error;
+ (unsigned int)getpid (), ctx->inbound.fd,
+ strerror (errno));
+ return _assuan_error (ASSUAN_Read_Error);
}
if (!nread)
{
assert (ctx->inbound.eof);
if (ctx->log_fp)
- fprintf (ctx->log_fp, "%s[%u.%p] DBG: <- [EOF]\n",
+ fprintf (ctx->log_fp, "%s[%u.%d] DBG: <- [EOF]\n",
assuan_get_assuan_log_prefix (),
- (unsigned int)getpid (), ctx);
- return -1;
+ (unsigned int)getpid (), ctx->inbound.fd);
+ return _assuan_error (-1);
}
ctx->inbound.attic.pending = 0;
ctx->inbound.linelen = endp - line;
if (ctx->log_fp)
{
- fprintf (ctx->log_fp, "%s[%u.%p] DBG: <- ",
+ fprintf (ctx->log_fp, "%s[%u.%d] DBG: <- ",
assuan_get_assuan_log_prefix (),
- (unsigned int)getpid (), ctx);
+ (unsigned int)getpid (), ctx->inbound.fd);
if (ctx->confidential)
fputs ("[Confidential data not shown]", ctx->log_fp);
else
else
{
if (ctx->log_fp)
- fprintf (ctx->log_fp, "%s[%u.%p] DBG: <- [Invalid line]\n",
+ fprintf (ctx->log_fp, "%s[%u.%d] DBG: <- [Invalid line]\n",
assuan_get_assuan_log_prefix (),
- (unsigned int)getpid (), ctx);
+ (unsigned int)getpid (), ctx->inbound.fd);
*line = 0;
ctx->inbound.linelen = 0;
- return ctx->inbound.eof ? ASSUAN_Line_Not_Terminated
- : ASSUAN_Line_Too_Long;
+ return _assuan_error (ctx->inbound.eof
+ ? ASSUAN_Line_Not_Terminated
+ : ASSUAN_Line_Too_Long);
}
}
See also: assuan_pending_line().
*/
assuan_error_t
-assuan_read_line (ASSUAN_CONTEXT ctx, char **line, size_t *linelen)
+assuan_read_line (assuan_context_t ctx, char **line, size_t *linelen)
{
assuan_error_t err;
if (!ctx)
- return ASSUAN_Invalid_Value;
+ return _assuan_error (ASSUAN_Invalid_Value);
err = _assuan_read_line (ctx);
*line = ctx->inbound.line;
/* Return true if a full line is buffered (i.e. an entire line may be
read without any I/O). */
int
-assuan_pending_line (ASSUAN_CONTEXT ctx)
+assuan_pending_line (assuan_context_t ctx)
{
return ctx && ctx->inbound.attic.pending;
}
_assuan_write_line (assuan_context_t ctx, const char *prefix,
const char *line, size_t len)
{
- int rc = 0;
+ assuan_error_t rc = 0;
size_t prefixlen = prefix? strlen (prefix):0;
/* Make sure that the line is short enough. */
if (len + prefixlen + 2 > ASSUAN_LINELENGTH)
{
if (ctx->log_fp)
- fprintf (ctx->log_fp, "%s[%u.%p] DBG: -> "
+ fprintf (ctx->log_fp, "%s[%u.%d] DBG: -> "
"[supplied line too long -truncated]\n",
assuan_get_assuan_log_prefix (),
- (unsigned int)getpid (), ctx);
+ (unsigned int)getpid (), ctx->inbound.fd);
if (prefixlen > 5)
prefixlen = 5;
if (len > ASSUAN_LINELENGTH - prefixlen - 2)
/* Fixme: we should do some kind of line buffering. */
if (ctx->log_fp)
{
- fprintf (ctx->log_fp, "%s[%u.%p] DBG: -> ",
+ fprintf (ctx->log_fp, "%s[%u.%d] DBG: -> ",
assuan_get_assuan_log_prefix (),
- (unsigned int)getpid (), ctx);
+ (unsigned int)getpid (), ctx->inbound.fd);
if (ctx->confidential)
fputs ("[Confidential data not shown]", ctx->log_fp);
else
- _assuan_log_print_buffer (ctx->log_fp, line, len);
+ {
+ if (prefixlen)
+ _assuan_log_print_buffer (ctx->log_fp, prefix, prefixlen);
+ _assuan_log_print_buffer (ctx->log_fp, line, len);
+ }
putc ('\n', ctx->log_fp);
}
{
rc = writen (ctx, prefix, prefixlen);
if (rc)
- rc = ASSUAN_Write_Error;
+ rc = _assuan_error (ASSUAN_Write_Error);
}
if (!rc)
{
rc = writen (ctx, line, len);
if (rc)
- rc = ASSUAN_Write_Error;
+ rc = _assuan_error (ASSUAN_Write_Error);
if (!rc)
{
rc = writen (ctx, "\n", 1);
if (rc)
- rc = ASSUAN_Write_Error;
+ rc = _assuan_error (ASSUAN_Write_Error);
}
}
return rc;
assuan_error_t
-assuan_write_line (ASSUAN_CONTEXT ctx, const char *line)
+assuan_write_line (assuan_context_t ctx, const char *line)
{
size_t len;
const char *s;
if (!ctx)
- return ASSUAN_Invalid_Value;
+ return _assuan_error (ASSUAN_Invalid_Value);
/* Make sure that we never take a LF from the user - this might
violate the protocol. */
len = s? (s-line) : strlen (line);
if (ctx->log_fp && s)
- fprintf (ctx->log_fp, "%s[%u.%p] DBG: -> "
- "[supplied line contained a LF -truncated]\n",
+ fprintf (ctx->log_fp, "%s[%u.%d] DBG: -> "
+ "[supplied line contained a LF - truncated]\n",
assuan_get_assuan_log_prefix (),
- (unsigned int)getpid (), ctx);
+ (unsigned int)getpid (), ctx->inbound.fd);
return _assuan_write_line (ctx, NULL, line, len);
}
int
_assuan_cookie_write_data (void *cookie, const char *buffer, size_t orig_size)
{
- ASSUAN_CONTEXT ctx = cookie;
+ assuan_context_t ctx = cookie;
size_t size = orig_size;
char *line;
size_t linelen;
{
if (ctx->log_fp)
{
- fprintf (ctx->log_fp, "%s[%u.%p] DBG: -> ",
+ fprintf (ctx->log_fp, "%s[%u.%d] DBG: -> ",
assuan_get_assuan_log_prefix (),
- (unsigned int)getpid (), ctx);
+ (unsigned int)getpid (), ctx->inbound.fd);
if (ctx->confidential)
fputs ("[Confidential data not shown]", ctx->log_fp);
linelen++;
if (writen (ctx, ctx->outbound.data.line, linelen))
{
- ctx->outbound.data.error = ASSUAN_Write_Error;
+ ctx->outbound.data.error = _assuan_error (ASSUAN_Write_Error);
return 0;
}
line = ctx->outbound.data.line;
int
_assuan_cookie_write_flush (void *cookie)
{
- ASSUAN_CONTEXT ctx = cookie;
+ assuan_context_t ctx = cookie;
char *line;
size_t linelen;
{
if (ctx->log_fp)
{
- fprintf (ctx->log_fp, "%s[%u.%p] DBG: -> ",
+ fprintf (ctx->log_fp, "%s[%u.%d] DBG: -> ",
assuan_get_assuan_log_prefix (),
- (unsigned int)getpid (), ctx);
+ (unsigned int)getpid (), ctx->inbound.fd);
if (ctx->confidential)
fputs ("[Confidential data not shown]", ctx->log_fp);
else
linelen++;
if (writen (ctx, ctx->outbound.data.line, linelen))
{
- ctx->outbound.data.error = ASSUAN_Write_Error;
+ ctx->outbound.data.error = _assuan_error (ASSUAN_Write_Error);
return 0;
}
ctx->outbound.data.linelen = 0;
**/
\f
assuan_error_t
-assuan_send_data (ASSUAN_CONTEXT ctx, const void *buffer, size_t length)
+assuan_send_data (assuan_context_t ctx, const void *buffer, size_t length)
{
if (!ctx)
- return ASSUAN_Invalid_Value;
+ return _assuan_error (ASSUAN_Invalid_Value);
if (!buffer && length)
- return ASSUAN_Invalid_Value;
+ return _assuan_error (ASSUAN_Invalid_Value);
if (!buffer)
{ /* flush what we have */
}
assuan_error_t
-assuan_sendfd (ASSUAN_CONTEXT ctx, int fd)
+assuan_sendfd (assuan_context_t ctx, int fd)
{
if (! ctx->io->sendfd)
return set_error (ctx, Not_Implemented,
}
assuan_error_t
-assuan_receivefd (ASSUAN_CONTEXT ctx, int *fd)
+assuan_receivefd (assuan_context_t ctx, int *fd)
{
if (! ctx->io->receivefd)
return set_error (ctx, Not_Implemented,
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
*/
#include <config.h>
assuan_error_t
-_assuan_read_from_server (ASSUAN_CONTEXT ctx, int *okay, int *off)
+_assuan_read_from_server (assuan_context_t ctx, int *okay, int *off)
{
char *line;
int linelen;
*off = 3;
}
else
- rc = ASSUAN_Invalid_Response;
+ rc = _assuan_error (ASSUAN_Invalid_Response);
return rc;
}
/**
* assuan_transact:
* @ctx: The Assuan context
- * @command: Coimmand line to be send to server
+ * @command: Command line to be send to the server
* @data_cb: Callback function for data lines
* @data_cb_arg: first argument passed to @data_cb
* @inquire_cb: Callback function for a inquire response
*
* Return value: 0 on success or error code. The error code may be
* the one one returned by the server in error lines or from the
- * callback functions.
+ * callback functions. Take care: When a callback returns an error
+ * this function returns immediately with an error and thus the caller
+ * will altter return an Assuan error (write erro in most cases).
**/
assuan_error_t
-assuan_transact (ASSUAN_CONTEXT ctx,
+assuan_transact (assuan_context_t ctx,
const char *command,
- assuan_error_t (*data_cb)(void *, const void *, size_t),
+ int (*data_cb)(void *, const void *, size_t),
void *data_cb_arg,
- assuan_error_t (*inquire_cb)(void*, const char *),
+ int (*inquire_cb)(void*, const char *),
void *inquire_cb_arg,
- assuan_error_t (*status_cb)(void*, const char *),
+ int (*status_cb)(void*, const char *),
void *status_cb_arg)
{
- int rc, okay, off;
+ assuan_error_t rc;
+ int okay, off;
char *line;
int linelen;
if (!okay)
{
- rc = atoi (line);
+ rc = _assuan_error (atoi (line));
if (rc < 100)
rc = ASSUAN_Server_Fault;
}
else if (okay == 2)
{
if (!data_cb)
- rc = ASSUAN_No_Data_Callback;
+ rc = _assuan_error (ASSUAN_No_Data_Callback);
else
{
char *s, *d;
{
assuan_write_line (ctx, "END"); /* get out of inquire mode */
_assuan_read_from_server (ctx, &okay, &off); /* dummy read */
- rc = ASSUAN_No_Inquire_Callback;
+ rc = _assuan_error (ASSUAN_No_Inquire_Callback);
}
else
{
else if (okay == 5)
{
if (!data_cb)
- rc = ASSUAN_No_Data_Callback;
+ rc = _assuan_error (ASSUAN_No_Data_Callback);
else
{
rc = data_cb (data_cb_arg, NULL, 0);
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
*/
#ifdef HAVE_CONFIG_H
}
}
-/* Return the PID of the peer or -1 if not known. */
+/* Return the PID of the peer or -1 if not known. This function works
+ in some situations where assuan_get_ucred fails. */
pid_t
assuan_get_pid (assuan_context_t ctx)
{
return (ctx && ctx->pid)? ctx->pid : -1;
}
+
+/* Return user credentials. PID, UID and GID amy be gived as NULL if
+ you are not interested in this value. For getting the pid of the
+ peer the assuan_get_pid is usually better suited. */
+assuan_error_t
+assuan_get_peercred (assuan_context_t ctx, pid_t *pid, uid_t *uid, gid_t *gid)
+{
+ if (!ctx)
+ return _assuan_error (ASSUAN_Invalid_Value);
+ if (!ctx->peercred.valid)
+ return _assuan_error (ASSUAN_General_Error);
+ if (pid)
+ *pid = ctx->peercred.pid;
+ if (uid)
+ *uid = ctx->peercred.uid;
+ if (gid)
+ *gid = ctx->peercred.gid;
+ return 0;
+}
/* 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.
*
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
*/
#ifndef ASSUAN_DEFS_H
#define LINELENGTH ASSUAN_LINELENGTH
+
struct cmdtbl_s
{
const char *name;
- int (*handler)(ASSUAN_CONTEXT, char *line);
+ int (*handler)(assuan_context_t, char *line);
};
+
+/* A structure to dispatch I/O functions. All these functions need to
+ return 0 on success and set ERRNO on failure. */
struct assuan_io
{
/* Routine to read from input_fd. */
- ssize_t (*readfnc) (ASSUAN_CONTEXT, void *, size_t);
+ ssize_t (*readfnc) (assuan_context_t, void *, size_t);
/* Routine to write to output_fd. */
- ssize_t (*writefnc) (ASSUAN_CONTEXT, const void *, size_t);
+ ssize_t (*writefnc) (assuan_context_t, const void *, size_t);
/* Send a file descriptor. */
- assuan_error_t (*sendfd) (ASSUAN_CONTEXT, int);
+ assuan_error_t (*sendfd) (assuan_context_t, int);
/* Receive a file descriptor. */
- assuan_error_t (*receivefd) (ASSUAN_CONTEXT, int *);
-};
+ assuan_error_t (*receivefd) (assuan_context_t, int *);
+};
+
+/* The context we use with most functions. */
struct assuan_context_s
{
assuan_error_t err_no;
error codes. */
/* Context specific flags (cf. assuan_flag_t). */
- struct
+ struct
{
unsigned int no_waitpid:1; /* See ASSUAN_NO_WAITPID. */
- } flags;
+ } flags;
int confidential;
int is_server; /* Set if this is context belongs to a server */
int in_inquire;
char *hello_line;
char *okay_line; /* See assuan_set_okay_line() */
-
- void *user_pointer; /* For assuan_get_pointer and assuan-set_pointer (). */
+
+ void *user_pointer; /* For assuan_get_pointer and assuan_set_pointer (). */
FILE *log_fp;
char line[LINELENGTH];
int linelen; /* w/o CR, LF - might not be the same as
strlen(line) due to embedded nuls. However a nul
- is always written at this pos */
+ is always written at this pos. */
struct {
char line[LINELENGTH];
int linelen ;
struct {
FILE *fp;
char line[LINELENGTH];
- int linelen;
+ int linelen;
int error;
- } data;
+ } data;
} outbound;
int pipe_mode; /* We are in pipe mode, i.e. we can handle just one
- connection and must terminate then */
- pid_t pid; /* The the pid of the peer. */
+ connection and must terminate then. */
+ pid_t pid; /* The pid of the peer. */
int listen_fd; /* The fd we are listening on (used by socket servers) */
int connected_fd; /* helper */
+ struct {
+ int valid; /* Whether this structure has valid information. */
+ pid_t pid; /* The pid of the peer. */
+ uid_t uid; /* The uid of the peer. */
+ gid_t gid; /* The gid of the peer. */
+ } peercred;
/* Used for Unix domain sockets. */
struct sockaddr_un myaddr;
struct sockaddr_un serveraddr;
- /* When reading from datagram sockets, we must read an entire
- message at a time. This means that we have to do our own
- buffering to be able to get the semantics of read. */
- void *domainbuffer;
- /* Offset of start of buffer. */
- int domainbufferoffset;
- /* Bytes buffered. */
- int domainbuffersize;
- /* Memory allocated. */
- int domainbufferallocated;
-
- int *pendingfds;
- int pendingfdscount;
-
- void (*deinit_handler)(ASSUAN_CONTEXT);
- int (*accept_handler)(ASSUAN_CONTEXT);
- int (*finish_handler)(ASSUAN_CONTEXT);
+
+ /* Structure used for unix domain socket buffering. FIXME: We don't
+ use datagrams anymore thus we could get away with a simpler
+ buffering approach. */
+ struct {
+ void *buffer; /* Malloced buffer. */
+ int bufferallocated; /* Memory allocated. */
+ int bufferoffset; /* Offset of start of buffer. */
+ int buffersize; /* Bytes buffered. */
+
+ int pendingfds[5]; /* Array to save received descriptors. */
+ int pendingfdscount; /* Number of received descriptors. */
+ } uds;
+
+ void (*deinit_handler)(assuan_context_t);
+ int (*accept_handler)(assuan_context_t);
+ int (*finish_handler)(assuan_context_t);
struct cmdtbl_s *cmdtbl;
size_t cmdtbl_used; /* used entries */
size_t cmdtbl_size; /* allocated size of table */
- void (*bye_notify_fnc)(ASSUAN_CONTEXT);
- void (*reset_notify_fnc)(ASSUAN_CONTEXT);
- void (*cancel_notify_fnc)(ASSUAN_CONTEXT);
- int (*option_handler_fnc)(ASSUAN_CONTEXT,const char*, const char*);
- void (*input_notify_fnc)(ASSUAN_CONTEXT, const char *);
- void (*output_notify_fnc)(ASSUAN_CONTEXT, const char *);
+ void (*bye_notify_fnc)(assuan_context_t);
+ void (*reset_notify_fnc)(assuan_context_t);
+ void (*cancel_notify_fnc)(assuan_context_t);
+ int (*option_handler_fnc)(assuan_context_t,const char*, const char*);
+ void (*input_notify_fnc)(assuan_context_t, const char *);
+ void (*output_notify_fnc)(assuan_context_t, const char *);
int input_fd; /* set by INPUT command */
int output_fd; /* set by OUTPUT command */
};
/*-- assuan-pipe-server.c --*/
-int _assuan_new_context (ASSUAN_CONTEXT *r_ctx);
-void _assuan_release_context (ASSUAN_CONTEXT ctx);
+int _assuan_new_context (assuan_context_t *r_ctx);
+void _assuan_release_context (assuan_context_t ctx);
+
+/*-- assuan-uds.c --*/
+void _assuan_uds_close_fds (assuan_context_t ctx);
+void _assuan_uds_deinit (assuan_context_t ctx);
+void _assuan_init_uds_io (assuan_context_t ctx);
-/*-- assuan-domain-connect.c --*/
-/* Make a connection to the Unix domain socket NAME and return a new
- Assuan context in CTX. SERVER_PID is currently not used but may
- become handy in the future. */
-assuan_error_t _assuan_domain_init (ASSUAN_CONTEXT *r_ctx,
- int rendezvousfd,
- pid_t peer);
/*-- assuan-handler.c --*/
-int _assuan_register_std_commands (ASSUAN_CONTEXT ctx);
+int _assuan_register_std_commands (assuan_context_t ctx);
/*-- assuan-buffer.c --*/
-int _assuan_read_line (ASSUAN_CONTEXT ctx);
+assuan_error_t _assuan_read_line (assuan_context_t ctx);
int _assuan_cookie_write_data (void *cookie, const char *buffer, size_t size);
int _assuan_cookie_write_flush (void *cookie);
assuan_error_t _assuan_write_line (assuan_context_t ctx, const char *prefix,
const char *line, size_t len);
/*-- assuan-client.c --*/
-assuan_error_t _assuan_read_from_server (ASSUAN_CONTEXT ctx, int *okay, int *off);
+assuan_error_t _assuan_read_from_server (assuan_context_t ctx,
+ int *okay, int *off);
+
+/*-- assuan-error.c --*/
+
+
+/* Map error codes as used in this implementaion to the libgpg-error
+ codes. */
+assuan_error_t _assuan_error (int oldcode);
+
+/* Extrac the erro code from A. This works for both the old and the
+ new style error codes. This needs to be whenever an error code is
+ compared. */
+#define err_code(a) ((a) & 0x00ffffff)
+
+/* Check whether A is the erro code for EOF. We allow forold and new
+ style EOF error codes here. */
+#define err_is_eof(a) ((a) == (-1) || err_code (a) == 16383)
+
/*-- assuan-util.c --*/
#define xtryrealloc(a,b) _assuan_realloc((a),(b))
#define xfree(a) _assuan_free ((a))
-#define set_error(c,e,t) assuan_set_error ((c), ASSUAN_ ## e, (t))
-
-void _assuan_log_print_buffer (FILE *fp, const void *buffer, size_t length);
-void _assuan_log_sanitized_string (const char *string);
+#define set_error(c,e,t) \
+ assuan_set_error ((c), _assuan_error (ASSUAN_ ## e), (t))
#ifdef HAVE_W32_SYSTEM
const char *_assuan_w32_strerror (int ec);
__attribute__ ((format (printf,1,2)))
#endif
;
+void _assuan_log_print_buffer (FILE *fp, const void *buffer, size_t length);
+void _assuan_log_sanitized_string (const char *string);
+
/*-- assuan-io.c --*/
-ssize_t _assuan_simple_read (ASSUAN_CONTEXT ctx, void *buffer, size_t size);
-ssize_t _assuan_simple_write (ASSUAN_CONTEXT ctx, const void *buffer,
+pid_t _assuan_waitpid (pid_t pid, int *status, int options);
+
+ssize_t _assuan_simple_read (assuan_context_t ctx, void *buffer, size_t size);
+ssize_t _assuan_simple_write (assuan_context_t ctx, const void *buffer,
size_t size);
+ssize_t _assuan_simple_sendmsg (assuan_context_t ctx, struct msghdr *msg);
+ssize_t _assuan_simple_recvmsg (assuan_context_t ctx, struct msghdr *msg);
/*-- assuan-socket.c --*/
int _assuan_close (int fd);
#define funopen(a,r,w,s,c) _assuan_funopen ((a), (r), (w), (s), (c))
#endif /*HAVE_FOPENCOOKIE*/
-#endif /*ASSUAN_DEFS_H*/
+/* Prototypes for replacement functions. */
+#ifndef HAVE_MEMRCHR
+void *memrchr (const void *block, int c, size_t size);
+#endif
+#ifndef HAVE_STPCPY
+char *stpcpy (char *dest, const char *src);
+#endif
+#ifndef HAVE_SETENV
+#define setenv _assuan_setenv
+#define unsetenv _assuan_unsetenv
+#define clearenv _assuan_clearenv
+int setenv (const char *name, const char *value, int replace);
+#endif
+#ifndef HAVE_PUTC_UNLOCKED
+int putc_unlocked (int c, FILE *stream)
+#endif
+#define DIM(v) (sizeof(v)/sizeof((v)[0]))
+#define DIMof(type,member) DIM(((type *)0)->member)
+
+
+#endif /*ASSUAN_DEFS_H*/
-/* 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;
-}
-/* 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;
-}
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
*/
#include <config.h>
static int
-dummy_handler (ASSUAN_CONTEXT ctx, char *line)
+dummy_handler (assuan_context_t ctx, char *line)
{
return set_error (ctx, Server_Fault, "no handler registered");
}
static int
-std_handler_nop (ASSUAN_CONTEXT ctx, char *line)
+std_handler_nop (assuan_context_t ctx, char *line)
{
return 0; /* okay */
}
static int
-std_handler_cancel (ASSUAN_CONTEXT ctx, char *line)
+std_handler_cancel (assuan_context_t ctx, char *line)
{
if (ctx->cancel_notify_fnc)
ctx->cancel_notify_fnc (ctx);
}
static int
-std_handler_option (ASSUAN_CONTEXT ctx, char *line)
+std_handler_option (assuan_context_t ctx, char *line)
{
char *key, *value, *p;
}
static int
-std_handler_bye (ASSUAN_CONTEXT ctx, char *line)
+std_handler_bye (assuan_context_t ctx, char *line)
{
if (ctx->bye_notify_fnc)
ctx->bye_notify_fnc (ctx);
}
static int
-std_handler_auth (ASSUAN_CONTEXT ctx, char *line)
+std_handler_auth (assuan_context_t ctx, char *line)
{
return set_error (ctx, Not_Implemented, NULL);
}
static int
-std_handler_reset (ASSUAN_CONTEXT ctx, char *line)
+std_handler_reset (assuan_context_t ctx, char *line)
{
if (ctx->reset_notify_fnc)
ctx->reset_notify_fnc (ctx);
assuan_close_input_fd (ctx);
assuan_close_output_fd (ctx);
+ _assuan_uds_close_fds (ctx);
return 0;
}
static int
-std_handler_end (ASSUAN_CONTEXT ctx, char *line)
+std_handler_end (assuan_context_t ctx, char *line)
{
return set_error (ctx, Not_Implemented, NULL);
}
assuan_error_t
-assuan_command_parse_fd (ASSUAN_CONTEXT ctx, char *line, int *rfd)
+assuan_command_parse_fd (assuan_context_t ctx, char *line, int *rfd)
{
char *endp;
- if (strncmp (line, "FD", 2) != 0 || (line[2] != '=' && line[2] != '\0'))
+ if ( (strncmp (line, "FD", 2) && strncmp (line, "fd", 2))
+ || (line[2] != '=' && line[2] != '\0'))
return set_error (ctx, Syntax_Error, "FD[=<n>] expected");
line += 2;
if (*line == '=')
if (!digitp (*line))
return set_error (ctx, Syntax_Error, "number required");
*rfd = strtoul (line, &endp, 10);
- /* remove that argument so that a notify handler won't see it */
+ /* Remove that argument so that a notify handler won't see it. */
memset (line, ' ', endp? (endp-line):strlen(line));
if (*rfd == ctx->inbound.fd)
/* Format is INPUT FD=<n> */
static int
-std_handler_input (ASSUAN_CONTEXT ctx, char *line)
+std_handler_input (assuan_context_t ctx, char *line)
{
int rc, fd;
/* Format is OUTPUT FD=<n> */
static int
-std_handler_output (ASSUAN_CONTEXT ctx, char *line)
+std_handler_output (assuan_context_t ctx, char *line)
{
int rc, fd;
with default handlers */
static struct {
const char *name;
- int (*handler)(ASSUAN_CONTEXT, char *line);
+ int (*handler)(assuan_context_t, char *line);
int always; /* always initialize this command */
} std_cmd_table[] = {
{ "NOP", std_handler_nop, 1 },
* Return value: 0 on success or an error code
**/
int
-assuan_register_command (ASSUAN_CONTEXT ctx,
+assuan_register_command (assuan_context_t ctx,
const char *cmd_name,
- int (*handler)(ASSUAN_CONTEXT, char *))
+ int (*handler)(assuan_context_t, char *))
{
int i;
const char *s;
cmd_name = NULL;
if (!cmd_name)
- return ASSUAN_Invalid_Value;
+ return _assuan_error (ASSUAN_Invalid_Value);
if (!handler)
{ /* find a default handler. */
ctx->cmdtbl_size = 50;
ctx->cmdtbl = xtrycalloc ( ctx->cmdtbl_size, sizeof *ctx->cmdtbl);
if (!ctx->cmdtbl)
- return ASSUAN_Out_Of_Core;
+ return _assuan_error (ASSUAN_Out_Of_Core);
ctx->cmdtbl_used = 0;
}
else if (ctx->cmdtbl_used >= ctx->cmdtbl_size)
x = xtryrealloc ( ctx->cmdtbl, (ctx->cmdtbl_size+10) * sizeof *x);
if (!x)
- return ASSUAN_Out_Of_Core;
+ return _assuan_error (ASSUAN_Out_Of_Core);
ctx->cmdtbl = x;
ctx->cmdtbl_size += 50;
}
}
int
-assuan_register_bye_notify (ASSUAN_CONTEXT ctx, void (*fnc)(ASSUAN_CONTEXT))
+assuan_register_bye_notify (assuan_context_t ctx,
+ void (*fnc)(assuan_context_t))
{
if (!ctx)
- return ASSUAN_Invalid_Value;
+ return _assuan_error (ASSUAN_Invalid_Value);
ctx->bye_notify_fnc = fnc;
return 0;
}
int
-assuan_register_reset_notify (ASSUAN_CONTEXT ctx, void (*fnc)(ASSUAN_CONTEXT))
+assuan_register_reset_notify (assuan_context_t ctx,
+ void (*fnc)(assuan_context_t))
{
if (!ctx)
- return ASSUAN_Invalid_Value;
+ return _assuan_error (ASSUAN_Invalid_Value);
ctx->reset_notify_fnc = fnc;
return 0;
}
int
-assuan_register_cancel_notify (ASSUAN_CONTEXT ctx, void (*fnc)(ASSUAN_CONTEXT))
+assuan_register_cancel_notify (assuan_context_t ctx,
+ void (*fnc)(assuan_context_t))
{
if (!ctx)
- return ASSUAN_Invalid_Value;
+ return _assuan_error (ASSUAN_Invalid_Value);
ctx->cancel_notify_fnc = fnc;
return 0;
}
int
-assuan_register_option_handler (ASSUAN_CONTEXT ctx,
- int (*fnc)(ASSUAN_CONTEXT,
+assuan_register_option_handler (assuan_context_t ctx,
+ int (*fnc)(assuan_context_t,
const char*, const char*))
{
if (!ctx)
- return ASSUAN_Invalid_Value;
+ return _assuan_error (ASSUAN_Invalid_Value);
ctx->option_handler_fnc = fnc;
return 0;
}
int
-assuan_register_input_notify (ASSUAN_CONTEXT ctx,
- void (*fnc)(ASSUAN_CONTEXT, const char *))
+assuan_register_input_notify (assuan_context_t ctx,
+ void (*fnc)(assuan_context_t, const char *))
{
if (!ctx)
- return ASSUAN_Invalid_Value;
+ return _assuan_error (ASSUAN_Invalid_Value);
ctx->input_notify_fnc = fnc;
return 0;
}
int
-assuan_register_output_notify (ASSUAN_CONTEXT ctx,
- void (*fnc)(ASSUAN_CONTEXT, const char *))
+assuan_register_output_notify (assuan_context_t ctx,
+ void (*fnc)(assuan_context_t, const char *))
{
if (!ctx)
- return ASSUAN_Invalid_Value;
+ return _assuan_error (ASSUAN_Invalid_Value);
ctx->output_notify_fnc = fnc;
return 0;
}
/* Helper to register the standards commands */
int
-_assuan_register_std_commands (ASSUAN_CONTEXT ctx)
+_assuan_register_std_commands (assuan_context_t ctx)
{
int i, rc;
/* Process the special data lines. The "D " has already been removed
from the line. As all handlers this function may modify the line. */
static int
-handle_data_line (ASSUAN_CONTEXT ctx, char *line, int linelen)
+handle_data_line (assuan_context_t ctx, char *line, int linelen)
{
return set_error (ctx, Not_Implemented, NULL);
}
table, remove leading and white spaces from the arguments, call the
handler with the argument line and return the error */
static int
-dispatch_command (ASSUAN_CONTEXT ctx, char *line, int linelen)
+dispatch_command (assuan_context_t ctx, char *line, int linelen)
{
char *p;
const char *s;
for (p=line; *p && *p != ' ' && *p != '\t'; p++)
;
if (p==line)
- return set_error (ctx, Invalid_Command, "leading white-space");
+ return set_error (ctx, Syntax_Error, "leading white-space");
if (*p)
{ /* Skip over leading WS after the keyword */
*p++ = 0;
\f
static int
-process_request (ASSUAN_CONTEXT ctx)
+process_request (assuan_context_t ctx)
{
int rc;
if (ctx->in_inquire)
- return ASSUAN_Nested_Commands;
+ return _assuan_error (ASSUAN_Nested_Commands);
rc = _assuan_read_line (ctx);
if (rc)
{
rc = assuan_write_line (ctx, ctx->okay_line? ctx->okay_line : "OK");
}
- else if (rc == -1)
- { /* No error checking because the peer may have already disconnect */
+ else if (err_is_eof (rc))
+ { /* No error checking because the peer may have already disconnect. */
assuan_write_line (ctx, "OK closing connection");
ctx->finish_handler (ctx);
}
if (rc < 100)
sprintf (errline, "ERR %d server fault (%.50s)",
- ASSUAN_Server_Fault, assuan_strerror (rc));
+ _assuan_error (ASSUAN_Server_Fault), assuan_strerror (rc));
else
{
const char *text = ctx->err_no == rc? ctx->err_str:NULL;
strings from libgpg-error without creating a dependency.
They are used for debugging purposes only, so there is no
problem if they are not available. We need to make sure
- that we are using elf because only this guarantees that
+ that we are using ELF because only this guarantees that
weak symbol support is available in case GNU ld is not
used. */
unsigned int source, code;
* failed. Note, that no error is returned for operational errors.
**/
int
-assuan_process (ASSUAN_CONTEXT ctx)
+assuan_process (assuan_context_t ctx)
{
int rc;
rc = process_request (ctx);
} while (!rc);
- if (rc == -1)
+ if (err_is_eof (rc))
rc = 0;
return rc;
* Return value: -1 for end of server, 0 on success or an error code
**/
int
-assuan_process_next (ASSUAN_CONTEXT ctx)
+assuan_process_next (assuan_context_t ctx)
{
return process_request (ctx);
}
* error which is most likely a too small fdarray.
**/
int
-assuan_get_active_fds (ASSUAN_CONTEXT ctx, int what,
+assuan_get_active_fds (assuan_context_t ctx, int what,
int *fdarray, int fdarraysize)
{
int n = 0;
implementaion for systems w/o a glibc, a simple implementation
could use a child process */
FILE *
-assuan_get_data_fp (ASSUAN_CONTEXT ctx)
+assuan_get_data_fp (assuan_context_t ctx)
{
#if defined (HAVE_FOPENCOOKIE) || defined (HAVE_FUNOPEN)
if (ctx->outbound.data.fp)
/* Set the text used for the next OK reponse. This string is
automatically reset to NULL after the next command. */
assuan_error_t
-assuan_set_okay_line (ASSUAN_CONTEXT ctx, const char *line)
+assuan_set_okay_line (assuan_context_t ctx, const char *line)
{
if (!ctx)
- return ASSUAN_Invalid_Value;
+ return _assuan_error (ASSUAN_Invalid_Value);
if (!line)
{
xfree (ctx->okay_line);
we should allocate the entire line in secure memory */
char *buf = xtrymalloc (3+strlen(line)+1);
if (!buf)
- return ASSUAN_Out_Of_Core;
+ return _assuan_error (ASSUAN_Out_Of_Core);
strcpy (buf, "OK ");
strcpy (buf+3, line);
xfree (ctx->okay_line);
assuan_error_t
-assuan_write_status (ASSUAN_CONTEXT ctx, const char *keyword, const char *text)
+assuan_write_status (assuan_context_t ctx,
+ const char *keyword, const char *text)
{
char buffer[256];
char *helpbuf;
assuan_error_t ae;
if ( !ctx || !keyword)
- return ASSUAN_Invalid_Value;
+ return _assuan_error (ASSUAN_Invalid_Value);
if (!text)
text = "";
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
*/
#include <config.h>
int nodataexpected;
if (!ctx || !keyword || (10 + strlen (keyword) >= sizeof (cmdbuf)))
- return ASSUAN_Invalid_Value;
+ return _assuan_error (ASSUAN_Invalid_Value);
nodataexpected = !r_buffer && !r_length && !maxlen;
if (!nodataexpected && (!r_buffer || !r_length))
- return ASSUAN_Invalid_Value;
+ return _assuan_error (ASSUAN_Invalid_Value);
if (!ctx->is_server)
- return ASSUAN_Not_A_Server;
+ return _assuan_error (ASSUAN_Not_A_Server);
if (ctx->in_inquire)
- return ASSUAN_Nested_Commands;
+ return _assuan_error (ASSUAN_Nested_Commands);
ctx->in_inquire = 1;
if (nodataexpected)
break; /* END command received*/
if (line[0] == 'C' && line[1] == 'A' && line[2] == 'N')
{
- rc = ASSUAN_Canceled;
+ rc = _assuan_error (ASSUAN_Canceled);
goto leave;
}
if (line[0] != 'D' || line[1] != ' ' || nodataexpected)
{
- rc = ASSUAN_Unexpected_Command;
+ rc = _assuan_error (ASSUAN_Unexpected_Command);
goto leave;
}
if (linelen < 3)
}
if (mb.too_large)
{
- rc = ASSUAN_Too_Much_Data;
+ rc = _assuan_error (ASSUAN_Too_Much_Data);
goto leave;
}
}
{
*r_buffer = get_membuf (&mb, r_length);
if (!*r_buffer)
- rc = ASSUAN_Out_Of_Core;
+ rc = _assuan_error (ASSUAN_Out_Of_Core);
}
leave:
/* 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.
*
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
-#include "assuan-defs.h"
#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#if HAVE_SYS_UIO_H
+# include <sys/uio.h>
+#endif
#include <unistd.h>
+#include <errno.h>
#ifdef HAVE_W32_SYSTEM
-#include <windows.h>
+# 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
+extern pid_t pth_waitpid (pid_t pid, int *status, int options);
extern ssize_t pth_read (int fd, void *buffer, size_t size);
extern ssize_t pth_write (int fd, const void *buffer, size_t size);
+extern int pth_fdmode (int, int);
+extern int pth_select(int, fd_set*, fd_set*, fd_set*, struct timeval*);
#ifndef HAVE_W32_SYSTEM
+#pragma weak pth_waitpid
#pragma weak pth_read
#pragma weak pth_write
+#pragma weak pth_fdmode
+#pragma weak pth_select
#endif
#endif /*!_ASSUAN_NO_PTH*/
+#ifndef _ASSUAN_NO_PTH
+/* Wrapper around pth_fdmode. */
+static int
+my_pth_fdmode (int fd, int mode)
+{
+ if (pth_fdmode)
+ return pth_fdmode (fd, mode);
+ else
+ return MY_PTH_FDMODE_NONBLOCK; /* This is okay, given the way we use it. */
+}
+#endif /*_ASSUAN_NO_PTH*/
+
+#ifndef _ASSUAN_NO_PTH
+/* Wrapper around pth_select. */
+static int
+my_pth_select (int nfd, fd_set *rfds, fd_set *wfds, fd_set *efds,
+ struct timeval *timeout)
+{
+ if (pth_select)
+ return pth_select (nfd, rfds, wfds, efds, timeout);
+ else
+ return 1; /* Fake one fd ready; this is okay, given the way we use it. */
+}
+#endif /*_ASSUAN_NO_PTH*/
+
+#ifndef HAVE_W32_SYSTEM
+pid_t
+_assuan_waitpid (pid_t pid, int *status, int options)
+{
+#ifdef _ASSUAN_NO_PTH
+ return waitpid (pid, status, options);
+#else
+ return (pth_waitpid ? pth_waitpid : waitpid) (pid, status, options);
+#endif
+}
+#endif
+
+
ssize_t
_assuan_simple_read (assuan_context_t ctx, void *buffer, size_t size)
{
return pth_read ? pth_read (ctx->inbound.fd, buffer, size)
: recv (ctx->inbound.fd, buffer, size, 0);
# endif
-# endif
+#endif
}
ssize_t
# 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
+}
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
*/
#include <config.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
+#include <errno.h>
#include "assuan-defs.h"
assuan_set_hello_line (assuan_context_t ctx, const char *line)
{
if (!ctx)
- return ASSUAN_Invalid_Value;
+ return _assuan_error (ASSUAN_Invalid_Value);
if (!line)
{
xfree (ctx->hello_line);
{
char *buf = xtrymalloc (3+strlen(line)+1);
if (!buf)
- return ASSUAN_Out_Of_Core;
+ return _assuan_error (ASSUAN_Out_Of_Core);
if (strchr (line, '\n'))
strcpy (buf, line);
else
const char *p, *pend;
if (!ctx)
- return ASSUAN_Invalid_Value;
+ return _assuan_error (ASSUAN_Invalid_Value);
if (ctx->pipe_mode > 1)
return -1; /* second invocation for pipemode -> terminate */
assuan_close_input_fd (assuan_context_t ctx)
{
if (!ctx || ctx->input_fd == -1)
- return ASSUAN_Invalid_Value;
+ return _assuan_error (ASSUAN_Invalid_Value);
_assuan_close (ctx->input_fd);
ctx->input_fd = -1;
return 0;
assuan_close_output_fd (assuan_context_t ctx)
{
if (!ctx || ctx->output_fd == -1)
- return ASSUAN_Invalid_Value;
+ return _assuan_error (ASSUAN_Invalid_Value);
_assuan_close (ctx->output_fd);
ctx->output_fd = -1;
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#ifdef HAVE_W32_SYSTEM
#include <windows.h>
#endif /*HAVE_W32_SYSTEM*/
+#include <errno.h>
+#include <ctype.h>
#include "assuan-defs.h"
static char prefix_buffer[80];
static FILE *_assuan_log;
+static int full_logging;
void
_assuan_set_default_log_stream (FILE *fp)
{
if (!_assuan_log)
- _assuan_log = fp;
+ {
+ _assuan_log = fp;
+ full_logging = !!getenv ("ASSUAN_FULL_LOGGING");
+ }
}
void
_assuan_log = fp;
}
+
+/* Set the per context log stream. Also enable the default log stream
+ if it has not been set. */
+void
+assuan_set_log_stream (assuan_context_t ctx, FILE *fp)
+{
+ if (ctx)
+ {
+ if (ctx->log_fp)
+ fflush (ctx->log_fp);
+ ctx->log_fp = fp;
+ _assuan_set_default_log_stream (fp);
+ }
+}
+
+
FILE *
assuan_get_assuan_log_stream (void)
{
va_list arg_ptr;
FILE *fp;
const char *prf;
-
+ int save_errno = errno;
+
fp = assuan_get_assuan_log_stream ();
prf = assuan_get_assuan_log_prefix ();
if (*prf)
- {
- fputs (prf, fp);
- fputs (": ", fp);
- }
+ fprintf (fp, "%s[%u]: ", prf, (unsigned int)getpid ());
va_start (arg_ptr, format);
vfprintf (fp, format, arg_ptr );
va_end (arg_ptr);
+ errno = save_errno;
+}
+
+
+/* Dump a possibly binary string (used for debugging). Distinguish
+ ascii text from binary and print it accordingly. This function
+ takes FILE pointer arg becuase logging may be enabled on a per
+ context basis. */
+void
+_assuan_log_print_buffer (FILE *fp, const void *buffer, size_t length)
+{
+ const unsigned char *s;
+ int n;
+
+ for (n=length,s=buffer; n; n--, s++)
+ if ((!isascii (*s) || iscntrl (*s) || !isprint (*s)) && !(*s >= 0x80))
+ break;
+
+ s = buffer;
+ if (!n && *s != '[')
+ fwrite (buffer, length, 1, fp);
+ else
+ {
+#ifdef HAVE_FLOCKFILE
+ flockfile (fp);
+#endif
+ putc_unlocked ('[', fp);
+ if ( length > 16 && !full_logging)
+ {
+ for (n=0; n < 12; n++, s++)
+ fprintf (fp, " %02x", *s);
+ fprintf (fp, " ...(%d bytes skipped)", (int)length - 12);
+ }
+ else
+ {
+ for (n=0; n < length; n++, s++)
+ fprintf (fp, " %02x", *s);
+ }
+ putc_unlocked (' ', fp);
+ putc_unlocked (']', fp);
+#ifdef HAVE_FUNLOCKFILE
+ funlockfile (fp);
+#endif
+ }
+}
+
+/* Log a user supplied string. Escapes non-printable before
+ printing. */
+void
+_assuan_log_sanitized_string (const char *string)
+{
+ const unsigned char *s = (const unsigned char *) string;
+ FILE *fp = assuan_get_assuan_log_stream ();
+
+ if (! *s)
+ return;
+
+#ifdef HAVE_FLOCKFILE
+ flockfile (fp);
+#endif
+
+ for (; *s; s++)
+ {
+ int c = 0;
+
+ switch (*s)
+ {
+ case '\r':
+ c = 'r';
+ break;
+
+ case '\n':
+ c = 'n';
+ break;
+
+ case '\f':
+ c = 'f';
+ break;
+
+ case '\v':
+ c = 'v';
+ break;
+
+ case '\b':
+ c = 'b';
+ break;
+
+ default:
+ if ((isascii (*s) && isprint (*s)) || (*s >= 0x80))
+ putc_unlocked (*s, fp);
+ else
+ {
+ putc_unlocked ('\\', fp);
+ fprintf (fp, "x%02x", *s);
+ }
+ }
+
+ if (c)
+ {
+ putc_unlocked ('\\', fp);
+ putc_unlocked (c, fp);
+ }
+ }
+
+#ifdef HAVE_FUNLOCKFILE
+ funlockfile (fp);
+#endif
}
/* 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.
*
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
*/
#ifdef HAVE_CONFIG_H
#include "assuan-defs.h"
+/* Hacks for Slowaris. */
+#ifndef PF_LOCAL
+# ifdef PF_UNIX
+# define PF_LOCAL PF_UNIX
+# else
+# define PF_LOCAL AF_UNIX
+# endif
+#endif
+#ifndef AF_LOCAL
+# define AF_LOCAL AF_UNIX
+#endif
+
+
#ifdef _POSIX_OPEN_MAX
#define MAX_OPEN_FDS _POSIX_OPEN_MAX
#else
if (ctx->inbound.fd != -1)
{
_assuan_close (ctx->inbound.fd);
+ if (ctx->inbound.fd == ctx->outbound.fd)
+ ctx->outbound.fd = -1;
ctx->inbound.fd = -1;
}
if (ctx->outbound.fd != -1)
#ifndef HAVE_W32_SYSTEM
#ifndef _ASSUAN_USE_DOUBLE_FORK
if (!ctx->flags.no_waitpid)
- waitpid (ctx->pid, NULL, 0);
+ _assuan_waitpid (ctx->pid, NULL, 0);
ctx->pid = -1;
#endif
#endif /*!HAVE_W32_SYSTEM*/
}
+/* Helper for pipe_connect. */
+static assuan_error_t
+initial_handshake (assuan_context_t *ctx)
+{
+ int okay, off;
+ assuan_error_t err;
+
+ err = _assuan_read_from_server (*ctx, &okay, &off);
+ if (err)
+ _assuan_log_printf ("can't connect server: %s\n",
+ assuan_strerror (err));
+ else if (okay != 1)
+ {
+ _assuan_log_printf ("can't connect server: `%s'\n",
+ (*ctx)->inbound.line);
+ err = _assuan_error (ASSUAN_Connect_Failed);
+ }
+
+ if (err)
+ {
+ assuan_disconnect (*ctx);
+ *ctx = NULL;
+ }
+ return err;
+}
+
+
+#ifndef HAVE_W32_SYSTEM
+#define pipe_connect pipe_connect_unix
+/* Unix version of the pipe connection code. We use an extra macro to
+ make ChangeLog entries easier. */
+static assuan_error_t
+pipe_connect_unix (assuan_context_t *ctx,
+ const char *name, const char *const argv[],
+ int *fd_child_list,
+ void (*atfork) (void *opaque, int reserved),
+ void *atforkvalue)
+{
+ assuan_error_t err;
+ int rp[2];
+ int wp[2];
+ char mypidstr[50];
+
+ if (!ctx || !name || !argv || !argv[0])
+ return _assuan_error (ASSUAN_Invalid_Value);
+
+ fix_signals ();
+
+ sprintf (mypidstr, "%lu", (unsigned long)getpid ());
+
+ if (pipe (rp) < 0)
+ return _assuan_error (ASSUAN_General_Error);
+
+ if (pipe (wp) < 0)
+ {
+ close (rp[0]);
+ close (rp[1]);
+ return _assuan_error (ASSUAN_General_Error);
+ }
+
+ err = _assuan_new_context (ctx);
+ if (err)
+ {
+ close (rp[0]);
+ close (rp[1]);
+ close (wp[0]);
+ close (wp[1]);
+ return err;
+ }
+ (*ctx)->pipe_mode = 1;
+ (*ctx)->inbound.fd = rp[0]; /* Our inbound is read end of read pipe. */
+ (*ctx)->outbound.fd = wp[1]; /* Our outbound is write end of write pipe. */
+ (*ctx)->deinit_handler = do_deinit;
+ (*ctx)->finish_handler = do_finish;
+
+ /* FIXME: For GPGME we should better use _gpgme_io_spawn. The PID
+ stored here is actually soon useless. */
+ (*ctx)->pid = fork ();
+ if ((*ctx)->pid < 0)
+ {
+ close (rp[0]);
+ close (rp[1]);
+ close (wp[0]);
+ close (wp[1]);
+ _assuan_release_context (*ctx);
+ return _assuan_error (ASSUAN_General_Error);
+ }
+
+ if ((*ctx)->pid == 0)
+ {
+#ifdef _ASSUAN_USE_DOUBLE_FORK
+ pid_t pid;
+
+ if ((pid = fork ()) == 0)
+#endif
+ {
+ int i, n;
+ char errbuf[512];
+ int *fdp;
+
+ if (atfork)
+ atfork (atforkvalue, 0);
+
+ /* Dup handles to stdin/stdout. */
+ if (rp[1] != STDOUT_FILENO)
+ {
+ if (dup2 (rp[1], STDOUT_FILENO) == -1)
+ {
+ _assuan_log_printf ("dup2 failed in child: %s\n",
+ strerror (errno));
+ _exit (4);
+ }
+ }
+ if (wp[0] != STDIN_FILENO)
+ {
+ if (dup2 (wp[0], STDIN_FILENO) == -1)
+ {
+ _assuan_log_printf ("dup2 failed in child: %s\n",
+ strerror (errno));
+ _exit (4);
+ }
+ }
+
+ /* Dup stderr to /dev/null unless it is in the list of FDs to be
+ passed to the child. */
+ fdp = fd_child_list;
+ if (fdp)
+ {
+ for (; *fdp != -1 && *fdp != STDERR_FILENO; fdp++)
+ ;
+ }
+ if (!fdp || *fdp == -1)
+ {
+ int fd = open ("/dev/null", O_WRONLY);
+ if (fd == -1)
+ {
+ _assuan_log_printf ("can't open `/dev/null': %s\n",
+ strerror (errno));
+ _exit (4);
+ }
+ if (dup2 (fd, STDERR_FILENO) == -1)
+ {
+ _assuan_log_printf ("dup2(dev/null, 2) failed: %s\n",
+ strerror (errno));
+ _exit (4);
+ }
+ }
+
+
+ /* Close all files which will not be duped and are not in the
+ fd_child_list. */
+ n = sysconf (_SC_OPEN_MAX);
+ if (n < 0)
+ n = MAX_OPEN_FDS;
+ for (i=0; i < n; i++)
+ {
+ if ( i == STDIN_FILENO || i == STDOUT_FILENO
+ || i == STDERR_FILENO)
+ continue;
+ fdp = fd_child_list;
+ if (fdp)
+ {
+ while (*fdp != -1 && *fdp != i)
+ fdp++;
+ }
+
+ if (!(fdp && *fdp != -1))
+ close(i);
+ }
+ errno = 0;
+
+ /* We store our parents pid in the environment so that the
+ execed assuan server is able to read the actual pid of the
+ client. The server can't use getppid because it might have
+ been double forked before the assuan server has been
+ initialized. */
+ setenv ("_assuan_pipe_connect_pid", mypidstr, 1);
+
+ /* Make sure that we never pass a connection fd variable
+ when using a simple pipe. */
+ unsetenv ("_assuan_connection_fd");
+
+ execv (name, (char *const *) argv);
+ /* oops - use the pipe to tell the parent about it */
+ snprintf (errbuf, sizeof(errbuf)-1,
+ "ERR %d can't exec `%s': %.50s\n",
+ _assuan_error (ASSUAN_Problem_Starting_Server),
+ name, strerror (errno));
+ errbuf[sizeof(errbuf)-1] = 0;
+ writen (1, errbuf, strlen (errbuf));
+ _exit (4);
+ }
+#ifdef _ASSUAN_USE_DOUBLE_FORK
+ if (pid == -1)
+ _exit (1);
+ else
+ _exit (0);
+#endif
+ }
+
+#ifdef _ASSUAN_USE_DOUBLE_FORK
+ _assuan_waitpid ((*ctx)->pid, NULL, 0);
+ (*ctx)->pid = -1;
+#endif
+
+ close (rp[1]);
+ close (wp[0]);
+
+ return initial_handshake (ctx);
+}
+#endif /*!HAVE_W32_SYSTEM*/
+
+
+#ifndef HAVE_W32_SYSTEM
+/* This function is similar to pipe_connect but uses a socketpair and
+ sets the I/O up to use sendmsg/recvmsg. */
+static assuan_error_t
+socketpair_connect (assuan_context_t *ctx,
+ const char *name, const char *const argv[],
+ int *fd_child_list,
+ void (*atfork) (void *opaque, int reserved),
+ void *atforkvalue)
+{
+ assuan_error_t err;
+ int fds[2];
+ char mypidstr[50];
+
+ if (!ctx
+ || (name && (!argv || !argv[0]))
+ || (!name && argv))
+ return _assuan_error (ASSUAN_Invalid_Value);
+
+ fix_signals ();
+
+ sprintf (mypidstr, "%lu", (unsigned long)getpid ());
+
+ if ( socketpair (AF_LOCAL, SOCK_STREAM, 0, fds) )
+ {
+ _assuan_log_printf ("socketpair failed: %s\n", strerror (errno));
+ return _assuan_error (ASSUAN_General_Error);
+ }
+
+ err = _assuan_new_context (ctx);
+ if (err)
+ {
+ close (fds[0]);
+ close (fds[1]);
+ return err;
+ }
+ (*ctx)->pipe_mode = 1;
+ (*ctx)->inbound.fd = fds[0];
+ (*ctx)->outbound.fd = fds[0];
+ _assuan_init_uds_io (*ctx);
+ (*ctx)->deinit_handler = _assuan_uds_deinit;
+ (*ctx)->finish_handler = do_finish;
+
+ (*ctx)->pid = fork ();
+ if ((*ctx)->pid < 0)
+ {
+ close (fds[0]);
+ close (fds[1]);
+ _assuan_release_context (*ctx);
+ *ctx = NULL;
+ return _assuan_error (ASSUAN_General_Error);
+ }
+
+ if ((*ctx)->pid == 0)
+ {
+#ifdef _ASSUAN_USE_DOUBLE_FORK
+ pid_t pid;
+
+ if ((pid = fork ()) == 0)
+#endif
+ {
+ int fd, i, n;
+ char errbuf[512];
+ int *fdp;
+
+ if (atfork)
+ atfork (atforkvalue, 0);
+
+ /* Connect stdin and stdout to /dev/null. */
+ fd = open ("/dev/null", O_RDONLY);
+ if (fd == -1 || dup2 (fd, STDIN_FILENO) == -1)
+ {
+ _assuan_log_printf ("dup2(dev/null) failed: %s\n",
+ strerror (errno));
+ _exit (4);
+ }
+ fd = open ("/dev/null", O_WRONLY);
+ if (fd == -1 || dup2 (fd, STDOUT_FILENO) == -1)
+ {
+ _assuan_log_printf ("dup2(dev/null) failed: %s\n",
+ strerror (errno));
+ _exit (4);
+ }
+
+ /* Dup stderr to /dev/null unless it is in the list of FDs to be
+ passed to the child. */
+ fdp = fd_child_list;
+ if (fdp)
+ {
+ for (; *fdp != -1 && *fdp != STDERR_FILENO; fdp++)
+ ;
+ }
+ if (!fdp || *fdp == -1)
+ {
+ fd = open ("/dev/null", O_WRONLY);
+ if (fd == -1 || dup2 (fd, STDERR_FILENO) == -1)
+ {
+ _assuan_log_printf ("dup2(dev/null) failed: %s\n",
+ strerror (errno));
+ _exit (4);
+ }
+ }
+
+
+ /* Close all files which will not be duped, are not in the
+ fd_child_list and are not the connection fd. */
+ n = sysconf (_SC_OPEN_MAX);
+ if (n < 0)
+ n = MAX_OPEN_FDS;
+ for (i=0; i < n; i++)
+ {
+ if ( i == STDIN_FILENO || i == STDOUT_FILENO
+ || i == STDERR_FILENO || i == fds[1])
+ continue;
+ fdp = fd_child_list;
+ if (fdp)
+ {
+ while (*fdp != -1 && *fdp != i)
+ fdp++;
+ }
+
+ if (!(fdp && *fdp != -1))
+ close(i);
+ }
+ errno = 0;
+
+ /* We store our parents pid in the environment so that the
+ execed assuan server is able to read the actual pid of the
+ client. The server can't use getppid becuase it might have
+ been double forked before the assuan server has been
+ initialized. */
+ setenv ("_assuan_pipe_connect_pid", mypidstr, 1);
+
+ /* Now set the environment variable used to convey the
+ connection's file descriptor. */
+ sprintf (mypidstr, "%d", fds[1]);
+ if (setenv ("_assuan_connection_fd", mypidstr, 1))
+ {
+ _assuan_log_printf ("setenv failed: %s\n", strerror (errno));
+ _exit (4);
+ }
+
+ if (!name && !argv)
+ {
+ /* No name and no args given, thus we don't do an exec
+ but continue the forked process. */
+ _assuan_release_context (*ctx);
+ *ctx = NULL;
+ return 0;
+ }
+
+ execv (name, (char *const *) argv);
+ /* oops - use the pipe to tell the parent about it */
+ snprintf (errbuf, sizeof(errbuf)-1,
+ "ERR %d can't exec `%s': %.50s\n",
+ _assuan_error (ASSUAN_Problem_Starting_Server),
+ name, strerror (errno));
+ errbuf[sizeof(errbuf)-1] = 0;
+ writen (fds[1], errbuf, strlen (errbuf));
+ _exit (4);
+ }
+#ifdef _ASSUAN_USE_DOUBLE_FORK
+ if (pid == -1)
+ _exit (1);
+ else
+ _exit (0);
+#endif
+ }
+
+
+#ifdef _ASSUAN_USE_DOUBLE_FORK
+ _assuan_waitpid ((*ctx)->pid, NULL, 0);
+ (*ctx)->pid = -1;
+#endif
+
+ close (fds[1]);
+
+ return initial_handshake (ctx);
+}
+#endif /*!HAVE_W32_SYSTEM*/
+
+
+
#ifdef HAVE_W32_SYSTEM
/* Build a command line for use with W32's CreateProcess. On success
CMDLINE gets the address of a newly allocated string. */
#endif /*HAVE_W32_SYSTEM*/
-/* Connect to a server over a pipe, creating the assuan context and
- returning it in CTX. The server filename is NAME, the argument
- vector in ARGV. FD_CHILD_LIST is a -1 terminated list of file
- descriptors not to close in the child. ATFORK is called in the
- child right after the fork; ATFORKVALUE is passed as the first
- argument and 0 is passed as the second argument. The ATFORK
- function should only act if the second value is 0. */
-assuan_error_t
-assuan_pipe_connect2 (assuan_context_t *ctx,
- const char *name, const char *const argv[],
- int *fd_child_list,
- void (*atfork) (void *opaque, int reserved),
- void *atforkvalue)
-{
#ifdef HAVE_W32_SYSTEM
+#define pipe_connect pipe_connect_w32
+/* W32 version of the pipe connection code. */
+static assuan_error_t
+pipe_connect_w32 (assuan_context_t *ctx,
+ const char *name, const char *const argv[],
+ int *fd_child_list,
+ void (*atfork) (void *opaque, int reserved),
+ void *atforkvalue)
+{
assuan_error_t err;
int rp[2];
int wp[2];
HANDLE nullfd = INVALID_HANDLE_VALUE;
if (!ctx || !name || !argv || !argv[0])
- return ASSUAN_Invalid_Value;
+ return _assuan_error (ASSUAN_Invalid_Value);
fix_signals ();
/* Build the command line. */
if (build_w32_commandline (argv, &cmdline))
- return ASSUAN_Out_Of_Core;
+ return _assuan_error (ASSUAN_Out_Of_Core);
/* Create thew two pipes. */
if (create_inheritable_pipe (rp, 0))
{
xfree (cmdline);
- return ASSUAN_General_Error;
+ return _assuan_error (ASSUAN_General_Error);
}
if (create_inheritable_pipe (wp, 1))
CloseHandle (fd_to_handle (rp[0]));
CloseHandle (fd_to_handle (rp[1]));
xfree (cmdline);
- return ASSUAN_General_Error;
+ return _assuan_error (ASSUAN_General_Error);
}
CloseHandle (fd_to_handle (wp[0]));
CloseHandle (fd_to_handle (wp[1]));
xfree (cmdline);
- return ASSUAN_General_Error;
+ return _assuan_error (ASSUAN_General_Error);
}
(*ctx)->pipe_mode = 1;
CloseHandle (nullfd);
xfree (cmdline);
_assuan_release_context (*ctx);
- return ASSUAN_General_Error;
+ return _assuan_error (ASSUAN_General_Error);
}
xfree (cmdline);
cmdline = NULL;
(*ctx)->pid = 0; /* We don't use the PID. */
CloseHandle (pi.hProcess); /* We don't need to wait for the process. */
-#else /*!HAVE_W32_SYSTEM*/
- assuan_error_t err;
- int rp[2];
- int wp[2];
- char mypidstr[50];
-
- if (!ctx || !name || !argv || !argv[0])
- return ASSUAN_Invalid_Value;
-
- fix_signals ();
-
- sprintf (mypidstr, "%lu", (unsigned long)getpid ());
-
- if (pipe (rp) < 0)
- return ASSUAN_General_Error;
-
- if (pipe (wp) < 0)
- {
- close (rp[0]);
- close (rp[1]);
- return ASSUAN_General_Error;
- }
-
- err = _assuan_new_context (ctx);
- if (err)
- {
- close (rp[0]);
- close (rp[1]);
- close (wp[0]);
- close (wp[1]);
- return err;
- }
- (*ctx)->pipe_mode = 1;
- (*ctx)->inbound.fd = rp[0]; /* Our inbound is read end of read pipe. */
- (*ctx)->outbound.fd = wp[1]; /* Our outbound is write end of write pipe. */
- (*ctx)->deinit_handler = do_deinit;
- (*ctx)->finish_handler = do_finish;
-
- /* FIXME: For GPGME we should better use _gpgme_io_spawn. The PID
- stored here is actually soon useless. */
- (*ctx)->pid = fork ();
- if ((*ctx)->pid < 0)
- {
- close (rp[0]);
- close (rp[1]);
- close (wp[0]);
- close (wp[1]);
- _assuan_release_context (*ctx);
- return ASSUAN_General_Error;
- }
-
- if ((*ctx)->pid == 0)
- {
-#ifdef _ASSUAN_USE_DOUBLE_FORK
- pid_t pid;
-
- if ((pid = fork ()) == 0)
-#endif
- {
- int i, n;
- char errbuf[512];
- int *fdp;
-
- if (atfork)
- atfork (atforkvalue, 0);
-
- /* Dup handles to stdin/stdout. */
- if (rp[1] != STDOUT_FILENO)
- {
- if (dup2 (rp[1], STDOUT_FILENO) == -1)
- {
- _assuan_log_printf ("dup2 failed in child: %s\n",
- strerror (errno));
- _exit (4);
- }
- }
- if (wp[0] != STDIN_FILENO)
- {
- if (dup2 (wp[0], STDIN_FILENO) == -1)
- {
- _assuan_log_printf ("dup2 failed in child: %s\n",
- strerror (errno));
- _exit (4);
- }
- }
-
- /* Dup stderr to /dev/null unless it is in the list of FDs to be
- passed to the child. */
- fdp = fd_child_list;
- if (fdp)
- {
- for (; *fdp != -1 && *fdp != STDERR_FILENO; fdp++)
- ;
- }
- if (!fdp || *fdp == -1)
- {
- int fd = open ("/dev/null", O_WRONLY);
- if (fd == -1)
- {
- _assuan_log_printf ("can't open `/dev/null': %s\n",
- strerror (errno));
- _exit (4);
- }
- if (dup2 (fd, STDERR_FILENO) == -1)
- {
- _assuan_log_printf ("dup2(dev/null, 2) failed: %s\n",
- strerror (errno));
- _exit (4);
- }
- }
-
-
- /* Close all files which will not be duped and are not in the
- fd_child_list. */
- n = sysconf (_SC_OPEN_MAX);
- if (n < 0)
- n = MAX_OPEN_FDS;
- for (i=0; i < n; i++)
- {
- if ( i == STDIN_FILENO || i == STDOUT_FILENO
- || i == STDERR_FILENO)
- continue;
- fdp = fd_child_list;
- if (fdp)
- {
- while (*fdp != -1 && *fdp != i)
- fdp++;
- }
-
- if (!(fdp && *fdp != -1))
- close(i);
- }
- errno = 0;
-
- /* We store our parents pid in the environment so that the
- execed assuan server is able to read the actual pid of the
- client. The server can't use getppid becuase it might have
- been double forked before the assuan server has been
- initialized. */
- setenv ("_assuan_pipe_connect_pid", mypidstr, 1);
-
- execv (name, (char *const *) argv);
- /* oops - use the pipe to tell the parent about it */
- snprintf (errbuf, sizeof(errbuf)-1,
- "ERR %d can't exec `%s': %.50s\n",
- ASSUAN_Problem_Starting_Server, name, strerror (errno));
- errbuf[sizeof(errbuf)-1] = 0;
- writen (1, errbuf, strlen (errbuf));
- _exit (4);
- }
-#ifdef _ASSUAN_USE_DOUBLE_FORK
- if (pid == -1)
- _exit (1);
- else
- _exit (0);
-#endif
- }
-
-#ifdef _ASSUAN_USE_DOUBLE_FORK
- waitpid ((*ctx)->pid, NULL, 0);
- (*ctx)->pid = -1;
-#endif
-
- close (rp[1]);
- close (wp[0]);
-
-#endif /*!HAVE_W32_SYSTEM*/
-
- /* initial handshake */
- {
- int okay, off;
-
- err = _assuan_read_from_server (*ctx, &okay, &off);
- if (err)
- _assuan_log_printf ("can't connect server: %s\n",
- assuan_strerror (err));
- else if (okay != 1)
- {
- _assuan_log_printf ("can't connect server: `%s'\n",
- (*ctx)->inbound.line);
- err = ASSUAN_Connect_Failed;
- }
- }
-
- if (err)
- {
- assuan_disconnect (*ctx);
- *ctx = NULL;
- }
-
- return err;
+ return initial_handshake (ctx);
}
+#endif /*HAVE_W32_SYSTEM*/
-
+\f
/* 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
assuan_pipe_connect (assuan_context_t *ctx, const char *name,
const char *const argv[], int *fd_child_list)
{
- return assuan_pipe_connect2 (ctx, name, argv, fd_child_list, NULL, NULL);
+ return pipe_connect (ctx, name, argv, fd_child_list, NULL, NULL);
+}
+
+
+
+assuan_error_t
+assuan_pipe_connect2 (assuan_context_t *ctx,
+ const char *name, const char *const argv[],
+ int *fd_child_list,
+ void (*atfork) (void *opaque, int reserved),
+ void *atforkvalue)
+{
+ return pipe_connect (ctx, name, argv, fd_child_list, atfork, atforkvalue);
+}
+
+
+/* Connect to a server over a full-duplex socket (i.e. created by
+ socketpair), creating the assuan context and returning it in CTX.
+ The server filename is NAME, the argument vector in ARGV.
+ FD_CHILD_LIST is a -1 terminated list of file descriptors not to
+ close in the child. ATFORK is called in the child right after the
+ fork; ATFORKVALUE is passed as the first argument and 0 is passed
+ as the second argument. The ATFORK function should only act if the
+ second value is 0.
+
+ For now FLAGS may either take the value 0 to behave like
+ assuan_pipe_connect2 or 1 to enable the described full-duplex
+ socket behaviour.
+
+ If NAME as well as ARGV are NULL, no exec is done but the same
+ process is continued. However all file descriptors are closed and
+ some special environment variables are set. To let the caller
+ detect whether the child or the parent continues, the child returns
+ a CTX of NULL. */
+assuan_error_t
+assuan_pipe_connect_ext (assuan_context_t *ctx,
+ const char *name, const char *const argv[],
+ int *fd_child_list,
+ void (*atfork) (void *opaque, int reserved),
+ void *atforkvalue, unsigned int flags)
+{
+ if ((flags & 1))
+ {
+#ifdef HAVE_W32_SYSTEM
+ return _assuan_error (ASSUAN_Not_Implemented);
+#else
+ return socketpair_connect (ctx, name, argv, fd_child_list,
+ atfork, atforkvalue);
+#endif
+ }
+ else
+ return pipe_connect (ctx, name, argv, fd_child_list, atfork, atforkvalue);
}
+
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
*/
#include <config.h>
#include <stdlib.h>
#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
#include <unistd.h>
#ifdef HAVE_W32_SYSTEM
#include <windows.h>
static void
-deinit_pipe_server (ASSUAN_CONTEXT ctx)
+deinit_pipe_server (assuan_context_t ctx)
{
/* nothing to do for this simple server */
}
static int
-accept_connection (ASSUAN_CONTEXT ctx)
+accept_connection (assuan_context_t ctx)
{
/* This is a NOP for a pipe server */
return 0;
}
static int
-finish_connection (ASSUAN_CONTEXT ctx)
+finish_connection (assuan_context_t ctx)
{
/* This is a NOP for a pipe server */
return 0;
/* Create a new context. Note that the handlers are set up for a pipe
server/client - this way we don't need extra dummy functions */
int
-_assuan_new_context (ASSUAN_CONTEXT *r_ctx)
+_assuan_new_context (assuan_context_t *r_ctx)
{
static struct assuan_io io = { _assuan_simple_read,
_assuan_simple_write,
0, 0 };
- ASSUAN_CONTEXT ctx;
+ assuan_context_t ctx;
int rc;
*r_ctx = NULL;
ctx = xtrycalloc (1, sizeof *ctx);
if (!ctx)
- return ASSUAN_Out_Of_Core;
+ return _assuan_error (ASSUAN_Out_Of_Core);
ctx->input_fd = -1;
ctx->output_fd = -1;
}
+/* Returns true if atoi(S) denotes a valid socket. */
+static int
+is_valid_socket (const char *s)
+{
+ struct stat buf;
+
+ if ( fstat (atoi (s), &buf ) )
+ return 0;
+ return S_ISSOCK (buf.st_mode);
+}
+
+
int
-assuan_init_pipe_server (ASSUAN_CONTEXT *r_ctx, int filedes[2])
+assuan_init_pipe_server (assuan_context_t *r_ctx, int filedes[2])
{
int rc;
rc = _assuan_new_context (r_ctx);
if (!rc)
{
- ASSUAN_CONTEXT ctx = *r_ctx;
+ assuan_context_t ctx = *r_ctx;
const char *s;
unsigned long ul;
ctx->inbound.fd = _get_osfhandle (filedes[0]);
ctx->outbound.fd = _get_osfhandle (filedes[1]);
#else
- ctx->inbound.fd = filedes[0];
- ctx->outbound.fd = filedes[1];
+ s = getenv ("_assuan_connection_fd");
+ if (s && *s && is_valid_socket (s) )
+ {
+ /* Well, we are called with an bi-directional file
+ descriptor. Prepare for using sendmsg/recvmsg. In this
+ case we ignore the passed file descriptors. */
+ ctx->inbound.fd = ctx->outbound.fd = atoi (s);
+ _assuan_init_uds_io (ctx);
+ ctx->deinit_handler = _assuan_uds_deinit;
+ }
+ else if (filedes && filedes[0] != -1 && filedes[1] != -1 )
+ {
+ /* Standard pipe server. */
+ ctx->inbound.fd = filedes[0];
+ ctx->outbound.fd = filedes[1];
+ }
+ else
+ {
+ _assuan_release_context (*r_ctx);
+ *r_ctx = NULL;
+ return ASSUAN_Problem_Starting_Server;
+ }
#endif
ctx->pipe_mode = 1;
void
-_assuan_release_context (ASSUAN_CONTEXT ctx)
+_assuan_release_context (assuan_context_t ctx)
{
if (ctx)
{
}
void
-assuan_deinit_server (ASSUAN_CONTEXT ctx)
+assuan_deinit_server (assuan_context_t ctx)
{
if (ctx)
{
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
*/
#include <config.h>
static int
-do_finish (ASSUAN_CONTEXT ctx)
+do_finish (assuan_context_t ctx)
{
if (ctx->inbound.fd != -1)
{
}
static void
-do_deinit (ASSUAN_CONTEXT ctx)
+do_deinit (assuan_context_t ctx)
{
do_finish (ctx);
}
+
+
/* Make a connection to the Unix domain socket NAME and return a new
Assuan context in CTX. SERVER_PID is currently not used but may
become handy in the future. */
assuan_error_t
-assuan_socket_connect (ASSUAN_CONTEXT *r_ctx,
+assuan_socket_connect (assuan_context_t *r_ctx,
const char *name, pid_t server_pid)
+{
+ return assuan_socket_connect_ext (r_ctx, name, server_pid, 0);
+}
+
+
+/* Make a connection to the Unix domain socket NAME and return a new
+ Assuan context in CTX. SERVER_PID is currently not used but may
+ become handy in the future. With flags set to 1 sendmsg and
+ recvmesg are used. */
+assuan_error_t
+assuan_socket_connect_ext (assuan_context_t *r_ctx,
+ const char *name, pid_t server_pid,
+ unsigned int flags)
{
static struct assuan_io io = { _assuan_simple_read,
_assuan_simple_write };
assuan_error_t err;
- ASSUAN_CONTEXT ctx;
+ assuan_context_t ctx;
int fd;
struct sockaddr_un srvr_addr;
size_t len;
const char *s;
if (!r_ctx || !name)
- return ASSUAN_Invalid_Value;
+ return _assuan_error (ASSUAN_Invalid_Value);
*r_ctx = NULL;
- /* We require that the name starts with a slash, so that we can
- alter reuse this function for other socket types. To make things
- easier we allow an optional dirver prefix. */
+ /* We require that the name starts with a slash, so that we
+ eventually can reuse this function for other socket types. To
+ make things easier we allow an optional dirver prefix. */
s = name;
if (*s && s[1] == ':')
s += 2;
if (*s != DIRSEP_C && *s != '/')
- return ASSUAN_Invalid_Value;
+ return _assuan_error (ASSUAN_Invalid_Value);
if (strlen (name)+1 >= sizeof srvr_addr.sun_path)
- return ASSUAN_Invalid_Value;
+ return _assuan_error (ASSUAN_Invalid_Value);
err = _assuan_new_context (&ctx);
if (err)
return err;
- ctx->deinit_handler = do_deinit;
+ ctx->deinit_handler = ((flags&1))? _assuan_uds_deinit : do_deinit;
ctx->finish_handler = do_finish;
-
fd = _assuan_sock_new (PF_LOCAL, SOCK_STREAM, 0);
if (fd == -1)
{
_assuan_log_printf ("can't create socket: %s\n", strerror (errno));
_assuan_release_context (ctx);
- return ASSUAN_General_Error;
+ return _assuan_error (ASSUAN_General_Error);
}
memset (&srvr_addr, 0, sizeof srvr_addr);
name, strerror (errno));
_assuan_release_context (ctx);
_assuan_close (fd);
- return ASSUAN_Connect_Failed;
+ return _assuan_error (ASSUAN_Connect_Failed);
}
ctx->inbound.fd = fd;
ctx->outbound.fd = fd;
ctx->io = &io;
-
+ if ((flags&1))
+ _assuan_init_uds_io (ctx);
+
/* initial handshake */
{
int okay, off;
/*LOG ("can't connect to server: `");*/
_assuan_log_sanitized_string (ctx->inbound.line);
fprintf (assuan_get_assuan_log_stream (), "'\n");
- err = ASSUAN_Connect_Failed;
+ err = _assuan_error (ASSUAN_Connect_Failed);
}
}
*r_ctx = ctx;
return 0;
}
+
+
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
*/
#include <config.h>
#include "assuan-defs.h"
+static struct assuan_io io = { _assuan_simple_read,
+ _assuan_simple_write };
+
+
static int
accept_connection_bottom (assuan_context_t ctx)
{
int fd = ctx->connected_fd;
+ ctx->peercred.valid = 0;
#ifdef HAVE_SO_PEERCRED
{
- /* This overrides any already set PID if the function returns a
- valid one. */
struct ucred cr;
- int cl = sizeof cr;
-
- if ( !getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &cr, &cl)
- && cr.pid != (pid_t)-1 && cr.pid )
- ctx->pid = cr.pid;
+ socklen_t cl = sizeof cr;
+
+ if ( !getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &cr, &cl))
+ {
+ ctx->peercred.pid = cr.pid;
+ ctx->peercred.uid = cr.uid;
+ ctx->peercred.gid = cr.gid;
+ ctx->peercred.valid = 1;
+
+ /* This overrides any already set PID if the function returns
+ a valid one. */
+ if (cr.pid != (pid_t)-1 && cr.pid)
+ ctx->pid = cr.pid;
+ }
}
#endif
{
int fd;
struct sockaddr_un clnt_addr;
- size_t len = sizeof clnt_addr;
+ socklen_t len = sizeof clnt_addr;
fd = accept (ctx->listen_fd, (struct sockaddr*)&clnt_addr, &len );
if (fd == -1)
{
ctx->os_errno = errno;
- return ASSUAN_Accept_Failed;
+ return _assuan_error (ASSUAN_Accept_Failed);
}
ctx->connected_fd = fd;
finish_connection (ctx);
}
-static struct assuan_io io = { _assuan_simple_read,
- _assuan_simple_write };
-
/* Initialize a server for the socket LISTEN_FD which has already be
put into listen mode */
int
assuan_init_socket_server (assuan_context_t *r_ctx, int listen_fd)
{
- assuan_context_t ctx;
- int rc;
-
- *r_ctx = NULL;
- ctx = xtrycalloc (1, sizeof *ctx);
- if (!ctx)
- return ASSUAN_Out_Of_Core;
- ctx->is_server = 1;
- ctx->input_fd = -1;
- ctx->output_fd = -1;
-
- ctx->inbound.fd = -1;
- ctx->outbound.fd = -1;
-
- ctx->listen_fd = listen_fd;
- ctx->connected_fd = -1;
- ctx->deinit_handler = deinit_socket_server;
- ctx->accept_handler = accept_connection;
- ctx->finish_handler = finish_connection;
-
- ctx->io = &io;
-
- rc = _assuan_register_std_commands (ctx);
- if (rc)
- xfree (ctx);
- else
- *r_ctx = ctx;
- return rc;
+ return assuan_init_socket_server_ext (r_ctx, listen_fd, 0);
}
-/* Initialize a server using the already accepted socket FD. */
+/* Initialize a server using the already accepted socket FD. This
+ fucntion is deprecated. */
int
assuan_init_connected_socket_server (assuan_context_t *r_ctx, int fd)
+{
+ return assuan_init_socket_server_ext (r_ctx, fd, 2);
+}
+
+
+/*
+ Flag bits: 0 - use sendmsg/recvmsg to allow descriptor passing
+ 1 - FD has already been accepted.
+*/
+int
+assuan_init_socket_server_ext (assuan_context_t *r_ctx, int fd,
+ unsigned int flags)
{
assuan_context_t ctx;
int rc;
*r_ctx = NULL;
ctx = xtrycalloc (1, sizeof *ctx);
if (!ctx)
- return ASSUAN_Out_Of_Core;
+ return _assuan_error (ASSUAN_Out_Of_Core);
ctx->is_server = 1;
- ctx->pipe_mode = 1; /* we want a second accept to indicate EOF */
+ if ((flags & 2))
+ ctx->pipe_mode = 1; /* We want a second accept to indicate EOF. */
ctx->input_fd = -1;
ctx->output_fd = -1;
ctx->inbound.fd = -1;
ctx->outbound.fd = -1;
- ctx->io = &io;
-
- ctx->listen_fd = -1;
- ctx->connected_fd = fd;
- ctx->deinit_handler = deinit_socket_server;
- ctx->accept_handler = accept_connection_bottom;
+ if ((flags & 2))
+ {
+ ctx->listen_fd = -1;
+ ctx->connected_fd = fd;
+ }
+ else
+ {
+ ctx->listen_fd = fd;
+ ctx->connected_fd = -1;
+ }
+ ctx->deinit_handler = (flags & 1)? _assuan_uds_deinit:deinit_socket_server;
+ ctx->accept_handler = ((flags & 2)
+ ? accept_connection_bottom
+ : accept_connection);
ctx->finish_handler = finish_connection;
+ ctx->io = &io;
+ if ((flags & 1))
+ _assuan_init_uds_io (ctx);
+
rc = _assuan_register_std_commands (ctx);
if (rc)
xfree (ctx);
*r_ctx = ctx;
return rc;
}
-
-
/* assuan-socket.c
- * Copyright (C) 2004 Free Software Foundation, Inc.
+ * Copyright (C) 2004, 2005 Free Software Foundation, Inc.
*
- * This file is part of GnuPG.
+ * This file is part of Assuan.
*
- * GnuPG is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * Assuan is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
*
- * GnuPG is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * Assuan is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
*/
+
#include <config.h>
#include <stdio.h>
#ifdef HAVE_W32_SYSTEM
#endif
#include "assuan-defs.h"
+/* Hacks for Slowaris. */
+#ifndef PF_LOCAL
+# ifdef PF_UNIX
+# define PF_LOCAL PF_UNIX
+# else
+# define PF_LOCAL AF_UNIX
+# endif
+#endif
+#ifndef AF_LOCAL
+# define AF_LOCAL AF_UNIX
+#endif
+
int
_assuan_close (int fd)
{
--- /dev/null
+/* 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;
+}
+
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
*/
#include <config.h>
}
-void
-assuan_set_log_stream (assuan_context_t ctx, FILE *fp)
-{
- if (ctx)
- {
- if (ctx->log_fp)
- fflush (ctx->log_fp);
- ctx->log_fp = fp;
- _assuan_set_default_log_stream (fp);
- }
-}
-
-
void
assuan_begin_confidential (assuan_context_t ctx)
{
}
-/* 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
-}
-
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
*/
#ifndef ASSUAN_H
#include <unistd.h>
-/* To use this file with libraries the following macros are often
- useful:
+/* To use this file with libraries the following macros are useful:
- #define _ASSUAN_EXT_SYM_PREFIX _foo_
+ #define _ASSUAN_EXT_SYM_PREFIX _foo_
This prefixes all external symbols with "_foo_".
- #define _ASSUAN_NO_PTH
+ #define _ASSUAN_ONLY_GPG_ERRORS
- This avoids inclusion of special GNU Pth hacks.
+ If this is defined all old-style Assuan error codes are made
+ inactive as well as other dereacted stuff.
- #define _ASSUAN_NO_FIXED_SIGNALS
+ The follwing macros are used internally in the implementation of
+ libassuan:
- This disables changing of certain signal handler; i.e. SIGPIPE.
+ #define _ASSUAN_NO_PTH
- #define _ASSUAN_USE_DOUBLE_FORK
+ This avoids inclusion of special GNU Pth hacks.
- Use a double fork approach when connecting to a server through a pipe.
+ #define _ASSUAN_NO_FIXED_SIGNALS
+
+ This disables changing of certain signal handler; i.e. SIGPIPE.
+
+ #define _ASSUAN_USE_DOUBLE_FORK
+
+ Use a double fork approach when connecting to a server through
+ a pipe.
*/
/**** Begin GPGME specific modifications. ******/
#define _ASSUAN_EXT_SYM_PREFIX _gpgme_
#define assuan_init_socket_server _ASSUAN_PREFIX(assuan_init_socket_server)
#define assuan_init_connected_socket_server \
_ASSUAN_PREFIX(assuan_init_connected_socket_server)
+#define assuan_init_socket_server_ext \
+ _ASSUAN_PREFIX(assuan_init_socket_server_ext)
#define assuan_pipe_connect _ASSUAN_PREFIX(assuan_pipe_connect)
+#define assuan_pipe_connect_ext _ASSUAN_PREFIX(assuan_pipe_connect_ext)
#define assuan_socket_connect _ASSUAN_PREFIX(assuan_socket_connect)
-#define assuan_domain_connect _ASSUAN_PREFIX(assuan_domain_connect)
-#define assuan_init_domain_server _ASSUAN_PREFIX(assuan_init_domain_server)
+#define assuan_socket_connect_ext _ASSUAN_PREFIX(assuan_socket_connect_ext)
#define assuan_disconnect _ASSUAN_PREFIX(assuan_disconnect)
#define assuan_get_pid _ASSUAN_PREFIX(assuan_get_pid)
+#define assuan_get_peercred _ASSUAN_PREFIX(assuan_get_peercred)
#define assuan_transact _ASSUAN_PREFIX(assuan_transact)
#define assuan_inquire _ASSUAN_PREFIX(assuan_inquire)
#define assuan_read_line _ASSUAN_PREFIX(assuan_read_line)
#define assuan_begin_confidential _ASSUAN_PREFIX(assuan_begin_confidential)
#define assuan_end_confidential _ASSUAN_PREFIX(assuan_end_confidential)
#define assuan_strerror _ASSUAN_PREFIX(assuan_strerror)
+#define assuan_set_assuan_err_source \
+ _ASSUAN_PREFIX(assuan_set_assuan_err_source)
#define assuan_set_assuan_log_stream \
_ASSUAN_PREFIX(assuan_set_assuan_log_stream)
#define assuan_get_assuan_log_stream \
#endif
-typedef enum
-{
- ASSUAN_No_Error = 0,
- ASSUAN_General_Error = 1,
- ASSUAN_Out_Of_Core = 2,
- ASSUAN_Invalid_Value = 3,
- ASSUAN_Timeout = 4,
- ASSUAN_Read_Error = 5,
- ASSUAN_Write_Error = 6,
- ASSUAN_Problem_Starting_Server = 7,
- ASSUAN_Not_A_Server = 8,
- ASSUAN_Not_A_Client = 9,
- ASSUAN_Nested_Commands = 10,
- ASSUAN_Invalid_Response = 11,
- ASSUAN_No_Data_Callback = 12,
- ASSUAN_No_Inquire_Callback = 13,
- ASSUAN_Connect_Failed = 14,
- ASSUAN_Accept_Failed = 15,
+/* Check for compiler features. */
+#if __GNUC__
+#define _ASSUAN_GCC_VERSION (__GNUC__ * 10000 \
+ + __GNUC_MINOR__ * 100 \
+ + __GNUC_PATCHLEVEL__)
+
+#if _ASSUAN_GCC_VERSION > 30100
+#define _ASSUAN_DEPRECATED __attribute__ ((__deprecated__))
+#endif
+#endif
+#ifndef _ASSUAN_DEPRECATED
+#define _ASSUAN_DEPRECATED
+#endif
+
+
+/* Assuan error codes. These are only used by old applications or
+ those applications which won't make use of libgpg-error. */
+#ifndef _ASSUAN_ONLY_GPG_ERRORS
+#ifndef _ASSUAN_IN_LIBASSUAN
+#define ASSUAN_No_Error 0
+#endif
+#define ASSUAN_General_Error 1
+#define ASSUAN_Out_Of_Core 2
+#define ASSUAN_Invalid_Value 3
+#ifndef _ASSUAN_IN_LIBASSUAN
+#define ASSUAN_Timeout 4
+#endif
+#define ASSUAN_Read_Error 5
+#define ASSUAN_Write_Error 6
+#define ASSUAN_Problem_Starting_Server 7
+#define ASSUAN_Not_A_Server 8
+#ifndef _ASSUAN_IN_LIBASSUAN
+#define ASSUAN_Not_A_Client 9
+#endif
+#define ASSUAN_Nested_Commands 10
+#define ASSUAN_Invalid_Response 11
+#define ASSUAN_No_Data_Callback 12
+#define ASSUAN_No_Inquire_Callback 13
+#define ASSUAN_Connect_Failed 14
+#define ASSUAN_Accept_Failed 15
/* Error codes above 99 are meant as status codes */
- ASSUAN_Not_Implemented = 100,
- ASSUAN_Server_Fault = 101,
- ASSUAN_Invalid_Command = 102,
- ASSUAN_Unknown_Command = 103,
- ASSUAN_Syntax_Error = 104,
- ASSUAN_Parameter_Error = 105,
- ASSUAN_Parameter_Conflict = 106,
- ASSUAN_Line_Too_Long = 107,
- ASSUAN_Line_Not_Terminated = 108,
- ASSUAN_No_Input = 109,
- ASSUAN_No_Output = 110,
- ASSUAN_Canceled = 111,
- ASSUAN_Unsupported_Algorithm = 112,
- ASSUAN_Server_Resource_Problem = 113,
- ASSUAN_Server_IO_Error = 114,
- ASSUAN_Server_Bug = 115,
- ASSUAN_No_Data_Available = 116,
- ASSUAN_Invalid_Data = 117,
- ASSUAN_Unexpected_Command = 118,
- ASSUAN_Too_Much_Data = 119,
- ASSUAN_Inquire_Unknown = 120,
- ASSUAN_Inquire_Error = 121,
- ASSUAN_Invalid_Option = 122,
- ASSUAN_Invalid_Index = 123,
- ASSUAN_Unexpected_Status = 124,
- ASSUAN_Unexpected_Data = 125,
- ASSUAN_Invalid_Status = 126,
- ASSUAN_Locale_Problem = 127,
- ASSUAN_Not_Confirmed = 128,
-
- /* Warning: Don't use the rror codes, below they are deprecated. */
- ASSUAN_Bad_Certificate = 201,
- ASSUAN_Bad_Certificate_Chain = 202,
- ASSUAN_Missing_Certificate = 203,
- ASSUAN_Bad_Signature = 204,
- ASSUAN_No_Agent = 205,
- ASSUAN_Agent_Error = 206,
- ASSUAN_No_Public_Key = 207,
- ASSUAN_No_Secret_Key = 208,
- ASSUAN_Invalid_Name = 209,
-
- ASSUAN_Cert_Revoked = 301,
- ASSUAN_No_CRL_For_Cert = 302,
- ASSUAN_CRL_Too_Old = 303,
- ASSUAN_Not_Trusted = 304,
-
- ASSUAN_Card_Error = 401,
- ASSUAN_Invalid_Card = 402,
- ASSUAN_No_PKCS15_App = 403,
- ASSUAN_Card_Not_Present = 404,
- ASSUAN_Invalid_Id = 405,
+#define ASSUAN_Not_Implemented 100
+#define ASSUAN_Server_Fault 101
+#ifndef _ASSUAN_IN_LIBASSUAN
+#define ASSUAN_Invalid_Command 102
+#endif
+#define ASSUAN_Unknown_Command 103
+#define ASSUAN_Syntax_Error 104
+#ifndef _ASSUAN_IN_LIBASSUAN
+#define ASSUAN_Parameter_Error 105
+#endif
+#define ASSUAN_Parameter_Conflict 106
+#define ASSUAN_Line_Too_Long 107
+#define ASSUAN_Line_Not_Terminated 108
+#ifndef _ASSUAN_IN_LIBASSUAN
+#define ASSUAN_No_Input 109
+#define ASSUAN_No_Output 110
+#endif
+#define ASSUAN_Canceled 111
+#ifndef _ASSUAN_IN_LIBASSUAN
+#define ASSUAN_Unsupported_Algorithm 112
+#define ASSUAN_Server_Resource_Problem 113
+#define ASSUAN_Server_IO_Error 114
+#define ASSUAN_Server_Bug 115
+#define ASSUAN_No_Data_Available 116
+#define ASSUAN_Invalid_Data 117
+#endif
+#define ASSUAN_Unexpected_Command 118
+#define ASSUAN_Too_Much_Data 119
+#ifndef _ASSUAN_IN_LIBASSUAN
+#define ASSUAN_Inquire_Unknown 120
+#define ASSUAN_Inquire_Error 121
+#define ASSUAN_Invalid_Option 122
+#define ASSUAN_Invalid_Index 123
+#define ASSUAN_Unexpected_Status 124
+#define ASSUAN_Unexpected_Data 125
+#define ASSUAN_Invalid_Status 126
+#define ASSUAN_Locale_Problem 127
+#define ASSUAN_Not_Confirmed 128
+
+ /* Warning: Don't use the Error codes, below they are deprecated. */
+#define ASSUAN_Bad_Certificate 201
+#define ASSUAN_Bad_Certificate_Chain 202
+#define ASSUAN_Missing_Certificate 203
+#define ASSUAN_Bad_Signature 204
+#define ASSUAN_No_Agent 205
+#define ASSUAN_Agent_Error 206
+#define ASSUAN_No_Public_Key 207
+#define ASSUAN_No_Secret_Key 208
+#define ASSUAN_Invalid_Name 209
+
+#define ASSUAN_Cert_Revoked 301
+#define ASSUAN_No_CRL_For_Cert 302
+#define ASSUAN_CRL_Too_Old 303
+#define ASSUAN_Not_Trusted 304
+
+#define ASSUAN_Card_Error 401
+#define ASSUAN_Invalid_Card 402
+#define ASSUAN_No_PKCS15_App 403
+#define ASSUAN_Card_Not_Present 404
+#define ASSUAN_Invalid_Id 405
/* Error codes in the range 1000 to 9999 may be used by applications
at their own discretion. */
- ASSUAN_USER_ERROR_FIRST = 1000,
- ASSUAN_USER_ERROR_LAST = 9999
+#define ASSUAN_USER_ERROR_FIRST 1000
+#define ASSUAN_USER_ERROR_LAST 9999
+#endif
-} assuan_error_t;
+typedef int assuan_error_t;
-typedef assuan_error_t AssuanError; /* Deprecated. */
+typedef assuan_error_t AssuanError _ASSUAN_DEPRECATED;
/* This is a list of pre-registered ASSUAN commands */
-/* NOTE, these command IDs are now deprectated and solely exists for
+/* Note, these command IDs are now deprectated and solely exists for
compatibility reasons. */
typedef enum
{
} AssuanCommand;
+#else /*!_ASSUAN_ONLY_GPG_ERRORS*/
+
+typedef int assuan_error_t;
+
+#endif /*!_ASSUAN_ONLY_GPG_ERRORS*/
+
+
/* Definitions of flags for assuan_set_flag(). */
typedef enum
{
struct assuan_context_s;
typedef struct assuan_context_s *assuan_context_t;
-typedef struct assuan_context_s *ASSUAN_CONTEXT;
+#ifndef _ASSUAN_ONLY_GPG_ERRORS
+typedef struct assuan_context_s *ASSUAN_CONTEXT _ASSUAN_DEPRECATED;
+#endif /*_ASSUAN_ONLY_GPG_ERRORS*/
/*-- assuan-handler.c --*/
int assuan_register_command (assuan_context_t ctx,
file descriptor via CTX and stores it in *RDF (the CTX must be
capable of passing file descriptors). */
assuan_error_t assuan_command_parse_fd (assuan_context_t ctx, char *line,
- int *rfd);
+ int *rfd);
/*-- assuan-listen.c --*/
assuan_error_t assuan_set_hello_line (assuan_context_t ctx, const char *line);
/*-- assuan-socket-server.c --*/
int assuan_init_socket_server (assuan_context_t *r_ctx, int listen_fd);
-int assuan_init_connected_socket_server (assuan_context_t *r_ctx, int fd);
-
+int assuan_init_connected_socket_server (assuan_context_t *r_ctx,
+ int fd) _ASSUAN_DEPRECATED;
+int assuan_init_socket_server_ext (assuan_context_t *r_ctx, int fd,
+ unsigned int flags);
/*-- assuan-pipe-connect.c --*/
-assuan_error_t assuan_pipe_connect (assuan_context_t *ctx, const char *name,
+assuan_error_t assuan_pipe_connect (assuan_context_t *ctx,
+ const char *name,
const char *const argv[],
int *fd_child_list);
-assuan_error_t assuan_pipe_connect2 (assuan_context_t *ctx, const char *name,
+assuan_error_t assuan_pipe_connect2 (assuan_context_t *ctx,
+ const char *name,
const char *const argv[],
int *fd_child_list,
void (*atfork) (void*, int),
- void *atforkvalue);
+ void *atforkvalue) _ASSUAN_DEPRECATED;
+assuan_error_t assuan_pipe_connect_ext (assuan_context_t *ctx,
+ const char *name,
+ const char *const argv[],
+ int *fd_child_list,
+ void (*atfork) (void *, int),
+ void *atforkvalue,
+ unsigned int flags);
+
/*-- assuan-socket-connect.c --*/
-assuan_error_t assuan_socket_connect (assuan_context_t *ctx, const char *name,
+assuan_error_t assuan_socket_connect (assuan_context_t *ctx,
+ const char *name,
pid_t server_pid);
-
-/*-- assuan-domain-connect.c --*/
-
-/* Connect to a Unix domain socket server. RENDEZVOUSFD is
- bidirectional file descriptor (normally returned via socketpair)
- which the client can use to rendezvous with the server. SERVER s
- the server's pid. */
-assuan_error_t assuan_domain_connect (assuan_context_t *r_ctx,
- int rendezvousfd,
- pid_t server);
-
-/*-- assuan-domain-server.c --*/
-
-/* RENDEZVOUSFD is a bidirectional file descriptor (normally returned
- via socketpair) that the domain server can use to rendezvous with
- the client. CLIENT is the client's pid. */
-assuan_error_t assuan_init_domain_server (assuan_context_t *r_ctx,
- int rendezvousfd,
- pid_t client);
-
+assuan_error_t assuan_socket_connect_ext (assuan_context_t *ctx,
+ const char *name,
+ pid_t server_pid,
+ unsigned int flags);
/*-- assuan-connect.c --*/
void assuan_disconnect (assuan_context_t ctx);
pid_t assuan_get_pid (assuan_context_t ctx);
+assuan_error_t assuan_get_peercred (assuan_context_t ctx,
+ pid_t *pid, uid_t *uid, gid_t *gid);
/*-- assuan-client.c --*/
assuan_error_t
assuan_transact (assuan_context_t ctx,
const char *command,
- assuan_error_t (*data_cb)(void *, const void *, size_t),
+ int (*data_cb)(void *, const void *, size_t),
void *data_cb_arg,
- assuan_error_t (*inquire_cb)(void*, const char *),
+ int (*inquire_cb)(void*, const char *),
void *inquire_cb_arg,
- assuan_error_t (*status_cb)(void*, const char *),
+ int (*status_cb)(void*, const char *),
void *status_cb_arg);
const void *buffer, size_t length);
/* The file descriptor must be pending before assuan_receivefd is
- call. This means that assuan_sendfd should be called *before* the
- trigger is sent (normally via assuan_send_data ("I sent you a
- descriptor")). */
+ called. This means that assuan_sendfd should be called *before* the
+ trigger is sent (normally via assuan_write_line ("INPUT FD")). */
assuan_error_t assuan_sendfd (assuan_context_t ctx, int fd);
assuan_error_t assuan_receivefd (assuan_context_t ctx, int *fd);
int assuan_get_flag (assuan_context_t ctx, assuan_flag_t flag);
-/*-- assuan-errors.c (built) --*/
+/*-- assuan-errors.c --*/
+
+#ifndef _ASSUAN_ONLY_GPG_ERRORS
+/* Return a string describing the assuan error. The use of this
+ function is deprecated; it is better to call
+ assuan_set_assuan_err_source once and then make use libgpg-error. */
const char *assuan_strerror (assuan_error_t err);
+#endif /*_ASSUAN_ONLY_GPG_ERRORS*/
+
+/* Enable gpg-error style error codes. ERRSOURCE is one of gpg-error
+ sources. Note, that this function is not thread-safe and should be
+ used right at startup. Switching back to the old style mode is not
+ supported. */
+void assuan_set_assuan_err_source (int errsource);
/*-- assuan-logging.c --*/
/* funopen.c - Replacement for funopen.
- * Copyright (C) 2003 Free Software Foundation, Inc.
+ * Copyright (C) 2003, 2005 Free Software Foundation, Inc.
*
- * This file is part of GnuPG.
+ * This file is part of Assuan.
*
- * GnuPG is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * Assuan is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
*
- * GnuPG is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * Assuan is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
*/
#ifdef HAVE_CONFIG_H
io.seek = seekfn;
io.close = closefn;
- return fopencookie (cookie,
+ return fopencookie (cookie,
readfn ? ( writefn ? "rw" : "r" )
: ( writefn ? "w" : ""), io);
}
#!/bin/sh
# mkerrors - Extract error strings from assuan.h
# and create C source for assuan_strerror
-# Copyright (C) 2001, 2002 Free Software Foundation, Inc.
+# Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
#
# This file is part of Assuan.
#
#
# You should have received a copy of the GNU Lesser General Public
# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
cat <<EOF
/* Generated automatically by mkerrors */
-/* Do not edit! */
+/* Do not edit! See mkerrors for copyright notice. */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
+#include <assert.h>
+#include <errno.h>
+
+#undef _ASSUAN_IN_LIBASSUAN /* undef to get all error codes. */
#include "assuan.h"
+/* If true the modern gpg-error style error codes are used in the
+ API. */
+static unsigned int err_source;
+
+/* Enable gpg-error style error codes. ERRSOURCE is one of gpg-error
+ sources. Note, that this function is not thread-safe and should be
+ used right at startup. Switching back to the old style mode is not
+ supported. */
+void
+assuan_set_assuan_err_source (int errsource)
+{
+ errsource &= 0xff;
+ err_source = errsource? errsource : 31 /*GPG_ERR_SOURCE_ANY*/;
+}
+
+
+/* Helper to map old style Assuan error codes to gpg-error codes.
+ This is used internally to keep an compatible ABI. */
+assuan_error_t
+_assuan_error (int oldcode)
+{
+ unsigned int n;
+
+ if (!err_source)
+ return (oldcode & 0x00ffffff); /* Make sure that the gpg-error
+ source part is cleared. */
+
+ switch (oldcode)
+ {
+ case ASSUAN_General_Error: n = 257; break;
+ case ASSUAN_Accept_Failed: n = 258; break;
+ case ASSUAN_Connect_Failed: n = 259; break;
+ case ASSUAN_Invalid_Response: n = 260; break;
+ case ASSUAN_Invalid_Value: n = 261; break;
+ case ASSUAN_Line_Not_Terminated: n = 262; break;
+ case ASSUAN_Line_Too_Long: n = 263; break;
+ case ASSUAN_Nested_Commands: n = 264; break;
+ case ASSUAN_No_Data_Callback: n = 265; break;
+ case ASSUAN_No_Inquire_Callback: n = 266; break;
+ case ASSUAN_Not_A_Server: n = 267; break;
+ case ASSUAN_Not_Implemented: n = 69; break;
+ case ASSUAN_Parameter_Conflict: n = 280; break;
+ case ASSUAN_Problem_Starting_Server: n = 269; break;
+ case ASSUAN_Server_Fault: n = 80; break;
+ case ASSUAN_Syntax_Error: n = 276; break;
+ case ASSUAN_Too_Much_Data: n = 273; break;
+ case ASSUAN_Unexpected_Command: n = 274; break;
+ case ASSUAN_Unknown_Command: n = 275; break;
+ case ASSUAN_Canceled: n = 277; break;
+ case ASSUAN_No_Secret_Key: n = 17; break;
+
+ case ASSUAN_Read_Error:
+ switch (errno)
+ {
+ case 0: n = 16381; /*GPG_ERR_MISSING_ERRNO*/ break;
+ default: n = 270; /*GPG_ERR_ASS_READ_ERROR*/ break;
+ }
+ break;
+
+ case ASSUAN_Write_Error:
+ switch (errno)
+ {
+ case 0: n = 16381; /*GPG_ERR_MISSING_ERRNO*/ break;
+ default: n = 271; /*GPG_ERR_ASS_WRITE_ERROR*/ break;
+ }
+ break;
+
+ case ASSUAN_Out_Of_Core:
+ switch (errno)
+ {
+ case 0: /* Should not happen but a user might have provided
+ an incomplete implemented malloc function. Give
+ him a chance to correct this fault but make sure
+ an error is indeed returned. */
+ n = 16381; /*GPG_ERR_MISSING_ERRNO*/
+ break;
+ case ENOMEM: n = (1 << 15) | 86; break;
+ default:
+ n = 16382; /*GPG_ERR_UNKNOWN_ERRNO*/
+ break;
+ }
+ break;
+
+ case -1: n = 16383 /*GPG_ERR_EOF*/; break;
+
+ default:
+ n = 257;
+ break;
+ }
+
+ return ((err_source << 24) | (n & 0x00ffffff));
+
+}
+
+
/**
* assuan_strerror:
* @err: Error code
* Return value: String with the error description.
**/
const char *
-assuan_strerror (AssuanError err)
+assuan_strerror (assuan_error_t err)
{
const char *s;
static char buf[50];
EOF
awk '
-/ASSUAN_No_Error/ { okay=1 }
-!okay {next}
-/}/ { exit 0 }
-/ASSUAN_[A-Za-z_]*/ { print_code($1) }
+/ASSUAN_No_Error/ { okay=1 }
+!okay {next}
+/^#define[ ]+ASSUAN_[A-Za-z_]*/ { print_code($2) }
+/ASSUAN_USER_ERROR_LAST/ { exit 0 }
function print_code( s )
'
cat <<EOF
+ case -1: s = "EOF (-1)"; break;
default:
{
- unsigned int source, code;
+ unsigned int source, code, n;
source = ((err >> 24) & 0xff);
code = (err & 0x00ffffff);
- if (source) /* Assume this is an libgpg-error. */
- sprintf (buf, "ec=%u.%u", source, code );
+ if (source)
+ {
+ /* Assume this is an libgpg-error and try to map the codes
+ back. */
+ switch (code)
+ {
+ case 257: n = ASSUAN_General_Error ; break;
+ case 258: n = ASSUAN_Accept_Failed ; break;
+ case 259: n = ASSUAN_Connect_Failed ; break;
+ case 260: n = ASSUAN_Invalid_Response ; break;
+ case 261: n = ASSUAN_Invalid_Value ; break;
+ case 262: n = ASSUAN_Line_Not_Terminated ; break;
+ case 263: n = ASSUAN_Line_Too_Long ; break;
+ case 264: n = ASSUAN_Nested_Commands ; break;
+ case 265: n = ASSUAN_No_Data_Callback ; break;
+ case 266: n = ASSUAN_No_Inquire_Callback ; break;
+ case 267: n = ASSUAN_Not_A_Server ; break;
+ case 69: n = ASSUAN_Not_Implemented ; break;
+ case 280: n = ASSUAN_Parameter_Conflict ; break;
+ case 269: n = ASSUAN_Problem_Starting_Server; break;
+ case 270: n = ASSUAN_Read_Error ; break;
+ case 271: n = ASSUAN_Write_Error ; break;
+ case 80: n = ASSUAN_Server_Fault ; break;
+ case 276: n = ASSUAN_Syntax_Error ; break;
+ case 273: n = ASSUAN_Too_Much_Data ; break;
+ case 274: n = ASSUAN_Unexpected_Command ; break;
+ case 275: n = ASSUAN_Unknown_Command ; break;
+ case 277: n = ASSUAN_Canceled ; break;
+ case ((1<<15)|86): n = ASSUAN_Out_Of_Core ; break;
+ default: n = 0; break;
+ }
+ if (n)
+ s = assuan_strerror (n);
+ else
+ {
+ sprintf (buf, "ec=%u.%u", source, code );
+ s=buf;
+ }
+ }
else
- sprintf (buf, "ec=%d", err );
- s=buf; break;
+ {
+ sprintf (buf, "ec=%d", err );
+ s=buf;
+ }
}
+ break;
}
return s;
}
-EOF
\ No newline at end of file
+EOF
# Checks for library functions.
AC_FUNC_FSEEKO
-AC_CHECK_FUNCS(stpcpy)
-
AC_REPLACE_FUNCS(vasprintf)
if test "$ac_cv_func_vasprintf" != yes; then
GNUPG_CHECK_VA_COPY
AC_REPLACE_FUNCS(isascii)
AC_REPLACE_FUNCS(putc_unlocked)
AC_REPLACE_FUNCS(memrchr)
+AC_REPLACE_FUNCS(stpcpy)
+# Check for unistd.h for setenv replacement function.
+AC_CHECK_HEADERS(unistd.h)
+AC_REPLACE_FUNCS(setenv)
# More assuan checks.
AC_CHECK_HEADERS([sys/uio.h])
AM_PATH_GPGME macro) check that this header matches the installed
library. Warning: Do not edit the next line. configure will do
that for you! */
-#define GPGME_VERSION "1.1.1-cvs1150"
+#define GPGME_VERSION "1.1.3-cvs1179"
\f
--- /dev/null
+/* 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
+
+