示例#1
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;
}
示例#2
0
int
assuan_sock_connect (assuan_fd_t sockfd, struct sockaddr *addr, int addrlen)
{
  return _assuan_sock_connect (sock_ctx, sockfd, addr, addrlen);
}
/* 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;
}