Beispiel #1
0
/* If STRING includes known @FOO@ macros, replace these macros and
   return a new static string.  Warning: STRING must have been
   allocated statically.  Note that this function allocates memory
   which will not be released (similar to gettext).  */
const char *
map_static_macro_string (const char *string)
{
  const char *s, *s2, *s3, *value;
  membuf_t mb;
  char *p;

  if ((s = already_mapped (string)))
    return s;
  s = string;
  value = find_macro (s, &s2, &s3);
  if (!value)
    return string; /* No macros at all.  */

  init_membuf (&mb, strlen (string) + 100);
  do
    {
      put_membuf (&mb, s, s2 - s);
      put_membuf_str (&mb, value);
      s = s3 + 1;
    }
  while ((value = find_macro (s, &s2, &s3)));
  put_membuf_str (&mb, s);
  put_membuf (&mb, "", 1);

  p = get_membuf_shrink (&mb, NULL);
  if (!p)
    log_fatal ("map_static_macro_string failed: %s\n", strerror (errno));

  return store_mapping (string, p);
}
Beispiel #2
0
/* The thread started by start_reader.  */
static void *
reader_thread_main (void *arg)
{
  struct reader_thread_parms *parm = arg;
  char buffer[4096];
  int nread;

  while ( (nread = npth_read (parm->fd, buffer, sizeof buffer)) )
    {
      if (nread < 0)
        {
          if (errno == EINTR)
            continue;
          *parm->err_addr = gpg_error_from_syserror ();
          break;  /* Read error.  */
        }

      put_membuf (parm->mb, buffer, nread);
    }

  if (close (parm->fd))
    log_error ("closing reader fd %d failed: %s\n", parm->fd, strerror (errno));
  xfree (parm);
  return NULL;
}
Beispiel #3
0
/* Return the S2K iteration count as computed by gpg-agent.  */
gpg_error_t
agent_get_s2k_count (unsigned long *r_count)
{
    gpg_error_t err;
    membuf_t data;
    char *buf;

    *r_count = 0;

    err = start_agent (0);
    if (err)
        return err;

    init_membuf (&data, 32);
    err = assuan_transact (agent_ctx, "GETINFO s2k_count",
                           membuf_data_cb, &data,
                           NULL, NULL, NULL, NULL);
    if (err)
        xfree (get_membuf (&data, NULL));
    else
    {
        put_membuf (&data, "", 1);
        buf = get_membuf (&data, NULL);
        if (!buf)
            err = gpg_error_from_syserror ();
        else
        {
            *r_count = strtoul (buf, NULL, 10);
            xfree (buf);
        }
    }
    return err;
}
Beispiel #4
0
static gpg_error_t
scd_atr_data_cb (void *opaque, const void *data, size_t datalen)
{
  membuf_t *mb = opaque;

  put_membuf (mb, data, datalen);
  return 0;
}
static gpg_error_t
get_cached_cert_data_cb (void *opaque, const void *buffer, size_t length)
{
  struct membuf *mb = opaque;

  if (buffer)
    put_membuf (mb, buffer, length);
  return 0;
}
Beispiel #6
0
static gpg_error_t
membuf_data_cb (void *opaque, const void *buffer, size_t length)
{
    membuf_t *data = opaque;

    if (buffer)
        put_membuf (data, buffer, length);
    return 0;
}
Beispiel #7
0
/* Use the assuan machinery to read the ATR.  */
static void
reload_data (GpaCMUnknown *card)
{
  gpg_error_t err, operr;
  char command[100];
  gpgme_ctx_t gpgagent;
  membuf_t mb;
  char *buf;

  gpgagent = GPA_CM_OBJECT (card)->agent_ctx;
  g_return_if_fail (gpgagent);

  card->reloading++;

  init_membuf (&mb, 512);

  err = gpgme_op_assuan_transact_ext (gpgagent,
                                      "SCD APDU --dump-atr",
                                      scd_atr_data_cb, &mb,
                                      NULL, NULL, NULL, NULL, &operr);
  if (!err)
    err = operr;

  if (!err)
    {
      put_membuf (&mb, "", 1);
      buf = get_membuf (&mb, NULL);
      if (buf)
        {
          buf = g_strdup_printf ("\n%s\n%s",
                                 _("The ATR of the card is:"),
                                 buf);
          gtk_label_set_text (GTK_LABEL (card->label), buf);
          g_free (buf);
        }
      else
        gtk_label_set_text (GTK_LABEL (card->label), "");
    }
  else
    {
      g_free (get_membuf (&mb, NULL));

      if (gpg_err_code (err) == GPG_ERR_CARD_NOT_PRESENT)
        ; /* Lost the card.  */
      else
        g_debug ("assuan command `%s' failed: %s <%s>\n",
                 command, gpg_strerror (err), gpg_strsource (err));
      gtk_label_set_text (GTK_LABEL (card->label), "");
    }
  card->reloading--;
}
Beispiel #8
0
/* The thread started by start_reader.  */
static void *
reader_thread_main (void *arg)
{
  gpg_error_t err = 0;
  struct reader_thread_parms *parm = arg;
  char buffer[4096];
  int nread;

  while ( (nread = npth_read (parm->fd, buffer, sizeof buffer)) )
    {
      if (nread < 0)
        {
          if (errno == EINTR)
            continue;
          err = my_error_from_syserror ();
          break;  /* Read error.  */
        }

      if (parm->stream)
        {
          const char *p = buffer;
          size_t nwritten;
          while (nread)
            {
              err = es_write (parm->stream, p, nread, &nwritten);
              if (err)
                {
                  log_error ("writing stream failed: %s\n",
                             gpg_strerror (err));
                  goto leave;
                }
              nread -= nwritten;
              p += nwritten;
            }
        }
      else
        put_membuf (parm->mb, buffer, nread);
    }

 leave:
  *parm->err_addr = err;
  if (close (parm->fd))
    log_error ("closing reader fd %d failed: %s\n", parm->fd, strerror (errno));
  xfree (parm);
  return NULL;
}
Beispiel #9
0
/* Lookup helpers*/
static gpg_error_t
lookup_cb (void *opaque, const void *buffer, size_t length)
{
  struct lookup_parm_s *parm = opaque;
  size_t len;
  char *buf;
  ksba_cert_t cert;
  int rc;

  if (parm->error)
    return 0;

  if (buffer)
    {
      put_membuf (&parm->data, buffer, length);
      return 0;
    }
  /* END encountered - process what we have */
  buf = get_membuf (&parm->data, &len);
  if (!buf)
    {
      parm->error = gpg_error (GPG_ERR_ENOMEM);
      return 0;
    }

  rc = ksba_cert_new (&cert);
  if (rc)
    {
      parm->error = rc;
      return 0;
    }
  rc = ksba_cert_init_from_mem (cert, buf, len);
  if (rc)
    {
      log_error ("failed to parse a certificate: %s\n", gpg_strerror (rc));
    }
  else
    {
      parm->cb (parm->cb_value, cert);
    }

  ksba_cert_release (cert);
  init_membuf (&parm->data, 4096);
  return 0;
}
Beispiel #10
0
Datei: cardman.c Projekt: gpg/gpa
/* Fill the app_selection box with the available applications.  */
static void
setup_app_selector (GpaCardManager *cardman)
{
  gpg_error_t err, operr;
  membuf_t mb;
  char *string;
  char *p, *p0, *p1;

  if (!cardman->gpgagent || !cardman->app_selector)
    return;

  init_membuf (&mb, 256);

  err = gpgme_op_assuan_transact_ext (cardman->gpgagent,
                                      "SCD GETINFO app_list",
                                      setup_app_selector_data_cb, &mb,
                                      NULL, NULL, NULL, NULL, &operr);
  if (err || operr)
    {
      g_free (get_membuf (&mb, NULL));
      return;
    }
  /* Make sure the data is a string and get it. */
  put_membuf (&mb, "", 1);
  string = get_membuf (&mb, NULL);
  if (!string)
    return; /* Out of core.  */

  for (p=p0=string; *p; p++)
    {
      if (*p == '\n')
        {
          *p = 0;
          p1 = strchr (p0, ':');
          if (p1)
            *p1 = 0;
          gtk_combo_box_append_text
            (GTK_COMBO_BOX (cardman->app_selector), p0);
          if (p[1])
            p0 = p+1;
        }
    }

  g_free (string);
}
Beispiel #11
0
/* Expands %i and %o in the args to the full temp files within the
   temp directory. */
static int 
expand_args(struct exec_info *info,const char *args_in)
{
  const char *ch = args_in;
  membuf_t command;

  info->flags.use_temp_files=0;
  info->flags.keep_temp_files=0;

  if(DBG_EXTPROG)
    log_debug("expanding string \"%s\"\n",args_in);

  init_membuf (&command, 100);

  while(*ch!='\0')
    {
      if(*ch=='%')
	{
	  char *append=NULL;

	  ch++;

	  switch(*ch)
	    {
	    case 'O':
	      info->flags.keep_temp_files=1;
	      /* fall through */

	    case 'o': /* out */
	      if(!info->flags.madedir)
		{
		  if(make_tempdir(info))
		    goto fail;
		}
	      append=info->tempfile_out;
	      info->flags.use_temp_files=1;
	      break;

	    case 'I':
	      info->flags.keep_temp_files=1;
	      /* fall through */

	    case 'i': /* in */
	      if(!info->flags.madedir)
		{
		  if(make_tempdir(info))
		    goto fail;
		}
	      append=info->tempfile_in;
	      info->flags.use_temp_files=1;
	      break;

	    case '%':
	      append="%";
	      break;
	    }

	  if(append)
            put_membuf_str (&command, append);
	}
      else
        put_membuf (&command, ch, 1);

      ch++;
    }

  put_membuf (&command, "", 1);  /* Terminate string.  */

  info->command = get_membuf (&command, NULL);
  if (!info->command)
    return gpg_error_from_syserror ();

  if(DBG_EXTPROG)
    log_debug("args expanded to \"%s\", use %u, keep %u\n",info->command,
	      info->flags.use_temp_files,info->flags.keep_temp_files);

  return 0;

 fail:
  xfree (get_membuf (&command, NULL));
  return G10ERR_GENERAL;
}
Beispiel #12
0
/* Note: All strings shall be UTF-8. On success the caller needs to
   free the string stored at R_PASSPHRASE. On error NULL will be
   stored at R_PASSPHRASE and an appropriate fpf error code
   returned. */
gpg_error_t
agent_get_passphrase (const char *cache_id,
                      const char *err_msg,
                      const char *prompt,
                      const char *desc_msg,
                      int repeat,
                      int check,
                      char **r_passphrase)
{
    int rc;
    char line[ASSUAN_LINELENGTH];
    char *arg1 = NULL;
    char *arg2 = NULL;
    char *arg3 = NULL;
    char *arg4 = NULL;
    membuf_t data;

    *r_passphrase = NULL;

    rc = start_agent (0);
    if (rc)
        return rc;

    /* Check that the gpg-agent understands the repeat option.  */
    if (assuan_transact (agent_ctx,
                         "GETINFO cmd_has_option GET_PASSPHRASE repeat",
                         NULL, NULL, NULL, NULL, NULL, NULL))
        return gpg_error (GPG_ERR_NOT_SUPPORTED);

    if (cache_id && *cache_id)
        if (!(arg1 = percent_plus_escape (cache_id)))
            goto no_mem;
    if (err_msg && *err_msg)
        if (!(arg2 = percent_plus_escape (err_msg)))
            goto no_mem;
    if (prompt && *prompt)
        if (!(arg3 = percent_plus_escape (prompt)))
            goto no_mem;
    if (desc_msg && *desc_msg)
        if (!(arg4 = percent_plus_escape (desc_msg)))
            goto no_mem;

    snprintf (line, DIM(line)-1,
              "GET_PASSPHRASE --data --repeat=%d%s -- %s %s %s %s",
              repeat,
              check? " --check --qualitybar":"",
              arg1? arg1:"X",
              arg2? arg2:"X",
              arg3? arg3:"X",
              arg4? arg4:"X");
    line[DIM(line)-1] = 0;
    xfree (arg1);
    xfree (arg2);
    xfree (arg3);
    xfree (arg4);

    init_membuf_secure (&data, 64);
    rc = assuan_transact (agent_ctx, line,
                          membuf_data_cb, &data,
                          default_inq_cb, NULL, NULL, NULL);

    if (rc)
        xfree (get_membuf (&data, NULL));
    else
    {
        put_membuf (&data, "", 1);
        *r_passphrase = get_membuf (&data, NULL);
        if (!*r_passphrase)
            rc = gpg_error_from_syserror ();
    }
    return rc;
no_mem:
    rc = gpg_error_from_syserror ();
    xfree (arg1);
    xfree (arg2);
    xfree (arg3);
    xfree (arg4);
    return rc;
}
Beispiel #13
0
/* Assume that the reader is at a pkcs#12 message and try to import
   certificates from that stupid format.  We will transfer secret
   keys to the agent.  */
static gpg_error_t
parse_p12 (ctrl_t ctrl, ksba_reader_t reader, struct stats_s *stats)
{
  gpg_error_t err = 0;
  char buffer[1024];
  size_t ntotal, nread;
  membuf_t p12mbuf;
  char *p12buffer = NULL;
  size_t p12buflen;
  size_t p12bufoff;
  gcry_mpi_t *kparms = NULL;
  struct rsa_secret_key_s sk;
  char *passphrase = NULL;
  unsigned char *key = NULL;
  size_t keylen;
  void *kek = NULL;
  size_t keklen;
  unsigned char *wrappedkey = NULL;
  size_t wrappedkeylen;
  gcry_cipher_hd_t cipherhd = NULL;
  gcry_sexp_t s_key = NULL;
  unsigned char grip[20];
  int bad_pass = 0;
  int i;
  struct store_cert_parm_s store_cert_parm;

  memset (&store_cert_parm, 0, sizeof store_cert_parm);
  store_cert_parm.ctrl = ctrl;
  store_cert_parm.stats = stats;

  init_membuf (&p12mbuf, 4096);
  ntotal = 0;
  while (!(err = ksba_reader_read (reader, buffer, sizeof buffer, &nread)))
    {
      if (ntotal >= MAX_P12OBJ_SIZE*1024)
        {
          /* Arbitrary limit to avoid DoS attacks. */
          err = gpg_error (GPG_ERR_TOO_LARGE);
          log_error ("pkcs#12 object is larger than %dk\n", MAX_P12OBJ_SIZE);
          break;
        }
      put_membuf (&p12mbuf, buffer, nread);
      ntotal += nread;
    }
  if (gpg_err_code (err) == GPG_ERR_EOF)
    err = 0;
  if (!err)
    {
      p12buffer = get_membuf (&p12mbuf, &p12buflen);
      if (!p12buffer)
        err = gpg_error_from_syserror ();
    }
  if (err)
    {
      log_error (_("error reading input: %s\n"), gpg_strerror (err));
      goto leave;
    }

  /* GnuPG 2.0.4 accidently created binary P12 files with the string
     "The passphrase is %s encoded.\n\n" prepended to the ASN.1 data.
     We fix that here.  */
  if (p12buflen > 29 && !memcmp (p12buffer, "The passphrase is ", 18))
    {
      for (p12bufoff=18;
           p12bufoff < p12buflen && p12buffer[p12bufoff] != '\n';
           p12bufoff++)
        ;
      p12bufoff++;
      if (p12bufoff < p12buflen && p12buffer[p12bufoff] == '\n')
        p12bufoff++;
    }
  else
    p12bufoff = 0;


  err = gpgsm_agent_ask_passphrase
    (ctrl,
     i18n_utf8 ("Please enter the passphrase to unprotect the PKCS#12 object."),
     0, &passphrase);
  if (err)
    goto leave;

  kparms = p12_parse (p12buffer + p12bufoff, p12buflen - p12bufoff,
                      passphrase, store_cert_cb, &store_cert_parm, &bad_pass);

  xfree (passphrase);
  passphrase = NULL;

  if (!kparms)
    {
      log_error ("error parsing or decrypting the PKCS#12 file\n");
      err = gpg_error (GPG_ERR_INV_OBJ);
      goto leave;
    }

/*    print_mpi ("   n", kparms[0]); */
/*    print_mpi ("   e", kparms[1]); */
/*    print_mpi ("   d", kparms[2]); */
/*    print_mpi ("   p", kparms[3]); */
/*    print_mpi ("   q", kparms[4]); */
/*    print_mpi ("dmp1", kparms[5]); */
/*    print_mpi ("dmq1", kparms[6]); */
/*    print_mpi ("   u", kparms[7]); */

  sk.n = kparms[0];
  sk.e = kparms[1];
  sk.d = kparms[2];
  sk.q = kparms[3];
  sk.p = kparms[4];
  sk.u = kparms[7];
  err = rsa_key_check (&sk);
  if (err)
    goto leave;
/*    print_mpi ("   n", sk.n); */
/*    print_mpi ("   e", sk.e); */
/*    print_mpi ("   d", sk.d); */
/*    print_mpi ("   p", sk.p); */
/*    print_mpi ("   q", sk.q); */
/*    print_mpi ("   u", sk.u); */

  /* Create an S-expresion from the parameters. */
  err = gcry_sexp_build (&s_key, NULL,
                         "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))",
                         sk.n, sk.e, sk.d, sk.p, sk.q, sk.u, NULL);
  for (i=0; i < 8; i++)
    gcry_mpi_release (kparms[i]);
  gcry_free (kparms);
  kparms = NULL;
  if (err)
    {
      log_error ("failed to create S-expression from key: %s\n",
                 gpg_strerror (err));
      goto leave;
    }

  /* Compute the keygrip. */
  if (!gcry_pk_get_keygrip (s_key, grip))
    {
      err = gpg_error (GPG_ERR_GENERAL);
      log_error ("can't calculate keygrip\n");
      goto leave;
    }
  log_printhex ("keygrip=", grip, 20);

  /* Convert to canonical encoding using a function which pads it to a
     multiple of 64 bits.  We need this padding for AESWRAP.  */
  err = make_canon_sexp_pad (s_key, 1, &key, &keylen);
  if (err)
    {
      log_error ("error creating canonical S-expression\n");
      goto leave;
    }
  gcry_sexp_release (s_key);
  s_key = NULL;

  /* Get the current KEK.  */
  err = gpgsm_agent_keywrap_key (ctrl, 0, &kek, &keklen);
  if (err)
    {
      log_error ("error getting the KEK: %s\n", gpg_strerror (err));
      goto leave;
    }

  /* Wrap the key.  */
  err = gcry_cipher_open (&cipherhd, GCRY_CIPHER_AES128,
                          GCRY_CIPHER_MODE_AESWRAP, 0);
  if (err)
    goto leave;
  err = gcry_cipher_setkey (cipherhd, kek, keklen);
  if (err)
    goto leave;
  xfree (kek);
  kek = NULL;

  wrappedkeylen = keylen + 8;
  wrappedkey = xtrymalloc (wrappedkeylen);
  if (!wrappedkey)
    {
      err = gpg_error_from_syserror ();
      goto leave;
    }

  err = gcry_cipher_encrypt (cipherhd, wrappedkey, wrappedkeylen, key, keylen);
  if (err)
    goto leave;
  xfree (key);
  key = NULL;
  gcry_cipher_close (cipherhd);
  cipherhd = NULL;

  /* Send the wrapped key to the agent.  */
  err = gpgsm_agent_import_key (ctrl, wrappedkey, wrappedkeylen);
  if (!err)
    {
      stats->count++;
      stats->secret_read++;
      stats->secret_imported++;
    }
  else if ( gpg_err_code (err) == GPG_ERR_EEXIST )
    {
      err = 0;
      stats->count++;
      stats->secret_read++;
      stats->secret_dups++;
    }

  /* If we did not get an error from storing the secret key we return
     a possible error from parsing the certificates.  We do this after
     storing the secret keys so that a bad certificate does not
     inhibit our chance to store the secret key.  */
  if (!err && store_cert_parm.err)
    err = store_cert_parm.err;

 leave:
  if (kparms)
    {
      for (i=0; i < 8; i++)
        gcry_mpi_release (kparms[i]);
      gcry_free (kparms);
      kparms = NULL;
    }
  xfree (key);
  gcry_sexp_release (s_key);
  xfree (passphrase);
  gcry_cipher_close (cipherhd);
  xfree (wrappedkey);
  xfree (kek);
  xfree (get_membuf (&p12mbuf, NULL));
  xfree (p12buffer);

  if (bad_pass)
    {
      /* We only write a plain error code and not direct
         BAD_PASSPHRASE because the pkcs12 parser might issue this
         message multiple times, BAD_PASSPHRASE in general requires a
         keyID and parts of the import might actually succeed so that
         IMPORT_PROBLEM is also not appropriate. */
      gpgsm_status_with_err_code (ctrl, STATUS_ERROR,
                                  "import.parsep12", GPG_ERR_BAD_PASSPHRASE);
    }

  return err;
}
Beispiel #14
0
/**
 * assuan_inquire:
 * @ctx: An assuan context
 * @keyword: The keyword used for the inquire
 * @r_buffer: Returns an allocated buffer
 * @r_length: Returns the length of this buffer
 * @maxlen: If not 0, the size limit of the inquired data.
 * 
 * A Server may use this to Send an inquire.  r_buffer, r_length and
 * maxlen may all be NULL/0 to indicate that no real data is expected.
 * 
 * Return value: 0 on success or an ASSUAN error code
 **/
assuan_error_t
assuan_inquire (assuan_context_t ctx, const char *keyword,
                unsigned char **r_buffer, size_t *r_length, size_t maxlen)
{
  assuan_error_t rc;
  struct membuf mb;
  char cmdbuf[LINELENGTH-10]; /* (10 = strlen ("INQUIRE ")+CR,LF) */
  unsigned char *line, *p;
  int linelen;
  int nodataexpected;

  if (!ctx || !keyword || (10 + strlen (keyword) >= sizeof (cmdbuf)))
    return _assuan_error (ASSUAN_Invalid_Value);
  nodataexpected = !r_buffer && !r_length && !maxlen;
  if (!nodataexpected && (!r_buffer || !r_length))
    return _assuan_error (ASSUAN_Invalid_Value);
  if (!ctx->is_server)
    return _assuan_error (ASSUAN_Not_A_Server);
  if (ctx->in_inquire)
    return _assuan_error (ASSUAN_Nested_Commands);
  
  ctx->in_inquire = 1;
  if (nodataexpected)
    memset (&mb, 0, sizeof mb); /* avoid compiler warnings */
  else
    init_membuf (&mb, maxlen? maxlen:1024, maxlen);

  strcpy (stpcpy (cmdbuf, "INQUIRE "), keyword);
  rc = assuan_write_line (ctx, cmdbuf);
  if (rc)
    goto leave;

  for (;;)
    {
      do 
        {
	  do
	    rc = _assuan_read_line (ctx);
	  while (_assuan_error_is_eagain (rc));
          if (rc)
            goto leave;
          line = (unsigned char *) ctx->inbound.line;
          linelen = ctx->inbound.linelen;
        }    
      while (*line == '#' || !linelen);
      if (line[0] == 'E' && line[1] == 'N' && line[2] == 'D'
          && (!line[3] || line[3] == ' '))
        break; /* END command received*/
      if (line[0] == 'C' && line[1] == 'A' && line[2] == 'N')
        {
          rc = _assuan_error (ASSUAN_Canceled);
          goto leave;
        }
      if (line[0] != 'D' || line[1] != ' ' || nodataexpected)
        {
          rc = _assuan_error (ASSUAN_Unexpected_Command);
          goto leave;
        }
      if (linelen < 3)
        continue;
      line += 2;
      linelen -= 2;

      p = line;
      while (linelen)
        {
          for (;linelen && *p != '%'; linelen--, p++)
            ;
          put_membuf (&mb, line, p-line);
          if (linelen > 2)
            { /* handle escaping */
              unsigned char tmp[1];
              p++;
              *tmp = xtoi_2 (p);
              p += 2;
              linelen -= 3;
              put_membuf (&mb, tmp, 1);
            }
          line = p;
        }
      if (mb.too_large)
        {
          rc = _assuan_error (ASSUAN_Too_Much_Data);
          goto leave;
        }
    }

  if (!nodataexpected)
    {
      *r_buffer = get_membuf (&mb, r_length);
      if (!*r_buffer)
        rc = _assuan_error (ASSUAN_Out_Of_Core);
    }

 leave:
  if (!nodataexpected)
    free_membuf (&mb);
  ctx->in_inquire = 0;
  return rc;
}
Beispiel #15
0
int
_assuan_inquire_ext_cb (assuan_context_t ctx)
{
  int rc;
  unsigned char *line;
  int linelen;
  struct membuf *mb;
  unsigned char *p;

  line = (unsigned char *) ctx->inbound.line;
  linelen = ctx->inbound.linelen;
  mb = ctx->inquire_membuf;

  if (line[0] == 'C' && line[1] == 'A' && line[2] == 'N')
    {
      rc = _assuan_error (ASSUAN_Canceled);
      goto leave;
    }
  if (line[0] == 'E' && line[1] == 'N' && line[2] == 'D'
      && (!line[3] || line[3] == ' '))
    {
      rc = 0;
      goto leave;
    }

  if (line[0] != 'D' || line[1] != ' ' || mb == NULL)
    {
      rc = _assuan_error (ASSUAN_Unexpected_Command);
      goto leave;
    }
  
  if (linelen < 3)
    return 0;
  line += 2;
  linelen -= 2;
  
  p = line;
  while (linelen)
    {
      for (;linelen && *p != '%'; linelen--, p++)
	;
      put_membuf (mb, line, p-line);
      if (linelen > 2)
	{ /* handle escaping */
	  unsigned char tmp[1];
	  p++;
	  *tmp = xtoi_2 (p);
	  p += 2;
	  linelen -= 3;
	  put_membuf (mb, tmp, 1);
	}
      line = p;
    }
  if (mb->too_large)
    {
      rc = _assuan_error (ASSUAN_Too_Much_Data);
      goto leave;
    }

  return 0;

 leave:
  {
    size_t buf_len = 0;
    unsigned char *buf = NULL;

    if (mb)
      {
	buf = get_membuf (mb, &buf_len);
	if (!buf)
	  rc = _assuan_error (ASSUAN_Out_Of_Core);
	free_membuf (mb);
	free (mb);
	ctx->inquire_membuf = NULL;
      }
    ctx->in_inquire = 0;
    rc = (ctx->inquire_cb) (ctx->inquire_cb_data, rc, buf, buf_len);
  }
  return rc;
}
/**
 * assuan_inquire:
 * @ctx: An assuan context
 * @keyword: The keyword used for the inquire
 * @r_buffer: Returns an allocated buffer
 * @r_length: Returns the length of this buffer
 * @maxlen: If not 0, the size limit of the inquired data.
 * 
 * A Server may use this to Send an inquire.  r_buffer, r_length and
 * maxlen may all be NULL/0 to indicate that no real data is expected.
 * 
 * Return value: 0 on success or an ASSUAN error code
 **/
gpg_error_t
assuan_inquire (assuan_context_t ctx, const char *keyword,
                unsigned char **r_buffer, size_t *r_length, size_t maxlen)
{
  gpg_error_t rc;
  struct membuf mb;
  char cmdbuf[LINELENGTH-10]; /* (10 = strlen ("INQUIRE ")+CR,LF) */
  unsigned char *line, *p;
  int linelen;
  int nodataexpected;

  if (!ctx || !keyword || (10 + strlen (keyword) >= sizeof (cmdbuf)))
    return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
  nodataexpected = !r_buffer && !r_length && !maxlen;
  if (!nodataexpected && (!r_buffer || !r_length))
    return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
  if (!ctx->is_server)
    return _assuan_error (ctx, GPG_ERR_ASS_NOT_A_SERVER);
  if (ctx->in_inquire)
    return _assuan_error (ctx, GPG_ERR_ASS_NESTED_COMMANDS);
  
  ctx->in_inquire = 1;
  if (nodataexpected)
    memset (&mb, 0, sizeof mb); /* avoid compiler warnings */
  else
    init_membuf (ctx, &mb, maxlen? maxlen:1024, maxlen);

  strcpy (stpcpy (cmdbuf, "INQUIRE "), keyword);
  rc = assuan_write_line (ctx, cmdbuf);
  if (rc)
    goto leave;

  for (;;)
    {
      do 
        {
	  do
	    rc = _assuan_read_line (ctx);
	  while (_assuan_error_is_eagain (ctx, rc));
          if (rc)
            goto leave;
          line = (unsigned char *) ctx->inbound.line;
          linelen = ctx->inbound.linelen;
        }    
      while (*line == '#' || !linelen);
      if (line[0] == 'E' && line[1] == 'N' && line[2] == 'D'
          && (!line[3] || line[3] == ' '))
        break; /* END command received*/
      if (line[0] == 'C' && line[1] == 'A' && line[2] == 'N')
        {
          rc = _assuan_error (ctx, GPG_ERR_ASS_CANCELED);
          goto leave;
        }
      if (line[0] != 'D' || line[1] != ' ' || nodataexpected)
        {
          rc = _assuan_error (ctx, GPG_ERR_ASS_UNEXPECTED_CMD);
          goto leave;
        }
      if (linelen < 3)
        continue;
      line += 2;
      linelen -= 2;

      p = line;
      while (linelen)
        {
          for (;linelen && *p != '%'; linelen--, p++)
            ;
          put_membuf (ctx, &mb, line, p-line);
          if (linelen > 2)
            { /* handle escaping */
              unsigned char tmp[1];
              p++;
              *tmp = xtoi_2 (p);
              p += 2;
              linelen -= 3;
              put_membuf (ctx, &mb, tmp, 1);
            }
          line = p;
        }
      if (mb.too_large)
        {
          rc = _assuan_error (ctx, GPG_ERR_ASS_TOO_MUCH_DATA);
          goto leave;
        }
    }

  if (!nodataexpected)
    {
      *r_buffer = get_membuf (ctx, &mb, r_length);
      if (!*r_buffer)
	rc = _assuan_error (ctx, gpg_err_code_from_syserror ());
    }

 leave:
  if (!nodataexpected)
    free_membuf (ctx, &mb);
  ctx->in_inquire = 0;
  return rc;
}
gpg_error_t
_assuan_inquire_ext_cb (assuan_context_t ctx)
{
  gpg_error_t rc;
  unsigned char *line;
  int linelen;
  struct membuf *mb;
  unsigned char *p;

  line = (unsigned char *) ctx->inbound.line;
  linelen = ctx->inbound.linelen;
  mb = ctx->inquire_membuf;

  if (line[0] == 'C' && line[1] == 'A' && line[2] == 'N')
    {
      rc = _assuan_error (ctx, GPG_ERR_ASS_CANCELED);
      goto leave;
    }
  if (line[0] == 'E' && line[1] == 'N' && line[2] == 'D'
      && (!line[3] || line[3] == ' '))
    {
      rc = 0;
      goto leave;
    }

  if (line[0] != 'D' || line[1] != ' ' || mb == NULL)
    {
      rc = _assuan_error (ctx, GPG_ERR_ASS_UNEXPECTED_CMD);
      goto leave;
    }
  
  if (linelen < 3)
    return 0;
  line += 2;
  linelen -= 2;
  
  p = line;
  while (linelen)
    {
      for (;linelen && *p != '%'; linelen--, p++)
	;
      put_membuf (ctx, mb, line, p-line);
      if (linelen > 2)
	{ /* handle escaping */
	  unsigned char tmp[1];
	  p++;
	  *tmp = xtoi_2 (p);
	  p += 2;
	  linelen -= 3;
	  put_membuf (ctx, mb, tmp, 1);
	}
      line = p;
    }
  if (mb->too_large)
    {
      rc = _assuan_error (ctx, GPG_ERR_ASS_TOO_MUCH_DATA);
      goto leave;
    }

  return 0;

 leave:
  {
    size_t buf_len = 0;
    unsigned char *buf = NULL;
    
    if (mb)
      {
	buf = get_membuf (ctx, mb, &buf_len);
	if (!buf)
	  rc = _assuan_error (ctx, gpg_err_code_from_syserror ());
	free_membuf (ctx, mb);
	free (mb);
	ctx->inquire_membuf = NULL;
      }
    ctx->in_inquire = 0;
    rc = (ctx->inquire_cb) (ctx->inquire_cb_data, rc, buf, buf_len);
  }
  return rc;
}
Beispiel #18
0
/* Ask for a passphrase via gpg-agent.  On success the caller needs to
   free the string stored at R_PASSPHRASE.  On error NULL will be
   stored at R_PASSPHRASE and an appropriate gpg error code is
   returned.  With REPEAT set to 1, gpg-agent will ask the user to
   repeat the just entered passphrase.  CACHE_ID is a gpg-agent style
   passphrase cache id or NULL.  ERR_MSG is a error message to be
   presented to the user (e.g. "bad passphrase - try again") or NULL.
   PROMPT is the prompt string to label the entry box, it may be NULL
   for a default one.  DESC_MSG is a longer description to be
   displayed above the entry box, if may be NULL for a default one.
   If USE_SECMEM is true, the returned passphrase is retruned in
   secure memory.  The length of all these strings is limited; they
   need to fit in their encoded form into a standard Assuan line (i.e
   less then about 950 characters).  All strings shall be UTF-8.  */
gpg_error_t
gnupg_get_passphrase (const char *cache_id,
                      const char *err_msg,
                      const char *prompt,
                      const char *desc_msg,
                      int repeat,
                      int check_quality,
                      int use_secmem,
                      char **r_passphrase)
{
  gpg_error_t err;
  char line[ASSUAN_LINELENGTH];
  const char *arg1 = NULL;
  char *arg2 = NULL;
  char *arg3 = NULL;
  char *arg4 = NULL;
  membuf_t data;

  *r_passphrase = NULL;

  err = start_agent ();
  if (err)
    return err;

  /* Check that the gpg-agent understands the repeat option.  */
  if (assuan_transact (agent_ctx,
                       "GETINFO cmd_has_option GET_PASSPHRASE repeat",
                       NULL, NULL, NULL, NULL, NULL, NULL))
    return gpg_error (GPG_ERR_NOT_SUPPORTED);

  arg1 = cache_id && *cache_id? cache_id:NULL;
  if (err_msg && *err_msg)
    if (!(arg2 = percent_plus_escape (err_msg)))
      goto no_mem;
  if (prompt && *prompt)
    if (!(arg3 = percent_plus_escape (prompt)))
      goto no_mem;
  if (desc_msg && *desc_msg)
    if (!(arg4 = percent_plus_escape (desc_msg)))
      goto no_mem;

  snprintf (line, DIM(line)-1,
            "GET_PASSPHRASE --data %s--repeat=%d -- %s %s %s %s",
            check_quality? "--check ":"",
            repeat,
            arg1? arg1:"X",
            arg2? arg2:"X",
            arg3? arg3:"X",
            arg4? arg4:"X");
  line[DIM(line)-1] = 0;
  xfree (arg2);
  xfree (arg3);
  xfree (arg4);

  if (use_secmem)
    init_membuf_secure (&data, 64);
  else
    init_membuf (&data, 64);
  err = assuan_transact (agent_ctx, line,
                         membuf_data_cb, &data,
                         default_inq_cb, NULL, NULL, NULL);

  /* Older Pinentries return the old assuan error code for canceled
     which gets translated bt libassuan to GPG_ERR_ASS_CANCELED and
     not to the code for a user cancel.  Fix this here. */
  if (err && gpg_err_source (err)
      && gpg_err_code (err) == GPG_ERR_ASS_CANCELED)
    err = gpg_err_make (gpg_err_source (err), GPG_ERR_CANCELED);

  if (err)
    {
      void *p;
      size_t n;

      p = get_membuf (&data, &n);
      if (p)
        wipememory (p, n);
      xfree (p);
    }
  else
    {
      put_membuf (&data, "", 1);
      *r_passphrase = get_membuf (&data, NULL);
      if (!*r_passphrase)
        err = gpg_error_from_syserror ();
    }
  return err;
 no_mem:
  err = gpg_error_from_syserror ();
  xfree (arg2);
  xfree (arg3);
  xfree (arg4);
  return err;
}
Beispiel #19
0
/* Try to find KEY in the file FNAME.  */
static char *
findkey_fname (const char *key, const char *fname)
{
  gpg_error_t err = 0;
  FILE *fp;
  int lnr = 0;
  int c;
  char *p, line[256];
  int in_item = 0;
  membuf_t mb = MEMBUF_ZERO;

  fp = fopen (fname, "r");
  if (!fp)
    {
      if (errno != ENOENT)
        {
          err = gpg_error_from_syserror ();
          log_error (_("can't open `%s': %s\n"), fname, gpg_strerror (err));
        }
      return NULL;
    }

  while (fgets (line, DIM(line)-1, fp))
    {
      lnr++;
      
      if (!*line || line[strlen(line)-1] != '\n')
        {
          /* Eat until end of line. */
          while ( (c=getc (fp)) != EOF && c != '\n')
            ;
          err = gpg_error (*line? GPG_ERR_LINE_TOO_LONG
                           : GPG_ERR_INCOMPLETE_LINE);
          log_error (_("file `%s', line %d: %s\n"),
                     fname, lnr, gpg_strerror (err));
        }
      else
        line[strlen(line)-1] = 0; /* Chop the LF. */
      
    again:
      if (!in_item)
        {
          /* Allow for empty lines and spaces while not in an item. */
          for (p=line; spacep (p); p++)
            ;
          if (!*p || *p == '#')
            continue;
          if (*line != '.' || spacep(line+1))
            {
              log_info (_("file `%s', line %d: %s\n"),
                        fname, lnr, _("ignoring garbage line"));
              continue;
            }
          trim_trailing_spaces (line);
          in_item = 1;
          if (!strcmp (line+1, key))
            {
              /* Found.  Start collecting.  */
              init_membuf (&mb, 1024);
            }
          continue;
        }

      /* If in an item only allow for comments in the first column
         and provide ". " as an escape sequence to allow for
         leading dots and hash marks in the actual text.  */
      if (*line == '#')
        continue;
      if (*line == '.')
        { 
          if (spacep(line+1))
            p = line + 2;
          else
            {
              trim_trailing_spaces (line);
              in_item = 0;
              if (is_membuf_ready (&mb))
                break;        /* Yep, found and collected the item.  */
              if (!line[1])
                continue;     /* Just an end of text dot. */
              goto again;     /* A new key line.  */
            }
        }
      else
        p = line;

      if (is_membuf_ready (&mb))
        {
          put_membuf_str (&mb, p);
          put_membuf (&mb, "\n", 1);
        }

    }
  if ( !err && ferror (fp) )
    {
      err = gpg_error_from_syserror ();
      log_error (_("error reading `%s', line %d: %s\n"),
                 fname, lnr, gpg_strerror (err));
    }
  
  fclose (fp);
  if (is_membuf_ready (&mb))
    {
      /* We have collected something.  */
      if (err)
        {
          xfree (get_membuf (&mb, NULL));
          return NULL;
        }
      else
        {
          put_membuf (&mb, "", 1);  /* Terminate string.  */
          return get_membuf (&mb, NULL);
        }
    }
  else
    return NULL;
}
Beispiel #20
0
/* Debug function to print the entire hosttable.  */
gpg_error_t
ks_hkp_print_hosttable (ctrl_t ctrl)
{
  gpg_error_t err;
  int idx, idx2;
  hostinfo_t hi;
  membuf_t mb;
  time_t curtime;
  char *p, *died;
  const char *diedstr;

  err = ks_print_help (ctrl, "hosttable (idx, ipv6, ipv4, dead, name, time):");
  if (err)
    return err;

  /* FIXME: We need a lock for the hosttable.  */
  curtime = gnupg_get_time ();
  for (idx=0; idx < hosttable_size; idx++)
    if ((hi=hosttable[idx]))
      {
        if (hi->dead && hi->died_at)
          {
            died = elapsed_time_string (hi->died_at, curtime);
            diedstr = died? died : "error";
          }
        else
          diedstr = died = NULL;

        if (!hi->iporname_valid)
          {
            char *canon = NULL;

            xfree (hi->iporname);
            hi->iporname = NULL;

            /* Do a lookup just for the display purpose.  */
            if (hi->onion || hi->pool)
              ;
            else if (is_ip_address (hi->name))
              {
                dns_addrinfo_t aibuf, ai;

                /* Turn the numerical IP address string into an AI and
                 * then do a DNS PTR lookup.  */
                if (!resolve_dns_name (hi->name, 0, 0,
                                       SOCK_STREAM,
                                       &aibuf, &canon))
                  {
                    if (canon && is_ip_address (canon))
                      {
                        xfree (canon);
                        canon = NULL;
                      }
                    for (ai = aibuf; !canon && ai; ai = ai->next)
                      {
                        resolve_dns_addr (ai->addr, ai->addrlen,
                                          DNS_WITHBRACKET, &canon);
                        if (canon && is_ip_address (canon))
                          {
                            /* We already have the numeric IP - no need to
                             * display it a second time.  */
                            xfree (canon);
                            canon = NULL;
                          }
                      }
                  }
                free_dns_addrinfo (aibuf);
              }
            else
              {
                dns_addrinfo_t aibuf, ai;

                /* Get the IP address as a string from a name.  Note
                 * that resolve_dns_addr allocates CANON on success
                 * and thus terminates the loop. */
                if (!resolve_dns_name (hi->name, 0,
                                       hi->v6? AF_INET6 : AF_INET,
                                       SOCK_STREAM,
                                       &aibuf, NULL))
                  {
                    for (ai = aibuf; !canon && ai; ai = ai->next)
                      {
                        resolve_dns_addr (ai->addr, ai->addrlen,
                                          DNS_NUMERICHOST|DNS_WITHBRACKET,
                                          &canon);
                      }
                  }
                free_dns_addrinfo (aibuf);
              }

            hi->iporname = canon;
            hi->iporname_valid = 1;
          }

        err = ks_printf_help (ctrl, "%3d %s %s %s %s%s%s%s%s%s%s\n",
                              idx,
                              hi->onion? "O" : hi->v6? "6":" ",
                              hi->v4? "4":" ",
                              hi->dead? "d":" ",
                              hi->name,
                              hi->iporname? " (":"",
                              hi->iporname? hi->iporname : "",
                              hi->iporname? ")":"",
                              diedstr? "  (":"",
                              diedstr? diedstr:"",
                              diedstr? ")":""   );
        xfree (died);
        if (err)
          return err;

        if (hi->cname)
          err = ks_printf_help (ctrl, "  .       %s", hi->cname);
        if (err)
          return err;

        if (hi->pool)
          {
            init_membuf (&mb, 256);
            put_membuf_printf (&mb, "  .   -->");
            for (idx2 = 0; idx2 < hi->pool_len && hi->pool[idx2] != -1; idx2++)
              {
                put_membuf_printf (&mb, " %d", hi->pool[idx2]);
                if (hi->poolidx == hi->pool[idx2])
                  put_membuf_printf (&mb, "*");
              }
            put_membuf( &mb, "", 1);
            p = get_membuf (&mb, NULL);
            if (!p)
              return gpg_error_from_syserror ();
            err = ks_print_help (ctrl, p);
            xfree (p);
            if (err)
              return err;
          }
      }
  return 0;
}
Beispiel #21
0
/* Search for keys on the keyservers.  The patterns are given in the
   string list TOKENS.  */
gpg_error_t
keyserver_search (ctrl_t ctrl, strlist_t tokens)
{
  gpg_error_t err;
  char *searchstr;
  struct search_line_handler_parm_s parm;

  memset (&parm, 0, sizeof parm);

  if (!tokens)
    return 0;  /* Return success if no patterns are given.  */

  if (!opt.keyserver)
    {
      log_error (_("no keyserver known (use option --keyserver)\n"));
      return gpg_error (GPG_ERR_NO_KEYSERVER);
    }

  /* Write global options */

  /* for(temp=opt.keyserver_options.other;temp;temp=temp->next) */
  /*   fprintf(spawn->tochild,"OPTION %s\n",temp->d); */

  /* Write per-keyserver options */

  /* for(temp=keyserver->options;temp;temp=temp->next) */
  /*   fprintf(spawn->tochild,"OPTION %s\n",temp->d); */

  {
    membuf_t mb;
    strlist_t item;

    init_membuf (&mb, 1024);
    for (item = tokens; item; item = item->next)
    {
      if (item != tokens)
        put_membuf (&mb, " ", 1);
      put_membuf_str (&mb, item->d);
    }
    put_membuf (&mb, "", 1); /* Append Nul.  */
    searchstr = get_membuf (&mb, NULL);
    if (!searchstr)
      {
        err = gpg_error_from_syserror ();
        goto leave;
      }
  }
  /* FIXME: Enable the next line */
  /* log_info (_("searching for \"%s\" from %s\n"), searchstr, keyserver->uri); */

  parm.ctrl = ctrl;
  if (searchstr)
    parm.searchstr_disp = utf8_to_native (searchstr, strlen (searchstr), 0);

  err = gpg_dirmngr_ks_search (ctrl, searchstr, search_line_handler, &parm);

  if (parm.not_found)
    {
      if (parm.searchstr_disp)
        log_info (_("key \"%s\" not found on keyserver\n"),
                  parm.searchstr_disp);
      else
        log_info (_("key not found on keyserver\n"));
    }

  if (gpg_err_code (err) == GPG_ERR_NO_KEYSERVER)
    log_error (_("no keyserver known (use option --keyserver)\n"));
  else if (err)
    log_error ("error searching keyserver: %s\n", gpg_strerror (err));

  /* switch(ret) */
  /*   { */
  /*   case KEYSERVER_SCHEME_NOT_FOUND: */
  /*     log_error(_("no handler for keyserver scheme '%s'\n"), */
  /*   	    opt.keyserver->scheme); */
  /*     break; */

  /*   case KEYSERVER_NOT_SUPPORTED: */
  /*     log_error(_("action '%s' not supported with keyserver " */
  /*   	      "scheme '%s'\n"), "search", opt.keyserver->scheme); */
  /*     break; */

  /*   case KEYSERVER_TIMEOUT: */
  /*     log_error(_("keyserver timed out\n")); */
  /*     break; */

  /*   case KEYSERVER_INTERNAL_ERROR: */
  /*   default: */
  /*     log_error(_("keyserver internal error\n")); */
  /*     break; */
  /*   } */

  /* return gpg_error (GPG_ERR_KEYSERVER); */


 leave:
  xfree (parm.desc);
  xfree (parm.searchstr_disp);
  xfree(searchstr);

  return err;
}
Beispiel #22
0
/* Debug function to print the entire hosttable.  */
gpg_error_t
ks_hkp_print_hosttable (ctrl_t ctrl)
{
  gpg_error_t err;
  int idx, idx2;
  hostinfo_t hi;
  membuf_t mb;
  time_t curtime;
  char *p, *died;
  const char *diedstr;

  err = ks_print_help (ctrl, "hosttable (idx, ipv6, ipv4, dead, name, time):");
  if (err)
    return err;

  curtime = gnupg_get_time ();
  for (idx=0; idx < hosttable_size; idx++)
    if ((hi=hosttable[idx]))
      {
        if (hi->dead && hi->died_at)
          {
            died = elapsed_time_string (hi->died_at, curtime);
            diedstr = died? died : "error";
          }
        else
          diedstr = died = NULL;
        err = ks_printf_help (ctrl, "%3d %s %s %s %s%s%s%s%s%s%s%s\n",
                              idx, hi->v6? "6":" ", hi->v4? "4":" ",
                              hi->dead? "d":" ",
                              hi->name,
                              hi->v6addr? " v6=":"",
                              hi->v6addr? hi->v6addr:"",
                              hi->v4addr? " v4=":"",
                              hi->v4addr? hi->v4addr:"",
                              diedstr? "  (":"",
                              diedstr? diedstr:"",
                              diedstr? ")":""   );
        xfree (died);
        if (err)
          return err;

        if (hi->cname)
          err = ks_printf_help (ctrl, "  .       %s", hi->cname);
        if (err)
          return err;

        if (hi->pool)
          {
            init_membuf (&mb, 256);
            put_membuf_printf (&mb, "  .   -->");
            for (idx2=0; hi->pool[idx2] != -1; idx2++)
              {
                put_membuf_printf (&mb, " %d", hi->pool[idx2]);
                if (hi->poolidx == hi->pool[idx2])
                  put_membuf_printf (&mb, "*");
              }
            put_membuf( &mb, "", 1);
            p = get_membuf (&mb, NULL);
            if (!p)
              return gpg_error_from_syserror ();
            err = ks_print_help (ctrl, p);
            xfree (p);
            if (err)
              return err;
          }
      }
  return 0;
}