Blame src/assuan-support.c

Packit Service 30b792
/* assuan-support.c - Assuan wrappers
Packit Service 30b792
 * Copyright (C) 2009 g10 Code GmbH
Packit Service 30b792
 *
Packit Service 30b792
 * This file is part of GPGME.
Packit Service 30b792
 *
Packit Service 30b792
 * GPGME is free software; you can redistribute it and/or modify it
Packit Service 30b792
 * under the terms of the GNU Lesser General Public License as
Packit Service 30b792
 * published by the Free Software Foundation; either version 2.1 of
Packit Service 30b792
 * the License, or (at your option) any later version.
Packit Service 30b792
 *
Packit Service 30b792
 * GPGME is distributed in the hope that it will be useful, but
Packit Service 30b792
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 30b792
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 30b792
 * Lesser General Public License for more details.
Packit Service 30b792
 *
Packit Service 30b792
 * You should have received a copy of the GNU Lesser General Public
Packit Service 30b792
 * License along with this program; if not, see <https://gnu.org/licenses/>.
Packit Service 30b792
 * SPDX-License-Identifier: LGPL-2.1-or-later
Packit Service 30b792
 */
Packit Service 30b792
Packit Service 30b792
Packit d7e8d0
#if HAVE_CONFIG_H
Packit d7e8d0
#include <config.h>
Packit d7e8d0
#endif
Packit d7e8d0
Packit d7e8d0
#include <assert.h>
Packit d7e8d0
#include <stdlib.h>
Packit d7e8d0
#include <errno.h>
Packit d7e8d0
Packit d7e8d0
#include "assuan.h"
Packit d7e8d0
Packit d7e8d0
#include "gpgme.h"
Packit d7e8d0
#include "ath.h"
Packit d7e8d0
#include "priv-io.h"
Packit d7e8d0
#include "debug.h"
Packit d7e8d0
Packit d7e8d0

Packit d7e8d0
struct assuan_malloc_hooks _gpgme_assuan_malloc_hooks =
Packit d7e8d0
  {
Packit d7e8d0
    malloc,
Packit d7e8d0
    realloc,
Packit d7e8d0
    free
Packit d7e8d0
  };
Packit d7e8d0
Packit d7e8d0

Packit d7e8d0
int
Packit d7e8d0
_gpgme_assuan_log_cb (assuan_context_t ctx, void *hook,
Packit d7e8d0
		      unsigned int cat, const char *msg)
Packit d7e8d0
{
Packit d7e8d0
  (void)ctx;
Packit d7e8d0
  (void)hook;
Packit d7e8d0
  (void)cat;
Packit d7e8d0
Packit d7e8d0
  if (msg == NULL)
Packit d7e8d0
    return 1;
Packit d7e8d0
Packit Service 30b792
  _gpgme_debug (NULL, DEBUG_ASSUAN, -1, NULL, NULL, NULL, "%s", msg);
Packit d7e8d0
  return 0;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0

Packit d7e8d0
static void
Packit d7e8d0
my_usleep (assuan_context_t ctx, unsigned int usec)
Packit d7e8d0
{
Packit d7e8d0
  /* FIXME: Add to ath.  */
Packit d7e8d0
  __assuan_usleep (ctx, usec);
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
/* Create a pipe with an inheritable end.  */
Packit d7e8d0
static int
Packit d7e8d0
my_pipe (assuan_context_t ctx, assuan_fd_t fds[2], int inherit_idx)
Packit d7e8d0
{
Packit d7e8d0
  int res;
Packit d7e8d0
  int gfds[2];
Packit d7e8d0
Packit d7e8d0
  (void)ctx;
Packit d7e8d0
Packit d7e8d0
  res = _gpgme_io_pipe (gfds, inherit_idx);
Packit d7e8d0
Packit d7e8d0
  /* For now... */
Packit d7e8d0
  fds[0] = (assuan_fd_t) gfds[0];
Packit d7e8d0
  fds[1] = (assuan_fd_t) gfds[1];
Packit d7e8d0
Packit d7e8d0
  return res;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
/* Close the given file descriptor, created with _assuan_pipe or one
Packit d7e8d0
   of the socket functions.  */
Packit d7e8d0
static int
Packit d7e8d0
my_close (assuan_context_t ctx, assuan_fd_t fd)
Packit d7e8d0
{
Packit d7e8d0
  (void)ctx;
Packit d7e8d0
  return _gpgme_io_close ((int) fd);
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
static gpgme_ssize_t
Packit d7e8d0
my_read (assuan_context_t ctx, assuan_fd_t fd, void *buffer, size_t size)
Packit d7e8d0
{
Packit d7e8d0
  (void)ctx;
Packit d7e8d0
  return _gpgme_io_read ((int) fd, buffer, size);
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
static gpgme_ssize_t
Packit d7e8d0
my_write (assuan_context_t ctx, assuan_fd_t fd, const void *buffer, size_t size)
Packit d7e8d0
{
Packit d7e8d0
  (void)ctx;
Packit d7e8d0
  return _gpgme_io_write ((int) fd, buffer, size);
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
static int
Packit d7e8d0
my_recvmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg,
Packit d7e8d0
	    int flags)
Packit d7e8d0
{
Packit d7e8d0
  (void)ctx;
Packit d7e8d0
#ifdef HAVE_W32_SYSTEM
Packit d7e8d0
  (void)fd;
Packit d7e8d0
  (void)msg;
Packit d7e8d0
  (void)flags;
Packit d7e8d0
  gpg_err_set_errno (ENOSYS);
Packit d7e8d0
  return -1;
Packit d7e8d0
#else
Packit d7e8d0
  return _gpgme_io_recvmsg ((int) fd, msg, flags);
Packit d7e8d0
#endif
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
static int
Packit d7e8d0
my_sendmsg (assuan_context_t ctx, assuan_fd_t fd, const assuan_msghdr_t msg,
Packit d7e8d0
	    int flags)
Packit d7e8d0
{
Packit d7e8d0
  (void)ctx;
Packit d7e8d0
#ifdef HAVE_W32_SYSTEM
Packit d7e8d0
  (void)fd;
Packit d7e8d0
  (void)msg;
Packit d7e8d0
  (void)flags;
Packit d7e8d0
  gpg_err_set_errno (ENOSYS);
Packit d7e8d0
  return -1;
Packit d7e8d0
#else
Packit d7e8d0
  return _gpgme_io_sendmsg ((int) fd, msg, flags);
Packit d7e8d0
#endif
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
/* If NAME is NULL, don't exec, just fork.  FD_CHILD_LIST is modified
Packit d7e8d0
   to reflect the value of the FD in the peer process (on
Packit d7e8d0
   Windows).  */
Packit d7e8d0
static int
Packit d7e8d0
my_spawn (assuan_context_t ctx, pid_t *r_pid, const char *name,
Packit d7e8d0
	  const char **argv,
Packit d7e8d0
	  assuan_fd_t fd_in, assuan_fd_t fd_out,
Packit d7e8d0
	  assuan_fd_t *fd_child_list,
Packit d7e8d0
	  void (*atfork) (void *opaque, int reserved),
Packit d7e8d0
	  void *atforkvalue, unsigned int flags)
Packit d7e8d0
{
Packit Service 30b792
  int err = 0;
Packit d7e8d0
  struct spawn_fd_item_s *fd_items;
Packit d7e8d0
  int i;
Packit d7e8d0
Packit d7e8d0
  (void)ctx;
Packit d7e8d0
  (void)flags;
Packit d7e8d0
Packit d7e8d0
  assert (name);
Packit d7e8d0
Packit d7e8d0
  if (! name)
Packit d7e8d0
    {
Packit d7e8d0
      gpg_err_set_errno (ENOSYS);
Packit d7e8d0
      return -1;
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
  i = 0;
Packit d7e8d0
  if (fd_child_list)
Packit d7e8d0
    {
Packit d7e8d0
      while (fd_child_list[i] != ASSUAN_INVALID_FD)
Packit d7e8d0
	i++;
Packit d7e8d0
    }
Packit d7e8d0
  /* fd_in, fd_out, terminator */
Packit d7e8d0
  i += 3;
Packit d7e8d0
  fd_items = calloc (i, sizeof (struct spawn_fd_item_s));
Packit d7e8d0
  if (! fd_items)
Packit d7e8d0
    return -1;
Packit d7e8d0
  i = 0;
Packit d7e8d0
  if (fd_child_list)
Packit d7e8d0
    {
Packit d7e8d0
      while (fd_child_list[i] != ASSUAN_INVALID_FD)
Packit d7e8d0
	{
Packit d7e8d0
	  fd_items[i].fd = (int) fd_child_list[i];
Packit d7e8d0
	  fd_items[i].dup_to = -1;
Packit d7e8d0
	  i++;
Packit d7e8d0
	}
Packit d7e8d0
    }
Packit d7e8d0
  if (fd_in != ASSUAN_INVALID_FD)
Packit d7e8d0
    {
Packit d7e8d0
      fd_items[i].fd = (int) fd_in;
Packit d7e8d0
      fd_items[i].dup_to = 0;
Packit d7e8d0
      i++;
Packit d7e8d0
    }
Packit d7e8d0
  if (fd_out != ASSUAN_INVALID_FD)
Packit d7e8d0
    {
Packit d7e8d0
      fd_items[i].fd = (int) fd_out;
Packit d7e8d0
      fd_items[i].dup_to = 1;
Packit d7e8d0
      i++;
Packit d7e8d0
    }
Packit d7e8d0
  fd_items[i].fd = -1;
Packit d7e8d0
  fd_items[i].dup_to = -1;
Packit d7e8d0
Packit Service 30b792
#ifdef HAVE_W32_SYSTEM
Packit Service 30b792
  /* Fix up a potential logger fd so that on windows the fd
Packit Service 30b792
   * translation can work through gpgme-w32spawn.
Packit Service 30b792
   *
Packit Service 30b792
   * We do this here as a hack because we would
Packit Service 30b792
   * otherwise have to change assuan_api and the current
Packit Service 30b792
   * plan in 2019 is to change away from this to gpgrt
Packit Service 30b792
   * based IPC. */
Packit Service 30b792
  if (argv)
Packit Service 30b792
    {
Packit Service 30b792
      int loc = 0;
Packit Service 30b792
      while (argv[loc])
Packit Service 30b792
        {
Packit Service 30b792
          if (!strcmp ("--logger-fd", argv[loc]))
Packit Service 30b792
            {
Packit Service 30b792
              long logger_fd = -1;
Packit Service 30b792
              char *tail;
Packit Service 30b792
              int k = 0;
Packit Service 30b792
              loc++;
Packit Service 30b792
              if (!argv[loc])
Packit Service 30b792
                {
Packit Service 30b792
                  err = GPG_ERR_INV_ARG;
Packit Service 30b792
                  break;
Packit Service 30b792
                }
Packit Service 30b792
              logger_fd = strtol (argv[loc], &tail, 10);
Packit Service 30b792
              if (tail == argv[loc] || logger_fd < 0)
Packit Service 30b792
                {
Packit Service 30b792
                  err = GPG_ERR_INV_ARG;
Packit Service 30b792
                  break;
Packit Service 30b792
                }
Packit Service 30b792
              while (fd_items[k++].fd != -1)
Packit Service 30b792
                {
Packit Service 30b792
                  if (fd_items[k].fd == logger_fd)
Packit Service 30b792
                    {
Packit Service 30b792
                      fd_items[k].arg_loc = loc;
Packit Service 30b792
                      break;
Packit Service 30b792
                    }
Packit Service 30b792
                }
Packit Service 30b792
              break;
Packit Service 30b792
            }
Packit Service 30b792
          loc++;
Packit Service 30b792
        }
Packit Service 30b792
    }
Packit Service 30b792
#endif
Packit Service 30b792
Packit Service 30b792
  if (!err)
Packit Service 30b792
    {
Packit Service 30b792
      err = _gpgme_io_spawn (name, (char*const*)argv,
Packit Service 30b792
                             (IOSPAWN_FLAG_NOCLOSE | IOSPAWN_FLAG_DETACHED),
Packit Service 30b792
                             fd_items, atfork, atforkvalue, r_pid);
Packit Service 30b792
    }
Packit Service 30b792
  if (!err)
Packit d7e8d0
    {
Packit d7e8d0
      i = 0;
Packit d7e8d0
Packit d7e8d0
      if (fd_child_list)
Packit d7e8d0
	{
Packit d7e8d0
	  while (fd_child_list[i] != ASSUAN_INVALID_FD)
Packit d7e8d0
	    {
Packit d7e8d0
	      fd_child_list[i] = (assuan_fd_t) fd_items[i].peer_name;
Packit d7e8d0
	      i++;
Packit d7e8d0
	    }
Packit d7e8d0
	}
Packit d7e8d0
    }
Packit d7e8d0
  free (fd_items);
Packit d7e8d0
  return err;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
/* If action is 0, like waitpid.  If action is 1, just release the PID?  */
Packit d7e8d0
static pid_t
Packit d7e8d0
my_waitpid (assuan_context_t ctx, pid_t pid,
Packit d7e8d0
	    int nowait, int *status, int options)
Packit d7e8d0
{
Packit d7e8d0
  (void)ctx;
Packit d7e8d0
#ifdef HAVE_W32_SYSTEM
Packit d7e8d0
  (void)nowait;
Packit d7e8d0
  (void)status;
Packit d7e8d0
  (void)options;
Packit Service 30b792
  (void)pid;  /* Just a number without a kernel object.  */
Packit d7e8d0
#else
Packit d7e8d0
  /* We can't just release the PID, a waitpid is mandatory.  But
Packit d7e8d0
     NOWAIT in POSIX systems just means the caller already did the
Packit d7e8d0
     waitpid for this child.  */
Packit d7e8d0
  if (! nowait)
Packit d7e8d0
    return _gpgme_ath_waitpid (pid, status, options);
Packit d7e8d0
#endif
Packit d7e8d0
  return 0;
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
static int
Packit d7e8d0
my_socketpair (assuan_context_t ctx, int namespace, int style,
Packit d7e8d0
	       int protocol, assuan_fd_t filedes[2])
Packit d7e8d0
{
Packit d7e8d0
#ifdef HAVE_W32_SYSTEM
Packit d7e8d0
  (void)ctx;
Packit d7e8d0
  (void)namespace;
Packit d7e8d0
  (void)style;
Packit d7e8d0
  (void)protocol;
Packit d7e8d0
  (void)filedes;
Packit d7e8d0
  gpg_err_set_errno (ENOSYS);
Packit d7e8d0
  return -1;
Packit d7e8d0
#else
Packit d7e8d0
  /* FIXME: Debug output missing.  */
Packit d7e8d0
  return __assuan_socketpair (ctx, namespace, style, protocol, filedes);
Packit d7e8d0
#endif
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
static int
Packit d7e8d0
my_socket (assuan_context_t ctx, int namespace, int style, int protocol)
Packit d7e8d0
{
Packit d7e8d0
  (void)ctx;
Packit d7e8d0
  return _gpgme_io_socket (namespace, style, protocol);
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
static int
Packit d7e8d0
my_connect (assuan_context_t ctx, int sock, struct sockaddr *addr,
Packit d7e8d0
	    socklen_t length)
Packit d7e8d0
{
Packit d7e8d0
  (void)ctx;
Packit d7e8d0
  return _gpgme_io_connect (sock, addr, length);
Packit d7e8d0
}
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
/* Note for Windows: Ignore the incompatible pointer type warning for
Packit d7e8d0
   my_read and my_write.  Mingw has been changed to use int for
Packit d7e8d0
   ssize_t on 32 bit systems while we use long.  For 64 bit we use
Packit d7e8d0
   int64_t while mingw uses __int64_t.  It doe not matter at all
Packit d7e8d0
   because under Windows long and int are both 32 bit even on 64
Packit d7e8d0
   bit.  */
Packit d7e8d0
struct assuan_system_hooks _gpgme_assuan_system_hooks =
Packit d7e8d0
  {
Packit d7e8d0
    ASSUAN_SYSTEM_HOOKS_VERSION,
Packit d7e8d0
    my_usleep,
Packit d7e8d0
    my_pipe,
Packit d7e8d0
    my_close,
Packit d7e8d0
    my_read,
Packit d7e8d0
    my_write,
Packit d7e8d0
    my_recvmsg,
Packit d7e8d0
    my_sendmsg,
Packit d7e8d0
    my_spawn,
Packit d7e8d0
    my_waitpid,
Packit d7e8d0
    my_socketpair,
Packit d7e8d0
    my_socket,
Packit d7e8d0
    my_connect
Packit d7e8d0
  };