コード例 #1
0
ファイル: assuan-handler.c プロジェクト: tierney/lockbox-py
static gpg_error_t
std_handler_help (assuan_context_t ctx, char *line)
{
  unsigned int i;
  char buf[ASSUAN_LINELENGTH];
  const char *helpstr;
  size_t n;

  n = strcspn (line, " \t\n");
  if (!n)
    {
      /* Print all commands.  If a help string is available and that
         starts with the command name, print the first line of the
         help string.  */
      for (i = 0; i < ctx->cmdtbl_used; i++)
        {
          n = strlen (ctx->cmdtbl[i].name);
          helpstr = ctx->cmdtbl[i].helpstr;
          if (helpstr
              && !strncmp (ctx->cmdtbl[i].name, helpstr, n)
              && (!helpstr[n] || helpstr[n] == '\n' || helpstr[n] == ' ')
              && (n = strcspn (helpstr, "\n"))          )
            snprintf (buf, sizeof (buf), "# %.*s", (int)n, helpstr);
          else
            snprintf (buf, sizeof (buf), "# %s", ctx->cmdtbl[i].name);
          buf[ASSUAN_LINELENGTH - 1] = '\0';
          assuan_write_line (ctx, buf);
        }
    }
  else
    {
      /* Print the help for the given command.  */
      int c = line[n];
      line[n] = 0;
      for (i=0; ctx->cmdtbl[i].name; i++)
        if (!my_strcasecmp (line, ctx->cmdtbl[i].name))
          break;
      line[n] = c;
      if (!ctx->cmdtbl[i].name)
        return PROCESS_DONE (ctx, set_error (ctx,GPG_ERR_UNKNOWN_COMMAND,NULL));
      helpstr = ctx->cmdtbl[i].helpstr;
      if (!helpstr)
        return PROCESS_DONE (ctx, set_error (ctx, GPG_ERR_NOT_FOUND, NULL));
      do
        {
          n = strcspn (helpstr, "\n");
          snprintf (buf, sizeof (buf), "# %.*s", (int)n, helpstr);
          helpstr += n;
          if (*helpstr == '\n')
            helpstr++;
          buf[ASSUAN_LINELENGTH - 1] = '\0';
          assuan_write_line (ctx, buf);
        }
      while (*helpstr);
    }

  return PROCESS_DONE (ctx, 0);
}
コード例 #2
0
assuan_error_t
assuan_send_data (assuan_context_t ctx, const void *buffer, size_t length)
{
  if (!ctx)
    return ASSUAN_Invalid_Value;
  if (!buffer && length)
    return ASSUAN_Invalid_Value;

  if (!buffer)
    { /* flush what we have */
      _assuan_cookie_write_flush (ctx);
      if (ctx->outbound.data.error)
        return ctx->outbound.data.error;
      if (!ctx->is_server)
        return assuan_write_line (ctx, "END");
    }
  else
    {
      _assuan_cookie_write_data (ctx, buffer, length);
      if (ctx->outbound.data.error)
        return ctx->outbound.data.error;
    }

  return 0;
}
コード例 #3
0
gpg_error_t
assuan_send_data (assuan_context_t ctx, const void *buffer, size_t length)
{
  if (!ctx)
    return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
  if (!buffer && length > 1)
    return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);

  if (!buffer)
    { /* flush what we have */
      _assuan_cookie_write_flush (ctx);
      if (ctx->outbound.data.error)
        return ctx->outbound.data.error;
      if (!ctx->is_server)
        return assuan_write_line (ctx, length == 1? "CAN":"END");
    }
  else
    {
      _assuan_cookie_write_data (ctx, buffer, length);
      if (ctx->outbound.data.error)
        return ctx->outbound.data.error;
    }

  return 0;
}
コード例 #4
0
ファイル: client.c プロジェクト: GroovIM/transport
/* Disconnect and release the context CTX.  */
void
_assuan_client_release (assuan_context_t ctx)
{
  assuan_write_line (ctx, "BYE");

  _assuan_client_finish (ctx);
}
コード例 #5
0
ファイル: call-scd.c プロジェクト: CSNW/gnupg
static gpg_error_t
pass_status_thru (void *opaque, const char *line)
{
  assuan_context_t ctx = opaque;
  char keyword[200];
  int i;

  if (line[0] == '#' && (!line[1] || spacep (line+1)))
    {
      /* We are called in convey comments mode.  Now, if we see a
         comment marker as keyword we forward the line verbatim to the
         the caller.  This way the comment lines from scdaemon won't
         appear as status lines with keyword '#'.  */
      assuan_write_line (ctx, line);
    }
  else
    {
      for (i=0; *line && !spacep (line) && i < DIM(keyword)-1; line++, i++)
        keyword[i] = *line;
      keyword[i] = 0;

      /* Truncate any remaining keyword stuff.  */
      for (; *line && !spacep (line); line++)
        ;
      while (spacep (line))
        line++;

      assuan_write_status (ctx, keyword, line);
    }
  return 0;
}
コード例 #6
0
ファイル: engine-gpgsm.c プロジェクト: bilalnurhusien/gpgme
static gpgme_error_t
start (engine_gpgsm_t gpgsm, const char *command)
{
  gpgme_error_t err;
  assuan_fd_t afdlist[5];
  int fdlist[5];
  int nfds;
  int i;

  /* We need to know the fd used by assuan for reads.  We do this by
     using the assumption that the first returned fd from
     assuan_get_active_fds() is always this one.  */
  nfds = assuan_get_active_fds (gpgsm->assuan_ctx, 0 /* read fds */,
                                afdlist, DIM (afdlist));
  if (nfds < 1)
    return gpg_error (GPG_ERR_GENERAL);	/* FIXME */
  /* For now... */
  for (i = 0; i < nfds; i++)
    fdlist[i] = (int) afdlist[i];

  /* We "duplicate" the file descriptor, so we can close it here (we
     can't close fdlist[0], as that is closed by libassuan, and
     closing it here might cause libassuan to close some unrelated FD
     later).  Alternatively, we could special case status_fd and
     register/unregister it manually as needed, but this increases
     code duplication and is more complicated as we can not use the
     close notifications etc.  A third alternative would be to let
     Assuan know that we closed the FD, but that complicates the
     Assuan interface.  */

  gpgsm->status_cb.fd = _gpgme_io_dup (fdlist[0]);
  if (gpgsm->status_cb.fd < 0)
    return gpg_error_from_syserror ();

  if (_gpgme_io_set_close_notify (gpgsm->status_cb.fd,
				  close_notify_handler, gpgsm))
    {
      _gpgme_io_close (gpgsm->status_cb.fd);
      gpgsm->status_cb.fd = -1;
      return gpg_error (GPG_ERR_GENERAL);
    }

  err = add_io_cb (gpgsm, &gpgsm->status_cb, status_handler);
  if (!err && gpgsm->input_cb.fd != -1)
    err = add_io_cb (gpgsm, &gpgsm->input_cb, _gpgme_data_outbound_handler);
  if (!err && gpgsm->output_cb.fd != -1)
    err = add_io_cb (gpgsm, &gpgsm->output_cb, _gpgme_data_inbound_handler);
  if (!err && gpgsm->message_cb.fd != -1)
    err = add_io_cb (gpgsm, &gpgsm->message_cb, _gpgme_data_outbound_handler);

  if (!err)
    err = assuan_write_line (gpgsm->assuan_ctx, command);

  if (!err)
    gpgsm_io_event (gpgsm, GPGME_EVENT_START, NULL);

  return err;
}
コード例 #7
0
/**
 * assuan_accept:
 * @ctx: context
 * 
 * Cancel any existing connection and wait for a connection from a
 * client.  The initial handshake is performed which may include an
 * initial authentication or encryption negotiation.
 * 
 * Return value: 0 on success or an error if the connection could for
 * some reason not be established.
 **/
assuan_error_t
assuan_accept (assuan_context_t ctx)
{
  int rc;
  const char *p, *pend;

  if (!ctx)
    return _assuan_error (ASSUAN_Invalid_Value);

  if (ctx->pipe_mode > 1)
    return -1; /* second invocation for pipemode -> terminate */
  ctx->finish_handler (ctx);

  rc = ctx->accept_handler (ctx);
  if (rc)
    return rc;

  /* Send the hello. */
  p = ctx->hello_line;
  if (p && (pend = strchr (p, '\n')))
    { /* This is a multi line hello.  Send all but the last line as
         comments. */
      do
        {
          rc = _assuan_write_line (ctx, "# ", p, pend - p);
          if (rc)
            return rc;
          p = pend + 1;
          pend = strchr (p, '\n');
        }
      while (pend);
      rc = _assuan_write_line (ctx, "OK ", p, strlen (p));
    }
  else if (p)
    rc = assuan_write_line (ctx, p);
  else
    rc = assuan_write_line (ctx, "OK Pleased to meet you");
  if (rc)
    return rc;
  
  if (ctx->pipe_mode)
    ctx->pipe_mode = 2;
  
  return 0;
}
コード例 #8
0
ファイル: engine-gpgsm.c プロジェクト: bilalnurhusien/gpgme
static gpgme_error_t
gpgsm_assuan_simple_command (assuan_context_t ctx, char *cmd,
			     engine_status_handler_t status_fnc,
			     void *status_fnc_value)
{
  gpg_error_t err;
  char *line;
  size_t linelen;

  err = assuan_write_line (ctx, cmd);
  if (err)
    return err;

  do
    {
      err = assuan_read_line (ctx, &line, &linelen);
      if (err)
	return err;

      if (*line == '#' || !linelen)
	continue;

      if (linelen >= 2
	  && line[0] == 'O' && line[1] == 'K'
	  && (line[2] == '\0' || line[2] == ' '))
	return 0;
      else if (linelen >= 4
	  && line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
	  && line[3] == ' ')
	err = atoi (&line[4]);
      else if (linelen >= 2
	       && line[0] == 'S' && line[1] == ' ')
	{
	  char *rest;
	  gpgme_status_code_t r;

	  rest = strchr (line + 2, ' ');
	  if (!rest)
	    rest = line + linelen; /* set to an empty string */
	  else
	    *(rest++) = 0;

	  r = _gpgme_parse_status (line + 2);

	  if (r >= 0 && status_fnc)
	    err = status_fnc (status_fnc_value, r, rest);
	  else
	    err = gpg_error (GPG_ERR_GENERAL);
	}
      else
	err = gpg_error (GPG_ERR_GENERAL);
    }
  while (!err);

  return err;
}
コード例 #9
0
ファイル: assuan-handler.c プロジェクト: tierney/lockbox-py
gpg_error_t
assuan_write_status (assuan_context_t ctx,
                     const char *keyword, const char *text)
{
  char buffer[256];
  char *helpbuf;
  size_t n;
  gpg_error_t ae;

  if ( !ctx || !keyword)
    return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
  if (!text)
    text = "";

  n = 2 + strlen (keyword) + 1 + strlen (text) + 1;
  if (n < sizeof (buffer))
    {
      strcpy (buffer, "S ");
      strcat (buffer, keyword);
      if (*text)
        {
          strcat (buffer, " ");
          strcat (buffer, text);
        }
      ae = assuan_write_line (ctx, buffer);
    }
  else if ( (helpbuf = _assuan_malloc (ctx, n)) )
    {
      strcpy (helpbuf, "S ");
      strcat (helpbuf, keyword);
      if (*text)
        {
          strcat (helpbuf, " ");
          strcat (helpbuf, text);
        }
      ae = assuan_write_line (ctx, helpbuf);
      _assuan_free (ctx, helpbuf);
    }
  else
    ae = 0;
  return ae;
}
コード例 #10
0
ファイル: engine-gpgsm.c プロジェクト: serghei/kde3-kdepim
static gpgme_error_t
start(engine_gpgsm_t gpgsm, const char *command)
{
    gpgme_error_t err;
    int fdlist[5];
    int nfds;

    /* We need to know the fd used by assuan for reads.  We do this by
       using the assumption that the first returned fd from
       assuan_get_active_fds() is always this one.  */
    nfds = assuan_get_active_fds(gpgsm->assuan_ctx, 0 /* read fds */,
                                 fdlist, DIM(fdlist));
    if(nfds < 1)
        return gpg_error(GPG_ERR_GENERAL);	/* FIXME */

    /* We duplicate the file descriptor, so we can close it without
       disturbing assuan.  Alternatively, we could special case
       status_fd and register/unregister it manually as needed, but this
       increases code duplication and is more complicated as we can not
       use the close notifications etc.  */
    gpgsm->status_cb.fd = dup(fdlist[0]);
    if(gpgsm->status_cb.fd < 0)
        return gpg_error_from_syserror();

    if(_gpgme_io_set_close_notify(gpgsm->status_cb.fd,
                                  close_notify_handler, gpgsm))
    {
        close(gpgsm->status_cb.fd);
        gpgsm->status_cb.fd = -1;
        return gpg_error(GPG_ERR_GENERAL);
    }

    err = add_io_cb(gpgsm, &gpgsm->status_cb, status_handler);
    if(!err && gpgsm->input_cb.fd != -1)
        err = add_io_cb(gpgsm, &gpgsm->input_cb, _gpgme_data_outbound_handler);
    if(!err && gpgsm->output_cb.fd != -1)
        err = add_io_cb(gpgsm, &gpgsm->output_cb, _gpgme_data_inbound_handler);
    if(!err && gpgsm->message_cb.fd != -1)
        err = add_io_cb(gpgsm, &gpgsm->message_cb, _gpgme_data_outbound_handler);

    if(!err)
        err = map_assuan_error(assuan_write_line(gpgsm->assuan_ctx, command));

    if(!err)
        (*gpgsm->io_cbs.event)(gpgsm->io_cbs.event_priv, GPGME_EVENT_START, NULL);

    return err;
}
コード例 #11
0
ファイル: assuan-inquire.c プロジェクト: autoscatto/poldi
/**
 * assuan_inquire_ext:
 * @ctx: An assuan context
 * @keyword: The keyword used for the inquire
 * @maxlen: If not 0, the size limit of the inquired data.
 * @cb: A callback handler which is invoked after the operation completed.
 * @cb_data: A user-provided value passed to the callback handler.
 * 
 * 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.
 * When this function returns, 
 *
 * Return value: 0 on success or an ASSUAN error code
 **/
assuan_error_t
assuan_inquire_ext (assuan_context_t ctx, const char *keyword, size_t maxlen,
		    int (*cb) (void *cb_data, int rc, unsigned char *buf,
			       size_t len),
		    void *cb_data)
{
  assuan_error_t rc;
  struct membuf *mb = NULL;
  char cmdbuf[LINELENGTH-10]; /* (10 = strlen ("INQUIRE ")+CR,LF) */

  if (!ctx || !keyword || (10 + strlen (keyword) >= sizeof (cmdbuf)))
    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);

  mb = malloc (sizeof (struct membuf));
  if (!mb)
    return _assuan_error (ASSUAN_Out_Of_Core);
  init_membuf (mb, maxlen ? maxlen : 1024, maxlen);

  strcpy (stpcpy (cmdbuf, "INQUIRE "), keyword);
  rc = assuan_write_line (ctx, cmdbuf);
  if (rc)
    {
      free_membuf (mb); 
      free (mb);
      return rc;
    }

  ctx->in_inquire = 1;

  /* Set up the continuation.  */
  ctx->inquire_cb = cb;
  ctx->inquire_cb_data = cb_data;
  ctx->inquire_membuf = mb;

  return 0;
}
コード例 #12
0
/**
 * assuan_inquire_ext:
 * @ctx: An assuan context
 * @keyword: The keyword used for the inquire
 * @maxlen: If not 0, the size limit of the inquired data.
 * @cb: A callback handler which is invoked after the operation completed.
 * @cb_data: A user-provided value passed to the callback handler.
 * 
 * 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.
 * When this function returns, 
 *
 * Return value: 0 on success or an ASSUAN error code
 **/
gpg_error_t
assuan_inquire_ext (assuan_context_t ctx, const char *keyword, size_t maxlen,
		    gpg_error_t (*cb) (void *cb_data, gpg_error_t rc,
				       unsigned char *buf, size_t len),
		    void *cb_data)
{
  gpg_error_t rc;
  struct membuf *mb = NULL;
  char cmdbuf[LINELENGTH-10]; /* (10 = strlen ("INQUIRE ")+CR,LF) */

  if (!ctx || !keyword || (10 + strlen (keyword) >= sizeof (cmdbuf)))
    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);

  mb = malloc (sizeof (struct membuf));
  if (!mb)
    return _assuan_error (ctx, gpg_err_code_from_syserror ());
  init_membuf (ctx, mb, maxlen ? maxlen : 1024, maxlen);

  strcpy (stpcpy (cmdbuf, "INQUIRE "), keyword);
  rc = assuan_write_line (ctx, cmdbuf);
  if (rc)
    {
      free_membuf (ctx, mb); 
      free (mb);
      return rc;
    }

  ctx->in_inquire = 1;

  /* Set up the continuation.  */
  ctx->inquire_cb = cb;
  ctx->inquire_cb_data = cb_data;
  ctx->inquire_membuf = mb;

  return 0;
}
コード例 #13
0
ファイル: call-scd.c プロジェクト: CSNW/gnupg
static gpg_error_t
cancel_inquire (ctrl_t ctrl, gpg_error_t rc)
{
  gpg_error_t oldrc = rc;

  /* The inquire callback was called and transact returned a
     cancel error.  We assume that the inquired process sent a
     CANCEL.  The passthrough code is not able to pass on the
     CANCEL and thus scdaemon would stuck on this.  As a
     workaround we send a CANCEL now.  */
  rc = assuan_write_line (ctrl->scd_local->ctx, "CAN");
  if (!rc) {
    char *line;
    size_t len;

    rc = assuan_read_line (ctrl->scd_local->ctx, &line, &len);
    if (!rc)
      rc = oldrc;
  }

  return rc;
}
コード例 #14
0
ファイル: engine-gpgsm.c プロジェクト: bilalnurhusien/gpgme
static gpgme_error_t
status_handler (void *opaque, int fd)
{
  struct io_cb_data *data = (struct io_cb_data *) opaque;
  engine_gpgsm_t gpgsm = (engine_gpgsm_t) data->handler_value;
  gpgme_error_t err = 0;
  char *line;
  size_t linelen;

  do
    {
      err = assuan_read_line (gpgsm->assuan_ctx, &line, &linelen);
      if (err)
	{
	  /* Try our best to terminate the connection friendly.  */
	  /*	  assuan_write_line (gpgsm->assuan_ctx, "BYE"); */
          TRACE3 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
		  "fd 0x%x: error from assuan (%d) getting status line : %s",
                  fd, err, gpg_strerror (err));
	}
      else if (linelen >= 3
	       && line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
	       && (line[3] == '\0' || line[3] == ' '))
	{
	  if (line[3] == ' ')
	    err = atoi (&line[4]);
	  if (! err)
	    err = gpg_error (GPG_ERR_GENERAL);
          TRACE2 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
		  "fd 0x%x: ERR line - mapped to: %s",
                  fd, err ? gpg_strerror (err) : "ok");
	  /* Try our best to terminate the connection friendly.  */
	  /*	  assuan_write_line (gpgsm->assuan_ctx, "BYE"); */
	}
      else if (linelen >= 2
	       && line[0] == 'O' && line[1] == 'K'
	       && (line[2] == '\0' || line[2] == ' '))
	{
	  if (gpgsm->status.fnc)
	    err = gpgsm->status.fnc (gpgsm->status.fnc_value,
				     GPGME_STATUS_EOF, "");

	  if (!err && gpgsm->colon.fnc && gpgsm->colon.any)
            {
              /* We must tell a colon function about the EOF. We do
                 this only when we have seen any data lines.  Note
                 that this inlined use of colon data lines will
                 eventually be changed into using a regular data
                 channel. */
              gpgsm->colon.any = 0;
              err = gpgsm->colon.fnc (gpgsm->colon.fnc_value, NULL);
            }
          TRACE2 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
		  "fd 0x%x: OK line - final status: %s",
                  fd, err ? gpg_strerror (err) : "ok");
	  _gpgme_io_close (gpgsm->status_cb.fd);
	  return err;
	}
      else if (linelen > 2
	       && line[0] == 'D' && line[1] == ' '
	       && gpgsm->colon.fnc)
        {
	  /* We are using the colon handler even for plain inline data
             - strange name for that function but for historic reasons
             we keep it.  */
          /* FIXME We can't use this for binary data because we
             assume this is a string.  For the current usage of colon
             output it is correct.  */
          char *src = line + 2;
	  char *end = line + linelen;
	  char *dst;
          char **aline = &gpgsm->colon.attic.line;
	  int *alinelen = &gpgsm->colon.attic.linelen;

	  if (gpgsm->colon.attic.linesize < *alinelen + linelen + 1)
	    {
	      char *newline = realloc (*aline, *alinelen + linelen + 1);
	      if (!newline)
		err = gpg_error_from_syserror ();
	      else
		{
		  *aline = newline;
		  gpgsm->colon.attic.linesize += linelen + 1;
		}
	    }
	  if (!err)
	    {
	      dst = *aline + *alinelen;

	      while (!err && src < end)
		{
		  if (*src == '%' && src + 2 < end)
		    {
		      /* Handle escaped characters.  */
		      ++src;
		      *dst = _gpgme_hextobyte (src);
		      (*alinelen)++;
		      src += 2;
		    }
		  else
		    {
		      *dst = *src++;
		      (*alinelen)++;
		    }

		  if (*dst == '\n')
		    {
		      /* Terminate the pending line, pass it to the colon
			 handler and reset it.  */

		      gpgsm->colon.any = 1;
		      if (*alinelen > 1 && *(dst - 1) == '\r')
			dst--;
		      *dst = '\0';

		      /* FIXME How should we handle the return code?  */
		      err = gpgsm->colon.fnc (gpgsm->colon.fnc_value, *aline);
		      if (!err)
			{
			  dst = *aline;
			  *alinelen = 0;
			}
		    }
		  else
		    dst++;
		}
	    }
          TRACE2 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
		  "fd 0x%x: D line; final status: %s",
                  fd, err? gpg_strerror (err):"ok");
        }
      else if (linelen > 2
	       && line[0] == 'D' && line[1] == ' '
	       && gpgsm->inline_data)
        {
          char *src = line + 2;
	  char *end = line + linelen;
	  char *dst = src;
          ssize_t nwritten;

          linelen = 0;
          while (src < end)
            {
              if (*src == '%' && src + 2 < end)
                {
                  /* Handle escaped characters.  */
                  ++src;
                  *dst++ = _gpgme_hextobyte (src);
                  src += 2;
                }
              else
                *dst++ = *src++;

              linelen++;
            }

          src = line + 2;
          while (linelen > 0)
            {
              nwritten = gpgme_data_write (gpgsm->inline_data, src, linelen);
              if (!nwritten || (nwritten < 0 && errno != EINTR)
                  || nwritten > linelen)
                {
                  err = gpg_error_from_syserror ();
                  break;
                }
              src += nwritten;
              linelen -= nwritten;
            }

          TRACE2 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
		  "fd 0x%x: D inlinedata; final status: %s",
                  fd, err? gpg_strerror (err):"ok");
        }
      else if (linelen > 2
	       && line[0] == 'S' && line[1] == ' ')
	{
	  char *rest;
	  gpgme_status_code_t r;

	  rest = strchr (line + 2, ' ');
	  if (!rest)
	    rest = line + linelen; /* set to an empty string */
	  else
	    *(rest++) = 0;

	  r = _gpgme_parse_status (line + 2);

	  if (r >= 0)
	    {
	      if (gpgsm->status.fnc)
		err = gpgsm->status.fnc (gpgsm->status.fnc_value, r, rest);
	    }
	  else
	    fprintf (stderr, "[UNKNOWN STATUS]%s %s", line + 2, rest);
          TRACE3 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
		  "fd 0x%x: S line (%s) - final status: %s",
                  fd, line+2, err? gpg_strerror (err):"ok");
	}
      else if (linelen >= 7
               && line[0] == 'I' && line[1] == 'N' && line[2] == 'Q'
               && line[3] == 'U' && line[4] == 'I' && line[5] == 'R'
               && line[6] == 'E'
               && (line[7] == '\0' || line[7] == ' '))
        {
          char *keyword = line+7;

          while (*keyword == ' ')
            keyword++;;
          default_inq_cb (gpgsm, keyword);
          assuan_write_line (gpgsm->assuan_ctx, "END");
        }

    }
  while (!err && assuan_pending_line (gpgsm->assuan_ctx));

  return err;
}
コード例 #15
0
ファイル: assuan-handler.c プロジェクト: tierney/lockbox-py
/* Call this to acknowledge the current command.  */
gpg_error_t
assuan_process_done (assuan_context_t ctx, gpg_error_t rc)
{
  if (!ctx->in_command)
    return _assuan_error (ctx, GPG_ERR_ASS_GENERAL);

  ctx->in_command = 0;

  /* Check for data write errors.  */
  if (ctx->outbound.data.fp)
    {
      /* Flush the data lines.  */
      fclose (ctx->outbound.data.fp);
      ctx->outbound.data.fp = NULL;
      if (!rc && ctx->outbound.data.error)
	rc = ctx->outbound.data.error;
    }
  else
    {
      /* Flush any data send without using the data FP.  */
      assuan_send_data (ctx, NULL, 0);
      if (!rc && ctx->outbound.data.error)
	rc = ctx->outbound.data.error;
    }

  /* Error handling.  */
  if (!rc)
    {
      if (ctx->process_complete)
	{
	  /* No error checking because the peer may have already
	     disconnect. */
	  assuan_write_line (ctx, "OK closing connection");
	  ctx->finish_handler (ctx);
	}
      else
	rc = assuan_write_line (ctx, ctx->okay_line ? ctx->okay_line : "OK");
    }
  else
    {
      char errline[300];
      const char *text = ctx->err_no == rc ? ctx->err_str : NULL;
      char ebuf[50];

      gpg_strerror_r (rc, ebuf, sizeof (ebuf));
      sprintf (errline, "ERR %d %.50s <%.30s>%s%.100s",
	       rc, ebuf, gpg_strsource (rc),
	       text? " - ":"", text?text:"");

      rc = assuan_write_line (ctx, errline);
    }

  if (ctx->post_cmd_notify_fnc)
    ctx->post_cmd_notify_fnc (ctx, rc);

  ctx->flags.confidential = 0;
  if (ctx->okay_line)
    {
      _assuan_free (ctx, ctx->okay_line);
      ctx->okay_line = NULL;
    }

  return rc;
}
コード例 #16
0
ファイル: assuan-inquire.c プロジェクト: autoscatto/poldi
/**
 * 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;
}
コード例 #17
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
 **/
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;
}
コード例 #18
0
ファイル: engine-g13.c プロジェクト: danielmelogpi/gpgme
static gpgme_error_t
status_handler (void *opaque, int fd)
{
  struct io_cb_data *data = (struct io_cb_data *) opaque;
  engine_g13_t g13 = (engine_g13_t) data->handler_value;
  gpgme_error_t err = 0;
  char *line;
  size_t linelen;

  do
    {
      err = assuan_read_line (g13->assuan_ctx, &line, &linelen);
      if (err)
	{
	  /* Try our best to terminate the connection friendly.  */
	  /*	  assuan_write_line (g13->assuan_ctx, "BYE"); */
          TRACE2 (DEBUG_CTX, "gpgme:status_handler", g13,
		  "fd 0x%x: error reading assuan line: %s",
                  fd, gpg_strerror (err));
	}
      else if (linelen >= 3
	       && line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
	       && (line[3] == '\0' || line[3] == ' '))
	{
	  if (line[3] == ' ')
	    err = atoi (&line[4]);
	  if (! err)
	    err = gpg_error (GPG_ERR_GENERAL);
          TRACE2 (DEBUG_CTX, "gpgme:status_handler", g13,
		  "fd 0x%x: ERR line: %s",
                  fd, err ? gpg_strerror (err) : "ok");

	  /* Command execution errors are not fatal, as we use
	     a session based protocol.  */
	  data->op_err = err;

	  /* The caller will do the rest (namely, call cancel_op,
	     which closes status_fd).  */
	  return 0;
	}
      else if (linelen >= 2
	       && line[0] == 'O' && line[1] == 'K'
	       && (line[2] == '\0' || line[2] == ' '))
	{
          TRACE1 (DEBUG_CTX, "gpgme:status_handler", g13,
		  "fd 0x%x: OK line", fd);

	  _gpgme_io_close (g13->status_cb.fd);
	  return 0;
	}
      else if (linelen > 2
	       && line[0] == 'D' && line[1] == ' ')
        {
	  /* We are using the colon handler even for plain inline data
             - strange name for that function but for historic reasons
             we keep it.  */
          /* FIXME We can't use this for binary data because we
             assume this is a string.  For the current usage of colon
             output it is correct.  */
          char *src = line + 2;
	  char *end = line + linelen;
	  char *dst = src;

          linelen = 0;
          while (src < end)
            {
              if (*src == '%' && src + 2 < end)
                {
                  /* Handle escaped characters.  */
                  ++src;
                  *dst++ = _gpgme_hextobyte (src);
                  src += 2;
                }
              else
                *dst++ = *src++;

              linelen++;
            }

          src = line + 2;
          if (linelen && g13->user.data_cb)
            err = g13->user.data_cb (g13->user.data_cb_value,
                                       src, linelen);
          else
            err = 0;

          TRACE2 (DEBUG_CTX, "gpgme:g13_status_handler", g13,
		  "fd 0x%x: D inlinedata; status from cb: %s",
                  fd, (g13->user.data_cb ?
                       (err? gpg_strerror (err):"ok"):"no callback"));

        }
      else if (linelen > 2
	       && line[0] == 'S' && line[1] == ' ')
	{
	  char *src;
	  char *args;

	  src = line + 2;
          while (*src == ' ')
            src++;

	  args = strchr (line + 2, ' ');
	  if (!args)
	    args = line + linelen; /* set to an empty string */
	  else
	    *(args++) = 0;

          while (*args == ' ')
            args++;

          if (g13->user.status_cb)
            err = g13->user.status_cb (g13->user.status_cb_value,
				       src, args);
          else
            err = 0;

          TRACE3 (DEBUG_CTX, "gpgme:g13_status_handler", g13,
		  "fd 0x%x: S line (%s) - status from cb: %s",
                  fd, line+2, (g13->user.status_cb ?
                               (err? gpg_strerror (err):"ok"):"no callback"));
	}
      else if (linelen >= 7
               && line[0] == 'I' && line[1] == 'N' && line[2] == 'Q'
               && line[3] == 'U' && line[4] == 'I' && line[5] == 'R'
               && line[6] == 'E'
               && (line[7] == '\0' || line[7] == ' '))
        {
          char *src;
	  char *args;

          for (src=line+7; *src == ' '; src++)
            ;

	  args = strchr (src, ' ');
	  if (!args)
	    args = line + linelen; /* Let it point to an empty string.  */
	  else
	    *(args++) = 0;

          while (*args == ' ')
            args++;

          err = default_inq_cb (g13, src, args);
          if (!err)
            {
              /* Flush and send END.  */
              err = assuan_send_data (g13->assuan_ctx, NULL, 0);
            }
          else if (gpg_err_code (err) == GPG_ERR_ASS_CANCELED)
            {
              /* Flush and send CANcel.  */
              err = assuan_send_data (g13->assuan_ctx, NULL, 1);
            }
          assuan_write_line (g13->assuan_ctx, "END");
        }
    }
  while (!err && assuan_pending_line (g13->assuan_ctx));

  return err;
}
コード例 #19
0
ファイル: pinentry.c プロジェクト: JThramer/pinentry-mac
/* Run a quality inquiry for PASSPHRASE of LENGTH.  (We need LENGTH
   because not all backends might be able to return a proper
   C-string.).  Returns: A value between -100 and 100 to give an
   estimate of the passphrase's quality.  Negative values are use if
   the caller won't even accept that passphrase.  Note that we expect
   just one data line which should not be escaped in any represent a
   numeric signed decimal value.  Extra data is currently ignored but
   should not be send at all.  */
int
pinentry_inq_quality (pinentry_t pin, const char *passphrase, size_t length)
{
  ASSUAN_CONTEXT ctx = pin->ctx_assuan;
  const char prefix[] = "INQUIRE QUALITY ";
  char *command;
  char *line;
  size_t linelen;
  int gotvalue = 0;
  int value = 0;
  int rc;

  if (!ctx)
    return 0; /* Can't run the callback.  */

  if (length > 300)
    length = 300;  /* Limit so that it definitely fits into an Assuan
                      line.  */

  command = secmem_malloc (strlen (prefix) + 3*length + 1);
  if (!command)
    return 0;
  strcpy (command, prefix);
  copy_and_escape (command + strlen(command), passphrase, length);
  rc = assuan_write_line (ctx, command);
  secmem_free (command);
  if (rc)
    {
      fprintf (stderr, "ASSUAN WRITE LINE failed: rc=%d\n", rc);
      return 0;
    }

  for (;;)
    {
      do 
        {
          rc = assuan_read_line (ctx, &line, &linelen);
          if (rc)
            {
              fprintf (stderr, "ASSUAN READ LINE failed: rc=%d\n", rc);
              return 0;
            }
        }    
      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'
          && (!line[3] || line[3] == ' '))
        break; /* CAN command received*/
      if (line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
          && (!line[3] || line[3] == ' '))
        break; /* ERR command received*/
      if (line[0] != 'D' || line[1] != ' ' || linelen < 3 || gotvalue)
        continue;
      gotvalue = 1;
      value = atoi (line+2);
    }
  if (value < -100)
    value = -100;
  else if (value > 100)
    value = 100;

  return value;
}
コード例 #20
0
ファイル: assuan-client.c プロジェクト: autoscatto/poldi
/**
 * assuan_transact:
 * @ctx: The Assuan context
 * @command: Command line to be send to the server
 * @data_cb: Callback function for data lines
 * @data_cb_arg: first argument passed to @data_cb
 * @inquire_cb: Callback function for a inquire response
 * @inquire_cb_arg: first argument passed to @inquire_cb
 * @status_cb: Callback function for a status response
 * @status_cb_arg: first argument passed to @status_cb
 * 
 * FIXME: Write documentation
 * 
 * Return value: 0 on success or error code.  The error code may be
 * the one one returned by the server in error lines or from the
 * callback functions.  Take care: When a callback returns an error
 * this function returns immediately with an error and thus the caller
 * will altter return an Assuan error (write erro in most cases).
 **/
assuan_error_t
assuan_transact (assuan_context_t ctx,
                 const char *command,
                 int (*data_cb)(void *, const void *, size_t),
                 void *data_cb_arg,
                 int (*inquire_cb)(void*, const char *),
                 void *inquire_cb_arg,
                 int (*status_cb)(void*, const char *),
                 void *status_cb_arg)
{
  assuan_error_t rc;
  int okay, off;
  char *line;
  int linelen;

  rc = assuan_write_line (ctx, command);
  if (rc)
    return rc;

  if (*command == '#' || !*command)
    return 0; /* Don't expect a response for a comment line.  */

 again:
  rc = _assuan_read_from_server (ctx, &okay, &off);
  if (rc)
    return rc; /* error reading from server */

  line = ctx->inbound.line + off;
  linelen = ctx->inbound.linelen - off;

  if (!okay)
    {
      rc = atoi (line);
      if (rc > 0 && rc < 100)
        rc = _assuan_error (ASSUAN_Server_Fault);
      else if (rc > 0 && rc <= 405)
        rc = _assuan_error (rc);
    }
  else if (okay == 2)
    {
      if (!data_cb)
        rc = _assuan_error (ASSUAN_No_Data_Callback);
      else 
        {
          char *s, *d;

          for (s=d=line; linelen; linelen--)
            {
              if (*s == '%' && linelen > 2)
                { /* handle escaping */
                  s++;
                  *d++ = xtoi_2 (s);
                  s += 2;
                  linelen -= 2;
                }
              else
                *d++ = *s++;
            }
          *d = 0; /* add a hidden string terminator */
          rc = data_cb (data_cb_arg, line, d - line);
          if (!rc)
            goto again;
        }
    }
  else if (okay == 3)
    {
      if (!inquire_cb)
        {
          assuan_write_line (ctx, "END"); /* get out of inquire mode */
          _assuan_read_from_server (ctx, &okay, &off); /* dummy read */
          rc = _assuan_error (ASSUAN_No_Inquire_Callback);
        }
      else
        {
          rc = inquire_cb (inquire_cb_arg, line);
          if (!rc)
            rc = assuan_send_data (ctx, NULL, 0); /* flush and send END */
          if (!rc)
            goto again;
        }
    }
  else if (okay == 4)
    {
      if (status_cb)
        rc = status_cb (status_cb_arg, line);
      if (!rc)
        goto again;
    }
  else if (okay == 5)
    {
      if (!data_cb)
        rc = _assuan_error (ASSUAN_No_Data_Callback);
      else 
        {
          rc = data_cb (data_cb_arg, NULL, 0);
          if (!rc)
            goto again;
        }
    }

  return rc;
}
コード例 #21
0
ファイル: client.c プロジェクト: GroovIM/transport
/**
 * assuan_transact:
 * @ctx: The Assuan context
 * @command: Command line to be send to the server
 * @data_cb: Callback function for data lines
 * @data_cb_arg: first argument passed to @data_cb
 * @inquire_cb: Callback function for a inquire response
 * @inquire_cb_arg: first argument passed to @inquire_cb
 * @status_cb: Callback function for a status response
 * @status_cb_arg: first argument passed to @status_cb
 * 
 * FIXME: Write documentation
 * 
 * Return value: 0 on success or an error code.  The error code may be
 * the one one returned by the server via error lines or from the
 * callback functions.  Take care:  If a callback returns an error
 * this function returns immediately with this error.
 **/
gpg_error_t
assuan_transact (assuan_context_t ctx,
                 const char *command,
                 gpg_error_t (*data_cb)(void *, const void *, size_t),
                 void *data_cb_arg,
                 gpg_error_t (*inquire_cb)(void*, const char *),
                 void *inquire_cb_arg,
                 gpg_error_t (*status_cb)(void*, const char *),
                 void *status_cb_arg)
{
  gpg_error_t rc;
  assuan_response_t response;
  int off;
  char *line;
  int linelen;

  rc = assuan_write_line (ctx, command);
  if (rc)
    return rc;

  if (*command == '#' || !*command)
    return 0; /* Don't expect a response for a comment line.  */

 again:
  rc = _assuan_read_from_server (ctx, &response, &off,
                                 ctx->flags.convey_comments);
  if (rc)
    return rc; /* error reading from server */

  line = ctx->inbound.line + off;
  linelen = ctx->inbound.linelen - off;

  if (response == ASSUAN_RESPONSE_ERROR)
    rc = atoi (line);
  else if (response == ASSUAN_RESPONSE_DATA)
    {
      if (!data_cb)
        rc = _assuan_error (ctx, GPG_ERR_ASS_NO_DATA_CB);
      else 
        {
          rc = data_cb (data_cb_arg, line, linelen);
          if (!rc)
            goto again;
        }
    }
  else if (response == ASSUAN_RESPONSE_INQUIRE)
    {
      if (!inquire_cb)
        {
          assuan_write_line (ctx, "END"); /* get out of inquire mode */
          _assuan_read_from_server (ctx, &response, &off, 0); /* dummy read */
          rc = _assuan_error (ctx, GPG_ERR_ASS_NO_INQUIRE_CB);
        }
      else
        {
          rc = inquire_cb (inquire_cb_arg, line);
          if (!rc)
            rc = assuan_send_data (ctx, NULL, 0); /* flush and send END */
          if (!rc)
            goto again;
        }
    }
  else if (response == ASSUAN_RESPONSE_STATUS)
    {
      if (status_cb)
        rc = status_cb (status_cb_arg, line);
      if (!rc)
        goto again;
    }
  else if (response == ASSUAN_RESPONSE_COMMENT && ctx->flags.convey_comments)
    {
      line -= off; /* Send line with the comment marker.  */
      if (status_cb)
        rc = status_cb (status_cb_arg, line);
      if (!rc)
        goto again;
    }
  else if (response == ASSUAN_RESPONSE_END)
    {
      if (!data_cb)
        rc = _assuan_error (ctx, GPG_ERR_ASS_NO_DATA_CB);
      else 
        {
          rc = data_cb (data_cb_arg, NULL, 0);
          if (!rc)
            goto again;
        }
    }

  return rc;
}
コード例 #22
0
/**
 * assuan_transact2:
 * @ctx: The Assuan context
 * @command: Coimmand line to be send to server
 * @data_cb: Callback function for data lines
 * @data_cb_arg: first argument passed to @data_cb
 * @inquire_cb: Callback function for a inquire response
 * @inquire_cb_arg: first argument passed to @inquire_cb
 * @status_cb: Callback function for a status response
 * @status_cb_arg: first argument passed to @status_cb
 * @okay_cb: Callback function for the final  OK response
 * @okay_cb_arg: first argument passed to @okay_cb
 * 
 * FIXME: Write documentation
 * 
 * Return value: 0 on success or error code.  The error code may be
 * the one one returned by the server in error lines or from the
 * callback functions.
 **/
assuan_error_t
assuan_transact2 (assuan_context_t ctx,
                  const char *command,
                  assuan_error_t (*data_cb)(void *, const void *, size_t),
                  void *data_cb_arg,
                  assuan_error_t (*inquire_cb)(void*, const char *),
                  void *inquire_cb_arg,
                  assuan_error_t (*status_cb)(void*, const char *),
                  void *status_cb_arg,
                  assuan_error_t (*okay_cb)(void*, const char *),
                  void *okay_cb_arg)
{
  int rc, okay, off;
  unsigned char *line;
  int linelen;

  rc = assuan_write_line (ctx, command);
  if (rc)
    return rc;

  if (*command == '#' || !*command)
    return 0; /* Don't expect a response for a comment line.  */

 again:
  rc = _assuan_read_from_server (ctx, &okay, &off);
  if (rc)
    return rc; /* error reading from server */

  line = ctx->inbound.line + off;
  linelen = ctx->inbound.linelen - off;

  if (!okay)
    {
      rc = atoi (line);
      if (rc < 100)
        rc = ASSUAN_Server_Fault;
    }
  else if (okay == 1) /* Received OK. */
    {
      if (okay_cb)
        {
          rc = okay_cb (okay_cb_arg, line);
          /* We better wipe out the buffer after processing it.  This
             is no real guarantee that it won't get swapped out but at
             least for the standard cases we can make sure that a
             passphrase returned with the OK line is rendered
             unreadable.  In fact the current Assuan interface suffers
             from the problem that it is not possible to do assuan I/O
             through secure memory.  There is no easy solution given
             the current implementation but we need to address it
             sooner or later.  The problem was introduced with
             gpg-agent's GET_PASPHRASE command but it might also make
             sense to have a way to convey sessions keys through
             secured memory.  Note that the old implementation in gpg
             for accessing the passphrase in fact used secure memory
             but had the drawback of using a limited and not fully
             conforming Assuan implementation - given that pinentry
             and gpg-agent neither use secured memory for Assuan I/O,
             it is negligible to drop the old implementation in gpg's
             passphrase.c and use the wipememory workaround here.  */
          memset (line, 0, strlen (line));
        }
    }
  else if (okay == 2)
    {
      if (!data_cb)
        rc = ASSUAN_No_Data_Callback;
      else 
        {
          unsigned char *s, *d;

          for (s=d=line; linelen; linelen--)
            {
              if (*s == '%' && linelen > 2)
                { /* handle escaping */
                  s++;
                  *d++ = xtoi_2 (s);
                  s += 2;
                  linelen -= 2;
                }
              else
                *d++ = *s++;
            }
          *d = 0; /* add a hidden string terminator */
          rc = data_cb (data_cb_arg, line, d - line);
          if (!rc)
            goto again;
        }
    }
  else if (okay == 3)
    {
      if (!inquire_cb)
        {
          assuan_write_line (ctx, "END"); /* get out of inquire mode */
          _assuan_read_from_server (ctx, &okay, &off); /* dummy read */
          rc = ASSUAN_No_Inquire_Callback;
        }
      else
        {
          rc = inquire_cb (inquire_cb_arg, line);
          if (!rc)
            rc = assuan_send_data (ctx, NULL, 0); /* flush and send END */
          if (!rc)
            goto again;
        }
    }
  else if (okay == 4)
    {
      if (status_cb)
        rc = status_cb (status_cb_arg, line);
      if (!rc)
        goto again;
    }
  else if (okay == 5)
    {
      if (!data_cb)
        rc = ASSUAN_No_Data_Callback;
      else 
        {
          rc = data_cb (data_cb_arg, NULL, 0);
          if (!rc)
            goto again;
        }
    }

  return rc;
}