示例#1
0
static gpgme_error_t
build_fd_data_map (engine_spawn_t esp)
{
  struct datalist_s *a;
  size_t datac;
  int fds[2];

  for (datac = 0, a = esp->arglist; a; a = a->next)
    if (a->data)
      datac++;

  free_fd_data_map (esp->fd_data_map);
  esp->fd_data_map = calloc (datac + 1, sizeof *esp->fd_data_map);
  if (!esp->fd_data_map)
    return gpg_error_from_syserror ();

  for (datac = 0, a = esp->arglist; a; a = a->next)
    {
      assert (a->data);

      if (_gpgme_io_pipe (fds, a->inbound ? 1 : 0) == -1)
        {
          free (esp->fd_data_map);
          esp->fd_data_map = NULL;
          return gpg_error_from_syserror ();
        }
      if (_gpgme_io_set_close_notify (fds[0], close_notify_handler, esp)
          || _gpgme_io_set_close_notify (fds[1], close_notify_handler, esp))
        {
          /* FIXME: Need error cleanup.  */
          return gpg_error (GPG_ERR_GENERAL);
        }

      esp->fd_data_map[datac].inbound = a->inbound;
      if (a->inbound)
        {
          esp->fd_data_map[datac].fd       = fds[0];
          esp->fd_data_map[datac].peer_fd  = fds[1];
        }
      else
        {
          esp->fd_data_map[datac].fd       = fds[1];
          esp->fd_data_map[datac].peer_fd  = fds[0];
        }
      esp->fd_data_map[datac].data    = a->data;
      esp->fd_data_map[datac].dup_to  = a->dup_to;
      datac++;
    }

  return 0;
}
示例#2
0
/* Create a pipe with an inheritable end.  */
static int
my_pipe (assuan_context_t ctx, assuan_fd_t fds[2], int inherit_idx)
{
  int res;
  int gfds[2];

  res = _gpgme_io_pipe (gfds, inherit_idx);

  /* For now... */
  fds[0] = (assuan_fd_t) gfds[0];
  fds[1] = (assuan_fd_t) gfds[1];

  return res;
}
示例#3
0
static gpgme_error_t
gpgsm_set_fd (engine_gpgsm_t gpgsm, fd_type_t fd_type, const char *opt)
{
  gpg_error_t err = 0;
  char line[COMMANDLINELEN];
  char *which;
  iocb_data_t *iocb_data;
  int dir;

  switch (fd_type)
    {
    case INPUT_FD:
      which = "INPUT";
      iocb_data = &gpgsm->input_cb;
      break;

    case OUTPUT_FD:
      which = "OUTPUT";
      iocb_data = &gpgsm->output_cb;
      break;

    case MESSAGE_FD:
      which = "MESSAGE";
      iocb_data = &gpgsm->message_cb;
      break;

    default:
      return gpg_error (GPG_ERR_INV_VALUE);
    }

  dir = iocb_data->dir;

#if USE_DESCRIPTOR_PASSING
  /* We try to short-cut the communication by giving GPGSM direct
     access to the file descriptor, rather than using a pipe.  */
  iocb_data->server_fd = _gpgme_data_get_fd (iocb_data->data);
  if (iocb_data->server_fd < 0)
    {
      int fds[2];

      if (_gpgme_io_pipe (fds, dir) < 0)
	return gpg_error_from_syserror ();

      iocb_data->fd = dir ? fds[0] : fds[1];
      iocb_data->server_fd = dir ? fds[1] : fds[0];

      if (_gpgme_io_set_close_notify (iocb_data->fd,
				      close_notify_handler, gpgsm))
	{
	  err = gpg_error (GPG_ERR_GENERAL);
	  goto leave_set_fd;
	}
    }

  err = assuan_sendfd (gpgsm->assuan_ctx, iocb_data->server_fd);
  if (err)
    goto leave_set_fd;

  _gpgme_io_close (iocb_data->server_fd);
  iocb_data->server_fd = -1;

  if (opt)
    snprintf (line, COMMANDLINELEN, "%s FD %s", which, opt);
  else
    snprintf (line, COMMANDLINELEN, "%s FD", which);
#else
  if (opt)
    snprintf (line, COMMANDLINELEN, "%s FD=%s %s",
              which, iocb_data->server_fd_str, opt);
  else
    snprintf (line, COMMANDLINELEN, "%s FD=%s",
              which, iocb_data->server_fd_str);
#endif

  err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, line, NULL, NULL);

#if USE_DESCRIPTOR_PASSING
 leave_set_fd:
  if (err)
    {
      _gpgme_io_close (iocb_data->fd);
      iocb_data->fd = -1;
      if (iocb_data->server_fd != -1)
        {
          _gpgme_io_close (iocb_data->server_fd);
          iocb_data->server_fd = -1;
        }
    }
#endif

  return err;
}
示例#4
0
static gpgme_error_t
gpgsm_new (void **engine, const char *file_name, const char *home_dir)
{
  gpgme_error_t err = 0;
  engine_gpgsm_t gpgsm;
  const char *argv[5];
  int argc;
#if !USE_DESCRIPTOR_PASSING
  int fds[2];
  int child_fds[4];
#endif
  char *dft_display = NULL;
  char dft_ttyname[64];
  char *dft_ttytype = NULL;
  char *optstr;

  gpgsm = calloc (1, sizeof *gpgsm);
  if (!gpgsm)
    return gpg_error_from_syserror ();

  gpgsm->status_cb.fd = -1;
  gpgsm->status_cb.dir = 1;
  gpgsm->status_cb.tag = 0;
  gpgsm->status_cb.data = gpgsm;

  gpgsm->input_cb.fd = -1;
  gpgsm->input_cb.dir = 0;
  gpgsm->input_cb.tag = 0;
  gpgsm->input_cb.server_fd = -1;
  *gpgsm->input_cb.server_fd_str = 0;
  gpgsm->output_cb.fd = -1;
  gpgsm->output_cb.dir = 1;
  gpgsm->output_cb.tag = 0;
  gpgsm->output_cb.server_fd = -1;
  *gpgsm->output_cb.server_fd_str = 0;
  gpgsm->message_cb.fd = -1;
  gpgsm->message_cb.dir = 0;
  gpgsm->message_cb.tag = 0;
  gpgsm->message_cb.server_fd = -1;
  *gpgsm->message_cb.server_fd_str = 0;

  gpgsm->status.fnc = 0;
  gpgsm->colon.fnc = 0;
  gpgsm->colon.attic.line = 0;
  gpgsm->colon.attic.linesize = 0;
  gpgsm->colon.attic.linelen = 0;
  gpgsm->colon.any = 0;

  gpgsm->inline_data = NULL;

  gpgsm->io_cbs.add = NULL;
  gpgsm->io_cbs.add_priv = NULL;
  gpgsm->io_cbs.remove = NULL;
  gpgsm->io_cbs.event = NULL;
  gpgsm->io_cbs.event_priv = NULL;

#if !USE_DESCRIPTOR_PASSING
  if (_gpgme_io_pipe (fds, 0) < 0)
    {
      err = gpg_error_from_syserror ();
      goto leave;
    }
  gpgsm->input_cb.fd = fds[1];
  gpgsm->input_cb.server_fd = fds[0];

  if (_gpgme_io_pipe (fds, 1) < 0)
    {
      err = gpg_error_from_syserror ();
      goto leave;
    }
  gpgsm->output_cb.fd = fds[0];
  gpgsm->output_cb.server_fd = fds[1];

  if (_gpgme_io_pipe (fds, 0) < 0)
    {
      err = gpg_error_from_syserror ();
      goto leave;
    }
  gpgsm->message_cb.fd = fds[1];
  gpgsm->message_cb.server_fd = fds[0];

  child_fds[0] = gpgsm->input_cb.server_fd;
  child_fds[1] = gpgsm->output_cb.server_fd;
  child_fds[2] = gpgsm->message_cb.server_fd;
  child_fds[3] = -1;
#endif

  argc = 0;
  argv[argc++] = "gpgsm";
  if (home_dir)
    {
      argv[argc++] = "--homedir";
      argv[argc++] = home_dir;
    }
  argv[argc++] = "--server";
  argv[argc++] = NULL;

  err = assuan_new_ext (&gpgsm->assuan_ctx, GPG_ERR_SOURCE_GPGME,
			&_gpgme_assuan_malloc_hooks, _gpgme_assuan_log_cb,
			NULL);
  if (err)
    goto leave;
  assuan_ctx_set_system_hooks (gpgsm->assuan_ctx, &_gpgme_assuan_system_hooks);

#if USE_DESCRIPTOR_PASSING
  err = assuan_pipe_connect
    (gpgsm->assuan_ctx, file_name ? file_name : _gpgme_get_gpgsm_path (),
     argv, NULL, NULL, NULL, ASSUAN_PIPE_CONNECT_FDPASSING);
#else
  {
    assuan_fd_t achild_fds[4];
    int i;

    /* For now... */
    for (i = 0; i < 4; i++)
      achild_fds[i] = (assuan_fd_t) child_fds[i];

    err = assuan_pipe_connect
      (gpgsm->assuan_ctx, file_name ? file_name : _gpgme_get_gpgsm_path (),
       argv, achild_fds, NULL, NULL, 0);

    /* For now... */
    for (i = 0; i < 4; i++)
      child_fds[i] = (int) achild_fds[i];
  }

  /* On Windows, handles are inserted in the spawned process with
     DuplicateHandle, and child_fds contains the server-local names
     for the inserted handles when assuan_pipe_connect returns.  */
  if (!err)
    {
      /* Note: We don't use _gpgme_io_fd2str here.  On W32 the
	 returned handles are real W32 system handles, not whatever
	 GPGME uses internally (which may be a system handle, a C
	 library handle or a GLib/Qt channel.  Confusing, yes, but
	 remember these are server-local names, so they are not part
	 of GPGME at all.  */
      snprintf (gpgsm->input_cb.server_fd_str,
		sizeof gpgsm->input_cb.server_fd_str, "%d", child_fds[0]);
      snprintf (gpgsm->output_cb.server_fd_str,
		sizeof gpgsm->output_cb.server_fd_str, "%d", child_fds[1]);
      snprintf (gpgsm->message_cb.server_fd_str,
		sizeof gpgsm->message_cb.server_fd_str, "%d", child_fds[2]);
    }
#endif
  if (err)
    goto leave;

  err = _gpgme_getenv ("DISPLAY", &dft_display);
  if (err)
    goto leave;
  if (dft_display)
    {
      if (asprintf (&optstr, "OPTION display=%s", dft_display) < 0)
        {
	  free (dft_display);
	  err = gpg_error_from_syserror ();
	  goto leave;
	}
      free (dft_display);

      err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL, NULL,
			     NULL, NULL, NULL);
      free (optstr);
      if (err)
	goto leave;
    }

  if (isatty (1))
    {
      int rc;

      rc = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname));
      if (rc)
	{
	  err = gpg_error_from_errno (rc);
	  goto leave;
	}
      else
	{
	  if (asprintf (&optstr, "OPTION ttyname=%s", dft_ttyname) < 0)
	    {
	      err = gpg_error_from_syserror ();
	      goto leave;
	    }
	  err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL, NULL,
				 NULL, NULL, NULL);
	  free (optstr);
	  if (err)
	    goto leave;

	  err = _gpgme_getenv ("TERM", &dft_ttytype);
	  if (err)
	    goto leave;
	  if (dft_ttytype)
	    {
	      if (asprintf (&optstr, "OPTION ttytype=%s", dft_ttytype) < 0)
		{
		  free (dft_ttytype);
		  err = gpg_error_from_syserror ();
		  goto leave;
		}
	      free (dft_ttytype);

	      err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL,
				     NULL, NULL, NULL, NULL);
	      free (optstr);
	      if (err)
		goto leave;
	    }
	}
    }

  /* Ask gpgsm to enable the audit log support.  */
  if (!err)
    {
      err = assuan_transact (gpgsm->assuan_ctx, "OPTION enable-audit-log=1",
                             NULL, NULL, NULL, NULL, NULL, NULL);
      if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION)
        err = 0; /* This is an optional feature of gpgsm.  */
    }


#ifdef HAVE_W32_SYSTEM
  /* Under Windows we need to use AllowSetForegroundWindow.  Tell
     gpgsm to tell us when it needs it.  */
  if (!err)
    {
      err = assuan_transact (gpgsm->assuan_ctx, "OPTION allow-pinentry-notify",
                             NULL, NULL, NULL, NULL, NULL, NULL);
      if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION)
        err = 0; /* This is a new feature of gpgsm.  */
    }
#endif /*HAVE_W32_SYSTEM*/

#if !USE_DESCRIPTOR_PASSING
  if (!err
      && (_gpgme_io_set_close_notify (gpgsm->input_cb.fd,
				      close_notify_handler, gpgsm)
	  || _gpgme_io_set_close_notify (gpgsm->output_cb.fd,
					 close_notify_handler, gpgsm)
	  || _gpgme_io_set_close_notify (gpgsm->message_cb.fd,
					 close_notify_handler, gpgsm)))
    {
      err = gpg_error (GPG_ERR_GENERAL);
      goto leave;
    }
#endif

 leave:
  /* Close the server ends of the pipes (because of this, we must use
     the stored server_fd_str in the function start).  Our ends are
     closed in gpgsm_release().  */
#if !USE_DESCRIPTOR_PASSING
  if (gpgsm->input_cb.server_fd != -1)
    _gpgme_io_close (gpgsm->input_cb.server_fd);
  if (gpgsm->output_cb.server_fd != -1)
    _gpgme_io_close (gpgsm->output_cb.server_fd);
  if (gpgsm->message_cb.server_fd != -1)
    _gpgme_io_close (gpgsm->message_cb.server_fd);
#endif

  if (err)
    gpgsm_release (gpgsm);
  else
    *engine = gpgsm;

  return err;
}
示例#5
0
static gpgme_error_t
gpgconf_write (void *engine, char *arg1, char *arg2, gpgme_data_t conf)
{
  struct engine_gpgconf *gpgconf = engine;
  gpgme_error_t err = 0;
#define BUFLEN 1024
  char buf[BUFLEN];
  int buflen = 0;
  char *argv[] = { NULL /* file_name */, arg1, arg2, 0 };
  int rp[2];
  struct spawn_fd_item_s cfd[] = { {-1, 0 /* STDIN_FILENO */}, {-1, -1} };
  int status;
  int nwrite;

  /* FIXME: Deal with engine->home_dir.  */

  /* _gpgme_engine_new guarantees that this is not NULL.  */
  argv[0] = gpgconf->file_name;

  if (_gpgme_io_pipe (rp, 0) < 0)
    return gpg_error_from_syserror ();

  cfd[0].fd = rp[0];

  status = _gpgme_io_spawn (gpgconf->file_name, argv, 0, cfd, NULL, NULL, NULL);
  if (status < 0)
    {
      _gpgme_io_close (rp[0]);
      _gpgme_io_close (rp[1]);
      return gpg_error_from_syserror ();
    }

  for (;;)
    {
      if (buflen == 0)
	{
	  do
	    {
	      buflen = gpgme_data_read (conf, buf, BUFLEN);
	    }
	  while (buflen < 0 && errno == EAGAIN);

	  if (buflen < 0)
	    {
	      err = gpg_error_from_syserror ();
	      _gpgme_io_close (rp[1]);
	      return err;
	    }
	  else if (buflen == 0)
	    {
	      /* All is written.  */
	      _gpgme_io_close (rp[1]);
	      return 0;
	    }
	}

      do
	{
	  nwrite = _gpgme_io_write (rp[1], buf, buflen);
	}
      while (nwrite < 0 && errno == EAGAIN);

      if (nwrite > 0)
	{
	  buflen -= nwrite;
	  if (buflen > 0)
	    memmove (&buf[0], &buf[nwrite], buflen);
	}
      else if (nwrite < 0)
	{
	  _gpgme_io_close (rp[1]);
	  return gpg_error_from_syserror ();
	}
    }

  return 0;
}
示例#6
0
/* Read from gpgconf and pass line after line to the hook function.
   We put a limit of 64 k on the maximum size for a line.  This should
   allow for quite a long "group" line, which is usually the longest
   line (mine is currently ~3k).  */
static gpgme_error_t
gpgconf_read (void *engine, char *arg1, char *arg2,
	      gpgme_error_t (*cb) (void *hook, char *line),
	      void *hook)
{
  struct engine_gpgconf *gpgconf = engine;
  gpgme_error_t err = 0;
  char *linebuf;
  size_t linebufsize;
  int linelen;
  char *argv[4] = { NULL /* file_name */, NULL, NULL, NULL };
  int rp[2];
  struct spawn_fd_item_s cfd[] = { {-1, 1 /* STDOUT_FILENO */, -1, 0},
				   {-1, -1} };
  int status;
  int nread;
  char *mark = NULL;

  argv[1] = arg1;
  argv[2] = arg2;


  /* FIXME: Deal with engine->home_dir.  */

  /* _gpgme_engine_new guarantees that this is not NULL.  */
  argv[0] = gpgconf->file_name;

  if (_gpgme_io_pipe (rp, 1) < 0)
    return gpg_error_from_syserror ();

  cfd[0].fd = rp[1];

  status = _gpgme_io_spawn (gpgconf->file_name, argv, 0, cfd, NULL, NULL, NULL);
  if (status < 0)
    {
      _gpgme_io_close (rp[0]);
      _gpgme_io_close (rp[1]);
      return gpg_error_from_syserror ();
    }

  linebufsize = 1024; /* Usually enough for conf lines.  */
  linebuf = malloc (linebufsize);
  if (!linebuf)
    {
      err = gpg_error_from_syserror ();
      goto leave;
    }
  linelen = 0;

  while ((nread = _gpgme_io_read (rp[0], linebuf + linelen,
                                  linebufsize - linelen - 1)))
    {
      char *line;
      const char *lastmark = NULL;
      size_t nused;

      if (nread < 0)
        {
          err = gpg_error_from_syserror ();
          goto leave;
        }

      linelen += nread;
      linebuf[linelen] = '\0';

      for (line=linebuf; (mark = strchr (line, '\n')); line = mark+1 )
        {
          lastmark = mark;
          if (mark > line && mark[-1] == '\r')
            mark[-1] = '\0';
          else
            mark[0] = '\0';

          /* Got a full line.  Due to the CR removal code (which
             occurs only on Windows) we might be one-off and thus
             would see empty lines.  Don't pass them to the
             callback. */
          err = *line? (*cb) (hook, line) : 0;
          if (err)
            goto leave;
        }

      nused = lastmark? (lastmark + 1 - linebuf) : 0;
      memmove (linebuf, linebuf + nused, linelen - nused);
      linelen -= nused;

      if (!(linelen < linebufsize - 1))
        {
          char *newlinebuf;

          if (linelen <  8 * 1024 - 1)
            linebufsize = 8 * 1024;
          else if (linelen < 64 * 1024 - 1)
            linebufsize = 64 * 1024;
          else
            {
              /* We reached our limit - give up.  */
              err = gpg_error (GPG_ERR_LINE_TOO_LONG);
              goto leave;
            }

          newlinebuf = realloc (linebuf, linebufsize);
          if (!newlinebuf)
            {
              err = gpg_error_from_syserror ();
              goto leave;
            }
          linebuf = newlinebuf;
        }
    }

 leave:
  free (linebuf);
  _gpgme_io_close (rp[0]);
  return err;
}
示例#7
0
static gpgme_error_t
gpgsm_new(void **engine, const char *file_name, const char *home_dir)
{
    gpgme_error_t err = 0;
    engine_gpgsm_t gpgsm;
    const char *argv[5];
    int argc;
#if !USE_DESCRIPTOR_PASSING
    int fds[2];
    int child_fds[4];
#endif
    char *dft_display = NULL;
    char dft_ttyname[64];
    char *dft_ttytype = NULL;
    char *optstr;

    gpgsm = calloc(1, sizeof * gpgsm);
    if(!gpgsm)
        return gpg_error_from_errno(errno);

    gpgsm->status_cb.fd = -1;
    gpgsm->status_cb.dir = 1;
    gpgsm->status_cb.tag = 0;
    gpgsm->status_cb.data = gpgsm;

    gpgsm->input_cb.fd = -1;
    gpgsm->input_cb.dir = 0;
    gpgsm->input_cb.tag = 0;
    gpgsm->input_cb.server_fd = -1;
    gpgsm->output_cb.fd = -1;
    gpgsm->output_cb.dir = 1;
    gpgsm->output_cb.tag = 0;
    gpgsm->output_cb.server_fd = -1;
    gpgsm->message_cb.fd = -1;
    gpgsm->message_cb.dir = 0;
    gpgsm->message_cb.tag = 0;
    gpgsm->message_cb.server_fd = -1;

    gpgsm->status.fnc = 0;
    gpgsm->colon.fnc = 0;
    gpgsm->colon.attic.line = 0;
    gpgsm->colon.attic.linesize = 0;
    gpgsm->colon.attic.linelen = 0;
    gpgsm->colon.any = 0;

    gpgsm->io_cbs.add = NULL;
    gpgsm->io_cbs.add_priv = NULL;
    gpgsm->io_cbs.remove = NULL;
    gpgsm->io_cbs.event = NULL;
    gpgsm->io_cbs.event_priv = NULL;

#if !USE_DESCRIPTOR_PASSING
    if(_gpgme_io_pipe(fds, 0) < 0)
    {
        err = gpg_error_from_errno(errno);
        goto leave;
    }
    gpgsm->input_cb.fd = fds[1];
    gpgsm->input_cb.server_fd = fds[0];

    if(_gpgme_io_pipe(fds, 1) < 0)
    {
        err = gpg_error_from_errno(errno);
        goto leave;
    }
    gpgsm->output_cb.fd = fds[0];
    gpgsm->output_cb.server_fd = fds[1];

    if(_gpgme_io_pipe(fds, 0) < 0)
    {
        err = gpg_error_from_errno(errno);
        goto leave;
    }
    gpgsm->message_cb.fd = fds[1];
    gpgsm->message_cb.server_fd = fds[0];

    child_fds[0] = gpgsm->input_cb.server_fd;
    child_fds[1] = gpgsm->output_cb.server_fd;
    child_fds[2] = gpgsm->message_cb.server_fd;
    child_fds[3] = -1;
#endif

    argc = 0;
    argv[argc++] = "gpgsm";
    if(home_dir)
    {
        argv[argc++] = "--homedir";
        argv[argc++] = home_dir;
    }
    argv[argc++] = "--server";
    argv[argc++] = NULL;

#if USE_DESCRIPTOR_PASSING
    err = assuan_pipe_connect_ext
          (&gpgsm->assuan_ctx, file_name ? file_name : _gpgme_get_gpgsm_path(),
           argv, NULL, NULL, NULL, 1);
#else
    err = assuan_pipe_connect
          (&gpgsm->assuan_ctx, file_name ? file_name : _gpgme_get_gpgsm_path(),
           argv, child_fds);
#endif
    if(err)
        goto leave;

    err = _gpgme_getenv("DISPLAY", &dft_display);
    if(err)
        goto leave;
    if(dft_display)
    {
        if(asprintf(&optstr, "OPTION display=%s", dft_display) < 0)
        {
            free(dft_display);
            err = gpg_error_from_errno(errno);
            goto leave;
        }
        free(dft_display);

        err = assuan_transact(gpgsm->assuan_ctx, optstr, NULL, NULL, NULL,
                              NULL, NULL, NULL);
        free(optstr);
        if(err)
        {
            err = map_assuan_error(err);
            goto leave;
        }
    }

    if(isatty(1))
    {
        if(ttyname_r(1, dft_ttyname, sizeof(dft_ttyname)))
        {
            err = gpg_error_from_errno(errno);
            goto leave;
        }
        else
        {
            if(asprintf(&optstr, "OPTION ttyname=%s", dft_ttyname) < 0)
            {
                err = gpg_error_from_errno(errno);
                goto leave;
            }
            err = assuan_transact(gpgsm->assuan_ctx, optstr, NULL, NULL, NULL,
                                  NULL, NULL, NULL);
            free(optstr);
            if(err)
            {
                err = map_assuan_error(err);
                goto leave;
            }

            err = _gpgme_getenv("TERM", &dft_ttytype);
            if(err)
                goto leave;
            if(dft_ttytype)
            {
                if(asprintf(&optstr, "OPTION ttytype=%s", dft_ttytype) < 0)
                {
                    free(dft_ttytype);
                    err = gpg_error_from_errno(errno);
                    goto leave;
                }
                free(dft_ttytype);

                err = assuan_transact(gpgsm->assuan_ctx, optstr, NULL, NULL,
                                      NULL, NULL, NULL, NULL);
                free(optstr);
                if(err)
                {
                    err = map_assuan_error(err);
                    goto leave;
                }
            }
        }
    }

#if !USE_DESCRIPTOR_PASSING
    if(!err
            && (_gpgme_io_set_close_notify(gpgsm->input_cb.fd,
                                           close_notify_handler, gpgsm)
                || _gpgme_io_set_close_notify(gpgsm->output_cb.fd,
                        close_notify_handler, gpgsm)
                || _gpgme_io_set_close_notify(gpgsm->message_cb.fd,
                        close_notify_handler, gpgsm)))
    {
        err = gpg_error(GPG_ERR_GENERAL);
        goto leave;
    }
#endif

leave:
    /* Close the server ends of the pipes.  Our ends are closed in
       gpgsm_release().  */
#if !USE_DESCRIPTOR_PASSING
    if(gpgsm->input_cb.server_fd != -1)
        _gpgme_io_close(gpgsm->input_cb.server_fd);
    if(gpgsm->output_cb.server_fd != -1)
        _gpgme_io_close(gpgsm->output_cb.server_fd);
    if(gpgsm->message_cb.server_fd != -1)
        _gpgme_io_close(gpgsm->message_cb.server_fd);
#endif

    if(err)
        gpgsm_release(gpgsm);
    else
        *engine = gpgsm;

    return err;
}
示例#8
0
static gpgme_error_t
gpgconf_read (void *engine, char *arg1, char *arg2,
	      gpgme_error_t (*cb) (void *hook, char *line),
	      void *hook)
{
  struct engine_gpgconf *gpgconf = engine;
  gpgme_error_t err = 0;
#define LINELENGTH 1024
  char linebuf[LINELENGTH] = "";
  int linelen = 0;
  char *argv[4] = { NULL /* file_name */, NULL, NULL, NULL };
  int rp[2];
  struct spawn_fd_item_s cfd[] = { {-1, 1 /* STDOUT_FILENO */, -1, 0},
				   {-1, -1} };
  int status;
  int nread;
  char *mark = NULL;

  argv[1] = arg1;
  argv[2] = arg2;


  /* FIXME: Deal with engine->home_dir.  */

  /* _gpgme_engine_new guarantees that this is not NULL.  */
  argv[0] = gpgconf->file_name;
  
  if (_gpgme_io_pipe (rp, 1) < 0)
    return gpg_error_from_syserror ();

  cfd[0].fd = rp[1];

  status = _gpgme_io_spawn (gpgconf->file_name, argv, 0, cfd, NULL, NULL, NULL);
  if (status < 0)
    {
      _gpgme_io_close (rp[0]);
      _gpgme_io_close (rp[1]);
      return gpg_error_from_syserror ();
    }

  do
    {
      nread = _gpgme_io_read (rp[0], 
                              linebuf + linelen, LINELENGTH - linelen - 1);
      if (nread > 0)
	{
          char *line;
          const char *lastmark = NULL;
          size_t nused;

	  linelen += nread;
	  linebuf[linelen] = '\0';

	  for (line=linebuf; (mark = strchr (line, '\n')); line = mark+1 )
	    {
              lastmark = mark;
	      if (mark > line && mark[-1] == '\r')
		mark[-1] = '\0';
              else
                mark[0] = '\0';

	      /* Got a full line.  Due to the CR removal code (which
                 occurs only on Windows) we might be one-off and thus
                 would see empty lines.  Don't pass them to the
                 callback. */
	      err = *line? (*cb) (hook, line) : 0;
	      if (err)
		goto leave;
	    }

          nused = lastmark? (lastmark + 1 - linebuf) : 0;
          memmove (linebuf, linebuf + nused, linelen - nused);
          linelen -= nused;
	}
    }
  while (nread > 0 && linelen < LINELENGTH - 1);
  
  if (!err && nread < 0)
    err = gpg_error_from_syserror ();
  if (!err && nread > 0)
    err = gpg_error (GPG_ERR_LINE_TOO_LONG);

 leave:
  _gpgme_io_close (rp[0]);

  return err;
}
示例#9
0
/* Create a pipe with an inheritable end.  */
static int
my_pipe (assuan_context_t ctx, assuan_fd_t fds[2], int inherit_idx)
{
  return _gpgme_io_pipe (fds, inherit_idx);
}