+2005-08-08 Werner Koch <wk@g10code.com>
+
+ * configure.ac (stpcpy): Changed from replace to test.
+
2005-03-24 Marcus Brinkmann <marcus@g10code.de>
* configure.ac (AH_BOTTOM): Removed.
+2005-08-09 Werner Koch <wk@g10code.com>
+
+ * README.1st: Adjusted to cope with changes done in upstream Assuan.
+
+ Merged changes for W32 support from libassuan.
+
+ * assuan.h [_ASSUAN_EXT_SYM_PREFIX]: New.
+ * assuan-io.c [_ASSUAN_NO_PTH]: New.
+ * assuan-pipe-connect.c (fix_signals) [_ASSUAN_NO_FIXED_SIGNALS]: New.
+ (assuan_pipe_connect2) [_ASSUAN_USE_DOUBLE_FORK]: Use double fork.
+ (fix_signals) [_ASSUAN_USE_DOUBLE_FORK]: Do not wait..
+ * assuan-logging.c, assuan-io.c: Include config.h
+ Replaced all usages of _WIN32 by the new HAVE_W32_SYSTEM because
+ there is nothing winning in this API.
+ * assuan-pipe-connect.c (assuan_pipe_connect2) [_WIN32]: Return
+ error Not Imlemented.
+ * assuan-logging.c (_assuan_w32_strerror): New.
+ * assuan-defs.h (w32_strerror): new.
+ * assuan-pipe-connect.c (assuan_pipe_connect2, fix_signals):
+ Factored signal code out to new function.
+ (build_w32_commandline, create_inheritable_pipe): New. Taken
+ from gnupg 1.9.
+ (assuan_pipe_connect2) [W32]: Implemented for W32.
+ * assuan-pipe-server.c (assuan_init_pipe_server) [W32]: Map file
+ descriptors using _get_osfhandle.
+ * assuan-socket-connect.c (assuan_socket_connect) [W32]: Allow for
+ a drive letter in the path.
+ * assuan-client.c (assuan_transact): Handle empty and comment
+ commands correctly.
+ * assuan-util.c (_assuan_calloc): Avoid integer overflow.
+ * assuan-util.c (assuan_set_flag, assuan_get_flag): New.
+ * assuan-defs.h (struct assuan_context_s): New field flags.
+ * assuan.h (assuan_flag_t): New with one flag value
+ ASSUAN_NO_WAITPID for now.
+ * assuan-pipe-connect.c (do_finish): Take care of the no_waitpid
+ flag.
+ * mkerrors: Include config.h into assuan-errors.c. This is
+ required so that assuan.h knows about the W32 macro.
+
+2005-08-09 Timo Schulz <twoaday@g10code.com> (ported from libassuan by wk)
+
+ * assuan-io.c (_assuan_simple_read, _assuan_simple_write): W32
+ support.
+ * assuan-socket.c (_assuan_close): New.
+ (_assuan_sock_new): New.
+ (_assuan_sock_bind): New.
+
2005-03-22 Werner Koch <wk@g10code.com>
* assuan-defs.h (struct assuan_io): Renamed elements READ and
with ATH replacements.
* assuan.h
-** Define _ASSUAN_IN_GPGME to enable GPGME specific code.
-** Put all exported Assuan functions in the _gpgme namespace.
-** Also wrap all system functions that are wrapped by GNU Pth to
- _gpgme wrappers.
-
-* assuan-io.c
-** Don't try to support GNU Pth here.
-
-* assuan-pipe-connect.c
-** Do not install SIGPIPE signal handler here.
+** Preserve the block between "Begin/End GPGME specific modifications".
+ In particular make sure that
+ #define _ASSUAN_EXT_SYM_PREFIX _gpgme_
+ #define _ASSUAN_NO_PTH
+ #define _ASSUAN_NO_FIXED_SIGNALS
+ #define _ASSUAN_USE_DOUBLE_FORK
+ are defined. This puts all exported Assuan functions in the _gpgme
+ namespace. It also wraps all system functions that are wrapped by
+ GNU Pth to _gpgme wrappers.
Copyright 2004 g10 Code GmbH
/* assuan-buffer.c - read and send data
- * Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
+ * Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
*
* This file is part of Assuan.
*
#include <errno.h>
#include <unistd.h>
#include <assert.h>
+#ifdef HAVE_W32_SYSTEM
+#include <process.h>
+#endif
#include "assuan-defs.h"
static int
/* Read an entire line. */
static int
readline (ASSUAN_CONTEXT ctx, char *buf, size_t buflen,
- int *r_nread, int *eof)
+ int *r_nread, int *r_eof)
{
size_t nleft = buflen;
char *p;
- *eof = 0;
+ *r_eof = 0;
*r_nread = 0;
while (nleft > 0)
{
}
else if (!n)
{
- *eof = 1;
+ *r_eof = 1;
break; /* allow incomplete lines */
}
p = buf;
if (rc)
{
if (ctx->log_fp)
- fprintf (ctx->log_fp, "%s[%p] <- [Error: %s]\n",
- assuan_get_assuan_log_prefix (), ctx, strerror (errno));
+ fprintf (ctx->log_fp, "%s[%u.%p] DBG: <- [Error: %s]\n",
+ assuan_get_assuan_log_prefix (),
+ (unsigned int)getpid (), ctx, strerror (errno));
return ASSUAN_Read_Error;
}
if (!nread)
{
assert (ctx->inbound.eof);
if (ctx->log_fp)
- fprintf (ctx->log_fp, "%s[%p] <- [EOF]\n",
- assuan_get_assuan_log_prefix (), ctx);
+ fprintf (ctx->log_fp, "%s[%u.%p] DBG: <- [EOF]\n",
+ assuan_get_assuan_log_prefix (),
+ (unsigned int)getpid (), ctx);
return -1;
}
ctx->inbound.linelen = endp - line;
if (ctx->log_fp)
{
- fprintf (ctx->log_fp, "%s[%p] <- ",
- assuan_get_assuan_log_prefix (), ctx);
+ fprintf (ctx->log_fp, "%s[%u.%p] DBG: <- ",
+ assuan_get_assuan_log_prefix (),
+ (unsigned int)getpid (), ctx);
if (ctx->confidential)
fputs ("[Confidential data not shown]", ctx->log_fp);
else
else
{
if (ctx->log_fp)
- fprintf (ctx->log_fp, "%s[%p] <- [Invalid line]\n",
- assuan_get_assuan_log_prefix (), ctx);
+ fprintf (ctx->log_fp, "%s[%u.%p] DBG: <- [Invalid line]\n",
+ assuan_get_assuan_log_prefix (),
+ (unsigned int)getpid (), ctx);
*line = 0;
ctx->inbound.linelen = 0;
return ctx->inbound.eof ? ASSUAN_Line_Not_Terminated
Returns 0 on success or an assuan error code.
See also: assuan_pending_line().
*/
-AssuanError
+assuan_error_t
assuan_read_line (ASSUAN_CONTEXT ctx, char **line, size_t *linelen)
{
- AssuanError err;
+ assuan_error_t err;
if (!ctx)
return ASSUAN_Invalid_Value;
}
-AssuanError
-assuan_write_line (ASSUAN_CONTEXT ctx, const char *line)
+assuan_error_t
+_assuan_write_line (assuan_context_t ctx, const char *prefix,
+ const char *line, size_t len)
{
- int rc;
- size_t len;
- const char *s;
+ int rc = 0;
+ size_t prefixlen = prefix? strlen (prefix):0;
- if (!ctx)
- return ASSUAN_Invalid_Value;
-
- /* Make sure that we never take a LF from the user - this might
- violate the protocol. */
- s = strchr (line, '\n');
- len = s? (s-line) : strlen (line);
-
- if (len > LINELENGTH - 2)
- return ASSUAN_Line_Too_Long;
+ /* 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: -> "
+ "[supplied line too long -truncated]\n",
+ assuan_get_assuan_log_prefix (),
+ (unsigned int)getpid (), ctx);
+ if (prefixlen > 5)
+ prefixlen = 5;
+ if (len > ASSUAN_LINELENGTH - prefixlen - 2)
+ len = ASSUAN_LINELENGTH - prefixlen - 2 - 1;
+ }
- /* fixme: we should do some kind of line buffering. */
+ /* Fixme: we should do some kind of line buffering. */
if (ctx->log_fp)
{
- fprintf (ctx->log_fp, "%s[%p] -> ",
- assuan_get_assuan_log_prefix (), ctx);
- if (s)
- fputs ("[supplied line contained a LF]", ctx->log_fp);
+ fprintf (ctx->log_fp, "%s[%u.%p] DBG: -> ",
+ assuan_get_assuan_log_prefix (),
+ (unsigned int)getpid (), ctx);
if (ctx->confidential)
fputs ("[Confidential data not shown]", ctx->log_fp);
else
putc ('\n', ctx->log_fp);
}
- rc = writen (ctx, line, len);
- if (rc)
- rc = ASSUAN_Write_Error;
+ if (prefixlen)
+ {
+ rc = writen (ctx, prefix, prefixlen);
+ if (rc)
+ rc = ASSUAN_Write_Error;
+ }
if (!rc)
{
- rc = writen (ctx, "\n", 1);
+ rc = writen (ctx, line, len);
if (rc)
rc = ASSUAN_Write_Error;
+ if (!rc)
+ {
+ rc = writen (ctx, "\n", 1);
+ if (rc)
+ rc = ASSUAN_Write_Error;
+ }
}
-
return rc;
}
+assuan_error_t
+assuan_write_line (ASSUAN_CONTEXT ctx, const char *line)
+{
+ size_t len;
+ const char *s;
+
+ if (!ctx)
+ return ASSUAN_Invalid_Value;
+
+ /* Make sure that we never take a LF from the user - this might
+ violate the protocol. */
+ s = strchr (line, '\n');
+ 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",
+ assuan_get_assuan_log_prefix (),
+ (unsigned int)getpid (), ctx);
+
+ return _assuan_write_line (ctx, NULL, line, len);
+}
+
+
\f
/* Write out the data in buffer as datalines with line wrapping and
- percent escaping. This fucntion is used for GNU's custom streams */
+ percent escaping. This function is used for GNU's custom streams */
int
-_assuan_cookie_write_data (void *cookie, const char *buffer, size_t size)
+_assuan_cookie_write_data (void *cookie, const char *buffer, size_t orig_size)
{
ASSUAN_CONTEXT ctx = cookie;
+ size_t size = orig_size;
char *line;
size_t linelen;
{
if (ctx->log_fp)
{
- fprintf (ctx->log_fp, "%s[%p] -> ",
- assuan_get_assuan_log_prefix (), ctx);
+ fprintf (ctx->log_fp, "%s[%u.%p] DBG: -> ",
+ assuan_get_assuan_log_prefix (),
+ (unsigned int)getpid (), ctx);
if (ctx->confidential)
fputs ("[Confidential data not shown]", ctx->log_fp);
}
ctx->outbound.data.linelen = linelen;
- return 0;
+ return (int)orig_size;
}
/* Write out any buffered data
- This fucntion is used for GNU's custom streams */
+ This function is used for GNU's custom streams */
int
_assuan_cookie_write_flush (void *cookie)
{
{
if (ctx->log_fp)
{
- fprintf (ctx->log_fp, "%s[%p] -> ",
- assuan_get_assuan_log_prefix (), ctx);
+ fprintf (ctx->log_fp, "%s[%u.%p] DBG: -> ",
+ assuan_get_assuan_log_prefix (),
+ (unsigned int)getpid (), ctx);
if (ctx->confidential)
fputs ("[Confidential data not shown]", ctx->log_fp);
else
* Return value: 0 on success or an error code
**/
\f
-AssuanError
+assuan_error_t
assuan_send_data (ASSUAN_CONTEXT ctx, const void *buffer, size_t length)
{
if (!ctx)
return 0;
}
-AssuanError
+assuan_error_t
assuan_sendfd (ASSUAN_CONTEXT ctx, int fd)
{
if (! ctx->io->sendfd)
return ctx->io->sendfd (ctx, fd);
}
-AssuanError
+assuan_error_t
assuan_receivefd (ASSUAN_CONTEXT ctx, int *fd)
{
if (! ctx->io->receivefd)
#define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
-AssuanError
+assuan_error_t
_assuan_read_from_server (ASSUAN_CONTEXT ctx, int *okay, int *off)
{
char *line;
int linelen;
- AssuanError rc;
+ assuan_error_t rc;
*okay = 0;
*off = 0;
* the one one returned by the server in error lines or from the
* callback functions.
**/
-AssuanError
+assuan_error_t
assuan_transact (ASSUAN_CONTEXT ctx,
const char *command,
- AssuanError (*data_cb)(void *, const void *, size_t),
+ assuan_error_t (*data_cb)(void *, const void *, size_t),
void *data_cb_arg,
- AssuanError (*inquire_cb)(void*, const char *),
+ assuan_error_t (*inquire_cb)(void*, const char *),
void *inquire_cb_arg,
- AssuanError (*status_cb)(void*, const char *),
+ assuan_error_t (*status_cb)(void*, const char *),
void *status_cb_arg)
{
int rc, okay, off;
if (rc)
return rc;
+ if (*command == '#' || !*command)
+ return 0; /* Don't expect a response for a comment line. */
+
again:
rc = _assuan_read_from_server (ctx, &okay, &off);
if (rc)
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
+#ifndef HAVE_W32_SYSTEM
#include <sys/wait.h>
+#endif
#include "assuan-defs.h"
/* Disconnect and release the context CTX. */
void
-assuan_disconnect (ASSUAN_CONTEXT ctx)
+assuan_disconnect (assuan_context_t ctx)
{
if (ctx)
{
-#if 0
- /* This may not work if the pipe is full and the other end is
- blocked. */
assuan_write_line (ctx, "BYE");
-#endif
ctx->finish_handler (ctx);
ctx->deinit_handler (ctx);
ctx->deinit_handler = NULL;
}
}
+/* Return the PID of the peer or -1 if not known. */
pid_t
-assuan_get_pid (ASSUAN_CONTEXT ctx)
+assuan_get_pid (assuan_context_t ctx)
{
- return ctx ? ctx->pid : -1;
+ return (ctx && ctx->pid)? ctx->pid : -1;
}
+
/* assuan-defs.c - Internal definitions to Assuan
- * Copyright (C) 2001, 2002 Free Software Foundation, Inc.
+ * Copyright (C) 2001, 2002, 2004 Free Software Foundation, Inc.
*
* This file is part of Assuan.
*
#define ASSUAN_DEFS_H
#include <sys/types.h>
+#ifndef HAVE_W32_SYSTEM
#include <sys/socket.h>
#include <sys/un.h>
+#else
+#include <windows.h>
+#endif
#include <unistd.h>
#include "assuan.h"
+#ifndef HAVE_W32_SYSTEM
+#define DIRSEP_C '/'
+#else
+#define DIRSEP_C '\\'
+#endif
+
+#ifdef HAVE_W32_SYSTEM
+#define AF_LOCAL AF_UNIX
+/* We need to prefix the structure with a sockaddr_in header so we can
+ use it later for sendto and recvfrom. */
+struct sockaddr_un
+{
+ short sun_family;
+ unsigned short sun_port;
+ struct in_addr sun_addr;
+ char sun_path[108-2-4]; /* Path name. */
+};
+
+/* Not needed anymore because the current mingw32 defines this in
+ sys/types.h */
+/* typedef int ssize_t; */
+
+/* Missing W32 functions */
+int putc_unlocked (int c, FILE *stream);
+void * memrchr (const void *block, int c, size_t size);
+char * stpcpy (char *dest, const char *src);
+#endif
+
#define LINELENGTH ASSUAN_LINELENGTH
struct cmdtbl_s
/* Routine to write to output_fd. */
ssize_t (*writefnc) (ASSUAN_CONTEXT, const void *, size_t);
/* Send a file descriptor. */
- AssuanError (*sendfd) (ASSUAN_CONTEXT, int);
+ assuan_error_t (*sendfd) (ASSUAN_CONTEXT, int);
/* Receive a file descriptor. */
- AssuanError (*receivefd) (ASSUAN_CONTEXT, int *);
+ assuan_error_t (*receivefd) (ASSUAN_CONTEXT, int *);
};
struct assuan_context_s
{
- AssuanError err_no;
+ assuan_error_t err_no;
const char *err_str;
- int os_errno; /* last system error number used with certain error codes*/
+ int os_errno; /* Last system error number used with certain
+ error codes. */
+
+ /* Context specific flags (cf. assuan_flag_t). */
+ struct
+ {
+ unsigned int no_waitpid:1; /* See ASSUAN_NO_WAITPID. */
+ } flags;
int confidential;
- int is_server; /* set if this is context belongs to a server */
+ int is_server; /* Set if this is context belongs to a server */
int in_inquire;
char *hello_line;
- char *okay_line; /* see assan_set_okay_line() */
+ char *okay_line; /* See assuan_set_okay_line() */
- void *user_pointer; /* for assuan_[gs]et_pointer () */
+ void *user_pointer; /* For assuan_get_pointer and assuan-set_pointer (). */
FILE *log_fp;
int pipe_mode; /* We are in pipe mode, i.e. we can handle just one
connection and must terminate then */
- pid_t pid; /* In pipe mode, the pid of the child server process.
- In socket mode, the pid of the server */
+ pid_t pid; /* The the pid of the peer. */
int listen_fd; /* The fd we are listening on (used by socket servers) */
int connected_fd; /* helper */
- pid_t client_pid; /* for a socket server the PID of the client or -1
- if not available */
/* Used for Unix domain sockets. */
struct sockaddr_un myaddr;
/* 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. */
-AssuanError _assuan_domain_init (ASSUAN_CONTEXT *r_ctx,
+assuan_error_t _assuan_domain_init (ASSUAN_CONTEXT *r_ctx,
int rendezvousfd,
pid_t peer);
int _assuan_read_line (ASSUAN_CONTEXT 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 --*/
-AssuanError _assuan_read_from_server (ASSUAN_CONTEXT ctx, int *okay, int *off);
+assuan_error_t _assuan_read_from_server (ASSUAN_CONTEXT ctx, int *okay, int *off);
/*-- assuan-util.c --*/
void _assuan_log_print_buffer (FILE *fp, const void *buffer, size_t length);
void _assuan_log_sanitized_string (const char *string);
+#ifdef HAVE_W32_SYSTEM
+const char *_assuan_w32_strerror (int ec);
+#define w32_strerror(e) _assuan_w32_strerror ((e))
+#endif /*HAVE_W32_SYSTEM*/
+
+
+/*-- assuan-logging.c --*/
+void _assuan_set_default_log_stream (FILE *fp);
+
+void _assuan_log_printf (const char *format, ...)
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 )
+ __attribute__ ((format (printf,1,2)))
+#endif
+ ;
+
/*-- 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,
size_t size);
+/*-- assuan-socket.c --*/
+int _assuan_close (int fd);
+int _assuan_sock_new (int domain, int type, int proto);
+int _assuan_sock_bind (int sockfd, struct sockaddr *addr, int addrlen);
+int _assuan_sock_connect (int sockfd, struct sockaddr *addr, int addrlen);
+
#ifdef HAVE_FOPENCOOKIE
/* We have to implement funopen in terms of glibc's fopencookie. */
-FILE *funopen(const void *cookie, cookie_read_function_t *readfn,
- cookie_write_function_t *writefn,
- cookie_seek_function_t *seekfn,
- cookie_close_function_t *closefn);
+FILE *_assuan_funopen(void *cookie,
+ cookie_read_function_t *readfn,
+ cookie_write_function_t *writefn,
+ cookie_seek_function_t *seekfn,
+ cookie_close_function_t *closefn);
+#define funopen(a,r,w,s,c) _assuan_funopen ((a), (r), (w), (s), (c))
#endif /*HAVE_FOPENCOOKIE*/
#endif /*ASSUAN_DEFS_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 "assuan-defs.h"
-#define LOG(format, args...) \
- fprintf (assuan_get_assuan_log_stream (), \
- assuan_get_assuan_log_prefix (), \
- "%s" format , ## args)
+#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 ctx)
+do_deinit (assuan_context_t ctx)
{
if (ctx->inbound.fd != -1)
- close (ctx->inbound.fd);
+ _assuan_close (ctx->inbound.fd);
ctx->inbound.fd = -1;
ctx->outbound.fd = -1;
assert (ctx->pendingfdscount > 0);
for (i = 0; i < ctx->pendingfdscount; i ++)
- close (ctx->pendingfds[i]);
+ _assuan_close (ctx->pendingfds[i]);
free (ctx->pendingfds);
}
/* Read from the socket server. */
static ssize_t
-domain_reader (ASSUAN_CONTEXT ctx, void *buf, size_t buflen)
+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. */
/* 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. */
- LOG ("Not setup to receive messages from: `%s'.",
- ((struct sockaddr_un *) msg.msg_name)->sun_path);
+ _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)
{
- LOG ("domain_reader: %s\n", strerror (errno));
+ _assuan_log_printf ("domain_reader: %s\n", strerror (errno));
return -1;
}
sizeof (int) * (ctx->pendingfdscount + 1));
if (! tmp)
{
- LOG ("domain_reader: %s\n", strerror (errno));
+ _assuan_log_printf ("domain_reader: %s\n", strerror (errno));
return -1;
}
ctx->pendingfds[ctx->pendingfdscount++]
= *(int *) CMSG_DATA (&cmsg.hdr);
- LOG ("Received file descriptor %d from peer.\n",
+ _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. */
/* Write to the domain server. */
static ssize_t
-domain_writer (ASSUAN_CONTEXT ctx, const void *buf, size_t buflen)
+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;
len = sendmsg (ctx->outbound.fd, &msg, 0);
if (len < 0)
- LOG ("domain_writer: %s\n", strerror (errno));
-
+ _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 AssuanError
-domain_sendfd (ASSUAN_CONTEXT ctx, int fd)
+static assuan_error_t
+domain_sendfd (assuan_context_t ctx, int fd)
{
+#ifndef HAVE_W32_SYSTEM
struct msghdr msg;
struct
{
len = sendmsg (ctx->outbound.fd, &msg, 0);
if (len < 0)
{
- LOG ("domain_sendfd: %s\n", strerror (errno));
+ _assuan_log_printf ("domain_sendfd: %s\n", strerror (errno));
return ASSUAN_General_Error;
}
else
return 0;
+#else
+ return 0;
+#endif
}
-static AssuanError
-domain_receivefd (ASSUAN_CONTEXT ctx, int *fd)
+static assuan_error_t
+domain_receivefd (assuan_context_t ctx, int *fd)
{
+#ifndef HAVE_W32_SYSTEM
if (ctx->pendingfds == 0)
{
- LOG ("No pending file descriptors!\n");
+ _assuan_log_printf ("no pending file descriptors!\n");
return ASSUAN_General_Error;
}
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. */
-AssuanError
-_assuan_domain_init (ASSUAN_CONTEXT *r_ctx, int rendezvousfd, pid_t peer)
+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 };
- AssuanError err;
- ASSUAN_CONTEXT ctx;
+ assuan_error_t err;
+ assuan_context_t ctx;
int fd;
size_t len;
int tries;
/* Setup the socket. */
- fd = socket (PF_LOCAL, SOCK_DGRAM, 0);
+ fd = _assuan_sock_new (PF_LOCAL, SOCK_DGRAM, 0);
if (fd == -1)
{
- LOG ("can't create socket: %s\n", strerror (errno));
+ _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;
/* 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)
{
- LOG ("cannot determine an appropriate temporary file "
- "name. DOS in progress?\n");
+ _assuan_log_printf ("cannot determine an appropriate temporary file "
+ "name. DoS in progress?\n");
_assuan_release_context (ctx);
- close (fd);
+ _assuan_close (fd);
return ASSUAN_General_Error;
}
memcpy (ctx->myaddr.sun_path, buf, len);
len += offsetof (struct sockaddr_un, sun_path);
- err = bind (fd, (struct sockaddr *) &ctx->myaddr, len);
+ err = _assuan_sock_bind (fd, (struct sockaddr *) &ctx->myaddr, len);
if (! err)
break;
}
if (err)
{
- LOG ("can't bind to `%s': %s\n", ctx->myaddr.sun_path,
- strerror (errno));
+ _assuan_log_printf ("can't bind to `%s': %s\n", ctx->myaddr.sun_path,
+ strerror (errno));
_assuan_release_context (ctx);
- close (fd);
+ _assuan_close (fd);
return ASSUAN_Connect_Failed;
}
fp = fdopen (rendezvousfd, "w+");
if (! fp)
{
- LOG ("can't open rendezvous port: %s\n", strerror (errno));
+ _assuan_log_printf ("can't open rendezvous port: %s\n", strerror (errno));
return ASSUAN_Connect_Failed;
}
return 0;
}
-AssuanError
-assuan_domain_connect (ASSUAN_CONTEXT * r_ctx, int rendezvousfd, pid_t peer)
+assuan_error_t
+assuan_domain_connect (assuan_context_t * r_ctx, int rendezvousfd, pid_t peer)
{
- AssuanError aerr;
+ assuan_error_t aerr;
int okay, off;
aerr = _assuan_domain_init (r_ctx, rendezvousfd, peer);
/* Initial handshake. */
aerr = _assuan_read_from_server (*r_ctx, &okay, &off);
if (aerr)
- LOG ("can't connect to server: %s\n", assuan_strerror (aerr));
+ _assuan_log_printf ("can't connect to server: %s\n",
+ assuan_strerror (aerr));
else if (okay != 1)
{
- LOG ("can't connect to server: `");
+ _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;
#include "assuan-defs.h"
/* Initialize a server. */
-AssuanError
+assuan_error_t
assuan_init_domain_server (ASSUAN_CONTEXT *r_ctx,
int rendezvousfd,
pid_t peer)
{
- AssuanError err;
+ assuan_error_t err;
err = _assuan_domain_init (r_ctx, rendezvousfd, peer);
if (err)
return set_error (ctx, Not_Implemented, NULL);
}
-AssuanError
+assuan_error_t
assuan_command_parse_fd (ASSUAN_CONTEXT ctx, char *line, int *rfd)
{
char *endp;
}
/* Parse the line, break out the command, find it in the command
- table, remove leading and white spaces from the arguments, all the
+ 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)
}
else
{
- char errline[256];
+ char errline[300];
if (rc < 100)
sprintf (errline, "ERR %d server fault (%.50s)",
{
const char *text = ctx->err_no == rc? ctx->err_str:NULL;
- sprintf (errline, "ERR %d %.50s%s%.100s",
- rc, assuan_strerror (rc), text? " - ":"", text?text:"");
+#if defined(__GNUC__) && defined(__ELF__)
+ /* If we have weak symbol support we try to use the error
+ 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
+ weak symbol support is available in case GNU ld is not
+ used. */
+ unsigned int source, code;
+
+ int gpg_strerror_r (unsigned int err, char *buf, size_t buflen)
+ __attribute__ ((weak));
+
+ const char *gpg_strsource (unsigned int err)
+ __attribute__ ((weak));
+
+ source = ((rc >> 24) & 0xff);
+ code = (rc & 0x00ffffff);
+ if (source && gpg_strsource && gpg_strerror_r)
+ {
+ /* Assume this is an libgpg-error. */
+ char ebuf[50];
+
+ gpg_strerror_r (rc, ebuf, sizeof ebuf );
+ sprintf (errline, "ERR %d %.50s <%.30s>%s%.100s",
+ rc,
+ ebuf,
+ gpg_strsource (rc),
+ text? " - ":"", text?text:"");
+ }
+ else
+#endif /* __GNUC__ && __ELF__ */
+ sprintf (errline, "ERR %d %.50s%s%.100s",
+ rc, assuan_strerror (rc), text? " - ":"", text?text:"");
}
rc = assuan_write_line (ctx, errline);
}
* assuan_process:
* @ctx: assuan context
*
- * This fucntion is used to handle the assuan protocol after a
+ * This function is used to handle the assuan protocol after a
* connection has been established using assuan_accept(). This is the
* main protocol handler.
*
/* Set the text used for the next OK reponse. This string is
automatically reset to NULL after the next command. */
-AssuanError
+assuan_error_t
assuan_set_okay_line (ASSUAN_CONTEXT ctx, const char *line)
{
if (!ctx)
-void
+assuan_error_t
assuan_write_status (ASSUAN_CONTEXT ctx, const char *keyword, const char *text)
{
char buffer[256];
char *helpbuf;
size_t n;
+ assuan_error_t ae;
if ( !ctx || !keyword)
- return;
+ return ASSUAN_Invalid_Value;
if (!text)
text = "";
strcat (buffer, " ");
strcat (buffer, text);
}
- assuan_write_line (ctx, buffer);
+ ae = assuan_write_line (ctx, buffer);
}
else if ( (helpbuf = xtrymalloc (n)) )
{
strcat (helpbuf, " ");
strcat (helpbuf, text);
}
- assuan_write_line (ctx, helpbuf);
+ ae = assuan_write_line (ctx, helpbuf);
xfree (helpbuf);
}
+ else
+ ae = 0;
+ return ae;
}
*
* Return value: 0 on success or an ASSUAN error code
**/
-AssuanError
-assuan_inquire (ASSUAN_CONTEXT ctx, const char *keyword,
- char **r_buffer, size_t *r_length, size_t maxlen)
+assuan_error_t
+assuan_inquire (assuan_context_t ctx, const char *keyword,
+ unsigned char **r_buffer, size_t *r_length, size_t maxlen)
{
- AssuanError rc;
+ assuan_error_t rc;
struct membuf mb;
char cmdbuf[LINELENGTH-10]; /* (10 = strlen ("INQUIRE ")+CR,LF) */
unsigned char *line, *p;
/* assuan-io.c - Wraps the read and write functions.
- * Copyright (C) 2002 Free Software Foundation, Inc.
+ * Copyright (C) 2002, 2004 Free Software Foundation, Inc.
*
* This file is part of Assuan.
*
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
#include "assuan-defs.h"
#include <sys/types.h>
#include <unistd.h>
+#ifdef HAVE_W32_SYSTEM
+#include <windows.h>
+#endif
-#ifdef _ASSUAN_IN_GPGME
-ssize_t
-_assuan_simple_read (ASSUAN_CONTEXT ctx, void *buffer, size_t size)
-{
- return read (ctx->inbound.fd, buffer, size);
-}
-
-ssize_t
-_assuan_simple_write (ASSUAN_CONTEXT ctx, const void *buffer, size_t size)
-{
- return write (ctx->outbound.fd, buffer, size);
-}
-
-#else
-
+#ifndef _ASSUAN_NO_PTH
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);
+#ifndef HAVE_W32_SYSTEM
#pragma weak pth_read
#pragma weak pth_write
+#endif
+#endif /*!_ASSUAN_NO_PTH*/
ssize_t
-_assuan_simple_read (ASSUAN_CONTEXT ctx, void *buffer, size_t size)
+_assuan_simple_read (assuan_context_t ctx, void *buffer, size_t size)
{
+#ifdef _ASSUAN_NO_PTH
+ return read (ctx->inbound.fd, buffer, size);
+#else
+# ifndef HAVE_W32_SYSTEM
return (pth_read ? pth_read : read) (ctx->inbound.fd, buffer, size);
+# else
+ return pth_read ? pth_read (ctx->inbound.fd, buffer, size)
+ : recv (ctx->inbound.fd, buffer, size, 0);
+# endif
+# endif
}
ssize_t
-_assuan_simple_write (ASSUAN_CONTEXT ctx, const void *buffer, size_t size)
+_assuan_simple_write (assuan_context_t ctx, const void *buffer, size_t size)
{
+#ifdef _ASSUAN_NO_PTH
+ return write (ctx->outbound.fd, buffer, size);
+#else
+# ifndef HAVE_W32_SYSTEM
return (pth_write ? pth_write : write) (ctx->outbound.fd, buffer, size);
-}
-
+# else
+ return pth_write ? pth_write (ctx->outbound.fd, buffer, size)
+ : send (ctx->outbound.fd, buffer, size, 0);
+# endif
#endif
+}
/* assuan-listen.c - Wait for a connection (server)
- * Copyright (C) 2001, 2002 Free Software Foundation, Inc.
+ * Copyright (C) 2001, 2002, 2004 Free Software Foundation, Inc.
*
* This file is part of Assuan.
*
#include "assuan-defs.h"
-AssuanError
-assuan_set_hello_line (ASSUAN_CONTEXT ctx, const char *line)
+assuan_error_t
+assuan_set_hello_line (assuan_context_t ctx, const char *line)
{
if (!ctx)
return ASSUAN_Invalid_Value;
char *buf = xtrymalloc (3+strlen(line)+1);
if (!buf)
return ASSUAN_Out_Of_Core;
- strcpy (buf, "OK ");
- strcpy (buf+3, line);
+ if (strchr (line, '\n'))
+ strcpy (buf, line);
+ else
+ {
+ strcpy (buf, "OK ");
+ strcpy (buf+3, line);
+ }
xfree (ctx->hello_line);
ctx->hello_line = buf;
}
* Return value: 0 on success or an error if the connection could for
* some reason not be established.
**/
-AssuanError
-assuan_accept (ASSUAN_CONTEXT ctx)
+assuan_error_t
+assuan_accept (assuan_context_t ctx)
{
int rc;
+ const char *p, *pend;
if (!ctx)
return ASSUAN_Invalid_Value;
if (rc)
return rc;
- /* send the hello */
- rc = assuan_write_line (ctx, ctx->hello_line? ctx->hello_line
- : "OK Your orders please");
+ /* Send the hello. */
+ p = ctx->hello_line;
+ if (p && (pend = strchr (p, '\n')))
+ { /* This is a multi line hello. Send all but the last line as
+ comments. */
+ do
+ {
+ rc = _assuan_write_line (ctx, "# ", p, pend - p);
+ if (rc)
+ return rc;
+ p = pend + 1;
+ pend = strchr (p, '\n');
+ }
+ while (pend);
+ rc = _assuan_write_line (ctx, "OK ", p, strlen (p));
+ }
+ else if (p)
+ rc = assuan_write_line (ctx, p);
+ else
+ rc = assuan_write_line (ctx, "OK Pleased to meet you");
if (rc)
return rc;
int
-assuan_get_input_fd (ASSUAN_CONTEXT ctx)
+assuan_get_input_fd (assuan_context_t ctx)
{
return ctx? ctx->input_fd : -1;
}
int
-assuan_get_output_fd (ASSUAN_CONTEXT ctx)
+assuan_get_output_fd (assuan_context_t ctx)
{
return ctx? ctx->output_fd : -1;
}
/* Close the fd descriptor set by the command INPUT FD=n. We handle
this fd inside assuan so that we can do some initial checks */
-AssuanError
-assuan_close_input_fd (ASSUAN_CONTEXT ctx)
+assuan_error_t
+assuan_close_input_fd (assuan_context_t ctx)
{
if (!ctx || ctx->input_fd == -1)
return ASSUAN_Invalid_Value;
- close (ctx->input_fd);
+ _assuan_close (ctx->input_fd);
ctx->input_fd = -1;
return 0;
}
/* Close the fd descriptor set by the command OUTPUT FD=n. We handle
this fd inside assuan so that we can do some initial checks */
-AssuanError
-assuan_close_output_fd (ASSUAN_CONTEXT ctx)
+assuan_error_t
+assuan_close_output_fd (assuan_context_t ctx)
{
if (!ctx || ctx->output_fd == -1)
return ASSUAN_Invalid_Value;
- close (ctx->output_fd);
+ _assuan_close (ctx->output_fd);
ctx->output_fd = -1;
return 0;
}
/* assuan-logging.c - Default logging function.
- * Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+ * Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
*
* This file is part of Assuan.
*
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
-#include "assuan-defs.h"
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#ifdef HAVE_W32_SYSTEM
+#include <windows.h>
+#endif /*HAVE_W32_SYSTEM*/
+
+#include "assuan-defs.h"
+static char prefix_buffer[80];
static FILE *_assuan_log;
+void
+_assuan_set_default_log_stream (FILE *fp)
+{
+ if (!_assuan_log)
+ _assuan_log = fp;
+}
+
void
assuan_set_assuan_log_stream (FILE *fp)
{
return _assuan_log ? _assuan_log : stderr;
}
+
+/* Set the prefix to be used for logging to TEXT or
+ resets it to the default if TEXT is NULL. */
+void
+assuan_set_assuan_log_prefix (const char *text)
+{
+ if (text)
+ {
+ strncpy (prefix_buffer, text, sizeof (prefix_buffer)-1);
+ prefix_buffer[sizeof (prefix_buffer)-1] = 0;
+ }
+ else
+ *prefix_buffer = 0;
+}
+
const char *
assuan_get_assuan_log_prefix (void)
{
- return "";
+ return prefix_buffer;
+}
+
+
+void
+_assuan_log_printf (const char *format, ...)
+{
+ va_list arg_ptr;
+ FILE *fp;
+ const char *prf;
+
+ fp = assuan_get_assuan_log_stream ();
+ prf = assuan_get_assuan_log_prefix ();
+ if (*prf)
+ {
+ fputs (prf, fp);
+ fputs (": ", fp);
+ }
+
+ va_start (arg_ptr, format);
+ vfprintf (fp, format, arg_ptr );
+ va_end (arg_ptr);
+}
+
+
+
+#ifdef HAVE_W32_SYSTEM
+const char *
+_assuan_w32_strerror (int ec)
+{
+ static char strerr[256];
+
+ if (ec == -1)
+ ec = (int)GetLastError ();
+ FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, ec,
+ MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
+ strerr, sizeof (strerr)-1, NULL);
+ return strerr;
}
+#endif /*HAVE_W32_SYSTEM*/
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
+#ifndef HAVE_W32_SYSTEM
#include <sys/wait.h>
+#else
+#include <windows.h>
+#endif
#include "assuan-defs.h"
#define MAX_OPEN_FDS 20
#endif
-#define LOG(format, args...) \
- fprintf (assuan_get_assuan_log_stream (), \
- assuan_get_assuan_log_prefix (), \
- "%s" format , ## args)
+#ifdef HAVE_W32_SYSTEM
+/* We assume that a HANDLE can be represented by an int which should
+ be true for all i386 systems (HANDLE is defined as void *) and
+ these are the only systems for which Windows is available. Further
+ we assume that -1 denotes an invalid handle. */
+#define fd_to_handle(a) ((HANDLE)(a))
+#define handle_to_fd(a) ((int)(a))
+#define pid_to_handle(a) ((HANDLE)(a))
+#define handle_to_pid(a) ((int)(a))
+#endif /*HAVE_W32_SYSTEM*/
+
+
+/* This should be called to make sure that SIGPIPE gets ignored. */
+static void
+fix_signals (void)
+{
+#ifndef _ASSUAN_NO_FIXED_SIGNALS
+#ifndef HAVE_DOSISH_SYSTEM /* No SIGPIPE for these systems. */
+ static int fixed_signals;
+
+ if (!fixed_signals)
+ {
+ struct sigaction act;
+
+ sigaction (SIGPIPE, NULL, &act);
+ if (act.sa_handler == SIG_DFL)
+ {
+ act.sa_handler = SIG_IGN;
+ sigemptyset (&act.sa_mask);
+ act.sa_flags = 0;
+ sigaction (SIGPIPE, &act, NULL);
+ }
+ fixed_signals = 1;
+ /* FIXME: This is not MT safe */
+ }
+#endif /*HAVE_DOSISH_SYSTEM*/
+#endif /*!_ASSUAN_NO_FIXED_SIGNALS*/
+}
+
+#ifndef HAVE_W32_SYSTEM
static int
writen (int fd, const char *buffer, size_t length)
{
}
return 0; /* okay */
}
-
+#endif
static int
-do_finish (ASSUAN_CONTEXT ctx)
+do_finish (assuan_context_t ctx)
{
if (ctx->inbound.fd != -1)
{
- close (ctx->inbound.fd);
+ _assuan_close (ctx->inbound.fd);
ctx->inbound.fd = -1;
}
if (ctx->outbound.fd != -1)
{
- close (ctx->outbound.fd);
+ _assuan_close (ctx->outbound.fd);
ctx->outbound.fd = -1;
}
- if (ctx->pid != -1)
+ if (ctx->pid != -1 && ctx->pid)
{
-#if 0
- /* This is already done by the double fork. */
- waitpid (ctx->pid, NULL, 0); /* FIXME Check return value. */
+#ifndef HAVE_W32_SYSTEM
+#ifndef _ASSUAN_USE_DOUBLE_FORK
+ if (!ctx->flags.no_waitpid)
+ waitpid (ctx->pid, NULL, 0);
ctx->pid = -1;
#endif
+#endif /*!HAVE_W32_SYSTEM*/
}
return 0;
}
static void
-do_deinit (ASSUAN_CONTEXT ctx)
+do_deinit (assuan_context_t ctx)
{
do_finish (ctx);
}
+#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. */
+static int
+build_w32_commandline (char * const *argv, char **cmdline)
+{
+ int i, n;
+ const char *s;
+ char *buf, *p;
+
+ *cmdline = NULL;
+ n = 0;
+ for (i=0; (s=argv[i]); i++)
+ {
+ n += strlen (s) + 1 + 2; /* (1 space, 2 quoting */
+ for (; *s; s++)
+ if (*s == '\"')
+ n++; /* Need to double inner quotes. */
+ }
+ n++;
+
+ buf = p = xtrymalloc (n);
+ if (!buf)
+ return -1;
+
+ for (i=0; argv[i]; i++)
+ {
+ if (i)
+ p = stpcpy (p, " ");
+ if (!*argv[i]) /* Empty string. */
+ p = stpcpy (p, "\"\"");
+ else if (strpbrk (argv[i], " \t\n\v\f\""))
+ {
+ p = stpcpy (p, "\"");
+ for (s=argv[i]; *s; s++)
+ {
+ *p++ = *s;
+ if (*s == '\"')
+ *p++ = *s;
+ }
+ *p++ = '\"';
+ *p = 0;
+ }
+ else
+ p = stpcpy (p, argv[i]);
+ }
+
+ *cmdline= buf;
+ return 0;
+}
+#endif /*HAVE_W32_SYSTEM*/
+
+
+#ifdef HAVE_W32_SYSTEM
+/* Create pipe where one end end is inheritable. */
+static int
+create_inheritable_pipe (int filedes[2], int for_write)
+{
+ HANDLE r, w, h;
+ SECURITY_ATTRIBUTES sec_attr;
+
+ memset (&sec_attr, 0, sizeof sec_attr );
+ sec_attr.nLength = sizeof sec_attr;
+ sec_attr.bInheritHandle = FALSE;
+
+ if (!CreatePipe (&r, &w, &sec_attr, 0))
+ {
+ _assuan_log_printf ("CreatePipe failed: %s\n", w32_strerror (-1));
+ return -1;
+ }
+
+ if (!DuplicateHandle (GetCurrentProcess(), for_write? r : w,
+ GetCurrentProcess(), &h, 0,
+ TRUE, DUPLICATE_SAME_ACCESS ))
+ {
+ _assuan_log_printf ("DuplicateHandle failed: %s\n", w32_strerror (-1));
+ CloseHandle (r);
+ CloseHandle (w);
+ return -1;
+ }
+ if (for_write)
+ {
+ CloseHandle (r);
+ r = h;
+ }
+ else
+ {
+ CloseHandle (w);
+ w = h;
+ }
+
+ filedes[0] = handle_to_fd (r);
+ filedes[1] = handle_to_fd (w);
+ return 0;
+}
+#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. */
-AssuanError
-assuan_pipe_connect (ASSUAN_CONTEXT *ctx, const char *name, char *const argv[],
- int *fd_child_list)
+ 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, char *const argv[],
+ int *fd_child_list,
+ void (*atfork) (void *opaque, int reserved),
+ void *atforkvalue)
{
-#ifndef _ASSUAN_IN_GPGME
- static int fixed_signals = 0;
-#endif
- AssuanError err;
+#ifdef HAVE_W32_SYSTEM
+ assuan_error_t err;
int rp[2];
int wp[2];
+ char mypidstr[50];
+ char *cmdline;
+ SECURITY_ATTRIBUTES sec_attr;
+ PROCESS_INFORMATION pi =
+ {
+ NULL, /* Returns process handle. */
+ 0, /* Returns primary thread handle. */
+ 0, /* Returns pid. */
+ 0 /* Returns tid. */
+ };
+ STARTUPINFO si;
+ int fd, *fdp;
+ HANDLE nullfd = INVALID_HANDLE_VALUE;
if (!ctx || !name || !argv || !argv[0])
return ASSUAN_Invalid_Value;
-#ifndef _ASSUAN_IN_GPGME
- if (!fixed_signals)
- {
- struct sigaction act;
-
- sigaction (SIGPIPE, NULL, &act);
- if (act.sa_handler == SIG_DFL)
- {
- act.sa_handler = SIG_IGN;
- sigemptyset (&act.sa_mask);
- act.sa_flags = 0;
- sigaction (SIGPIPE, &act, NULL);
+ fix_signals ();
+
+ sprintf (mypidstr, "%lu", (unsigned long)getpid ());
+
+ /* Build the command line. */
+ if (build_w32_commandline (argv, &cmdline))
+ return ASSUAN_Out_Of_Core;
+
+ /* Create thew two pipes. */
+ if (create_inheritable_pipe (rp, 0))
+ {
+ xfree (cmdline);
+ return 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;
+ }
+
+
+ err = _assuan_new_context (ctx);
+ if (err)
+ {
+ CloseHandle (fd_to_handle (rp[0]));
+ CloseHandle (fd_to_handle (rp[1]));
+ CloseHandle (fd_to_handle (wp[0]));
+ CloseHandle (fd_to_handle (wp[1]));
+ xfree (cmdline);
+ return ASSUAN_General_Error;
+ }
+
+ (*ctx)->pipe_mode = 1;
+ (*ctx)->inbound.fd = rp[0]; /* Our inbound is read end of read pipe. */
+ (*ctx)->outbound.fd = wp[1]; /* Our outbound is write end of write pipe. */
+ (*ctx)->deinit_handler = do_deinit;
+ (*ctx)->finish_handler = do_finish;
+
+
+ /* fixme: Actually we should set the "_assuan_pipe_connect_pid" env
+ variable. However this requires us to write a full environment
+ handler, because the strings are expected in sorted order. The
+ suggestion given in the MS Reference Library, to save the old
+ value, changeit, create proces and restore it, is not thread
+ safe. */
+
+ /* Start the process. */
+ memset (&sec_attr, 0, sizeof sec_attr );
+ sec_attr.nLength = sizeof sec_attr;
+ sec_attr.bInheritHandle = FALSE;
+
+ memset (&si, 0, sizeof si);
+ si.cb = sizeof (si);
+ si.dwFlags = STARTF_USESTDHANDLES;
+ si.hStdInput = fd_to_handle (wp[0]);
+ si.hStdOutput = fd_to_handle (rp[1]);
+
+ /* Dup stderr to /dev/null unless it is in the list of FDs to be
+ passed to the child. */
+ fd = fileno (stderr);
+ fdp = fd_child_list;
+ if (fdp)
+ {
+ for (; *fdp != -1 && *fdp != fd; fdp++)
+ ;
+ }
+ if (!fdp || *fdp == -1)
+ {
+ nullfd = CreateFile ("nul", GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, OPEN_EXISTING, 0, NULL);
+ if (nullfd == INVALID_HANDLE_VALUE)
+ {
+ _assuan_log_printf ("can't open `nul': %s\n", w32_strerror (-1));
+ CloseHandle (fd_to_handle (rp[0]));
+ CloseHandle (fd_to_handle (rp[1]));
+ CloseHandle (fd_to_handle (wp[0]));
+ CloseHandle (fd_to_handle (wp[1]));
+ xfree (cmdline);
+ _assuan_release_context (*ctx);
+ return -1;
}
- fixed_signals = 1;
- /* FIXME: This is not MT safe */
+ si.hStdError = nullfd;
}
-#endif
+ else
+ si.hStdError = fd_to_handle (_get_osfhandle (fd));
+
+
+ /* Note: We inherit all handles flagged as inheritable. This seems
+ to be a security flaw but there seems to be no way of selecting
+ handles to inherit. */
+ /* _assuan_log_printf ("CreateProcess, path=`%s' cmdline=`%s'\n", */
+ /* name, cmdline); */
+ if (!CreateProcess (name, /* Program to start. */
+ cmdline, /* Command line arguments. */
+ &sec_attr, /* Process security attributes. */
+ &sec_attr, /* Thread security attributes. */
+ TRUE, /* Inherit handles. */
+ (CREATE_DEFAULT_ERROR_MODE
+ | GetPriorityClass (GetCurrentProcess ())
+ | CREATE_SUSPENDED), /* Creation flags. */
+ NULL, /* Environment. */
+ NULL, /* Use current drive/directory. */
+ &si, /* Startup information. */
+ &pi /* Returns process information. */
+ ))
+ {
+ _assuan_log_printf ("CreateProcess failed: %s\n", w32_strerror (-1));
+ CloseHandle (fd_to_handle (rp[0]));
+ CloseHandle (fd_to_handle (rp[1]));
+ CloseHandle (fd_to_handle (wp[0]));
+ CloseHandle (fd_to_handle (wp[1]));
+ if (nullfd != INVALID_HANDLE_VALUE)
+ CloseHandle (nullfd);
+ xfree (cmdline);
+ _assuan_release_context (*ctx);
+ return ASSUAN_General_Error;
+ }
+ xfree (cmdline);
+ cmdline = NULL;
+ if (nullfd != INVALID_HANDLE_VALUE)
+ {
+ CloseHandle (nullfd);
+ nullfd = INVALID_HANDLE_VALUE;
+ }
+
+ CloseHandle (fd_to_handle (rp[1]));
+ CloseHandle (fd_to_handle (wp[0]));
+
+ /* _assuan_log_printf ("CreateProcess ready: hProcess=%p hThread=%p" */
+ /* " dwProcessID=%d dwThreadId=%d\n", */
+ /* pi.hProcess, pi.hThread, */
+ /* (int) pi.dwProcessId, (int) pi.dwThreadId); */
+
+ ResumeThread (pi.hThread);
+ CloseHandle (pi.hThread);
+ (*ctx)->pid = 0; /* We don't use the PID. */
+ CloseHandle (pi.hProcess); /* We don't need to wait for the process. */
+
+#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;
(*ctx)->deinit_handler = do_deinit;
(*ctx)->finish_handler = do_finish;
- /* FIXME: Use _gpgme_io_spawn. The PID stored here is actually
- soon useless. */
+ /* 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)
{
if ((*ctx)->pid == 0)
{
- /* Intermediate child to prevent zombie processes. */
- pid_t pid;
-
+#ifdef _ASSUAN_USE_DOUBLE_FORK
if ((pid = fork ()) == 0)
+#endif
{
- /* Child. */
-
- int i, n;
- char errbuf[512];
- int *fdp;
-
- /* Dup handles to stdin/stdout. */
- if (rp[1] != STDOUT_FILENO)
- {
- if (dup2 (rp[1], STDOUT_FILENO) == -1)
- {
- LOG ("dup2 failed in child: %s\n", strerror (errno));
- _exit (4);
- }
- }
- if (wp[0] != STDIN_FILENO)
- {
- if (dup2 (wp[0], STDIN_FILENO) == -1)
- {
- LOG ("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)
- {
- LOG ("can't open `/dev/null': %s\n", strerror (errno));
- _exit (4);
- }
- if (dup2 (fd, STDERR_FILENO) == -1)
- {
- LOG ("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;
-
- execv (name, 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);
- } /* End child. */
+ 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, 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)
- LOG ("can't connect server: %s\n", assuan_strerror (err));
+ _assuan_log_printf ("can't connect server: %s\n",
+ assuan_strerror (err));
else if (okay != 1)
{
- LOG ("can't connect server: `%s'\n", (*ctx)->inbound.line);
+ _assuan_log_printf ("can't connect server: `%s'\n",
+ (*ctx)->inbound.line);
err = ASSUAN_Connect_Failed;
}
}
}
-
-
-
-
-
-
-
-
-
-
-
-
+/* 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. */
+assuan_error_t
+assuan_pipe_connect (assuan_context_t *ctx, const char *name, char *const argv[],
+ int *fd_child_list)
+{
+ return assuan_pipe_connect2 (ctx, name, argv, fd_child_list, NULL, NULL);
+}
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
+#ifdef HAVE_W32_SYSTEM
+#include <windows.h>
+#include <fcntl.h>
+#endif
#include "assuan-defs.h"
+
static void
deinit_pipe_server (ASSUAN_CONTEXT ctx)
{
ctx->io = &io;
ctx->listen_fd = -1;
- ctx->client_pid = (pid_t)-1;
/* Use the pipe server handler as a default. */
ctx->deinit_handler = deinit_pipe_server;
ctx->accept_handler = accept_connection;
}
-
int
assuan_init_pipe_server (ASSUAN_CONTEXT *r_ctx, int filedes[2])
{
if (!rc)
{
ASSUAN_CONTEXT ctx = *r_ctx;
+ const char *s;
+ unsigned long ul;
ctx->is_server = 1;
- ctx->inbound.fd = filedes[0];
+#ifdef HAVE_W32_SYSTEM
+ /* MS Windows has so many different types of handle that one
+ needs to tranlsate them at many place forth and back. Also
+ make sure that the fiel descriptos are in binary mode. */
+ setmode (filedes[0], O_BINARY);
+ setmode (filedes[1], O_BINARY);
+ 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];
+#endif
ctx->pipe_mode = 1;
+
+ s = getenv ("_assuan_pipe_connect_pid");
+ if (s && (ul=strtoul (s, NULL, 10)) && ul)
+ ctx->pid = (pid_t)ul;
+ else
+ ctx->pid = (pid_t)-1;
+
}
return rc;
}
/* assuan-socket-connect.c - Assuan socket based client
- * Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+ * Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
*
* This file is part of Assuan.
*
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
+#include <string.h>
#include <errno.h>
+#include <unistd.h>
#include <sys/types.h>
+#ifndef HAVE_W32_SYSTEM
#include <sys/socket.h>
#include <sys/un.h>
-#include <unistd.h>
+#else
+#include <windows.h>
+#endif
#include "assuan-defs.h"
-#define LOG(format, args...) \
- fprintf (assuan_get_assuan_log_stream (), \
- assuan_get_assuan_log_prefix (), \
- "%s" format , ## args)
-
+/* 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
+
+#ifndef SUN_LEN
+# define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) \
+ + strlen ((ptr)->sun_path))
+#endif
+
+
static int
do_finish (ASSUAN_CONTEXT ctx)
{
if (ctx->inbound.fd != -1)
{
- close (ctx->inbound.fd);
+ _assuan_close (ctx->inbound.fd);
}
ctx->inbound.fd = -1;
ctx->outbound.fd = -1;
/* 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. */
-AssuanError
+assuan_error_t
assuan_socket_connect (ASSUAN_CONTEXT *r_ctx,
const char *name, pid_t server_pid)
{
static struct assuan_io io = { _assuan_simple_read,
_assuan_simple_write };
- AssuanError err;
+ assuan_error_t err;
ASSUAN_CONTEXT ctx;
int fd;
struct sockaddr_un srvr_addr;
size_t len;
+ const char *s;
if (!r_ctx || !name)
return 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 */
- if (*name != '/')
+ /* 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. */
+ s = name;
+ if (*s && s[1] == ':')
+ s += 2;
+ if (*s != DIRSEP_C && *s != '/')
return ASSUAN_Invalid_Value;
+
if (strlen (name)+1 >= sizeof srvr_addr.sun_path)
return ASSUAN_Invalid_Value;
err = _assuan_new_context (&ctx);
if (err)
return err;
- ctx->pid = server_pid; /* save it in case we need it later */
ctx->deinit_handler = do_deinit;
ctx->finish_handler = do_finish;
- fd = socket (PF_LOCAL, SOCK_STREAM, 0);
+
+ fd = _assuan_sock_new (PF_LOCAL, SOCK_STREAM, 0);
if (fd == -1)
{
- LOG ("can't create socket: %s\n", strerror (errno));
+ _assuan_log_printf ("can't create socket: %s\n", strerror (errno));
_assuan_release_context (ctx);
return ASSUAN_General_Error;
}
memset (&srvr_addr, 0, sizeof srvr_addr);
srvr_addr.sun_family = AF_LOCAL;
- len = strlen (srvr_addr.sun_path) + 1;
- memcpy (srvr_addr.sun_path, name, len);
- len += (offsetof (struct sockaddr_un, sun_path));
+ strncpy (srvr_addr.sun_path, name, sizeof (srvr_addr.sun_path) - 1);
+ srvr_addr.sun_path[sizeof (srvr_addr.sun_path) - 1] = 0;
+ len = SUN_LEN (&srvr_addr);
+
- if (connect (fd, (struct sockaddr *) &srvr_addr, len) == -1)
+ if (_assuan_sock_connect (fd, (struct sockaddr *) &srvr_addr, len) == -1)
{
- LOG ("can't connect to `%s': %s\n", name, strerror (errno));
+ _assuan_log_printf ("can't connect to `%s': %s\n",
+ name, strerror (errno));
_assuan_release_context (ctx);
- close (fd);
+ _assuan_close (fd);
return ASSUAN_Connect_Failed;
}
err = _assuan_read_from_server (ctx, &okay, &off);
if (err)
- LOG ("can't connect to server: %s\n", assuan_strerror (err));
+ _assuan_log_printf ("can't connect to server: %s\n",
+ assuan_strerror (err));
else if (okay != 1)
{
- LOG ("can't connect to server: `");
+ /*LOG ("can't connect to server: `");*/
_assuan_log_sanitized_string (ctx->inbound.line);
fprintf (assuan_get_assuan_log_stream (), "'\n");
err = ASSUAN_Connect_Failed;
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
+#include <unistd.h>
#include <sys/types.h>
+#ifndef HAVE_W32_SYSTEM
#include <sys/socket.h>
#include <sys/un.h>
-#include <unistd.h>
+#else
+#include <windows.h>
+#endif
#include "assuan-defs.h"
static int
-accept_connection_bottom (ASSUAN_CONTEXT ctx)
+accept_connection_bottom (assuan_context_t ctx)
{
int fd = ctx->connected_fd;
- ctx->client_pid = (pid_t)-1;
#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) )
- ctx->client_pid = cr.pid;
+ if ( !getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &cr, &cl)
+ && cr.pid != (pid_t)-1 && cr.pid )
+ ctx->pid = cr.pid;
}
#endif
static int
-accept_connection (ASSUAN_CONTEXT ctx)
+accept_connection (assuan_context_t ctx)
{
int fd;
struct sockaddr_un clnt_addr;
size_t len = sizeof clnt_addr;
- ctx->client_pid = (pid_t)-1;
fd = accept (ctx->listen_fd, (struct sockaddr*)&clnt_addr, &len );
if (fd == -1)
{
}
static int
-finish_connection (ASSUAN_CONTEXT ctx)
+finish_connection (assuan_context_t ctx)
{
if (ctx->inbound.fd != -1)
{
- close (ctx->inbound.fd);
+ _assuan_close (ctx->inbound.fd);
}
ctx->inbound.fd = -1;
ctx->outbound.fd = -1;
static void
-deinit_socket_server (ASSUAN_CONTEXT ctx)
+deinit_socket_server (assuan_context_t ctx)
{
finish_connection (ctx);
}
/* Initialize a server for the socket LISTEN_FD which has already be
put into listen mode */
int
-assuan_init_socket_server (ASSUAN_CONTEXT *r_ctx, int listen_fd)
+assuan_init_socket_server (assuan_context_t *r_ctx, int listen_fd)
{
- ASSUAN_CONTEXT ctx;
+ assuan_context_t ctx;
int rc;
*r_ctx = NULL;
/* Initialize a server using the already accepted socket FD. */
int
-assuan_init_connected_socket_server (ASSUAN_CONTEXT *r_ctx, int fd)
+assuan_init_connected_socket_server (assuan_context_t *r_ctx, int fd)
{
- ASSUAN_CONTEXT ctx;
+ assuan_context_t ctx;
int rc;
*r_ctx = NULL;
/* assuan-util.c - Utility functions for Assuan
- * Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
+ * Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
*
* This file is part of Assuan.
*
#include <stdio.h>
#include <string.h>
#include <ctype.h>
+#include <errno.h>
#include "assuan-defs.h"
void *
_assuan_calloc (size_t n, size_t m)
{
- void *p = _assuan_malloc (n*m);
+ void *p;
+ size_t nbytes;
+
+ nbytes = n * m;
+ if (m && nbytes / m != n)
+ {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ p = _assuan_malloc (nbytes);
if (p)
- memset (p, 0, n* m);
+ memset (p, 0, nbytes);
return p;
}
can take out a descriptive text. Inside the assuan code, use the
macro set_error instead of this function. */
int
-assuan_set_error (ASSUAN_CONTEXT ctx, int err, const char *text)
+assuan_set_error (assuan_context_t ctx, int err, const char *text)
{
ctx->err_no = err;
ctx->err_str = text;
}
void
-assuan_set_pointer (ASSUAN_CONTEXT ctx, void *pointer)
+assuan_set_pointer (assuan_context_t ctx, void *pointer)
{
if (ctx)
ctx->user_pointer = pointer;
}
void *
-assuan_get_pointer (ASSUAN_CONTEXT ctx)
+assuan_get_pointer (assuan_context_t ctx)
{
return ctx? ctx->user_pointer : NULL;
}
void
-assuan_set_log_stream (ASSUAN_CONTEXT ctx, FILE *fp)
+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 ctx)
+assuan_begin_confidential (assuan_context_t ctx)
{
if (ctx)
{
}
void
-assuan_end_confidential (ASSUAN_CONTEXT ctx)
+assuan_end_confidential (assuan_context_t ctx)
{
if (ctx)
{
}
}
+
+
+/* For context CTX, set the flag FLAG to VALUE. Values for flags
+ are usually 1 or 0 but certain flags might allow for other values;
+ see the description of the type assuan_flag_t for details. */
+void
+assuan_set_flag (assuan_context_t ctx, assuan_flag_t flag, int value)
+{
+ if (!ctx)
+ return;
+ switch (flag)
+ {
+ case ASSUAN_NO_WAITPID: ctx->flags.no_waitpid = value; break;
+ }
+}
+
+/* Return the VALUE of FLAG in context CTX. */
+int
+assuan_get_flag (assuan_context_t ctx, assuan_flag_t flag)
+{
+ if (!ctx)
+ return 0;
+ switch (flag)
+ {
+ case ASSUAN_NO_WAITPID: return ctx->flags.no_waitpid;
+ }
+ return 0;
+}
+
+
/* Dump a possibly binary string (used for debugging). Distinguish
ascii text from binary and print it accordingly. */
void
int n;
for (n=length,s=buffer; n; n--, s++)
- if (!isascii (*s) || iscntrl (*s) || !isprint (*s))
+ if ((!isascii (*s) || iscntrl (*s) || !isprint (*s)) && !(*s >= 0x80))
break;
s = buffer;
break;
default:
- if (isascii (*s) && isprint (*s))
+ if ((isascii (*s) && isprint (*s)) || (*s >= 0x80))
putc_unlocked (*s, fp);
else
{
funlockfile (fp);
#endif
}
+
-/* assuan.c - Definitions for the Assuan protocol
- * Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
+/* assuan.c - Definitions for the Assuan IPC library
+ * Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
*
* This file is part of Assuan.
*
#include <sys/types.h>
#include <unistd.h>
-#include <sys/socket.h>
-#define _ASSUAN_IN_GPGME
-#ifdef _ASSUAN_IN_GPGME
+/* To use this file with libraries the following macros are often
+ useful:
+
+ #define _ASSUAN_EXT_SYM_PREFIX _foo_
+
+ This prefixes all external symbols with "_foo_".
+
+ #define _ASSUAN_NO_PTH
+
+ This avoids inclusion of special GNU Pth hacks.
+
+ #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_NO_PTH
+#define _ASSUAN_NO_FIXED_SIGNALS
+#define _ASSUAN_USE_DOUBLE_FORK
#ifdef _ASSUAN_IN_GPGME_BUILD_ASSUAN
int _gpgme_io_read (int fd, void *buffer, size_t count);
int _gpgme_io_write (int fd, const void *buffer, size_t count);
-ssize_t _gpgme_ath_select (int nfd, fd_set *rset, fd_set *wset, fd_set *eset,
- struct timeval *timeout);
ssize_t _gpgme_ath_waitpid (pid_t pid, int *status, int options);
+#ifdef HAVE_W32_SYSTEM
+int _gpgme_ath_accept (int s, void *addr, int *length_ptr);
+#else /*!HAVE_W32_SYSTEM*/
+ssize_t _gpgme_ath_select (int nfd, fd_set *rset, fd_set *wset, fd_set *eset,
+ struct timeval *timeout);
int _gpgme_ath_accept (int s, struct sockaddr *addr, socklen_t *length_ptr);
int _gpgme_ath_connect (int s, struct sockaddr *addr, socklen_t length);
int _gpgme_ath_sendmsg (int s, const struct msghdr *msg, int flags);
int _gpgme_ath_recvmsg (int s, struct msghdr *msg, int flags);
+#endif /*!HAVE_W32_SYSTEM*/
#define read _gpgme_io_read
#define write _gpgme_io_write
#define connect _gpgme_ath_connect
#define sendmsg _gpgme_ath_sendmsg
#define recvmsg _gpgme_ath_recvmsg
-#endif
-#endif
+#endif /*_ASSUAN_IN_GPGME_BUILD_ASSUAN*/
+/**** End GPGME specific modifications. ******/
+
#ifdef _ASSUAN_EXT_SYM_PREFIX
#define _ASSUAN_PREFIX1(x,y) x ## y
_ASSUAN_PREFIX(assuan_get_assuan_log_stream)
#define assuan_get_assuan_log_prefix \
_ASSUAN_PREFIX(assuan_get_assuan_log_prefix)
+#define assuan_set_flag _ASSUAN_PREFIX(assuan_set_flag)
+#define assuan_get_flag _ASSUAN_PREFIX(assuan_get_flag)
/* And now the internal functions, argh... */
#define _assuan_read_line _ASSUAN_PREFIX(_assuan_read_line)
#define _assuan_log_print_buffer _ASSUAN_PREFIX(_assuan_log_print_buffer)
#define _assuan_log_sanitized_string \
_ASSUAN_PREFIX(_assuan_log_sanitized_string)
+#define _assuan_log_printf _ASSUAN_PREFIX(_assuan_log_printf)
+#define _assuan_set_default_log_stream \
+ _ASSUAN_PREFIX(_assuan_set_default_log_stream)
+#define _assuan_w32_strerror _ASSUAN_PREFIX(_assuan_w32_strerror)
+#define _assuan_write_line _ASSUAN_PREFIX(_assuan_write_line)
+#define _assuan_close _ASSUAN_PREFIX(_assuan_close)
+#define _assuan_sock_new _ASSUAN_PREFIX(_assuan_sock_new)
+#define _assuan_sock_bind _ASSUAN_PREFIX(_assuan_sock_bind)
+#define _assuan_sock_connect _ASSUAN_PREFIX(_assuan_sock_connect)
+
+#endif /*_ASSUAN_EXT_SYM_PREFIX*/
-#endif
#ifdef __cplusplus
extern "C"
{
+#if 0
+}
#endif
-
+#endif
+
typedef enum
{
ASSUAN_Connect_Failed = 14,
ASSUAN_Accept_Failed = 15,
- /* error codes above 99 are meant as status codes */
+ /* Error codes above 99 are meant as status codes */
ASSUAN_Not_Implemented = 100,
ASSUAN_Server_Fault = 101,
ASSUAN_Invalid_Command = 102,
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_Invalid_Card = 402,
ASSUAN_No_PKCS15_App = 403,
ASSUAN_Card_Not_Present = 404,
- ASSUAN_Invalid_Id = 405
+ 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
+
+} assuan_error_t;
-} AssuanError;
+typedef assuan_error_t AssuanError; /* Deprecated. */
/* This is a list of pre-registered ASSUAN commands */
+/* NOTE, these command IDs are now deprectated and solely exists for
+ compatibility reasons. */
typedef enum
{
ASSUAN_CMD_NOP = 0,
ASSUAN_CMD_USER = 256 /* Other commands should be used with this offset*/
} AssuanCommand;
+
+/* Definitions of flags for assuan_set_flag(). */
+typedef enum
+ {
+ /* When using a pipe server, by default Assuan will wait for the
+ forked process to die in assuan_disconnect. In certain cases
+ this is not desirable. By setting this flag, the waitpid will
+ be skipped and the caller is responsible to cleanup a forked
+ process. */
+ ASSUAN_NO_WAITPID = 1
+ }
+assuan_flag_t;
+
#define ASSUAN_LINELENGTH 1002 /* 1000 + [CR,]LF */
struct assuan_context_s;
+typedef struct assuan_context_s *assuan_context_t;
typedef struct assuan_context_s *ASSUAN_CONTEXT;
/*-- assuan-handler.c --*/
-int assuan_register_command (ASSUAN_CONTEXT ctx,
+int assuan_register_command (assuan_context_t ctx,
const char *cmd_string,
- int (*handler)(ASSUAN_CONTEXT, char *));
-int assuan_register_bye_notify (ASSUAN_CONTEXT ctx,
- void (*fnc)(ASSUAN_CONTEXT));
-int assuan_register_reset_notify (ASSUAN_CONTEXT ctx,
- void (*fnc)(ASSUAN_CONTEXT));
-int assuan_register_cancel_notify (ASSUAN_CONTEXT ctx,
- void (*fnc)(ASSUAN_CONTEXT));
-int assuan_register_input_notify (ASSUAN_CONTEXT ctx,
- void (*fnc)(ASSUAN_CONTEXT, const char *));
-int assuan_register_output_notify (ASSUAN_CONTEXT ctx,
- void (*fnc)(ASSUAN_CONTEXT, const char *));
-
-int assuan_register_option_handler (ASSUAN_CONTEXT ctx,
- int (*fnc)(ASSUAN_CONTEXT,
+ int (*handler)(assuan_context_t, char *));
+int assuan_register_bye_notify (assuan_context_t ctx,
+ void (*fnc)(assuan_context_t));
+int assuan_register_reset_notify (assuan_context_t ctx,
+ void (*fnc)(assuan_context_t));
+int assuan_register_cancel_notify (assuan_context_t ctx,
+ void (*fnc)(assuan_context_t));
+int assuan_register_input_notify (assuan_context_t ctx,
+ void (*fnc)(assuan_context_t, const char *));
+int assuan_register_output_notify (assuan_context_t ctx,
+ void (*fnc)(assuan_context_t, const char *));
+
+int assuan_register_option_handler (assuan_context_t ctx,
+ int (*fnc)(assuan_context_t,
const char*, const char*));
-int assuan_process (ASSUAN_CONTEXT ctx);
-int assuan_process_next (ASSUAN_CONTEXT ctx);
-int assuan_get_active_fds (ASSUAN_CONTEXT ctx, int what,
+int assuan_process (assuan_context_t ctx);
+int assuan_process_next (assuan_context_t ctx);
+int assuan_get_active_fds (assuan_context_t ctx, int what,
int *fdarray, int fdarraysize);
-FILE *assuan_get_data_fp (ASSUAN_CONTEXT ctx);
-AssuanError assuan_set_okay_line (ASSUAN_CONTEXT ctx, const char *line);
-void assuan_write_status (ASSUAN_CONTEXT ctx,
- const char *keyword, const char *text);
+FILE *assuan_get_data_fp (assuan_context_t ctx);
+assuan_error_t assuan_set_okay_line (assuan_context_t ctx, const char *line);
+assuan_error_t assuan_write_status (assuan_context_t ctx,
+ const char *keyword, const char *text);
/* Negotiate a file descriptor. If LINE contains "FD=N", returns N
assuming a local file descriptor. If LINE contains "FD" reads a
file descriptor via CTX and stores it in *RDF (the CTX must be
capable of passing file descriptors). */
-AssuanError assuan_command_parse_fd (ASSUAN_CONTEXT ctx, char *line,
+assuan_error_t assuan_command_parse_fd (assuan_context_t ctx, char *line,
int *rfd);
/*-- assuan-listen.c --*/
-AssuanError assuan_set_hello_line (ASSUAN_CONTEXT ctx, const char *line);
-AssuanError assuan_accept (ASSUAN_CONTEXT ctx);
-int assuan_get_input_fd (ASSUAN_CONTEXT ctx);
-int assuan_get_output_fd (ASSUAN_CONTEXT ctx);
-AssuanError assuan_close_input_fd (ASSUAN_CONTEXT ctx);
-AssuanError assuan_close_output_fd (ASSUAN_CONTEXT ctx);
+assuan_error_t assuan_set_hello_line (assuan_context_t ctx, const char *line);
+assuan_error_t assuan_accept (assuan_context_t ctx);
+int assuan_get_input_fd (assuan_context_t ctx);
+int assuan_get_output_fd (assuan_context_t ctx);
+assuan_error_t assuan_close_input_fd (assuan_context_t ctx);
+assuan_error_t assuan_close_output_fd (assuan_context_t ctx);
/*-- assuan-pipe-server.c --*/
-int assuan_init_pipe_server (ASSUAN_CONTEXT *r_ctx, int filedes[2]);
-void assuan_deinit_server (ASSUAN_CONTEXT ctx);
+int assuan_init_pipe_server (assuan_context_t *r_ctx, int filedes[2]);
+void assuan_deinit_server (assuan_context_t ctx);
/*-- assuan-socket-server.c --*/
-int assuan_init_socket_server (ASSUAN_CONTEXT *r_ctx, int listen_fd);
-int assuan_init_connected_socket_server (ASSUAN_CONTEXT *r_ctx, int fd);
+int assuan_init_socket_server (assuan_context_t *r_ctx, int listen_fd);
+int assuan_init_connected_socket_server (assuan_context_t *r_ctx, int fd);
/*-- assuan-pipe-connect.c --*/
-AssuanError assuan_pipe_connect (ASSUAN_CONTEXT *ctx, const char *name,
+assuan_error_t assuan_pipe_connect (assuan_context_t *ctx, const char *name,
char *const argv[], int *fd_child_list);
+assuan_error_t assuan_pipe_connect2 (assuan_context_t *ctx, const char *name,
+ char *const argv[], int *fd_child_list,
+ void (*atfork) (void*, int),
+ void *atforkvalue);
/*-- assuan-socket-connect.c --*/
-AssuanError assuan_socket_connect (ASSUAN_CONTEXT *ctx, const char *name,
- pid_t server_pid);
+assuan_error_t assuan_socket_connect (assuan_context_t *ctx, const char *name,
+ pid_t server_pid);
/*-- assuan-domain-connect.c --*/
bidirectional file descriptor (normally returned via socketpair)
which the client can use to rendezvous with the server. SERVER s
the server's pid. */
-AssuanError assuan_domain_connect (ASSUAN_CONTEXT *r_ctx,
+assuan_error_t assuan_domain_connect (assuan_context_t *r_ctx,
int rendezvousfd,
pid_t server);
/* 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. */
-AssuanError assuan_init_domain_server (ASSUAN_CONTEXT *r_ctx,
+assuan_error_t assuan_init_domain_server (assuan_context_t *r_ctx,
int rendezvousfd,
pid_t client);
/*-- assuan-connect.c --*/
-void assuan_disconnect (ASSUAN_CONTEXT ctx);
-pid_t assuan_get_pid (ASSUAN_CONTEXT ctx);
+void assuan_disconnect (assuan_context_t ctx);
+pid_t assuan_get_pid (assuan_context_t ctx);
/*-- assuan-client.c --*/
-AssuanError
-assuan_transact (ASSUAN_CONTEXT ctx,
+assuan_error_t
+assuan_transact (assuan_context_t ctx,
const char *command,
- AssuanError (*data_cb)(void *, const void *, size_t),
+ assuan_error_t (*data_cb)(void *, const void *, size_t),
void *data_cb_arg,
- AssuanError (*inquire_cb)(void*, const char *),
+ assuan_error_t (*inquire_cb)(void*, const char *),
void *inquire_cb_arg,
- AssuanError (*status_cb)(void*, const char *),
+ assuan_error_t (*status_cb)(void*, const char *),
void *status_cb_arg);
/*-- assuan-inquire.c --*/
-AssuanError assuan_inquire (ASSUAN_CONTEXT ctx, const char *keyword,
- char **r_buffer, size_t *r_length, size_t maxlen);
+assuan_error_t assuan_inquire (assuan_context_t ctx, const char *keyword,
+ unsigned char **r_buffer, size_t *r_length,
+ size_t maxlen);
/*-- assuan-buffer.c --*/
-AssuanError assuan_read_line (ASSUAN_CONTEXT ctx,
+assuan_error_t assuan_read_line (assuan_context_t ctx,
char **line, size_t *linelen);
-int assuan_pending_line (ASSUAN_CONTEXT ctx);
-AssuanError assuan_write_line (ASSUAN_CONTEXT ctx, const char *line );
-AssuanError assuan_send_data (ASSUAN_CONTEXT ctx,
+int assuan_pending_line (assuan_context_t ctx);
+assuan_error_t assuan_write_line (assuan_context_t ctx, const char *line );
+assuan_error_t assuan_send_data (assuan_context_t ctx,
const void *buffer, size_t length);
/* The file descriptor must be pending before assuan_receivefd is
call. This means that assuan_sendfd should be called *before* the
trigger is sent (normally via assuan_send_data ("I sent you a
descriptor")). */
-AssuanError assuan_sendfd (ASSUAN_CONTEXT ctx, int fd);
-AssuanError assuan_receivefd (ASSUAN_CONTEXT ctx, int *fd);
+assuan_error_t assuan_sendfd (assuan_context_t ctx, int fd);
+assuan_error_t assuan_receivefd (assuan_context_t ctx, int *fd);
/*-- assuan-util.c --*/
void assuan_set_malloc_hooks ( void *(*new_alloc_func)(size_t n),
void *(*new_realloc_func)(void *p, size_t n),
void (*new_free_func)(void*) );
-void assuan_set_log_stream (ASSUAN_CONTEXT ctx, FILE *fp);
-int assuan_set_error (ASSUAN_CONTEXT ctx, int err, const char *text);
-void assuan_set_pointer (ASSUAN_CONTEXT ctx, void *pointer);
-void *assuan_get_pointer (ASSUAN_CONTEXT ctx);
+void assuan_set_log_stream (assuan_context_t ctx, FILE *fp);
+int assuan_set_error (assuan_context_t ctx, int err, const char *text);
+void assuan_set_pointer (assuan_context_t ctx, void *pointer);
+void *assuan_get_pointer (assuan_context_t ctx);
+
+void assuan_begin_confidential (assuan_context_t ctx);
+void assuan_end_confidential (assuan_context_t ctx);
+
+/* For context CTX, set the flag FLAG to VALUE. Values for flags
+ are usually 1 or 0 but certain flags might allow for other values;
+ see the description of the type assuan_flag_t for details. */
+void assuan_set_flag (assuan_context_t ctx, assuan_flag_t flag, int value);
+
+/* Return the VALUE of FLAG in context CTX. */
+int assuan_get_flag (assuan_context_t ctx, assuan_flag_t flag);
-void assuan_begin_confidential (ASSUAN_CONTEXT ctx);
-void assuan_end_confidential (ASSUAN_CONTEXT ctx);
/*-- assuan-errors.c (built) --*/
-const char *assuan_strerror (AssuanError err);
+const char *assuan_strerror (assuan_error_t err);
/*-- assuan-logging.c --*/
-/* Set the stream to which assuan should log. By default, this is
- stderr. */
+/* Set the stream to which assuan should log message not associated
+ with a context. By default, this is stderr. The default value
+ will be changed when the first log stream is associated with a
+ context. Note, that this function is not thread-safe and should
+ in general be used right at startup. */
extern void assuan_set_assuan_log_stream (FILE *fp);
-/* Return the stream which is currently being using for logging. */
+/* Return the stream which is currently being using for global logging. */
extern FILE *assuan_get_assuan_log_stream (void);
-/* User defined call back. Return a prefix to be used at the start of
- a line emitted by assuan on the log stream. The default
- implementation returns the empty string, i.e. "" */
-extern const char *assuan_get_assuan_log_prefix (void);
+/* Set the prefix to be used at the start of a line emitted by assuan
+ on the log stream. The default is the empty string. Note, that
+ this function is not thread-safe and should in general be used
+ right at startup. */
+void assuan_set_assuan_log_prefix (const char *text);
+
+/* Return a prefix to be used at the start of a line emitted by assuan
+ on the log stream. The default implementation returns the empty
+ string, i.e. "" */
+const char *assuan_get_assuan_log_prefix (void);
#ifdef __cplusplus
}
/* Generated automatically by mkerrors */
/* Do not edit! */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
#include <stdio.h>
#include "assuan.h"
# Checks for library functions.
AC_FUNC_FSEEKO
-AC_REPLACE_FUNCS(stpcpy)
+AC_CHECK_FUNCS(stpcpy)
AC_REPLACE_FUNCS(vasprintf)
if test "$ac_cv_func_vasprintf" != yes; then
+2005-08-08 Werner Koch <wk@g10code.com>
+
+ * util.h (stpcpy): Renamed to ..
+ (_gpgme_stpcpy): .. this and made inline. This avoids duplicate
+ definitions when linking statically.
+ * stpcpy.c: Removed.
+
2005-07-27 Marcus Brinkmann <marcus@g10code.de>
* gpgme.h (gpgme_status_code_t): Add GPGME_STATUS_PLAINTEXT.
/* util.h
Copyright (C) 2000 Werner Koch (dd9jn)
- Copyright (C) 2001, 2002, 2003, 2004 g10 Code GmbH
+ Copyright (C) 2001, 2002, 2003, 2004, 2005 g10 Code GmbH
This file is part of GPGME.
\f
/*-- replacement functions in <funcname>.c --*/
#ifdef HAVE_CONFIG_H
+
#ifndef HAVE_STPCPY
-char *stpcpy (char *a, const char *b);
-#endif
+static _GPGME_INLINE char *
+_gpgme_stpcpy (char *a, const char *b)
+{
+ while (*b)
+ *a++ = *b++;
+ *a = 0;
+ return a;
+}
+#define stpcpy(a,b) _gpgme_stpcpy ((a), (b))
+#endif /*!HAVE_STPCPY*/
#if !HAVE_VASPRINTF
#include <stdarg.h>