Ejemplo n.º 1
0
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;
}
Ejemplo n.º 2
0
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;
}
Ejemplo n.º 3
0
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;
}
Ejemplo n.º 4
0
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;
}
Ejemplo n.º 5
0
/* 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;
}
Ejemplo n.º 6
0
static gpgme_error_t
status_handler(void *opaque, int fd)
{
    gpg_error_t assuan_err;
    gpgme_error_t err = 0;
    engine_gpgsm_t gpgsm = opaque;
    char *line;
    size_t linelen;

    do
    {
        assuan_err = assuan_read_line(gpgsm->assuan_ctx, &line, &linelen);
        if(assuan_err)
        {
            /* Try our best to terminate the connection friendly.  */
            /*	  assuan_write_line (gpgsm->assuan_ctx, "BYE"); */
            err = map_assuan_error(assuan_err);
            DEBUG3("fd %d: error from assuan (%d) getting status line : %s \n",
                   fd, assuan_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 = map_assuan_error(atoi(&line[4]));
            else
                err = gpg_error(GPG_ERR_GENERAL);
            DEBUG2("fd %d: ERR line - mapped to: %s\n",
                   fd, err ? gpg_strerror(err) : "ok");
        }
        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);
            }
            _gpgme_io_close(gpgsm->status_cb.fd);
            DEBUG2("fd %d: OK line - final status: %s\n",
                   fd, err ? gpg_strerror(err) : "ok");
            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_errno(errno);
                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++;
                }
            }
            DEBUG2("fd %d: D line; final status: %s\n",
                   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 = 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);
            DEBUG3("fd %d: S line (%s) - final status: %s\n",
                   fd, line + 2, err ? gpg_strerror(err) : "ok");
        }
    }
    while(!err && assuan_pending_line(gpgsm->assuan_ctx));

    return err;
}