Esempio n. 1
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;
}
Esempio n. 2
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;
}
Esempio n. 3
0
/* Decode the C formatted string SRC and store the result in the
   buffer *DESTP which is LEN bytes long.  If LEN is zero, then a
   large enough buffer is allocated with malloc and *DESTP is set to
   the result.  Currently, LEN is only used to specify if allocation
   is desired or not, the caller is expected to make sure that *DESTP
   is large enough if LEN is not zero.  */
gpgme_error_t
_gpgme_decode_c_string (const char *src, char **destp, size_t len)
{
  char *dest;

  /* Set up the destination buffer.  */
  if (len)
    {
      if (len < strlen (src) + 1)
	return gpg_error (GPG_ERR_INTERNAL);

      dest = *destp;
    }
  else
    {
      /* The converted string will never be larger than the original
	 string.  */
      dest = malloc (strlen (src) + 1);
      if (!dest)
	return gpg_error_from_errno (errno);

      *destp = dest;
    }

  /* Convert the string.  */
  while (*src)
    {
      if (*src != '\\')
	{
	  *(dest++) = *(src++);
	  continue;
	}

      switch (src[1])
	{
#define DECODE_ONE(match,result)	\
	case match:			\
	  src += 2;			\
	  *(dest++) = result;		\
	  break;

	  DECODE_ONE ('\'', '\'');
	  DECODE_ONE ('\"', '\"');
	  DECODE_ONE ('\?', '\?');
	  DECODE_ONE ('\\', '\\');
	  DECODE_ONE ('a', '\a');
	  DECODE_ONE ('b', '\b');
	  DECODE_ONE ('f', '\f');
	  DECODE_ONE ('n', '\n');
	  DECODE_ONE ('r', '\r');
	  DECODE_ONE ('t', '\t');
	  DECODE_ONE ('v', '\v');

	case 'x':
	  {
	    int val = _gpgme_hextobyte (&src[2]);

	    if (val == -1)
	      {
		/* Should not happen.  */
		*(dest++) = *(src++);
		*(dest++) = *(src++);
		if (*src)
		  *(dest++) = *(src++);
		if (*src)
		  *(dest++) = *(src++);
	      }
	    else
	      {
		if (!val)
		  {
		    /* A binary zero is not representable in a C
		       string.  */
		    *(dest++) = '\\';
		    *(dest++) = '0'; 
		  }
		else 
		  *((unsigned char *) dest++) = val;
		src += 4;
	      }
	  }
	  break;

	default:
	  {
	    /* Should not happen.  */
	    *(dest++) = *(src++);
	    *(dest++) = *(src++);
	  }
        } 
    }
  *(dest++) = 0;

  return 0;
}
Esempio n. 4
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;
}
Esempio n. 5
0
/* Decode the percent escaped string SRC and store the result in the
   buffer *DESTP which is LEN bytes long.  If LEN is zero, then a
   large enough buffer is allocated with malloc and *DESTP is set to
   the result.  Currently, LEN is only used to specify if allocation
   is desired or not, the caller is expected to make sure that *DESTP
   is large enough if LEN is not zero.  If BINARY is 1, then '\0'
   characters are allowed in the output.  */
gpgme_error_t
_gpgme_decode_percent_string (const char *src, char **destp, size_t len,
			      int binary)
{
  char *dest;

  /* Set up the destination buffer.  */
  if (len)
    {
      if (len < strlen (src) + 1)
	return gpg_error (GPG_ERR_INTERNAL);

      dest = *destp;
    }
  else
    {
      /* The converted string will never be larger than the original
	 string.  */
      dest = malloc (strlen (src) + 1);
      if (!dest)
	return gpg_error_from_errno (errno);

      *destp = dest;
    }

  /* Convert the string.  */
  while (*src)
    {
      if (*src != '%')
	{
	  *(dest++) = *(src++);
	  continue;
	}
      else
	{
	  int val = _gpgme_hextobyte (&src[1]);
	  
	  if (val == -1)
	    {
	      /* Should not happen.  */
	      *(dest++) = *(src++);
	      if (*src)
		*(dest++) = *(src++);
	      if (*src)
		*(dest++) = *(src++);
	    }
	  else
	    {
	      if (!val && !binary)
		{
		  /* A binary zero is not representable in a C
		     string.  */
		  *(dest++) = '\\';
		  *(dest++) = '0'; 
		}
	      else 
		*((unsigned char *) dest++) = val;
	      src += 3;
	    }
	}
    }
  *(dest++) = 0;

  return 0;
}