Example #1
0
/* If NAME is NULL, don't exec, just fork.  FD_CHILD_LIST is modified
   to reflect the value of the FD in the peer process (on
   Windows).  */
static int
my_spawn (assuan_context_t ctx, pid_t *r_pid, const char *name,
	  const char **argv,
	  assuan_fd_t fd_in, assuan_fd_t fd_out,
	  assuan_fd_t *fd_child_list,
	  void (*atfork) (void *opaque, int reserved),
	  void *atforkvalue, unsigned int flags)
{
  int err;
  struct spawn_fd_item_s *fd_items;
  int i;

  assert (name);

  if (! name)
    {
      gpg_err_set_errno (ENOSYS);
      return -1;
    }

  i = 0;
  if (fd_child_list)
    {
      while (fd_child_list[i] != ASSUAN_INVALID_FD)
	i++;
    }
  /* fd_in, fd_out, terminator */
  i += 3;
  fd_items = calloc (i, sizeof (struct spawn_fd_item_s));
  if (! fd_items)
    return -1;
  i = 0;
  if (fd_child_list)
    {
      while (fd_child_list[i] != ASSUAN_INVALID_FD)
	{
	  fd_items[i].fd = (int) fd_child_list[i];
	  fd_items[i].dup_to = -1;
	  i++;
	}
    }
  if (fd_in != ASSUAN_INVALID_FD)
    {
      fd_items[i].fd = (int) fd_in;
      fd_items[i].dup_to = 0;
      i++;
    }
  if (fd_out != ASSUAN_INVALID_FD)
    {
      fd_items[i].fd = (int) fd_out;
      fd_items[i].dup_to = 1;
      i++;
    }
  fd_items[i].fd = -1;
  fd_items[i].dup_to = -1;

  err = _gpgme_io_spawn (name, (char*const*)argv,
                         (IOSPAWN_FLAG_NOCLOSE | IOSPAWN_FLAG_DETACHED),
			 fd_items, atfork, atforkvalue, r_pid);
  if (! err)
    {
      i = 0;

      if (fd_child_list)
	{
	  while (fd_child_list[i] != ASSUAN_INVALID_FD)
	    {
	      fd_child_list[i] = (assuan_fd_t) fd_items[i].peer_name;
	      i++;
	    }
	}
    }
  free (fd_items);
  return err;
}
Example #2
0
static gpgme_error_t
engspawn_start (engine_spawn_t esp, const char *file, const char *argv[],
                unsigned int flags)
{
  gpgme_error_t err;
  int i, n;
  int status;
  struct spawn_fd_item_s *fd_list;
  pid_t pid;
  unsigned int spflags;
  const char *save_argv0 = NULL;

  if (!esp || !file || !argv || !argv[0])
    return gpg_error (GPG_ERR_INV_VALUE);

  spflags = 0;
  if ((flags & GPGME_SPAWN_DETACHED))
    spflags |= IOSPAWN_FLAG_DETACHED;
  if ((flags & GPGME_SPAWN_ALLOW_SET_FG))
    spflags |= IOSPAWN_FLAG_ALLOW_SET_FG;


  err = build_fd_data_map (esp);
  if (err)
    return err;

  n = 0;
  for (i = 0; esp->fd_data_map[i].data; i++)
    n++;
  fd_list = calloc (n+1, sizeof *fd_list);
  if (!fd_list)
    return gpg_error_from_syserror ();

  /* Build the fd list for the child.  */
  n = 0;
  for (i = 0; esp->fd_data_map[i].data; i++)
    {
      fd_list[n].fd = esp->fd_data_map[i].peer_fd;
      fd_list[n].dup_to = esp->fd_data_map[i].dup_to;
      n++;
    }
  fd_list[n].fd = -1;
  fd_list[n].dup_to = -1;

  if (argv[0] && !*argv[0])
    {
      save_argv0 = argv[0];
      argv[0] = _gpgme_get_basename (file);
    }
  status = _gpgme_io_spawn (file, (char * const *)argv, spflags,
                            fd_list, NULL, NULL, &pid);
  if (save_argv0)
    argv[0] = save_argv0;
  free (fd_list);
  if (status == -1)
    return gpg_error_from_syserror ();

  for (i = 0; esp->fd_data_map[i].data; i++)
    {
      err = add_io_cb (esp, esp->fd_data_map[i].fd,
                       esp->fd_data_map[i].inbound,
                       esp->fd_data_map[i].inbound
                       ? _gpgme_data_inbound_handler
                       : _gpgme_data_outbound_handler,
                       esp->fd_data_map[i].data, &esp->fd_data_map[i].tag);
      if (err)
        return err;  /* FIXME: kill the child */
    }

  engspawn_io_event (esp, GPGME_EVENT_START, NULL);

  return 0;
}
Example #3
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;
}
Example #4
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;
}
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;
}