diff options
Diffstat (limited to '')
-rw-r--r-- | assuan/assuan-domain-connect.c | 504 |
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; -} |