Example #1
0
void
write_status_text (int no, const char *text)
{
  if (!statusfp || !status_currently_allowed (no) )
    return;  /* Not enabled or allowed. */

  es_fputs ("[GNUPG:] ", statusfp);
  es_fputs (get_status_string (no), statusfp);
  if ( text )
    {
      es_putc ( ' ', statusfp);
      for (; *text; text++)
        {
          if (*text == '\n')
            es_fputs ("\\n", statusfp);
          else if (*text == '\r')
            es_fputs ("\\r", statusfp);
          else
            es_fputc ( *(const byte *)text, statusfp);
        }
    }
  es_putc ('\n', statusfp);
  if (es_fflush (statusfp) && opt.exit_on_status_write_error)
    g10_exit (0);
}
Example #2
0
static gpg_error_t
part_data (void *cookie, const void *data, size_t datalen)
{
  receive_ctx_t ctx = cookie;

  if (data)
    {
      if (opt.debug)
        log_debug ("part_data: '%.*s'\n", (int)datalen, (const char*)data);
      if (ctx->collect_key_data)
        {
          if (es_write (ctx->key_data, data, datalen, NULL)
              || es_fputs ("\n", ctx->key_data))
            return gpg_error_from_syserror ();
        }
      if (ctx->collect_wkd_data)
        {
          if (es_write (ctx->wkd_data, data, datalen, NULL)
              || es_fputs ("\n", ctx->wkd_data))
            return gpg_error_from_syserror ();
        }
    }
  else
    {
      if (opt.debug)
        log_debug ("part_data: finished\n");
      ctx->collect_key_data = 0;
      ctx->collect_wkd_data = 0;
    }
  return 0;
}
Example #3
0
/* This is a variant of gpgsm_print_name sending it output to an estream. */
void
gpgsm_es_print_name2 (estream_t fp, const char *name, int translate)
{
  const unsigned char *s = (const unsigned char *)name;
  int i;

  if (!s)
    {
      es_fputs (_("[Error - No name]"), fp);
    }
  else if (*s == '<')
    {
      const char *s2 = strchr ( (char*)s+1, '>');

      if (s2)
        {
          if (translate)
            es_write_sanitized_utf8_buffer (fp, s + 1, s2 - (char*)s - 1,
                                            NULL, NULL);
          else
            es_write_sanitized (fp, s + 1, s2 - (char*)s - 1, NULL, NULL);
        }
    }
  else if (*s == '(')
    {
      pretty_es_print_sexp (fp, s, gcry_sexp_canon_len (s, 0, NULL, NULL));
    }
  else if (!((*s >= '0' && *s < '9')
             || (*s >= 'A' && *s <= 'Z')
             || (*s >= 'a' && *s <= 'z')))
    es_fputs (_("[Error - invalid encoding]"), fp);
  else
    {
      struct dn_array_s *dn = parse_dn (s);

      if (!dn)
        es_fputs (_("[Error - invalid DN]"), fp);
      else
        {
          print_dn_parts (NULL, fp, dn, translate);
          for (i=0; dn[i].key; i++)
            {
              xfree (dn[i].key);
              xfree (dn[i].value);
            }
          xfree (dn);
        }
    }
}
Example #4
0
/* Print some info about the certifciate CERT to FP or STREAM */
static void
print_short_info (ksba_cert_t cert, estream_t stream)
{
  char *p;
  ksba_sexp_t sexp;
  int idx;

  for (idx=0; (p = ksba_cert_get_issuer (cert, idx)); idx++)
    {
      es_fputs ((!idx
                 ?   "Issuer ...: "
                 : "\n   aka ...: "), stream);
      gpgsm_es_print_name (stream, p);
      xfree (p);
    }
  es_putc ('\n', stream);

  es_fputs ("Serial ...: ", stream);
  sexp = ksba_cert_get_serial (cert);
  if (sexp)
    {
      int len;
      const unsigned char *s = sexp;

      if (*s == '(')
        {
          s++;
          for (len=0; *s && *s != ':' && digitp (s); s++)
            len = len*10 + atoi_1 (s);
          if (*s == ':')
            es_write_hexstring (stream, s+1, len, 0, NULL);
        }
      xfree (sexp);
    }
  es_putc ('\n', stream);

  for (idx=0; (p = ksba_cert_get_subject (cert, idx)); idx++)
    {
      es_fputs ((!idx
                 ?   "Subject ..: "
                 : "\n    aka ..: "), stream);
      gpgsm_es_print_name (stream, p);
      xfree (p);
    }
  es_putc ('\n', stream);
}
Example #5
0
void
gpgsm_print_time (estream_t fp, ksba_isotime_t t)
{
  if (!t || !*t)
    es_fputs (_("none"), fp);
  else
    es_fprintf (fp, "%.4s-%.2s-%.2s %.2s:%.2s:%s",
                t, t+4, t+6, t+9, t+11, t+13);
}
Example #6
0
/* Write a status line with code NO followed by the outout of the
 * printf style FORMAT.  The caller needs to make sure that LFs and
 * CRs are not printed.  */
void
wks_write_status (int no, const char *format, ...)
{
  va_list arg_ptr;

  if (!statusfp)
    return;  /* Not enabled.  */

  es_fputs ("[GNUPG:] ", statusfp);
  es_fputs (get_status_string (no), statusfp);
  if (format)
    {
      es_putc (' ', statusfp);
      va_start (arg_ptr, format);
      es_vfprintf (statusfp, format, arg_ptr);
      va_end (arg_ptr);
    }
  es_putc ('\n', statusfp);
}
Example #7
0
/* Print the first element of an S-Expression. */
void
gpgsm_print_serial (estream_t fp, ksba_const_sexp_t sn)
{
  const char *p = (const char *)sn;
  unsigned long n;
  char *endp;

  if (!p)
    es_fputs (_("none"), fp);
  else if (*p != '(')
    es_fputs ("[Internal error - not an S-expression]", fp);
  else
    {
      p++;
      n = strtoul (p, &endp, 10);
      p = endp;
      if (*p++ != ':')
        es_fputs ("[Internal Error - invalid S-expression]", fp);
      else
        es_write_hexstring (fp, p, n, 0, NULL);
    }
}
Example #8
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;
}
Example #9
0
/* Helper for ks_hkp_put.  */
static gpg_error_t
put_post_cb (void *opaque, http_t http)
{
  struct put_post_parm_s *parm = opaque;
  gpg_error_t err = 0;
  estream_t fp;
  size_t len;

  fp = http_get_write_ptr (http);
  len = strlen (parm->datastring);

  es_fprintf (fp,
              "Content-Type: application/x-www-form-urlencoded\r\n"
              "Content-Length: %zu\r\n", len+8 /* 8 is for "keytext" */);
  http_start_data (http);
  if (es_fputs ("keytext=", fp) || es_write (fp, parm->datastring, len, NULL))
    err = gpg_error_from_syserror ();
  return err;
}
Example #10
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;
}
Example #11
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;
}
Example #12
0
/* Print the S-Expression in BUF to extended STREAM, which has a valid
   length of BUFLEN, as a human readable string in one line to FP. */
static void
pretty_es_print_sexp (estream_t fp, const unsigned char *buf, size_t buflen)
{
  size_t len;
  gcry_sexp_t sexp;
  char *result, *p;

  if ( gcry_sexp_sscan (&sexp, NULL, (const char*)buf, buflen) )
    {
      es_fputs (_("[Error - invalid encoding]"), fp);
      return;
    }
  len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_ADVANCED, NULL, 0);
  assert (len);
  result = xtrymalloc (len);
  if (!result)
    {
      es_fputs (_("[Error - out of core]"), fp);
      gcry_sexp_release (sexp);
      return;
    }
  len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_ADVANCED, result, len);
  assert (len);
  for (p = result; len; len--, p++)
    {
      if (*p == '\n')
        {
          if (len > 1) /* Avoid printing the trailing LF. */
            es_fputs ("\\n", fp);
        }
      else if (*p == '\r')
        es_fputs ("\\r", fp);
      else if (*p == '\v')
        es_fputs ("\\v", fp);
      else if (*p == '\t')
        es_fputs ("\\t", fp);
      else
        es_putc (*p, fp);
    }
  xfree (result);
  gcry_sexp_release (sexp);
}
Example #13
0
/* Send an HTTP request.  On success returns an estream object at
   R_FP.  HOSTPORTSTR is only used for diagnostics.  If HTTPHOST is
   not NULL it will be used as HTTP "Host" header.  If POST_CB is not
   NULL a post request is used and that callback is called to allow
   writing the post data.  */
static gpg_error_t
send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
              const char *httphost, unsigned int httpflags,
              gpg_error_t (*post_cb)(void *, http_t), void *post_cb_value,
              estream_t *r_fp)
{
  gpg_error_t err;
  http_session_t session = NULL;
  http_t http = NULL;
  int redirects_left = MAX_REDIRECTS;
  estream_t fp = NULL;
  char *request_buffer = NULL;

  *r_fp = NULL;

  err = http_session_new (&session, NULL);
  if (err)
    goto leave;
  http_session_set_log_cb (session, cert_log_cb);

 once_more:
  err = http_open (&http,
                   post_cb? HTTP_REQ_POST : HTTP_REQ_GET,
                   request,
                   httphost,
                   /* fixme: AUTH */ NULL,
                   (httpflags | (opt.honor_http_proxy? HTTP_FLAG_TRY_PROXY:0)),
                   ctrl->http_proxy,
                   session,
                   NULL,
                   /*FIXME curl->srvtag*/NULL);
  if (!err)
    {
      fp = http_get_write_ptr (http);
      /* Avoid caches to get the most recent copy of the key.  We set
         both the Pragma and Cache-Control versions of the header, so
         we're good with both HTTP 1.0 and 1.1.  */
      es_fputs ("Pragma: no-cache\r\n"
                "Cache-Control: no-cache\r\n", fp);
      if (post_cb)
        err = post_cb (post_cb_value, http);
      if (!err)
        {
          http_start_data (http);
          if (es_ferror (fp))
            err = gpg_error_from_syserror ();
        }
    }
  if (err)
    {
      /* Fixme: After a redirection we show the old host name.  */
      log_error (_("error connecting to '%s': %s\n"),
                 hostportstr, gpg_strerror (err));
      goto leave;
    }

  /* Wait for the response.  */
  dirmngr_tick (ctrl);
  err = http_wait_response (http);
  if (err)
    {
      log_error (_("error reading HTTP response for '%s': %s\n"),
                 hostportstr, gpg_strerror (err));
      goto leave;
    }

  if (http_get_tls_info (http, NULL))
    {
      /* Update the httpflags so that a redirect won't fallback to an
         unencrypted connection.  */
      httpflags |= HTTP_FLAG_FORCE_TLS;
    }

  switch (http_get_status_code (http))
    {
    case 200:
      err = 0;
      break; /* Success.  */

    case 301:
    case 302:
    case 307:
      {
        const char *s = http_get_header (http, "Location");

        log_info (_("URL '%s' redirected to '%s' (%u)\n"),
                  request, s?s:"[none]", http_get_status_code (http));
        if (s && *s && redirects_left-- )
          {
            xfree (request_buffer);
            request_buffer = xtrystrdup (s);
            if (request_buffer)
              {
                request = request_buffer;
                http_close (http, 0);
                http = NULL;
                goto once_more;
              }
            err = gpg_error_from_syserror ();
          }
        else
          err = gpg_error (GPG_ERR_NO_DATA);
        log_error (_("too many redirections\n"));
      }
      goto leave;

    default:
      log_error (_("error accessing '%s': http status %u\n"),
                 request, http_get_status_code (http));
      err = gpg_error (GPG_ERR_NO_DATA);
      goto leave;
    }

  /* FIXME: We should register a permanent redirection and whether a
     host has ever used TLS so that future calls will always use
     TLS. */

  fp = http_get_read_ptr (http);
  if (!fp)
    {
      err = gpg_error (GPG_ERR_BUG);
      goto leave;
    }

  /* Return the read stream and close the HTTP context.  */
  *r_fp = fp;
  http_close (http, 1);
  http = NULL;

 leave:
  http_close (http, 0);
  http_session_release (session);
  xfree (request_buffer);
  return err;
}
Example #14
0
/* Get the key from URL which is expected to specify a http style
   scheme.  On success R_FP has an open stream to read the data.  */
gpg_error_t
ks_http_fetch (ctrl_t ctrl, const char *url, estream_t *r_fp)
{
  gpg_error_t err;
  http_session_t session = NULL;
  http_t http = NULL;
  int redirects_left = MAX_REDIRECTS;
  estream_t fp = NULL;
  char *request_buffer = NULL;

  err = http_session_new (&session, NULL);
  if (err)
    goto leave;
  http_session_set_log_cb (session, cert_log_cb);

  *r_fp = NULL;
 once_more:
  err = http_open (&http,
                   HTTP_REQ_GET,
                   url,
                   /* httphost */ NULL,
                   /* fixme: AUTH */ NULL,
                   0,
                   /* fixme: proxy*/ NULL,
                   session,
                   NULL,
                   /*FIXME curl->srvtag*/NULL);
  if (!err)
    {
      fp = http_get_write_ptr (http);
      /* Avoid caches to get the most recent copy of the key.  We set
         both the Pragma and Cache-Control versions of the header, so
         we're good with both HTTP 1.0 and 1.1.  */
      es_fputs ("Pragma: no-cache\r\n"
                "Cache-Control: no-cache\r\n", fp);
      http_start_data (http);
      if (es_ferror (fp))
        err = gpg_error_from_syserror ();
    }
  if (err)
    {
      /* Fixme: After a redirection we show the old host name.  */
      log_error (_("error connecting to '%s': %s\n"),
                 url, gpg_strerror (err));
      goto leave;
    }

  /* Wait for the response.  */
  dirmngr_tick (ctrl);
  err = http_wait_response (http);
  if (err)
    {
      log_error (_("error reading HTTP response for '%s': %s\n"),
                 url, gpg_strerror (err));
      goto leave;
    }

  switch (http_get_status_code (http))
    {
    case 200:
      err = 0;
      break; /* Success.  */

    case 301:
    case 302:
    case 307:
      {
        const char *s = http_get_header (http, "Location");

        log_info (_("URL '%s' redirected to '%s' (%u)\n"),
                  url, s?s:"[none]", http_get_status_code (http));
        if (s && *s && redirects_left-- )
          {
            xfree (request_buffer);
            request_buffer = xtrystrdup (s);
            if (request_buffer)
              {
                url = request_buffer;
                http_close (http, 0);
                http = NULL;
                goto once_more;
              }
            err = gpg_error_from_syserror ();
          }
        else
          err = gpg_error (GPG_ERR_NO_DATA);
        log_error (_("too many redirections\n"));
      }
      goto leave;

    default:
      log_error (_("error accessing '%s': http status %u\n"),
                 url, http_get_status_code (http));
      err = gpg_error (GPG_ERR_NO_DATA);
      goto leave;
    }

  fp = http_get_read_ptr (http);
  if (!fp)
    {
      err = gpg_error (GPG_ERR_BUG);
      goto leave;
    }

  /* Return the read stream and close the HTTP context.  */
  *r_fp = fp;
  http_close (http, 1);
  http = NULL;

 leave:
  http_close (http, 0);
  http_session_release (session);
  xfree (request_buffer);
  return err;
}
Example #15
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;
}
Example #16
0
/* Insert the given fpr into our trustdb.  We expect FPR to be an all
   uppercase hexstring of 40 characters. FLAG is either 'P' or 'C'.
   This function does first check whether that key has already been put
   into the trustdb and returns success in this case.  Before a FPR
   actually gets inserted, the user is asked by means of the Pinentry
   whether this is actual want he wants to do.  */
gpg_error_t
agent_marktrusted (ctrl_t ctrl, const char *name, const char *fpr, int flag)
{
  gpg_error_t err = 0;
  char *desc;
  char *fname;
  estream_t fp;
  char *fprformatted;
  char *nameformatted;
  int is_disabled;
  int yes_i_trust;

  /* Check whether we are at all allowed to modify the trustlist.
     This is useful so that the trustlist may be a symlink to a global
     trustlist with only admin priviliges to modify it.  Of course
     this is not a secure way of denying access, but it avoids the
     usual clicking on an Okay button most users are used to. */
  fname = make_filename (opt.homedir, "trustlist.txt", NULL);
  if ( access (fname, W_OK) && errno != ENOENT)
    {
      xfree (fname);
      return gpg_error (GPG_ERR_EPERM);
    }
  xfree (fname);

  if (!agent_istrusted (ctrl, fpr, &is_disabled))
    {
      return 0; /* We already got this fingerprint.  Silently return
                   success. */
    }

  /* This feature must explicitly been enabled. */
  if (!opt.allow_mark_trusted)
    return gpg_error (GPG_ERR_NOT_SUPPORTED);

  if (is_disabled)
    {
      /* There is an disabled entry in the trustlist.  Return an error
         so that the user won't be asked again for that one.  Changing
         this flag with the integrated marktrusted feature is and will
         not be made possible.  */
      return gpg_error (GPG_ERR_NOT_TRUSTED);
    }


  /* Insert a new one. */
  nameformatted = reformat_name (name, "%0A   ");
  if (!nameformatted)
    return gpg_error_from_syserror ();

  /* First a general question whether this is trusted.  */
  desc = xtryasprintf (
                /* TRANSLATORS: This prompt is shown by the Pinentry
                   and has one special property: A "%%0A" is used by
                   Pinentry to insert a line break.  The double
                   percent sign is actually needed because it is also
                   a printf format string.  If you need to insert a
                   plain % sign, you need to encode it as "%%25".  The
                   "%s" gets replaced by the name as stored in the
                   certificate. */
                _("Do you ultimately trust%%0A"
                  "  \"%s\"%%0A"
                  "to correctly certify user certificates?"),
                nameformatted);
  if (!desc)
    {
      xfree (nameformatted);
      return out_of_core ();
    }
  err = agent_get_confirmation (ctrl, desc, _("Yes"), _("No"), 1);
  xfree (desc);
  if (!err)
    yes_i_trust = 1;
  else if (gpg_err_code (err) == GPG_ERR_NOT_CONFIRMED)
    yes_i_trust = 0;
  else
    {
      xfree (nameformatted);
      return err;
    }


  fprformatted = insert_colons (fpr);
  if (!fprformatted)
    {
      xfree (nameformatted);
      return out_of_core ();
    }

  /* If the user trusts this certificate he has to verify the
     fingerprint of course.  */
  if (yes_i_trust)
    {
      desc = xtryasprintf
        (
         /* TRANSLATORS: This prompt is shown by the Pinentry and has
            one special property: A "%%0A" is used by Pinentry to
            insert a line break.  The double percent sign is actually
            needed because it is also a printf format string.  If you
            need to insert a plain % sign, you need to encode it as
            "%%25".  The second "%s" gets replaced by a hexdecimal
            fingerprint string whereas the first one receives the name
            as stored in the certificate. */
         _("Please verify that the certificate identified as:%%0A"
           "  \"%s\"%%0A"
           "has the fingerprint:%%0A"
           "  %s"), nameformatted, fprformatted);
      if (!desc)
        {
          xfree (fprformatted);
          xfree (nameformatted);
          return out_of_core ();
        }

      /* TRANSLATORS: "Correct" is the label of a button and intended
         to be hit if the fingerprint matches the one of the CA.  The
         other button is "the default "Cancel" of the Pinentry. */
      err = agent_get_confirmation (ctrl, desc, _("Correct"), _("Wrong"), 1);
      xfree (desc);
      if (gpg_err_code (err) == GPG_ERR_NOT_CONFIRMED)
        yes_i_trust = 0;
      else if (err)
        {
          xfree (fprformatted);
          xfree (nameformatted);
          return err;
        }
    }


  /* Now check again to avoid duplicates.  We take the lock to make
     sure that nobody else plays with our file and force a reread.  */
  lock_trusttable ();
  agent_reload_trustlist ();
  if (!agent_istrusted (ctrl, fpr, &is_disabled) || is_disabled)
    {
      unlock_trusttable ();
      xfree (fprformatted);
      xfree (nameformatted);
      return is_disabled? gpg_error (GPG_ERR_NOT_TRUSTED) : 0;
    }

  fname = make_filename (opt.homedir, "trustlist.txt", NULL);
  if ( access (fname, F_OK) && errno == ENOENT)
    {
      fp = es_fopen (fname, "wx,mode=-rw-r");
      if (!fp)
        {
          err = gpg_error_from_syserror ();
          log_error ("can't create `%s': %s\n", fname, gpg_strerror (err));
          xfree (fname);
          unlock_trusttable ();
          xfree (fprformatted);
          xfree (nameformatted);
          return err;
        }
      es_fputs (headerblurb, fp);
      es_fclose (fp);
    }
  fp = es_fopen (fname, "a+,mode=-rw-r");
  if (!fp)
    {
      err = gpg_error_from_syserror ();
      log_error ("can't open `%s': %s\n", fname, gpg_strerror (err));
      xfree (fname);
      unlock_trusttable ();
      xfree (fprformatted);
      xfree (nameformatted);
      return err;
    }

  /* Append the key. */
  es_fputs ("\n# ", fp);
  xfree (nameformatted);
  nameformatted = reformat_name (name, "\n# ");
  if (!nameformatted || strchr (name, '\n'))
    {
      /* Note that there should never be a LF in NAME but we better
         play safe and print a sanitized version in this case.  */
      es_write_sanitized (fp, name, strlen (name), NULL, NULL);
    }
  else
    es_fputs (nameformatted, fp);
  es_fprintf (fp, "\n%s%s %c\n", yes_i_trust?"":"!", fprformatted, flag);
  if (es_ferror (fp))
    err = gpg_error_from_syserror ();

  if (es_fclose (fp))
    err = gpg_error_from_syserror ();

  agent_reload_trustlist ();
  xfree (fname);
  unlock_trusttable ();
  xfree (fprformatted);
  xfree (nameformatted);
  return err;
}
Example #17
0
/*
 * Write a status line with a buffer using %XX escapes.  If WRAP is >
 * 0 wrap the line after this length.  If STRING is not NULL it will
 * be prepended to the buffer, no escaping is done for string.
 * A wrap of -1 forces spaces not to be encoded as %20.
 */
void
write_status_text_and_buffer (int no, const char *string,
                              const char *buffer, size_t len, int wrap)
{
  const char *s, *text;
  int esc, first;
  int lower_limit = ' ';
  size_t n, count, dowrap;

  if (!statusfp || !status_currently_allowed (no))
    return;  /* Not enabled or allowed. */

  if (wrap == -1)
    {
      lower_limit--;
      wrap = 0;
    }

  text = get_status_string (no);
  count = dowrap = first = 1;
  do
    {
      if (dowrap)
        {
          es_fprintf (statusfp, "[GNUPG:] %s ", text);
          count = dowrap = 0;
          if (first && string)
            {
              es_fputs (string, statusfp);
              count += strlen (string);
              /* Make sure that there is a space after the string.  */
              if (*string && string[strlen (string)-1] != ' ')
                {
                  es_putc (' ', statusfp);
                  count++;
                }
            }
          first = 0;
        }
      for (esc=0, s=buffer, n=len; n && !esc; s++, n--)
        {
          if (*s == '%' || *(const byte*)s <= lower_limit
              || *(const byte*)s == 127 )
            esc = 1;
          if (wrap && ++count > wrap)
            {
              dowrap=1;
              break;
            }
        }
      if (esc)
        {
          s--; n++;
        }
      if (s != buffer)
        es_fwrite (buffer, s-buffer, 1, statusfp);
      if ( esc )
        {
          es_fprintf (statusfp, "%%%02X", *(const byte*)s );
          s++; n--;
        }
      buffer = s;
      len = n;
      if (dowrap && len)
        es_putc ('\n', statusfp);
    }
  while (len);

  es_putc ('\n',statusfp);
  if (es_fflush (statusfp) && opt.exit_on_status_write_error)
    g10_exit (0);
}
Example #18
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 #19
0
/* gpgconf main. */
int
main (int argc, char **argv)
{
  ARGPARSE_ARGS pargs;
  const char *fname;
  int no_more_options = 0;
  enum cmd_and_opt_values cmd = 0;
  estream_t outfp = NULL;

  early_system_init ();
  gnupg_reopen_std (GPGCONF_NAME);
  set_strusage (my_strusage);
  log_set_prefix (GPGCONF_NAME, 1);

  /* Make sure that our subsystems are ready.  */
  i18n_init();
  init_common_subsystems (&argc, &argv);

  /* Parse the command line. */
  pargs.argc  = &argc;
  pargs.argv  = &argv;
  pargs.flags =  1;  /* Do not remove the args.  */
  while (!no_more_options && optfile_parse (NULL, NULL, NULL, &pargs, opts))
    {
      switch (pargs.r_opt)
        {
        case oOutput:    opt.outfile = pargs.r.ret_str; break;
	case oQuiet:     opt.quiet = 1; break;
        case oDryRun:    opt.dry_run = 1; break;
        case oRuntime:
	  opt.runtime = 1;
	  break;
        case oVerbose:   opt.verbose++; break;
        case oNoVerbose: opt.verbose = 0; break;

	case aListDirs:
        case aListComponents:
        case aCheckPrograms:
        case aListOptions:
        case aChangeOptions:
        case aCheckOptions:
        case aApplyDefaults:
        case aListConfig:
        case aCheckConfig:
        case aReload:
        case aLaunch:
        case aKill:
	  cmd = pargs.r_opt;
	  break;

        default: pargs.err = 2; break;
	}
    }

  if (log_get_errorcount (0))
    exit (2);

  /* Print a warning if an argument looks like an option.  */
  if (!opt.quiet && !(pargs.flags & ARGPARSE_FLAG_STOP_SEEN))
    {
      int i;

      for (i=0; i < argc; i++)
        if (argv[i][0] == '-' && argv[i][1] == '-')
          log_info (_("Note: '%s' is not considered an option\n"), argv[i]);
    }

  fname = argc ? *argv : NULL;

  switch (cmd)
    {
    case aListComponents:
    default:
      /* List all components. */
      gc_component_list_components (get_outfp (&outfp));
      break;

    case aCheckPrograms:
      /* Check all programs. */
      gc_check_programs (get_outfp (&outfp));
      break;

    case aListOptions:
    case aChangeOptions:
    case aCheckOptions:
      if (!fname)
	{
	  es_fprintf (es_stderr, _("usage: %s [options] "), GPGCONF_NAME);
	  es_putc ('\n', es_stderr);
	  es_fputs (_("Need one component argument"), es_stderr);
	  es_putc ('\n', es_stderr);
	  exit (2);
	}
      else
	{
	  int idx = gc_component_find (fname);
	  if (idx < 0)
	    {
	      es_fputs (_("Component not found"), es_stderr);
	      es_putc ('\n', es_stderr);
	      exit (1);
	    }
          if (cmd == aCheckOptions)
	    gc_component_check_options (idx, get_outfp (&outfp), NULL);
          else
            {
              gc_component_retrieve_options (idx);
              if (gc_process_gpgconf_conf (NULL, 1, 0, NULL))
                exit (1);
              if (cmd == aListOptions)
                gc_component_list_options (idx, get_outfp (&outfp));
              else if (cmd == aChangeOptions)
                gc_component_change_options (idx, es_stdin, get_outfp (&outfp));
            }
	}
      break;

    case aLaunch:
    case aKill:
      if (!fname)
	{
	  es_fprintf (es_stderr, _("usage: %s [options] "), GPGCONF_NAME);
	  es_putc ('\n', es_stderr);
	  es_fputs (_("Need one component argument"), es_stderr);
	  es_putc ('\n', es_stderr);
	  exit (2);
	}
      else
        {
          /* Launch/Kill a given component.  */
          int idx;

          idx = gc_component_find (fname);
          if (idx < 0)
            {
              es_fputs (_("Component not found"), es_stderr);
              es_putc ('\n', es_stderr);
              exit (1);
            }
          else if (cmd == aLaunch)
            {
              if (gc_component_launch (idx))
                exit (1);
            }
          else
            {
              /* We don't error out if the kill failed because this
                 command should do nothing if the component is not
                 running.  */
              gc_component_kill (idx);
            }
        }
      break;

    case aReload:
      if (!fname)
	{
          /* Reload all.  */
          gc_component_reload (-1);
	}
      else
        {
          /* Reload given component.  */
          int idx;

          idx = gc_component_find (fname);
          if (idx < 0)
            {
              es_fputs (_("Component not found"), es_stderr);
              es_putc ('\n', es_stderr);
              exit (1);
            }
          else
            {
              gc_component_reload (idx);
            }
        }
      break;

    case aListConfig:
      if (gc_process_gpgconf_conf (fname, 0, 0, get_outfp (&outfp)))
        exit (1);
      break;

    case aCheckConfig:
      if (gc_process_gpgconf_conf (fname, 0, 0, NULL))
        exit (1);
      break;

    case aApplyDefaults:
      if (fname)
	{
	  es_fprintf (es_stderr, _("usage: %s [options] "), GPGCONF_NAME);
	  es_putc ('\n', es_stderr);
	  es_fputs (_("No argument allowed"), es_stderr);
	  es_putc ('\n', es_stderr);
	  exit (2);
	}
      gc_component_retrieve_options (-1);
      if (gc_process_gpgconf_conf (NULL, 1, 1, NULL))
        exit (1);
      break;

    case aListDirs:
      /* Show the system configuration directories for gpgconf.  */
      get_outfp (&outfp);
      es_fprintf (outfp, "sysconfdir:%s\n",
                  gc_percent_escape (gnupg_sysconfdir ()));
      es_fprintf (outfp, "bindir:%s\n",
                  gc_percent_escape (gnupg_bindir ()));
      es_fprintf (outfp, "libexecdir:%s\n",
                  gc_percent_escape (gnupg_libexecdir ()));
      es_fprintf (outfp, "libdir:%s\n",
                  gc_percent_escape (gnupg_libdir ()));
      es_fprintf (outfp, "datadir:%s\n",
                  gc_percent_escape (gnupg_datadir ()));
      es_fprintf (outfp, "localedir:%s\n",
                  gc_percent_escape (gnupg_localedir ()));

      if (dirmngr_user_socket_name ())
        {
          es_fprintf (outfp, "dirmngr-socket:%s\n",
                      gc_percent_escape (dirmngr_user_socket_name ()));
          es_fprintf (outfp, "dirmngr-sys-socket:%s\n",
                      gc_percent_escape (dirmngr_sys_socket_name ()));
        }
      else
        {
          es_fprintf (outfp, "dirmngr-socket:%s\n",
                      gc_percent_escape (dirmngr_sys_socket_name ()));
        }

      {
        char *tmp = make_filename (default_homedir (),
                                   GPG_AGENT_SOCK_NAME, NULL);
        es_fprintf (outfp, "agent-socket:%s\n", gc_percent_escape (tmp));
        xfree (tmp);
      }
      {
        /* We need to use make_filename to expand a possible "~/".  */
        char *tmp = make_filename (default_homedir (), NULL);
        es_fprintf (outfp, "homedir:%s\n", gc_percent_escape (tmp));
        xfree (tmp);
      }
      break;
    }

  if (outfp != es_stdout)
    if (es_fclose (outfp))
      gc_error (1, errno, "error closing '%s'", opt.outfile);

  return 0;
}