示例#1
0
/* Close all pending fds. */
void
_assuan_uds_close_fds (assuan_context_t ctx)
{
  int i;

  for (i = 0; i < ctx->uds.pendingfdscount; i++)
    _assuan_close (ctx, ctx->uds.pendingfds[i]);
  ctx->uds.pendingfdscount = 0;
}
示例#2
0
/* 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 */
assuan_error_t
assuan_close_input_fd (assuan_context_t ctx)
{
  if (!ctx || ctx->input_fd == -1)
    return _assuan_error (ASSUAN_Invalid_Value);
  _assuan_close (ctx->input_fd);
  ctx->input_fd = -1;
  return 0;
}
示例#3
0
static int
finish_connection (assuan_context_t ctx)
{
  if (ctx->inbound.fd != ASSUAN_INVALID_FD)
    {
      _assuan_close (ctx->inbound.fd);
    }
  ctx->inbound.fd = ASSUAN_INVALID_FD;
  ctx->outbound.fd = ASSUAN_INVALID_FD;
  return 0;
}
static int
do_finish(assuan_context_t ctx)
{
    if(ctx->inbound.fd != -1)
    {
        _assuan_close(ctx->inbound.fd);
    }
    ctx->inbound.fd = -1;
    ctx->outbound.fd = -1;
    return 0;
}
示例#5
0
void
_assuan_client_finish (assuan_context_t ctx)
{
  if (ctx->inbound.fd != ASSUAN_INVALID_FD)
    {
      _assuan_close (ctx, ctx->inbound.fd);
      if (ctx->inbound.fd == ctx->outbound.fd)
        ctx->outbound.fd = ASSUAN_INVALID_FD;
      ctx->inbound.fd = ASSUAN_INVALID_FD;
    }
  if (ctx->outbound.fd != ASSUAN_INVALID_FD)
    {
      _assuan_close (ctx, ctx->outbound.fd);
      ctx->outbound.fd = ASSUAN_INVALID_FD;
    }
  if (ctx->pid != ASSUAN_INVALID_PID && ctx->pid)
    {
      _assuan_waitpid (ctx, ctx->pid, ctx->flags.no_waitpid, NULL, 0);
      ctx->pid = ASSUAN_INVALID_PID;
    }

  _assuan_uds_deinit (ctx);
}
示例#6
0
static int
accept_connection (assuan_context_t ctx)
{
  assuan_fd_t fd;
  struct sockaddr_un clnt_addr;
  socklen_t len = sizeof clnt_addr;

  fd = SOCKET2HANDLE(accept (HANDLE2SOCKET(ctx->listen_fd), 
                             (struct sockaddr*)&clnt_addr, &len ));
  if (fd == ASSUAN_INVALID_FD)
    {
      ctx->os_errno = errno;
      return _assuan_error (ASSUAN_Accept_Failed);
    }
  if (_assuan_sock_check_nonce (fd, &ctx->listen_nonce))
    {
      _assuan_close (fd);
      ctx->os_errno = EACCES;
      return _assuan_error (ASSUAN_Accept_Failed);
    }

  ctx->connected_fd = fd;
  return accept_connection_bottom (ctx);
}
示例#7
0
int
assuan_sock_close (assuan_fd_t fd)
{
  return _assuan_close (sock_ctx, fd);
}
示例#8
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.  Defined flag bits are:

     ASSUAN_SOCKET_CONNECT_FDPASSING
        sendmsg and recvmsg are used.

   NAME must either start with a slash and optional with a drive
   prefix ("c:") or use one of these URL schemata:

      file://<fname>

        This is the same as the default just with an explicit schemata.

      assuan://<ipaddr>:<port>
      assuan://[<ip6addr>]:<port>

        Connect using TCP to PORT of the server with the numerical
        IPADDR.  Note that '[' and ']' are literal characters.

  */
gpg_error_t
assuan_socket_connect (assuan_context_t ctx, const char *name,
		       pid_t server_pid, unsigned int flags)
{
  gpg_error_t err = 0;
  assuan_fd_t fd;
#ifdef WITH_IPV6
  struct sockaddr_in6 srvr_addr_in6;
#endif
  struct sockaddr_un srvr_addr_un;
  struct sockaddr_in srvr_addr_in;
  struct sockaddr *srvr_addr = NULL;
  uint16_t port = 0;
  size_t len = 0;
  const char *s;
  int af = AF_LOCAL;
  int pf = PF_LOCAL;

  TRACE2 (ctx, ASSUAN_LOG_CTX, "assuan_socket_connect", ctx,
	  "name=%s, flags=0x%x", name ? name : "(null)", flags);

  if (!ctx || !name)
    return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);

  if (!strncmp (name, "file://", 7) && name[7])
    name += 7;
  else if (!strncmp (name, "assuan://", 9) && name[9])
    {
      name += 9;
      af = AF_INET;
      pf = PF_INET;
    }
  else /* Default.  */
    {
      /* We require that the name starts with a slash if no URL
         schemata is used.  To make things easier we allow an optional
         drive prefix.  */
      s = name;
      if (*s && s[1] == ':')
        s += 2;
      if (*s != DIRSEP_C && *s != '/')
        return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
    }

  if (af == AF_LOCAL)
    {
      if (strlen (name)+1 >= sizeof srvr_addr_un.sun_path)
        return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);

      memset (&srvr_addr_un, 0, sizeof srvr_addr_un);
      srvr_addr_un.sun_family = AF_LOCAL;
      strncpy (srvr_addr_un.sun_path, name, sizeof (srvr_addr_un.sun_path) - 1);
      srvr_addr_un.sun_path[sizeof (srvr_addr_un.sun_path) - 1] = 0;
      len = SUN_LEN (&srvr_addr_un);

      srvr_addr = (struct sockaddr *)&srvr_addr_un;
    }
  else
    {
      char *addrstr, *p;
#ifdef HAVE_INET_PTON
      void *addrbuf = NULL;
#endif

      addrstr = _assuan_malloc (ctx, strlen (name) + 1);
      if (!addrstr)
        return _assuan_error (ctx, gpg_err_code_from_syserror ());

      if (*name == '[')
        {
          strcpy (addrstr, name+1);
          p = strchr (addrstr, ']');
          if (!p || p[1] != ':' || !parse_portno (p+2, &port))
            err = _assuan_error (ctx, GPG_ERR_BAD_URI);
          else
            {
              *p = 0;
#ifdef WITH_IPV6
              af = AF_INET6;
              pf = PF_INET6;
              memset (&srvr_addr_in6, 0, sizeof srvr_addr_in6);
              srvr_addr_in6.sin6_family = af;
              srvr_addr_in6.sin6_port = htons (port);
#ifdef HAVE_INET_PTON
              addrbuf = &srvr_addr_in6.sin6_addr;
#endif
              srvr_addr = (struct sockaddr *)&srvr_addr_in6;
              len = sizeof srvr_addr_in6;
#else
              err =  _assuan_error (ctx, GPG_ERR_EAFNOSUPPORT);
#endif
            }
        }
      else
        {
          strcpy (addrstr, name);
          p = strchr (addrstr, ':');
          if (!p || !parse_portno (p+1, &port))
            err = _assuan_error (ctx, GPG_ERR_BAD_URI);
          else
            {
              *p = 0;
              memset (&srvr_addr_in, 0, sizeof srvr_addr_in);
              srvr_addr_in.sin_family = af;
              srvr_addr_in.sin_port = htons (port);
#ifdef HAVE_INET_PTON
              addrbuf = &srvr_addr_in.sin_addr;
#endif
              srvr_addr = (struct sockaddr *)&srvr_addr_in;
              len = sizeof srvr_addr_in;
            }
        }

      if (!err)
        {
#ifdef HAVE_INET_PTON
          switch (inet_pton (af, addrstr, addrbuf))
            {
            case 1:  break;
            case 0:  err = _assuan_error (ctx, GPG_ERR_BAD_URI); break;
            default: err = _assuan_error (ctx, gpg_err_code_from_syserror ());
            }
#else /*!HAVE_INET_PTON*/
          /* We need to use the old function.  If we are here v6
             support isn't enabled anyway and thus we can do fine
             without.  Note that Windows as a compatible inet_pton
             function named inetPton, but only since Vista.  */
          srvr_addr_in.sin_addr.s_addr = inet_addr (addrstr);
          if (srvr_addr_in.sin_addr.s_addr == INADDR_NONE)
            err = _assuan_error (ctx, GPG_ERR_BAD_URI);
#endif /*!HAVE_INET_PTON*/
        }

      _assuan_free (ctx, addrstr);
      if (err)
        return err;
    }

  fd = _assuan_sock_new (ctx, pf, SOCK_STREAM, 0);
  if (fd == ASSUAN_INVALID_FD)
    {
      err = _assuan_error (ctx, gpg_err_code_from_syserror ());
      TRACE1 (ctx, ASSUAN_LOG_SYSIO, "assuan_socket_connect", ctx,
              "can't create socket: %s", strerror (errno));
      return err;
    }

  if (_assuan_sock_connect (ctx, fd, srvr_addr, len) == -1)
    {
      TRACE2 (ctx, ASSUAN_LOG_SYSIO, "assuan_socket_connect", ctx,
	      "can't connect to `%s': %s\n", name, strerror (errno));
      _assuan_close (ctx, fd);
      return _assuan_error (ctx, GPG_ERR_ASS_CONNECT_FAILED);
    }

  err = _assuan_connect_finalize (ctx, fd, flags);

  if (err)
    _assuan_reset (ctx);

  return err;
}
示例#9
0
/* This function is similar to pipe_connect but uses a socketpair and
   sets the I/O up to use sendmsg/recvmsg. */
static gpg_error_t
socketpair_connect (assuan_context_t ctx,
                    const char *name, const char **argv,
                    assuan_fd_t *fd_child_list,
                    void (*atfork) (void *opaque, int reserved),
                    void *atforkvalue)
{
  gpg_error_t err;
  int idx;
  int fds[2];
  char mypidstr[50];
  pid_t pid;
  int *child_fds = NULL;
  int child_fds_cnt = 0;
  struct at_socketpair_fork atp;
  int rc;

  TRACE_BEG3 (ctx, ASSUAN_LOG_CTX, "socketpair_connect", ctx,
	      "name=%s,atfork=%p,atforkvalue=%p", name ? name : "(null)",
	      atfork, atforkvalue);

  atp.user_atfork = atfork;
  atp.user_atforkvalue = atforkvalue;
  atp.parent_pid = getpid ();

  if (!ctx
      || (name && (!argv || !argv[0]))
      || (!name && !argv))
    return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);

  if (! ctx->flags.no_fixsignals)
    fix_signals ();

  sprintf (mypidstr, "%lu", (unsigned long)getpid ());

  if (fd_child_list)
    while (fd_child_list[child_fds_cnt] != ASSUAN_INVALID_FD)
      child_fds_cnt++;
  child_fds = _assuan_malloc (ctx, (child_fds_cnt + 2) * sizeof (int));
  if (! child_fds)
    return TRACE_ERR (gpg_err_code_from_syserror ());
  child_fds[1] = ASSUAN_INVALID_FD;
  if (fd_child_list)
    memcpy (&child_fds[1], fd_child_list, (child_fds_cnt + 1) * sizeof (int));

  if (_assuan_socketpair (ctx, AF_LOCAL, SOCK_STREAM, 0, fds))
    {
      TRACE_LOG1 ("socketpair failed: %s", strerror (errno));
      _assuan_free (ctx, child_fds);
      return TRACE_ERR (GPG_ERR_ASS_GENERAL);
    }
  atp.peer_fd = fds[1];
  child_fds[0] = fds[1];

  rc = _assuan_spawn (ctx, &pid, name, argv, ASSUAN_INVALID_FD,
		      ASSUAN_INVALID_FD, child_fds, at_socketpair_fork_cb,
		      &atp, 0);
  if (rc < 0)
    {
      err = gpg_err_code_from_syserror ();
      _assuan_close (ctx, fds[0]);
      _assuan_close (ctx, fds[1]);
      _assuan_free (ctx, child_fds);
      return TRACE_ERR (err);
    }

  /* For W32, the user needs to know the server-local names of the
     inherited handles.  Return them here.  Note that the translation
     of the peer socketpair fd (fd_child_list[0]) must be done by the
     wrapper program based on the environment variable
     _assuan_connection_fd.  */
  if (fd_child_list)
    {
      for (idx = 0; fd_child_list[idx] != -1; idx++)
	/* We add 1 to skip over the socketpair end.  */
	fd_child_list[idx] = child_fds[idx + 1];
    }

  _assuan_free (ctx, child_fds);

  /* If this is the server child process, exit early.  */
  if (! name && (*argv)[0] == 's')
    {
      _assuan_close (ctx, fds[0]);
      return 0;
    }

  _assuan_close (ctx, fds[1]);

  ctx->engine.release = _assuan_client_release;
  ctx->finish_handler = _assuan_client_finish;
  ctx->max_accepts = 1;
  ctx->inbound.fd  = fds[0];
  ctx->outbound.fd = fds[0];
  _assuan_init_uds_io (ctx);

  err = initial_handshake (ctx);
  if (err)
    _assuan_reset (ctx);
  return err;
}
示例#10
0
static gpg_error_t
pipe_connect (assuan_context_t ctx,
	      const char *name, const char **argv,
	      assuan_fd_t *fd_child_list,
	      void (*atfork) (void *opaque, int reserved),
	      void *atforkvalue, unsigned int flags)
{
  gpg_error_t rc;
  assuan_fd_t rp[2];
  assuan_fd_t wp[2];
  pid_t pid;
  int res;
  struct at_pipe_fork atp;
  unsigned int spawn_flags;

  atp.user_atfork = atfork;
  atp.user_atforkvalue = atforkvalue;
  atp.parent_pid = getpid ();

  if (!ctx || !name || !argv || !argv[0])
    return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);

  if (! ctx->flags.no_fixsignals)
    fix_signals ();

  if (_assuan_pipe (ctx, rp, 1) < 0)
    return _assuan_error (ctx, gpg_err_code_from_syserror ());

  if (_assuan_pipe (ctx, wp, 0) < 0)
    {
      _assuan_close (ctx, rp[0]);
      _assuan_close_inheritable (ctx, rp[1]);
      return _assuan_error (ctx, gpg_err_code_from_syserror ());
    }

  spawn_flags = 0;
  if (flags & ASSUAN_PIPE_CONNECT_DETACHED)
    spawn_flags |= ASSUAN_SPAWN_DETACHED;

  /* FIXME: Use atfork handler that closes child fds on Unix.  */
  res = _assuan_spawn (ctx, &pid, name, argv, wp[0], rp[1],
		       fd_child_list, at_pipe_fork_cb, &atp, spawn_flags);
  if (res < 0)
    {
      rc = gpg_err_code_from_syserror ();
      _assuan_close (ctx, rp[0]);
      _assuan_close_inheritable (ctx, rp[1]);
      _assuan_close_inheritable (ctx, wp[0]);
      _assuan_close (ctx, wp[1]);
      return _assuan_error (ctx, rc);
    }

  /* Close the stdin/stdout child fds in the parent.  */
  _assuan_close_inheritable (ctx, rp[1]);
  _assuan_close_inheritable (ctx, wp[0]);

  ctx->engine.release = _assuan_client_release;
  ctx->engine.readfnc = _assuan_simple_read;
  ctx->engine.writefnc = _assuan_simple_write;
  ctx->engine.sendfd = NULL;
  ctx->engine.receivefd = NULL;
  ctx->finish_handler = _assuan_client_finish;
  ctx->max_accepts = 1;
  ctx->accept_handler = NULL;
  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->pid = pid;

  rc = initial_handshake (ctx);
  if (rc)
    _assuan_reset (ctx);
  return rc;
}
示例#11
0
/* Make a connection to the Unix domain socket NAME and return a new
   Assuan context in CTX.  SERVER_PID is currently not used but may
   become handy in the future.  With flags set to 1 sendmsg and
   recvmesg are used. */
assuan_error_t
assuan_socket_connect_ext(assuan_context_t *r_ctx,
                          const char *name, pid_t server_pid,
                          unsigned int flags)
{
    static struct assuan_io io = { _assuan_simple_read,
               _assuan_simple_write
    };

    assuan_error_t err;
    assuan_context_t ctx;
    int fd;
    struct sockaddr_un srvr_addr;
    size_t len;
    const char *s;

    if(!r_ctx || !name)
        return _assuan_error(ASSUAN_Invalid_Value);
    *r_ctx = NULL;

    /* We require that the name starts with a slash, so that we
       eventually can reuse this function for other socket types.  To
       make things easier we allow an optional dirver prefix.  */
    s = name;
    if(*s && s[1] == ':')
        s += 2;
    if(*s != DIRSEP_C && *s != '/')
        return _assuan_error(ASSUAN_Invalid_Value);

    if(strlen(name) + 1 >= sizeof srvr_addr.sun_path)
        return _assuan_error(ASSUAN_Invalid_Value);

    err = _assuan_new_context(&ctx);
    if(err)
        return err;
    ctx->deinit_handler = ((flags & 1)) ? _assuan_uds_deinit :  do_deinit;
    ctx->finish_handler = do_finish;

    fd = _assuan_sock_new(PF_LOCAL, SOCK_STREAM, 0);
    if(fd == -1)
    {
        _assuan_log_printf("can't create socket: %s\n", strerror(errno));
        _assuan_release_context(ctx);
        return _assuan_error(ASSUAN_General_Error);
    }

    memset(&srvr_addr, 0, sizeof srvr_addr);
    srvr_addr.sun_family = AF_LOCAL;
    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(_assuan_sock_connect(fd, (struct sockaddr *) &srvr_addr, len) == -1)
    {
        _assuan_log_printf("can't connect to `%s': %s\n",
                           name, strerror(errno));
        _assuan_release_context(ctx);
        _assuan_close(fd);
        return _assuan_error(ASSUAN_Connect_Failed);
    }

    ctx->inbound.fd = fd;
    ctx->outbound.fd = fd;
    ctx->io = &io;
    if((flags & 1))
        _assuan_init_uds_io(ctx);

    /* initial handshake */
    {
        int okay, off;

        err = _assuan_read_from_server(ctx, &okay, &off);
        if(err)
            _assuan_log_printf("can't connect to server: %s\n",
                               assuan_strerror(err));
        else if(okay != 1)
        {
            /*LOG ("can't connect to server: `");*/
            _assuan_log_sanitized_string(ctx->inbound.line);
            fprintf(assuan_get_assuan_log_stream(), "'\n");
            err = _assuan_error(ASSUAN_Connect_Failed);
        }
    }

    if(err)
    {
        assuan_disconnect(ctx);
    }
    else
        *r_ctx = ctx;
    return 0;
}
示例#12
0
/* Read from a unix domain socket using sendmsg.  */
static ssize_t
uds_reader (assuan_context_t ctx, void *buf, size_t buflen)
{
#ifndef HAVE_W32_SYSTEM
  int len = 0;
  /* This loop should be OK.  As FDs are followed by data, the
     readable status of the socket does not change and no new
     select/event-loop round is necessary.  */
  while (!len)  /* No data is buffered.  */
    {
      struct msghdr msg;
      struct iovec iovec;
#ifdef USE_DESCRIPTOR_PASSING
      union {
        struct cmsghdr cm;
        char control[CMSG_SPACE(sizeof (int))];
      } control_u;
      struct cmsghdr *cmptr;
#endif /*USE_DESCRIPTOR_PASSING*/

      memset (&msg, 0, sizeof (msg));

      msg.msg_name = NULL;
      msg.msg_namelen = 0;
      msg.msg_iov = &iovec;
      msg.msg_iovlen = 1;
      iovec.iov_base = buf;
      iovec.iov_len = buflen;
#ifdef USE_DESCRIPTOR_PASSING
      msg.msg_control = control_u.control;
      msg.msg_controllen = sizeof (control_u.control);
#endif

      len = _assuan_recvmsg (ctx, ctx->inbound.fd, &msg, 0);
      if (len < 0)
        return -1;
      if (len == 0)
	return 0;

#ifdef USE_DESCRIPTOR_PASSING
      cmptr = CMSG_FIRSTHDR (&msg);
      if (cmptr && cmptr->cmsg_len == CMSG_LEN (sizeof(int)))
        {
          if (cmptr->cmsg_level != SOL_SOCKET
              || cmptr->cmsg_type != SCM_RIGHTS)
            TRACE0 (ctx, ASSUAN_LOG_SYSIO, "uds_reader", ctx,
		    "unexpected ancillary data received");
          else
            {
              int fd;

	      memcpy (&fd, CMSG_DATA (cmptr), sizeof (fd));

              if (ctx->uds.pendingfdscount >= DIM (ctx->uds.pendingfds))
                {
		  TRACE1 (ctx, ASSUAN_LOG_SYSIO, "uds_reader", ctx,
			  "too many descriptors pending - "
			  "closing received descriptor %d", fd);
                  _assuan_close (ctx, fd);
                }
              else
                ctx->uds.pendingfds[ctx->uds.pendingfdscount++] = fd;
            }
	}
#endif /*USE_DESCRIPTOR_PASSING*/
    }

  return len;
#else /*HAVE_W32_SYSTEM*/
  int res = recvfrom (HANDLE2SOCKET(ctx->inbound.fd), buf, buflen, 0, NULL, NULL);
  if (res < 0)
    gpg_err_set_errno (_assuan_sock_wsa2errno (WSAGetLastError ()));
  return res;
#endif /*HAVE_W32_SYSTEM*/
}