Esempio n. 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;
}
Esempio n. 2
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;
}
Esempio n. 3
0
static gpg_error_t
collect_signeddata (void *cookie, const char *data)
{
  receive_ctx_t ctx = cookie;

  if (!ctx->signeddata)
    if (!(ctx->signeddata = es_fopenmem (MAX_SIGNEDDATA, "w+b,samethread")))
      return gpg_error_from_syserror ();
  if (data)
    es_fputs (data, ctx->signeddata);

  if (es_ferror (ctx->signeddata))
    return gpg_error_from_syserror ();
  return 0;
}
Esempio n. 4
0
static gpg_error_t
collect_signature (void *cookie, const char *data)
{
  receive_ctx_t ctx = cookie;

  if (!ctx->signature)
    if (!(ctx->signature = es_fopenmem (MAX_SIGNATURE, "w+b,samethread")))
      return gpg_error_from_syserror ();
  if (data)
    es_fputs (data, ctx->signature);

  if (es_ferror (ctx->signature))
    return gpg_error_from_syserror ();

  if (!data)
    {
      verify_signature (ctx);
    }

  return 0;
}
Esempio n. 5
0
static gpg_error_t
collect_encrypted (void *cookie, const char *data)
{
  receive_ctx_t ctx = cookie;

  if (!ctx->encrypted)
    if (!(ctx->encrypted = es_fopenmem (MAX_ENCRYPTED, "w+b,samethread")))
      return gpg_error_from_syserror ();
  if (data)
    es_fputs (data, ctx->encrypted);

  if (es_ferror (ctx->encrypted))
    return gpg_error_from_syserror ();

  if (!data)
    {
      decrypt_data (ctx);
    }

  return 0;
}
Esempio n. 6
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;
}
Esempio n. 7
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);
}
Esempio n. 8
0
static gpg_error_t
new_part (void *cookie, const char *mediatype, const char *mediasubtype)
{
  receive_ctx_t ctx = cookie;
  gpg_error_t err = 0;

  ctx->collect_key_data = 0;
  ctx->collect_wkd_data = 0;

  if (!strcmp (mediatype, "application")
      && !strcmp (mediasubtype, "pgp-keys"))
    {
      log_info ("new '%s/%s' message part\n", mediatype, mediasubtype);
      if (ctx->key_data)
        {
          log_error ("we already got a key - ignoring this part\n");
          err = gpg_error (GPG_ERR_FALSE);
        }
      else
        {
          ctx->key_data = es_fopenmem (0, "w+b");
          if (!ctx->key_data)
            {
              err = gpg_error_from_syserror ();
              log_error ("error allocating space for key: %s\n",
                         gpg_strerror (err));
            }
          else
            {
              ctx->collect_key_data = 1;
              err = gpg_error (GPG_ERR_TRUE); /* We want the part decoded.  */
            }
        }
    }
  else if (!strcmp (mediatype, "application")
           && !strcmp (mediasubtype, "vnd.gnupg.wks"))
    {
      log_info ("new '%s/%s' message part\n", mediatype, mediasubtype);
      if (ctx->wkd_data)
        {
          log_error ("we already got a wkd part - ignoring this part\n");
          err = gpg_error (GPG_ERR_FALSE);
        }
      else
        {
          ctx->wkd_data = es_fopenmem (0, "w+b");
          if (!ctx->wkd_data)
            {
              err = gpg_error_from_syserror ();
              log_error ("error allocating space for key: %s\n",
                         gpg_strerror (err));
            }
          else
            {
              ctx->collect_wkd_data = 1;
              err = gpg_error (GPG_ERR_TRUE); /* We want the part decoded.  */
            }
        }
    }
  else
    {
      log_error ("unexpected '%s/%s' message part\n", mediatype, mediasubtype);
      err = gpg_error (GPG_ERR_FALSE); /* We do not want the part.  */
    }

  return err;
}
Esempio n. 9
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;
}
Esempio n. 10
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;
}
Esempio n. 11
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;
}
Esempio n. 12
0
/* Ask the dirmngr for the submission address of a WKD server for the
 * mail address ADDRSPEC.  On success the submission address is stored
 * at R_ADDRSPEC.  */
gpg_error_t
wkd_get_submission_address (const char *addrspec, char **r_addrspec)
{
  gpg_error_t err;
  assuan_context_t ctx;
  struct wkd_get_parm_s parm;
  char *line = NULL;
  void *vp;
  char *buffer = NULL;
  char *p;

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

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

  line = es_bsprintf ("WKD_GET --submission-address -- %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_fputc (0, parm.memfp);
  if (es_fclose_snatch (parm.memfp, &vp, NULL))
    {
      err = gpg_error_from_syserror ();
      goto leave;
    }
  buffer = vp;
  parm.memfp = NULL;
  p = strchr (buffer, '\n');
  if (p)
    *p = 0;
  trim_spaces (buffer);
  if (!is_valid_mailbox (buffer))
    {
      err = gpg_error (GPG_ERR_INV_USER_ID);
      goto leave;
    }
  *r_addrspec = xtrystrdup (buffer);
  if (!*r_addrspec)
    err = gpg_error_from_syserror ();

 leave:
  es_free (buffer);
  es_fclose (parm.memfp);
  xfree (line);
  assuan_release (ctx);
  return err;
}