Example #1
0
static gpg_error_t
armor_data (char **r_string, const void *data, size_t datalen)
{
  gpg_error_t err;
  struct b64state b64state;
  estream_t fp;
  long length;
  char *buffer;
  size_t nread;

  *r_string = NULL;

  fp = es_fopenmem (0, "rw");
  if (!fp)
    return gpg_error_from_syserror ();

  if ((err=b64enc_start_es (&b64state, fp, "PGP PUBLIC KEY BLOCK"))
      || (err=b64enc_write (&b64state, data, datalen))
      || (err = b64enc_finish (&b64state)))
    {
      es_fclose (fp);
      return err;
    }

  /* FIXME: To avoid the extra buffer allocation estream should
     provide a function to snatch the internal allocated memory from
     such a memory stream.  */
  length = es_ftell (fp);
  if (length < 0)
    {
      err = gpg_error_from_syserror ();
      es_fclose (fp);
      return err;
    }

  buffer = xtrymalloc (length+1);
  if (!buffer)
    {
      err = gpg_error_from_syserror ();
      es_fclose (fp);
      return err;
    }

  es_rewind (fp);
  if (es_read (fp, buffer, length, &nread))
    {
      err = gpg_error_from_syserror ();
      es_fclose (fp);
      return err;
    }
  buffer[nread] = 0;
  es_fclose (fp);

  *r_string = buffer;
  return 0;
}
Example #2
0
/* Verify the signed data.  */
static void
verify_signature (receive_ctx_t ctx)
{
  gpg_error_t err;
  ccparray_t ccp;
  const char **argv;

  log_assert (ctx->signeddata);
  log_assert (ctx->signature);
  es_rewind (ctx->signeddata);
  es_rewind (ctx->signature);

  ccparray_init (&ccp, 0);

  ccparray_put (&ccp, "--batch");
  if (opt.verbose)
    ccparray_put (&ccp, "--verbose");
  ccparray_put (&ccp, "--enable-special-filenames");
  ccparray_put (&ccp, "--status-fd=2");
  ccparray_put (&ccp, "--verify");
  ccparray_put (&ccp, "--");
  ccparray_put (&ccp, "-&@INEXTRA@");
  ccparray_put (&ccp, "-");

  ccparray_put (&ccp, NULL);
  argv = ccparray_get (&ccp, NULL);
  if (!argv)
    {
      err = gpg_error_from_syserror ();
      goto leave;
    }
  err = gnupg_exec_tool_stream (opt.gpg_program, argv, ctx->signeddata,
                                ctx->signature, NULL,
                                verify_signature_status_cb, ctx);
  if (err)
    {
      log_error ("verification failed: %s\n", gpg_strerror (err));
      goto leave;
    }

 leave:
  xfree (argv);
}
Example #3
0
/* Helper to write mail to the output(s).  */
gpg_error_t
wks_send_mime (mime_maker_t mime)
{
  gpg_error_t err;
  estream_t mail;

  /* Without any option we take a short path.  */
  if (!opt.use_sendmail && !opt.output)
    {
      es_set_binary (es_stdout);
      return mime_maker_make (mime, es_stdout);
    }


  mail = es_fopenmem (0, "w+b");
  if (!mail)
    {
      err = gpg_error_from_syserror ();
      return err;
    }

  err = mime_maker_make (mime, mail);

  if (!err && opt.output)
    {
      es_rewind (mail);
      err = send_mail_to_file (mail, opt.output);
    }

  if (!err && opt.use_sendmail)
    {
      es_rewind (mail);
      err = send_mail (mail);
    }

  es_fclose (mail);
  return err;
}
Example #4
0
/* Ask the dirmngr for the policy flags and return them as an estream
 * memory stream.  If no policy flags are set, NULL is stored at
 * R_BUFFER.  */
gpg_error_t
wkd_get_policy_flags (const char *addrspec, estream_t *r_buffer)
{
  gpg_error_t err;
  assuan_context_t ctx;
  struct wkd_get_parm_s parm;
  char *line = NULL;
  char *buffer = NULL;

  memset (&parm, 0, sizeof parm);
  *r_buffer = NULL;

  err = connect_dirmngr (&ctx);
  if (err)
    return err;

  line = es_bsprintf ("WKD_GET --policy-flags -- %s", addrspec);
  if (!line)
    {
      err = gpg_error_from_syserror ();
      goto leave;
    }
  if (strlen (line) + 2 >= ASSUAN_LINELENGTH)
    {
      err = gpg_error (GPG_ERR_TOO_LARGE);
      goto leave;
    }

  parm.memfp = es_fopenmem (0, "rwb");
  if (!parm.memfp)
    {
      err = gpg_error_from_syserror ();
      goto leave;
    }
  err = assuan_transact (ctx, line, wkd_get_data_cb, &parm,
                         NULL, NULL, wkd_get_status_cb, &parm);
  if (err)
    goto leave;

  es_rewind (parm.memfp);
  *r_buffer = parm.memfp;
  parm.memfp = 0;

 leave:
  es_free (buffer);
  es_fclose (parm.memfp);
  xfree (line);
  assuan_release (ctx);
  return err;
}
Example #5
0
File: misc.c Project: FMayzek/gnupg
/* A KSBA reader callback to read from an estream.  */
static int
my_estream_ksba_reader_cb (void *cb_value, char *buffer, size_t count,
                           size_t *r_nread)
{
  estream_t fp = cb_value;

  if (!fp)
    return gpg_error (GPG_ERR_INV_VALUE);

  if (!buffer && !count && !r_nread)
    {
      es_rewind (fp);
      return 0;
    }

  *r_nread = es_fread (buffer, 1, count, fp);
  if (!*r_nread)
    return -1; /* EOF or error.  */
  return 0; /* Success.  */
}
Example #6
0
/* Fork and exec the PGMNAME, see exechelp.h for details.  */
gpg_error_t
gnupg_spawn_process (const char *pgmname, const char *argv[],
                     gpg_err_source_t errsource,
                     void (*preexec)(void), unsigned int flags,
                     estream_t infp,
                     estream_t *r_outfp,
                     estream_t *r_errfp,
                     pid_t *pid)
{
  gpg_error_t err;
  SECURITY_ATTRIBUTES sec_attr;
  PROCESS_INFORMATION pi =
    {
      NULL,      /* Returns process handle.  */
      0,         /* Returns primary thread handle.  */
      0,         /* Returns pid.  */
      0          /* Returns tid.  */
    };
  STARTUPINFO si;
  int cr_flags;
  char *cmdline;
  HANDLE inhandle = INVALID_HANDLE_VALUE;
  HANDLE outpipe[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE};
  HANDLE errpipe[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE};
  estream_t outfp = NULL;
  estream_t errfp = NULL;
  HANDLE nullhd[3] = {INVALID_HANDLE_VALUE,
                      INVALID_HANDLE_VALUE,
                      INVALID_HANDLE_VALUE};
  int i;
  es_syshd_t syshd;

  if (r_outfp)
    *r_outfp = NULL;
  if (r_errfp)
    *r_errfp = NULL;
  *pid = (pid_t)(-1); /* Always required.  */

  if (infp)
    {
      es_fflush (infp);
      es_rewind (infp);
      es_syshd (infp, &syshd);
      switch (syshd.type)
        {
        case ES_SYSHD_FD:
          inhandle = (HANDLE)_get_osfhandle (syshd.u.fd);
          break;
        case ES_SYSHD_SOCK:
          inhandle = (HANDLE)_get_osfhandle (syshd.u.sock);
          break;
        case ES_SYSHD_HANDLE:
          inhandle = syshd.u.handle;
          break;
        default:
          inhandle = INVALID_HANDLE_VALUE;
          break;
        }
      if (inhandle == INVALID_HANDLE_VALUE)
        return gpg_err_make (errsource, GPG_ERR_INV_VALUE);
      /* FIXME: In case we can't get a system handle (e.g. due to
         es_fopencookie we should create a piper and a feeder
         thread.  */
    }

  if (r_outfp)
    {
      if (create_inheritable_pipe (outpipe, 1))
        {
          err = gpg_err_make (errsource, GPG_ERR_GENERAL);
          log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
          return err;
        }

      syshd.type = ES_SYSHD_HANDLE;
      syshd.u.handle = outpipe[0];
      outfp = es_sysopen (&syshd, "r");
      if (!outfp)
        {
          err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
          log_error (_("error creating a stream for a pipe: %s\n"),
                     gpg_strerror (err));
          CloseHandle (outpipe[0]);
          CloseHandle (outpipe[1]);
          outpipe[0] = outpipe[1] = INVALID_HANDLE_VALUE;
          return err;
        }
    }

  if (r_errfp)
    {
      if (create_inheritable_pipe (errpipe, 1))
        {
          err = gpg_err_make (errsource, GPG_ERR_GENERAL);
          log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
          return err;
        }

      syshd.type = ES_SYSHD_HANDLE;
      syshd.u.handle = errpipe[0];
      errfp = es_sysopen (&syshd, "r");
      if (!errfp)
        {
          err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
          log_error (_("error creating a stream for a pipe: %s\n"),
                     gpg_strerror (err));
          CloseHandle (errpipe[0]);
          CloseHandle (errpipe[1]);
          errpipe[0] = errpipe[1] = INVALID_HANDLE_VALUE;
          if (outfp)
            es_fclose (outfp);
          else if (outpipe[0] != INVALID_HANDLE_VALUE)
            CloseHandle (outpipe[0]);
          if (outpipe[1] != INVALID_HANDLE_VALUE)
            CloseHandle (outpipe[1]);
          return err;
        }
    }

  /* Prepare security attributes.  */
  memset (&sec_attr, 0, sizeof sec_attr );
  sec_attr.nLength = sizeof sec_attr;
  sec_attr.bInheritHandle = FALSE;

  /* Build the command line.  */
  err = build_w32_commandline (pgmname, argv, &cmdline);
  if (err)
    return err;

  if (inhandle != INVALID_HANDLE_VALUE)
    nullhd[0] = w32_open_null (0);
  if (outpipe[1] != INVALID_HANDLE_VALUE)
    nullhd[1] = w32_open_null (0);
  if (errpipe[1] != INVALID_HANDLE_VALUE)
    nullhd[2] = w32_open_null (0);

  /* Start the process.  Note that we can't run the PREEXEC function
     because this might change our own environment. */
  (void)preexec;

  memset (&si, 0, sizeof si);
  si.cb = sizeof (si);
  si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
  si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE;
  si.hStdInput  =   inhandle == INVALID_HANDLE_VALUE? nullhd[0] : inhandle;
  si.hStdOutput = outpipe[1] == INVALID_HANDLE_VALUE? nullhd[1] : outpipe[1];
  si.hStdError  = errpipe[1] == INVALID_HANDLE_VALUE? nullhd[2] : errpipe[1];

  cr_flags = (CREATE_DEFAULT_ERROR_MODE
              | ((flags & 128)? DETACHED_PROCESS : 0)
              | GetPriorityClass (GetCurrentProcess ())
              | CREATE_SUSPENDED);
/*   log_debug ("CreateProcess, path=`%s' cmdline=`%s'\n", pgmname, cmdline); */
  if (!CreateProcess (pgmname,       /* Program to start.  */
                      cmdline,       /* Command line arguments.  */
                      &sec_attr,     /* Process security attributes.  */
                      &sec_attr,     /* Thread security attributes.  */
                      TRUE,          /* Inherit handles.  */
                      cr_flags,      /* Creation flags.  */
                      NULL,          /* Environment.  */
                      NULL,          /* Use current drive/directory.  */
                      &si,           /* Startup information. */
                      &pi            /* Returns process information.  */
                      ))
    {
      log_error ("CreateProcess failed: %s\n", w32_strerror (-1));
      xfree (cmdline);
      if (outfp)
        es_fclose (outfp);
      else if (outpipe[0] != INVALID_HANDLE_VALUE)
        CloseHandle (outpipe[0]);
      if (outpipe[1] != INVALID_HANDLE_VALUE)
        CloseHandle (outpipe[1]);
      if (errfp)
        es_fclose (errfp);
      else if (errpipe[0] != INVALID_HANDLE_VALUE)
        CloseHandle (errpipe[0]);
      if (errpipe[1] != INVALID_HANDLE_VALUE)
        CloseHandle (errpipe[1]);
      return gpg_err_make (errsource, GPG_ERR_GENERAL);
    }
  xfree (cmdline);
  cmdline = NULL;

  /* Close the inherited handles to /dev/null.  */
  for (i=0; i < DIM (nullhd); i++)
    if (nullhd[i] != INVALID_HANDLE_VALUE)
      CloseHandle (nullhd[i]);

  /* Close the inherited ends of the pipes.  */
  if (outpipe[1] != INVALID_HANDLE_VALUE)
    CloseHandle (outpipe[1]);
  if (errpipe[1] != INVALID_HANDLE_VALUE)
    CloseHandle (errpipe[1]);

  /* log_debug ("CreateProcess ready: hProcess=%p hThread=%p" */
  /*            " dwProcessID=%d dwThreadId=%d\n", */
  /*            pi.hProcess, pi.hThread, */
  /*            (int) pi.dwProcessId, (int) pi.dwThreadId); */
  /* log_debug ("                     outfp=%p errfp=%p\n", outfp, errfp); */

  /* Fixme: For unknown reasons AllowSetForegroundWindow returns an
     invalid argument error if we pass it the correct processID.  As a
     workaround we use -1 (ASFW_ANY).  */
  if ( (flags & 64) )
    gnupg_allow_set_foregound_window ((pid_t)(-1)/*pi.dwProcessId*/);

  /* Process has been created suspended; resume it now. */
  ResumeThread (pi.hThread);
  CloseHandle (pi.hThread);

  if (r_outfp)
    *r_outfp = outfp;
  if (r_errfp)
    *r_errfp = errfp;

  *pid = handle_to_pid (pi.hProcess);
  return 0;

}
/* Fork and exec the PGMNAME, see exechelp.h for details.  */
gpg_error_t
gnupg_spawn_process (const char *pgmname, const char *argv[],
                     gpg_err_source_t errsource,
                     void (*preexec)(void), unsigned int flags,
                     estream_t infp,
                     estream_t *r_outfp,
                     estream_t *r_errfp,
                     pid_t *pid)
{
    gpg_error_t err;
    int infd = -1;
    int outpipe[2] = {-1, -1};
    int errpipe[2] = {-1, -1};
    estream_t outfp = NULL;
    estream_t errfp = NULL;

    (void)flags; /* Currently not used.  */

    if (r_outfp)
        *r_outfp = NULL;
    if (r_errfp)
        *r_errfp = NULL;
    *pid = (pid_t)(-1); /* Always required.  */

    if (infp)
    {
        es_fflush (infp);
        es_rewind (infp);
        infd = es_fileno (infp);
        if (infd == -1)
            return gpg_err_make (errsource, GPG_ERR_INV_VALUE);
    }

    if (r_outfp)
    {
        err = create_pipe_and_estream (outpipe, &outfp, errsource);
        if (err)
            return err;
    }

    if (r_errfp)
    {
        err = create_pipe_and_estream (errpipe, &errfp, errsource);
        if (err)
        {
            if (outfp)
                es_fclose (outfp);
            else if (outpipe[0] != -1)
                close (outpipe[0]);
            if (outpipe[1] != -1)
                close (outpipe[1]);
            return err;
        }
    }


    *pid = fork ();
    if (*pid == (pid_t)(-1))
    {
        err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
        log_error (_("error forking process: %s\n"), gpg_strerror (err));

        if (outfp)
            es_fclose (outfp);
        else if (outpipe[0] != -1)
            close (outpipe[0]);
        if (outpipe[1] != -1)
            close (outpipe[1]);

        if (errfp)
            es_fclose (errfp);
        else if (errpipe[0] != -1)
            close (errpipe[0]);
        if (errpipe[1] != -1)
            close (errpipe[1]);
        return err;
    }

    if (!*pid)
    {
        /* This is the child. */
        gcry_control (GCRYCTL_TERM_SECMEM);
        es_fclose (outfp);
        es_fclose (errfp);
        do_exec (pgmname, argv, infd, outpipe[1], errpipe[1], preexec);
        /*NOTREACHED*/
    }

    /* This is the parent. */
    if (outpipe[1] != -1)
        close (outpipe[1]);
    if (errpipe[1] != -1)
        close (errpipe[1]);

    if (r_outfp)
        *r_outfp = outfp;
    if (r_errfp)
        *r_errfp = errfp;

    return 0;
}
Example #8
0
/* Decrypt the collected data.  */
static void
decrypt_data (receive_ctx_t ctx)
{
  gpg_error_t err;
  ccparray_t ccp;
  const char **argv;
  int c;

  es_rewind (ctx->encrypted);

  if (!ctx->plaintext)
    ctx->plaintext = es_fopenmem (0, "w+b");
  if (!ctx->plaintext)
    {
      err = gpg_error_from_syserror ();
      log_error ("error allocating space for plaintext: %s\n",
                 gpg_strerror (err));
      return;
    }

  ccparray_init (&ccp, 0);

  /* We limit the output to 64 KiB to avoid DoS using compression
   * tricks.  A regular client will anyway only send a minimal key;
   * that is one w/o key signatures and attribute packets.  */
  ccparray_put (&ccp, "--max-output=0xf0000"); /*FIXME: Change s/F/1/ */
  ccparray_put (&ccp, "--batch");
  if (opt.verbose)
    ccparray_put (&ccp, "--verbose");
  ccparray_put (&ccp, "--always-trust");
  ccparray_put (&ccp, "--decrypt");
  ccparray_put (&ccp, "--");

  ccparray_put (&ccp, NULL);
  argv = ccparray_get (&ccp, NULL);
  if (!argv)
    {
      err = gpg_error_from_syserror ();
      goto leave;
    }
  err = gnupg_exec_tool_stream (opt.gpg_program, argv, ctx->encrypted,
                                NULL, ctx->plaintext,
                                decrypt_data_status_cb, ctx);
  if (err)
    {
      log_error ("decryption failed: %s\n", gpg_strerror (err));
      goto leave;
    }

  if (opt.debug)
    {
      es_rewind (ctx->plaintext);
      log_debug ("plaintext: '");
      while ((c = es_getc (ctx->plaintext)) != EOF)
        log_printf ("%c", c);
      log_printf ("'\n");
    }
  es_rewind (ctx->plaintext);

 leave:
  xfree (argv);
}
Example #9
0
/* Receive a WKS mail from FP and process it accordingly.  On success
 * the RESULT_CB is called with the mediatype and a stream with the
 * decrypted data. */
gpg_error_t
wks_receive (estream_t fp,
             gpg_error_t (*result_cb)(void *opaque,
                                      const char *mediatype,
                                      estream_t data),
             void *cb_data)
{
  gpg_error_t err;
  receive_ctx_t ctx;
  mime_parser_t parser;
  estream_t plaintext = NULL;
  int c;

  ctx = xtrycalloc (1, sizeof *ctx);
  if (!ctx)
    return gpg_error_from_syserror ();

  err = mime_parser_new (&parser, ctx);
  if (err)
    goto leave;
  if (opt.verbose > 1 || opt.debug)
    mime_parser_set_verbose (parser, opt.debug? 10: 1);
  mime_parser_set_new_part (parser, new_part);
  mime_parser_set_part_data (parser, part_data);
  mime_parser_set_collect_encrypted (parser, collect_encrypted);
  mime_parser_set_collect_signeddata (parser, collect_signeddata);
  mime_parser_set_collect_signature (parser, collect_signature);

  err = mime_parser_parse (parser, fp);
  if (err)
    goto leave;

  if (ctx->key_data)
    log_info ("key data found\n");
  if (ctx->wkd_data)
    log_info ("wkd data found\n");

  if (ctx->plaintext)
    {
      if (opt.verbose)
        log_info ("parsing decrypted message\n");
      plaintext = ctx->plaintext;
      ctx->plaintext = NULL;
      if (ctx->encrypted)
        es_rewind (ctx->encrypted);
      if (ctx->signeddata)
        es_rewind (ctx->signeddata);
      if (ctx->signature)
        es_rewind (ctx->signature);
      err = mime_parser_parse (parser, plaintext);
      if (err)
        return err;
    }

  if (!ctx->key_data && !ctx->wkd_data)
    {
      log_error ("no suitable data found in the message\n");
      err = gpg_error (GPG_ERR_NO_DATA);
      goto leave;
    }

  if (ctx->key_data)
    {
      if (opt.debug)
        {
          es_rewind (ctx->key_data);
          log_debug ("Key: '");
          log_printf ("\n");
          while ((c = es_getc (ctx->key_data)) != EOF)
            log_printf ("%c", c);
          log_printf ("'\n");
        }
      if (result_cb)
        {
          es_rewind (ctx->key_data);
          err = result_cb (cb_data, "application/pgp-keys", ctx->key_data);
          if (err)
            goto leave;
        }
    }
  if (ctx->wkd_data)
    {
      if (opt.debug)
        {
          es_rewind (ctx->wkd_data);
          log_debug ("WKD: '");
          log_printf ("\n");
          while ((c = es_getc (ctx->wkd_data)) != EOF)
            log_printf ("%c", c);
          log_printf ("'\n");
        }
      if (result_cb)
        {
          es_rewind (ctx->wkd_data);
          err = result_cb (cb_data, "application/vnd.gnupg.wks", ctx->wkd_data);
          if (err)
            goto leave;
        }
    }


 leave:
  es_fclose (plaintext);
  mime_parser_release (parser);
  es_fclose (ctx->encrypted);
  es_fclose (ctx->plaintext);
  es_fclose (ctx->signeddata);
  es_fclose (ctx->signature);
  es_fclose (ctx->key_data);
  es_fclose (ctx->wkd_data);
  xfree (ctx);
  return err;
}
Example #10
0
/* Fork and exec the PGMNAME, see exechelp.h for details.  */
gpg_error_t
gnupg_spawn_process (const char *pgmname, const char *argv[],
                     gpg_err_source_t errsource,
                     void (*preexec)(void), unsigned int flags,
                     estream_t infp,
                     estream_t *r_outfp,
                     estream_t *r_errfp,
                     pid_t *pid)
{
  gpg_error_t err;
  PROCESS_INFORMATION pi = {NULL };
  char *cmdline;
  es_syshd_t syshd;
  struct {
    HANDLE hd;
    int rvid;
  } inpipe = {INVALID_HANDLE_VALUE, 0};
  struct {
    HANDLE hd;
    int rvid;
  } outpipe = {INVALID_HANDLE_VALUE, 0};
  struct {
    HANDLE hd;
    int rvid;
  } errpipe = {INVALID_HANDLE_VALUE, 0};
  estream_t outfp = NULL;
  estream_t errfp = NULL;

  (void)preexec;
  (void)flags;

  /* Setup return values.  */
  if (r_outfp)
    *r_outfp = NULL;
  if (r_errfp)
    *r_errfp = NULL;
  *pid = (pid_t)(-1); /* Always required.  */

  log_debug ("%s: enter\n", __func__);
  if (infp)
    {
      es_fflush (infp);
      es_rewind (infp);

      /* Create a pipe to copy our infile to the stdin of the child
         process.  On success inpipe.hd is owned by the feeder.  */
      inpipe.hd = _assuan_w32ce_prepare_pipe (&inpipe.rvid, 1);
      if (inpipe.hd == INVALID_HANDLE_VALUE)
        {
          log_error ("_assuan_w32ce_prepare_pipe failed: %s\n",
                     w32_strerror (-1));
          gpg_err_set_errno (EIO);
          return gpg_error_from_syserror ();
        }
      log_debug ("%s: inpipe %p created; hd=%p rvid=%d\n", __func__,
                 infp, inpipe.hd, inpipe.rvid);
      err = start_feeder (infp, inpipe.hd, 1);
      if (err)
        {
          log_error ("error spawning feeder: %s\n", gpg_strerror (err));
          CloseHandle (inpipe.hd);
          return err;
        }
      inpipe.hd = INVALID_HANDLE_VALUE; /* Now owned by the feeder.  */
      log_debug ("%s: inpipe %p created; feeder started\n", __func__,
                 infp);
    }

  if (r_outfp)
    {
      /* Create a pipe to make the stdout of the child process
         available as a stream.  */
      outpipe.hd = _assuan_w32ce_prepare_pipe (&outpipe.rvid, 0);
      if (outpipe.hd == INVALID_HANDLE_VALUE)
        {
          log_error ("_assuan_w32ce_prepare_pipe failed: %s\n",
                     w32_strerror (-1));
          gpg_err_set_errno (EIO);
          /* Fixme release other stuff/kill feeder.  */
          return gpg_error_from_syserror ();
        }
      syshd.type = ES_SYSHD_HANDLE;
      syshd.u.handle = outpipe.hd;
      err = 0;
      outfp = es_sysopen (&syshd, "r");
      if (!outfp)
        {
          err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
          log_error ("error opening pipe stream: %s\n", gpg_strerror (err));
          CloseHandle (outpipe.hd);
          return err;
        }
      log_debug ("%s: outpipe %p created; hd=%p rvid=%d\n", __func__,
                 outfp, outpipe.hd, outpipe.rvid);
      outpipe.hd = INVALID_HANDLE_VALUE; /* Now owned by the OUTFP.  */
    }

  if (r_errfp)
    {
      /* Create a pipe to make the stderr of the child process
         available as a stream.  */
      errpipe.hd = _assuan_w32ce_prepare_pipe (&errpipe.rvid, 0);
      if (errpipe.hd == INVALID_HANDLE_VALUE)
        {
          log_error ("_assuan_w32ce_prepare_pipe failed: %s\n",
                     w32_strerror (-1));
          gpg_err_set_errno (EIO);
          /* Fixme release other stuff/kill feeder.  */
          return gpg_error_from_syserror ();
        }
      syshd.type = ES_SYSHD_HANDLE;
      syshd.u.handle = errpipe.hd;
      err = 0;
      errfp = es_sysopen (&syshd, "r");
      if (!errfp)
        {
          err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
          log_error ("error opening pipe stream: %s\n", gpg_strerror (err));
          CloseHandle (errpipe.hd);
          return err;
        }
      log_debug ("%s: errpipe %p created; hd=%p rvid=%d\n", __func__,
                 errfp, errpipe.hd, errpipe.rvid);
      errpipe.hd = INVALID_HANDLE_VALUE; /* Now owned by the ERRFP.  */
    }



  /* Build the command line.  */
  err = build_w32_commandline (argv, inpipe.rvid, outpipe.rvid, errpipe.rvid,
                               &cmdline);
  if (err)
    {
      /* Fixme release other stuff/kill feeder.  */
      CloseHandle (errpipe.hd);
      return err;
    }

  log_debug ("CreateProcess, path='%s' cmdline='%s'\n", pgmname, cmdline);
  if (!create_process (pgmname, cmdline, &pi))
    {
      log_error ("CreateProcess failed: %s\n", w32_strerror (-1));
      xfree (cmdline);
      /* Fixme release other stuff/kill feeder.  */
      CloseHandle (errpipe.hd);
      return gpg_error (GPG_ERR_GENERAL);
    }
  xfree (cmdline);
  cmdline = NULL;

  /* Note: The other end of the pipe is a rendezvous id and thus there
     is no need for a close.  */

  log_debug ("CreateProcess ready: hProcess=%p hThread=%p"
             " dwProcessID=%d dwThreadId=%d\n",
             pi.hProcess, pi.hThread,
             (int) pi.dwProcessId, (int) pi.dwThreadId);


  /* Process has been created suspended; resume it now. */
  ResumeThread (pi.hThread);
  CloseHandle (pi.hThread);

  if (r_outfp)
    *r_outfp = outfp;
  if (r_errfp)
    *r_errfp = errfp;
  *pid = handle_to_pid (pi.hProcess);
  return 0;
}
Example #11
0
/* Run gpg as a filter on KEY and write the output to a new stream
 * stored at R_NEWKEY.  The new key will contain only the user id UID.
 * Returns 0 on success.  Only one key is expected in KEY.  If BINARY
 * is set the resulting key is returned as a binary (non-armored)
 * keyblock.  */
gpg_error_t
wks_filter_uid (estream_t *r_newkey, estream_t key, const char *uid,
                int binary)
{
  gpg_error_t err;
  ccparray_t ccp;
  const char **argv = NULL;
  estream_t newkey;
  char *filterexp = NULL;

  *r_newkey = NULL;

  /* Open a memory stream.  */
  newkey = es_fopenmem (0, "w+b");
  if (!newkey)
    {
      err = gpg_error_from_syserror ();
      log_error ("error allocating memory buffer: %s\n", gpg_strerror (err));
      return err;
    }

  /* Prefix the key with the MIME content type.  */
  if (!binary)
    es_fputs ("Content-Type: application/pgp-keys\n"
              "\n", newkey);

  filterexp = es_bsprintf ("keep-uid=uid=%s", uid);
  if (!filterexp)
    {
      err = gpg_error_from_syserror ();
      log_error ("error allocating memory buffer: %s\n", gpg_strerror (err));
      goto leave;
    }

  ccparray_init (&ccp, 0);

  ccparray_put (&ccp, "--no-options");
  if (!opt.verbose)
    ccparray_put (&ccp, "--quiet");
  else if (opt.verbose > 1)
    ccparray_put (&ccp, "--verbose");
  ccparray_put (&ccp, "--batch");
  ccparray_put (&ccp, "--status-fd=2");
  ccparray_put (&ccp, "--always-trust");
  if (!binary)
    ccparray_put (&ccp, "--armor");
  ccparray_put (&ccp, "--import-options=import-export");
  ccparray_put (&ccp, "--import-filter");
  ccparray_put (&ccp, filterexp);
  ccparray_put (&ccp, "--import");

  ccparray_put (&ccp, NULL);
  argv = ccparray_get (&ccp, NULL);
  if (!argv)
    {
      err = gpg_error_from_syserror ();
      goto leave;
    }
  err = gnupg_exec_tool_stream (opt.gpg_program, argv, key,
                                NULL, newkey,
                                key_status_cb, NULL);
  if (err)
    {
      log_error ("import/export failed: %s\n", gpg_strerror (err));
      goto leave;
    }

  es_rewind (newkey);
  *r_newkey = newkey;
  newkey = NULL;

 leave:
  xfree (filterexp);
  xfree (argv);
  es_fclose (newkey);
  return err;
}
Example #12
0
/* Run gpg on KEY and store the primary fingerprint at R_FPR and the
 * list of mailboxes at R_MBOXES.  Returns 0 on success; on error NULL
 * is stored at R_FPR and R_MBOXES and an error code is returned.
 * R_FPR may be NULL if the fingerprint is not needed.  */
gpg_error_t
wks_list_key (estream_t key, char **r_fpr, uidinfo_list_t *r_mboxes)
{
  gpg_error_t err;
  ccparray_t ccp;
  const char **argv;
  estream_t listing;
  char *line = NULL;
  size_t length_of_line = 0;
  size_t  maxlen;
  ssize_t len;
  char **fields = NULL;
  int nfields;
  int lnr;
  char *fpr = NULL;
  uidinfo_list_t mboxes = NULL;

  if (r_fpr)
    *r_fpr = NULL;
  *r_mboxes = NULL;

  /* Open a memory stream.  */
  listing = es_fopenmem (0, "w+b");
  if (!listing)
    {
      err = gpg_error_from_syserror ();
      log_error ("error allocating memory buffer: %s\n", gpg_strerror (err));
      return err;
    }

  ccparray_init (&ccp, 0);

  ccparray_put (&ccp, "--no-options");
  if (!opt.verbose)
    ccparray_put (&ccp, "--quiet");
  else if (opt.verbose > 1)
    ccparray_put (&ccp, "--verbose");
  ccparray_put (&ccp, "--batch");
  ccparray_put (&ccp, "--status-fd=2");
  ccparray_put (&ccp, "--always-trust");
  ccparray_put (&ccp, "--with-colons");
  ccparray_put (&ccp, "--dry-run");
  ccparray_put (&ccp, "--import-options=import-minimal,import-show");
  ccparray_put (&ccp, "--import");

  ccparray_put (&ccp, NULL);
  argv = ccparray_get (&ccp, NULL);
  if (!argv)
    {
      err = gpg_error_from_syserror ();
      goto leave;
    }
  err = gnupg_exec_tool_stream (opt.gpg_program, argv, key,
                                NULL, listing,
                                key_status_cb, NULL);
  if (err)
    {
      log_error ("import failed: %s\n", gpg_strerror (err));
      goto leave;
    }

  es_rewind (listing);
  lnr = 0;
  maxlen = 2048; /* Set limit.  */
  while ((len = es_read_line (listing, &line, &length_of_line, &maxlen)) > 0)
    {
      lnr++;
      if (!maxlen)
        {
          log_error ("received line too long\n");
          err = gpg_error (GPG_ERR_LINE_TOO_LONG);
          goto leave;
        }
      /* Strip newline and carriage return, if present.  */
      while (len > 0
	     && (line[len - 1] == '\n' || line[len - 1] == '\r'))
	line[--len] = '\0';
      /* log_debug ("line '%s'\n", line); */

      xfree (fields);
      fields = strtokenize (line, ":");
      if (!fields)
        {
          err = gpg_error_from_syserror ();
          log_error ("strtokenize failed: %s\n", gpg_strerror (err));
          goto leave;
        }
      for (nfields = 0; fields[nfields]; nfields++)
        ;
      if (!nfields)
        {
          err = gpg_error (GPG_ERR_INV_ENGINE);
          goto leave;
        }
      if (!strcmp (fields[0], "sec"))
        {
          /* gpg may return "sec" as the first record - but we do not
           * accept secret keys.  */
          err = gpg_error (GPG_ERR_NO_PUBKEY);
          goto leave;
        }
      if (lnr == 1 && strcmp (fields[0], "pub"))
        {
          /* First record is not a public key.  */
          err = gpg_error (GPG_ERR_INV_ENGINE);
          goto leave;
        }
      if (lnr > 1 && !strcmp (fields[0], "pub"))
        {
          /* More than one public key.  */
          err = gpg_error (GPG_ERR_TOO_MANY);
          goto leave;
        }
      if (!strcmp (fields[0], "sub") || !strcmp (fields[0], "ssb"))
        break; /* We can stop parsing here.  */

      if (!strcmp (fields[0], "fpr") && nfields > 9 && !fpr)
        {
          fpr = xtrystrdup (fields[9]);
          if (!fpr)
            {
              err = gpg_error_from_syserror ();
              goto leave;
            }
        }
      else if (!strcmp (fields[0], "uid") && nfields > 9)
        {
          /* Fixme: Unescape fields[9] */
          if (!append_to_uidinfo_list (&mboxes, fields[9],
                                       parse_timestamp (fields[5], NULL)))
            {
              err = gpg_error_from_syserror ();
              goto leave;
            }
        }
    }
  if (len < 0 || es_ferror (listing))
    {
      err = gpg_error_from_syserror ();
      log_error ("error reading memory stream\n");
      goto leave;
    }

  if (!fpr)
    {
      err = gpg_error (GPG_ERR_NO_PUBKEY);
      goto leave;
    }

  if (r_fpr)
    {
      *r_fpr = fpr;
      fpr = NULL;
    }
  *r_mboxes = mboxes;
  mboxes = NULL;

 leave:
  xfree (fpr);
  free_uidinfo_list (mboxes);
  xfree (fields);
  es_free (line);
  xfree (argv);
  es_fclose (listing);
  return err;
}
Example #13
0
/* Get a key by fingerprint from gpg's keyring and make sure that the
 * mail address ADDRSPEC is included in the key.  If EXACT is set the
 * returned user id must match Addrspec exactly and not just in the
 * addr-spec (mailbox) part.  The key is returned as a new memory
 * stream at R_KEY.  */
gpg_error_t
wks_get_key (estream_t *r_key, const char *fingerprint, const char *addrspec,
             int exact)
{
  gpg_error_t err;
  ccparray_t ccp;
  const char **argv = NULL;
  estream_t key = NULL;
  struct get_key_status_parm_s parm;
  char *filterexp = NULL;

  memset (&parm, 0, sizeof parm);

  *r_key = NULL;

  key = es_fopenmem (0, "w+b");
  if (!key)
    {
      err = gpg_error_from_syserror ();
      log_error ("error allocating memory buffer: %s\n", gpg_strerror (err));
      goto leave;
    }

  /* Prefix the key with the MIME content type.  */
  es_fputs ("Content-Type: application/pgp-keys\n"
            "\n", key);

  filterexp = es_bsprintf ("keep-uid=%s=%s", exact? "uid":"mbox", addrspec);
  if (!filterexp)
    {
      err = gpg_error_from_syserror ();
      log_error ("error allocating memory buffer: %s\n", gpg_strerror (err));
      goto leave;
    }

  ccparray_init (&ccp, 0);

  ccparray_put (&ccp, "--no-options");
  if (!opt.verbose)
    ccparray_put (&ccp, "--quiet");
  else if (opt.verbose > 1)
    ccparray_put (&ccp, "--verbose");
  ccparray_put (&ccp, "--batch");
  ccparray_put (&ccp, "--status-fd=2");
  ccparray_put (&ccp, "--always-trust");
  ccparray_put (&ccp, "--armor");
  ccparray_put (&ccp, "--export-options=export-minimal");
  ccparray_put (&ccp, "--export-filter");
  ccparray_put (&ccp, filterexp);
  ccparray_put (&ccp, "--export");
  ccparray_put (&ccp, "--");
  ccparray_put (&ccp, fingerprint);

  ccparray_put (&ccp, NULL);
  argv = ccparray_get (&ccp, NULL);
  if (!argv)
    {
      err = gpg_error_from_syserror ();
      goto leave;
    }
  parm.fpr = fingerprint;
  err = gnupg_exec_tool_stream (opt.gpg_program, argv, NULL,
                                NULL, key,
                                get_key_status_cb, &parm);
  if (!err && parm.count > 1)
    err = gpg_error (GPG_ERR_TOO_MANY);
  else if (!err && !parm.found)
    err = gpg_error (GPG_ERR_NOT_FOUND);
  if (err)
    {
      log_error ("export failed: %s\n", gpg_strerror (err));
      goto leave;
    }

  es_rewind (key);
  *r_key = key;
  key = NULL;

 leave:
  es_fclose (key);
  xfree (argv);
  xfree (filterexp);
  return err;
}