aboutsummaryrefslogtreecommitdiffstats
path: root/assuan/assuan-domain-connect.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--assuan/assuan-domain-connect.c504
1 files changed, 0 insertions, 504 deletions
diff --git a/assuan/assuan-domain-connect.c b/assuan/assuan-domain-connect.c
index b55e9c31..e69de29b 100644
--- a/assuan/assuan-domain-connect.c
+++ b/assuan/assuan-domain-connect.c
@@ -1,504 +0,0 @@
-/* assuan-domain-connect.c - Assuan unix domain socket based client
- * Copyright (C) 2002, 2003 Free Software Foundation, Inc.
- *
- * This file is part of Assuan.
- *
- * Assuan is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * Assuan is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include <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;
-}