示例#1
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;
}
示例#2
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;
}
示例#3
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;
}
示例#4
0
文件: gpgtar.c 项目: gpg/gnupg
/* Read the next record from STREAM.  RECORD is a buffer provided by
   the caller and must be at leadt of size RECORDSIZE.  The function
   return 0 on success and and error code on failure; a diagnostic
   printed as well.  Note that there is no need for an EOF indicator
   because a tarball has an explicit EOF record. */
gpg_error_t
read_record (estream_t stream, void *record)
{
    gpg_error_t err;
    size_t nread;

    nread = es_fread (record, 1, RECORDSIZE, stream);
    if (nread != RECORDSIZE)
    {
        err = gpg_error_from_syserror ();
        if (es_ferror (stream))
            log_error ("error reading '%s': %s\n",
                       es_fname_get (stream), gpg_strerror (err));
        else
            log_error ("error reading '%s': premature EOF "
                       "(size of last record: %zu)\n",
                       es_fname_get (stream), nread);
    }
    else
        err = 0;

    return err;
}
示例#5
0
文件: runner.c 项目: 0ndorio/gnupg
/* The thread spawned by runner_spawn.  */
static void *
runner_thread (void *arg)
{
  runner_t runner = arg;
  gpg_error_t err = 0;

  log_debug ("starting runner thread\n");
  /* If a status_fp is available, the thread's main task is to read
     from that stream and invoke the backend's handler function.  This
     is done on a line by line base and the line length is limited to
     a reasonable value (about 1000 characters). Other work will
     continue either due to an EOF of the stream or by demand of the
     engine.  */
  if (runner->status_fp)
    {
      int c, cont_line;
      unsigned int pos;
      char buffer[1024];
      estream_t fp = runner->status_fp;

      pos = 0;
      cont_line = 0;
      while (!err && !runner->cancel_flag && (c=es_getc (fp)) != EOF)
        {
          buffer[pos++] = c;
          if (pos >= sizeof buffer - 5 || c == '\n')
            {
              buffer[pos - (c == '\n')] = 0;
              if (opt.verbose)
                log_info ("%s%s: %s\n",
                          runner->name, cont_line? "(cont)":"", buffer);
              /* We handle only complete lines and ignore any stuff we
                 possibly had to truncate.  That is - at least for the
                 encfs engine - not an issue because our changes to
                 the tool make sure that only relatively short prompt
                 lines are of interest.  */
              if (!cont_line && runner->handler)
                err = runner->handler (runner->handler_data,
                                       runner, buffer);
              pos = 0;
              cont_line = (c != '\n');
            }
        }
      if (!err && runner->cancel_flag)
        log_debug ("runner thread noticed cancel flag\n");
      else
        log_debug ("runner thread saw EOF\n");
      if (pos)
        {
          buffer[pos] = 0;
          if (opt.verbose)
            log_info ("%s%s: %s\n",
                      runner->name, cont_line? "(cont)":"", buffer);
          if (!cont_line && !err && runner->handler)
            err = runner->handler (runner->handler_data,
                                          runner, buffer);
        }
      if (!err && es_ferror (fp))
        {
          err = gpg_error_from_syserror ();
          log_error ("error reading from %s: %s\n",
                     runner->name, gpg_strerror (err));
        }

      runner->status_fp = NULL;
      es_fclose (fp);
      log_debug ("runner thread closed status fp\n");
    }

  /* Now wait for the process to finish.  */
  if (!err && runner->pid != (pid_t)(-1))
    {
      int exitcode;

      log_debug ("runner thread waiting ...\n");
      err = gnupg_wait_process (runner->name, runner->pid, 1, &exitcode);
      gnupg_release_process (runner->pid);
      runner->pid = (pid_t)(-1);
      if (err)
        log_error ("running '%s' failed (exitcode=%d): %s\n",
                   runner->name, exitcode, gpg_strerror (err));
      log_debug ("runner thread waiting finished\n");
    }

  /* Get rid of the runner object (note: it is refcounted).  */
  log_debug ("runner thread releasing runner ...\n");
  {
    runner_t r, rprev;

    for (r = running_threads, rprev = NULL; r; rprev = r, r = r->next_running)
      if (r == runner)
        {
          if (!rprev)
            running_threads = r->next_running;
          else
            rprev->next_running = r->next_running;
          r->next_running = NULL;
          break;
        }
  }
  runner_release (runner);
  log_debug ("runner thread runner released\n");

  return NULL;
}
示例#6
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;
}
示例#7
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;
}
示例#8
0
文件: encrypt.c 项目: 0ndorio/gnupg
/* do the actual encryption */
static int
encrypt_cb (void *cb_value, char *buffer, size_t count, size_t *nread)
{
  struct encrypt_cb_parm_s *parm = cb_value;
  int blklen = parm->dek->ivlen;
  unsigned char *p;
  size_t n;

  *nread = 0;
  if (!buffer)
    return -1; /* not supported */

  if (parm->ready)
    return -1;

  if (count < blklen)
    BUG ();

  if (!parm->eof_seen)
    { /* fillup the buffer */
      p = parm->buffer;
      for (n=parm->buflen; n < parm->bufsize; n++)
        {
          int c = es_getc (parm->fp);
          if (c == EOF)
            {
              if (es_ferror (parm->fp))
                {
                  parm->readerror = errno;
                  return -1;
                }
              parm->eof_seen = 1;
              break;
            }
          p[n] = c;
        }
      parm->buflen = n;
    }

  n = parm->buflen < count? parm->buflen : count;
  n = n/blklen * blklen;
  if (n)
    { /* encrypt the stuff */
      gcry_cipher_encrypt (parm->dek->chd, buffer, n, parm->buffer, n);
      *nread = n;
      /* Who cares about cycles, take the easy way and shift the buffer */
      parm->buflen -= n;
      memmove (parm->buffer, parm->buffer+n, parm->buflen);
    }
  else if (parm->eof_seen)
    { /* no complete block but eof: add padding */
      /* fixme: we should try to do this also in the above code path */
      int i, npad = blklen - (parm->buflen % blklen);
      p = parm->buffer;
      for (n=parm->buflen, i=0; n < parm->bufsize && i < npad; n++, i++)
        p[n] = npad;
      gcry_cipher_encrypt (parm->dek->chd, buffer, n, parm->buffer, n);
      *nread = n;
      parm->ready = 1;
    }

  return 0;
}
示例#9
0
/* Re-import certifciates.  IN_FD is a list of linefeed delimited
   fingerprints t re-import.  The actual re-import is done by clearing
   the ephemeral flag.  */
static int
reimport_one (ctrl_t ctrl, struct stats_s *stats, int in_fd)
{
  gpg_error_t err = 0;
  estream_t fp = NULL;
  char line[100];  /* Sufficient for a fingerprint.  */
  KEYDB_HANDLE kh;
  KEYDB_SEARCH_DESC desc;
  ksba_cert_t cert = NULL;
  unsigned int flags;

  kh = keydb_new (0);
  if (!kh)
    {
      err = gpg_error (GPG_ERR_ENOMEM);;
      log_error (_("failed to allocate keyDB handle\n"));
      goto leave;
    }
  keydb_set_ephemeral (kh, 1);
   
  fp = es_fdopen_nc (in_fd, "r");
  if (!fp)
    {
      err = gpg_error_from_syserror ();
      log_error ("es_fdopen(%d) failed: %s\n", in_fd, gpg_strerror (err));
      goto leave;
    }

  while (es_fgets (line, DIM(line)-1, fp) )
    {
      if (*line && line[strlen(line)-1] != '\n')
        {
          err = gpg_error (GPG_ERR_LINE_TOO_LONG);
          goto leave;
	}
      trim_spaces (line);
      if (!*line)
        continue;
    
      stats->count++;

      err = keydb_classify_name (line, &desc);
      if (err)
        {
          print_import_problem (ctrl, NULL, 0);
          stats->not_imported++;
          continue;
        }

      keydb_search_reset (kh);
      err = keydb_search (kh, &desc, 1);
      if (err)
        {
          print_import_problem (ctrl, NULL, 0);
          stats->not_imported++;
          continue;
        }

      ksba_cert_release (cert);
      cert = NULL;
      err = keydb_get_cert (kh, &cert);
      if (err)
        {
          log_error ("keydb_get_cert() failed: %s\n", gpg_strerror (err));
          print_import_problem (ctrl, NULL, 1);
          stats->not_imported++;
          continue;
        }

      err = keydb_get_flags (kh, KEYBOX_FLAG_BLOB, 0, &flags);
      if (err)
        {
          log_error (_("error getting stored flags: %s\n"), gpg_strerror (err));
          print_imported_status (ctrl, cert, 0);
          stats->not_imported++;
          continue;
        }
      if ( !(flags & KEYBOX_FLAG_BLOB_EPHEMERAL) )
        {
          print_imported_status (ctrl, cert, 0);
          stats->unchanged++;
          continue;
        }

      err = keydb_set_cert_flags (cert, 1, KEYBOX_FLAG_BLOB, 0,
                                  KEYBOX_FLAG_BLOB_EPHEMERAL, 0);
      if (err)
        {
          log_error ("clearing ephemeral flag failed: %s\n",
                     gpg_strerror (err)); 
          print_import_problem (ctrl, cert, 0);
          stats->not_imported++;
          continue;
        }

      print_imported_status (ctrl, cert, 1);
      stats->imported++;
    }
  err = 0;
  if (es_ferror (fp))
    {
      err = gpg_error_from_syserror ();
      log_error ("error reading fd %d: %s\n", in_fd, gpg_strerror (err));
      goto leave;
    }

 leave:
  ksba_cert_release (cert);
  keydb_release (kh);
  es_fclose (fp);
  return err;
}
示例#10
0
/* Search the keyserver identified by URI for keys matching PATTERN.
   On success R_FP has an open stream to read the data.  */
gpg_error_t
ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
               estream_t *r_fp)
{
  gpg_error_t err;
  KEYDB_SEARCH_DESC desc;
  char fprbuf[2+40+1];
  char *hostport = NULL;
  char *request = NULL;
  estream_t fp = NULL;
  int reselect;
  unsigned int httpflags;
  char *httphost = NULL;
  unsigned int tries = SEND_REQUEST_RETRIES;

  *r_fp = NULL;

  /* Remove search type indicator and adjust PATTERN accordingly.
     Note that HKP keyservers like the 0x to be present when searching
     by keyid.  We need to re-format the fingerprint and keyids so to
     remove the gpg specific force-use-of-this-key flag ("!").  */
  err = classify_user_id (pattern, &desc, 1);
  if (err)
    return err;
  switch (desc.mode)
    {
    case KEYDB_SEARCH_MODE_EXACT:
    case KEYDB_SEARCH_MODE_SUBSTR:
    case KEYDB_SEARCH_MODE_MAIL:
    case KEYDB_SEARCH_MODE_MAILSUB:
      pattern = desc.u.name;
      break;
    case KEYDB_SEARCH_MODE_SHORT_KID:
      snprintf (fprbuf, sizeof fprbuf, "0x%08lX", (ulong)desc.u.kid[1]);
      pattern = fprbuf;
      break;
    case KEYDB_SEARCH_MODE_LONG_KID:
      snprintf (fprbuf, sizeof fprbuf, "0x%08lX%08lX",
                (ulong)desc.u.kid[0], (ulong)desc.u.kid[1]);
      pattern = fprbuf;
      break;
    case KEYDB_SEARCH_MODE_FPR16:
      bin2hex (desc.u.fpr, 16, fprbuf);
      pattern = fprbuf;
      break;
    case KEYDB_SEARCH_MODE_FPR20:
    case KEYDB_SEARCH_MODE_FPR:
      bin2hex (desc.u.fpr, 20, fprbuf);
      pattern = fprbuf;
      break;
    default:
      return gpg_error (GPG_ERR_INV_USER_ID);
    }

  /* Build the request string.  */
  reselect = 0;
 again:
  {
    char *searchkey;

    xfree (hostport); hostport = NULL;
    xfree (httphost); httphost = NULL;
    err = make_host_part (ctrl, uri->scheme, uri->host, uri->port, reselect,
                          &hostport, &httpflags, &httphost);
    if (err)
      goto leave;

    searchkey = http_escape_string (pattern, EXTRA_ESCAPE_CHARS);
    if (!searchkey)
      {
        err = gpg_error_from_syserror ();
        goto leave;
      }

    xfree (request);
    request = strconcat (hostport,
                         "/pks/lookup?op=index&options=mr&search=",
                         searchkey,
                         NULL);
    xfree (searchkey);
    if (!request)
      {
        err = gpg_error_from_syserror ();
        goto leave;
      }
  }

  /* Send the request.  */
  err = send_request (ctrl, request, hostport, httphost, httpflags,
                      NULL, NULL, &fp);
  if (handle_send_request_error (err, request, &tries))
    {
      reselect = 1;
      goto again;
    }
  if (err)
    goto leave;

  err = dirmngr_status (ctrl, "SOURCE", hostport, NULL);
  if (err)
    goto leave;

  /* Peek at the response.  */
  {
    int c = es_getc (fp);
    if (c == -1)
      {
        err = es_ferror (fp)?gpg_error_from_syserror ():gpg_error (GPG_ERR_EOF);
        log_error ("error reading response: %s\n", gpg_strerror (err));
        goto leave;
      }
    if (c == '<')
      {
        /* The document begins with a '<': Assume a HTML response,
           which we don't support.  */
        err = gpg_error (GPG_ERR_UNSUPPORTED_ENCODING);
        goto leave;
      }
    es_ungetc (c, fp);
  }

  /* Return the read stream.  */
  *r_fp = fp;
  fp = NULL;

 leave:
  es_fclose (fp);
  xfree (request);
  xfree (hostport);
  xfree (httphost);
  return err;
}
示例#11
0
文件: ocsp.c 项目: FMayzek/gnupg
/* Read from FP and return a newly allocated buffer in R_BUFFER with the
   entire data read from FP. */
static gpg_error_t
read_response (estream_t fp, unsigned char **r_buffer, size_t *r_buflen)
{
  gpg_error_t err;
  unsigned char *buffer;
  size_t bufsize, nbytes;

  *r_buffer = NULL;
  *r_buflen = 0;

  bufsize = 4096;
  buffer = xtrymalloc (bufsize);
  if (!buffer)
    return gpg_error_from_errno (errno);

  nbytes = 0;
  for (;;)
    {
      unsigned char *tmp;
      size_t nread = 0;

      assert (nbytes < bufsize);
      nread = es_fread (buffer+nbytes, 1, bufsize-nbytes, fp);
      if (nread < bufsize-nbytes && es_ferror (fp))
        {
          err = gpg_error_from_errno (errno);
          log_error (_("error reading from responder: %s\n"),
                     strerror (errno));
          xfree (buffer);
          return err;
        }
      if ( !(nread == bufsize-nbytes && !es_feof (fp)))
        { /* Response succesfully received. */
          nbytes += nread;
          *r_buffer = buffer;
          *r_buflen = nbytes;
          return 0;
        }

      nbytes += nread;

      /* Need to enlarge the buffer. */
      if (bufsize >= MAX_RESPONSE_SIZE)
        {
          log_error (_("response from server too large; limit is %d bytes\n"),
                     MAX_RESPONSE_SIZE);
          xfree (buffer);
          return gpg_error (GPG_ERR_TOO_LARGE);
        }

      bufsize += 4096;
      tmp = xtryrealloc (buffer, bufsize);
      if (!tmp)
        {
          err = gpg_error_from_errno (errno);
          xfree (buffer);
          return err;
        }
      buffer = tmp;
    }
}
示例#12
0
文件: t-poll.c 项目: cobaugh/rt-rpm
static void
test_poll (void)
{
  int ret;
  gpgrt_poll_t fds[3];
  char buffer[16];
  size_t used, nwritten;
  int c;

  memset (fds, 0, sizeof fds);
  fds[0].stream = test_stdin;
  fds[0].want_read = 1;
  fds[1].stream = test_stdout;
  fds[1].want_write = 1;
  /* FIXME: We don't use the next stream at all.  */
  fds[2].stream = test_stderr;
  fds[2].want_write = 1;
  fds[2].ignore = 1;


  used = 0;
  while (used || !fds[0].ignore)
    {
      ret = gpgrt_poll (fds, DIM(fds), -1);
      if (ret == -1)
        {
          fail ("gpgrt_poll failed: %s\n", strerror (errno));
          continue;
        }
      if (!ret)
        {
          fail ("gpgrt_poll unexpectedly timed out\n");
          continue;
        }
      show ("gpgrt_poll detected %d events\n", ret);
      if (fds[0].got_read)
        {
          /* Read from the producer.  */
          for (;;)
            {
              c = es_fgetc (fds[0].stream);
              if (c == EOF)
                {
                  if (es_feof (fds[0].stream))
                    {
                      show ("reading '%s': EOF\n", peer_stdin.name);
                      fds[0].ignore = 1; /* Not anymore needed.  */
                      peer_stdin.stop_me = 1; /* Tell the thread to stop.  */
                    }
                  else if (es_ferror (fds[0].stream))
                    {
                      fail ("error reading '%s': %s\n",
                            peer_stdin.name, strerror (errno));
                      fds[0].ignore = 1;    /* Disable.  */
                      peer_stdin.stop_me = 1; /* Tell the thread to stop.  */
                    }
                  else
                    show ("reading '%s': EAGAIN\n", peer_stdin.name);
                  break;
                }
              else
                {
                  if (used <= sizeof buffer -1)
                    buffer[used++] = c;
                  if (used == sizeof buffer)
                    {
                      show ("throttling reading from '%s'\n", peer_stdin.name);
                      fds[0].ignore = 1;
                      break;
                    }
                }
            }
          show ("read from '%s': %zu bytes\n", peer_stdin.name, used);
          if (used)
            fds[1].ignore = 0; /* Data to send.  */
        }
      if (fds[1].got_write)
        {
          if (used)
            {
              ret = es_write (fds[1].stream, buffer, used, &nwritten);
              show ("result for writing to '%s': ret=%d, n=%zu, nwritten=%zu\n",
                    peer_stdout.name, ret, used, nwritten);
              if (!ret)
                {
                  assert (nwritten <= used);
                  /* Move the remaining data to the front of buffer.  */
                  memmove (buffer, buffer + nwritten,
                           sizeof buffer - nwritten);
                  used -= nwritten;
                }
              ret = es_fflush (fds[1].stream);
              if (ret)
                fail ("Flushing for '%s' failed: %s\n",
                      peer_stdout.name, strerror (errno));
            }
          if (!used)
            fds[1].ignore = 1; /* No need to send data.  */
        }

      if (used < sizeof buffer / 2 && !peer_stdin.stop_me && fds[0].ignore)
        {
          show ("accelerate reading from '%s'\n", peer_stdin.name);
          fds[0].ignore = 0;
        }
    }
}
示例#13
0
文件: wks-util.c 项目: larryv/gnupg
/* 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;
}
示例#14
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;
}
示例#15
0
文件: tdbdump.c 项目: larryv/gnupg
void
import_ownertrust (ctrl_t ctrl, const char *fname )
{
    estream_t fp;
    int is_stdin=0;
    char line[256];
    char *p;
    size_t n, fprlen;
    unsigned int otrust;
    byte fpr[MAX_FINGERPRINT_LEN];
    int any = 0;
    int rc;

    init_trustdb (ctrl, 0);
    if( iobuf_is_pipe_filename (fname) ) {
	fp = es_stdin;
	fname = "[stdin]";
	is_stdin = 1;
    }
    else if( !(fp = es_fopen( fname, "r" )) ) {
	log_error ( _("can't open '%s': %s\n"), fname, strerror(errno) );
	return;
    }

    if (is_secured_file (es_fileno (fp)))
      {
        es_fclose (fp);
        gpg_err_set_errno (EPERM);
	log_error (_("can't open '%s': %s\n"), fname, strerror(errno) );
	return;
      }

    while (es_fgets (line, DIM(line)-1, fp)) {
	TRUSTREC rec;

	if( !*line || *line == '#' )
	    continue;
	n = strlen(line);
	if( line[n-1] != '\n' ) {
	    log_error (_("error in '%s': %s\n"), fname, _("line too long") );
	    /* ... or last line does not have a LF */
	    break; /* can't continue */
	}
	for(p = line; *p && *p != ':' ; p++ )
	    if( !hexdigitp(p) )
		break;
	if( *p != ':' ) {
	    log_error (_("error in '%s': %s\n"), fname, _("colon missing") );
	    continue;
	}
	fprlen = p - line;
	if( fprlen != 32 && fprlen != 40 && fprlen != 64) {
	    log_error (_("error in '%s': %s\n"),
                       fname, _("invalid fingerprint") );
	    continue;
	}
	if( sscanf(p, ":%u:", &otrust ) != 1 ) {
	    log_error (_("error in '%s': %s\n"),
                       fname, _("ownertrust value missing"));
	    continue;
	}
	if( !otrust )
	    continue; /* no otrust defined - no need to update or insert */
	/* Convert the ascii fingerprint to binary */
	for(p=line, fprlen=0;
            fprlen < MAX_FINGERPRINT_LEN && *p != ':';
            p += 2 )
          fpr[fprlen++] = HEXTOBIN(p[0]) * 16 + HEXTOBIN(p[1]);
	while (fprlen < MAX_FINGERPRINT_LEN)
	    fpr[fprlen++] = 0;

	rc = tdbio_search_trust_byfpr (fpr, &rec);
	if( !rc ) { /* found: update */
	    if (rec.r.trust.ownertrust != otrust)
              {
                if (!opt.quiet)
                  {
                    if( rec.r.trust.ownertrust )
                      log_info("changing ownertrust from %u to %u\n",
                               rec.r.trust.ownertrust, otrust );
                    else
                      log_info("setting ownertrust to %u\n", otrust );
                  }
                rec.r.trust.ownertrust = otrust;
                write_record (ctrl, &rec);
                any = 1;
              }
	}
	else if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND) { /* insert */
            if (!opt.quiet)
              log_info("inserting ownertrust of %u\n", otrust );
            memset (&rec, 0, sizeof rec);
            rec.recnum = tdbio_new_recnum (ctrl);
            rec.rectype = RECTYPE_TRUST;
            memcpy (rec.r.trust.fingerprint, fpr, 20);
            rec.r.trust.ownertrust = otrust;
            write_record (ctrl, &rec);
            any = 1;
	}
	else /* error */
	    log_error (_("error finding trust record in '%s': %s\n"),
                       fname, gpg_strerror (rc));
    }
    if (es_ferror (fp))
	log_error ( _("read error in '%s': %s\n"), fname, strerror(errno) );
    if (!is_stdin)
	es_fclose (fp);

    if (any)
      {
        revalidation_mark (ctrl);
        rc = tdbio_sync ();
        if (rc)
          log_error (_("trustdb: sync failed: %s\n"), gpg_strerror (rc) );
      }

}