Blame src/op-support.c

Packit Service 672cf4
/* op-support.c - Supporting functions.
Packit Service 6c01f9
   Copyright (C) 2002, 2003, 2004, 2007 g10 Code GmbH
Packit Service 6c01f9
Packit Service 6c01f9
   This file is part of GPGME.
Packit Service 6c01f9
Packit Service 6c01f9
   GPGME is free software; you can redistribute it and/or modify it
Packit Service 6c01f9
   under the terms of the GNU Lesser General Public License as
Packit Service 6c01f9
   published by the Free Software Foundation; either version 2.1 of
Packit Service 6c01f9
   the License, or (at your option) any later version.
Packit Service 6c01f9
Packit Service 6c01f9
   GPGME is distributed in the hope that it will be useful, but
Packit Service 6c01f9
   WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 6c01f9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 6c01f9
   Lesser General Public License for more details.
Packit Service 6c01f9
Packit Service 6c01f9
   You should have received a copy of the GNU Lesser General Public
Packit Service 6c01f9
   License along with this program; if not, see <https://www.gnu.org/licenses/>.
Packit Service 672cf4
 */
Packit Service 672cf4
Packit Service 672cf4
#if HAVE_CONFIG_H
Packit Service 672cf4
#include <config.h>
Packit Service 672cf4
#endif
Packit Service 672cf4
#include <stdlib.h>
Packit Service 672cf4
#include <errno.h>
Packit Service 672cf4
#include <string.h>
Packit Service 672cf4
#ifdef HAVE_LOCALE_H
Packit Service 672cf4
#include <locale.h>
Packit Service 672cf4
#endif
Packit Service 672cf4
Packit Service 672cf4
#include "gpgme.h"
Packit Service 672cf4
#include "context.h"
Packit Service 672cf4
#include "ops.h"
Packit Service 672cf4
#include "util.h"
Packit Service 672cf4
#include "debug.h"
Packit Service 672cf4
Packit Service 672cf4
#if GPG_ERROR_VERSION_NUMBER < 0x011700  /* 1.23 */
Packit Service 672cf4
# define GPG_ERR_SUBKEYS_EXP_OR_REV 217
Packit Service 672cf4
#endif
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4

Packit Service 672cf4
gpgme_error_t
Packit Service 672cf4
_gpgme_op_data_lookup (gpgme_ctx_t ctx, ctx_op_data_id_t type, void **hook,
Packit Service 672cf4
		       int size, void (*cleanup) (void *))
Packit Service 672cf4
{
Packit Service 672cf4
  struct ctx_op_data *data;
Packit Service 672cf4
Packit Service 672cf4
  if (!ctx)
Packit Service 672cf4
    return gpg_error (GPG_ERR_INV_VALUE);
Packit Service 672cf4
Packit Service 672cf4
  data = ctx->op_data;
Packit Service 672cf4
  while (data && data->type != type)
Packit Service 672cf4
    data = data->next;
Packit Service 672cf4
  if (!data)
Packit Service 672cf4
    {
Packit Service 672cf4
      if (size < 0)
Packit Service 672cf4
	{
Packit Service 672cf4
	  *hook = NULL;
Packit Service 672cf4
	  return 0;
Packit Service 672cf4
	}
Packit Service 672cf4
Packit Service 672cf4
      data = calloc (1, sizeof (struct ctx_op_data) + size);
Packit Service 672cf4
      if (!data)
Packit Service 672cf4
	return gpg_error_from_syserror ();
Packit Service 672cf4
      data->magic = CTX_OP_DATA_MAGIC;
Packit Service 672cf4
      data->next = ctx->op_data;
Packit Service 672cf4
      data->type = type;
Packit Service 672cf4
      data->cleanup = cleanup;
Packit Service 672cf4
      data->hook = (void *) (((char *) data) + sizeof (struct ctx_op_data));
Packit Service 672cf4
      data->references = 1;
Packit Service 672cf4
      ctx->op_data = data;
Packit Service 672cf4
    }
Packit Service 672cf4
  *hook = data->hook;
Packit Service 672cf4
  return 0;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
/* type is: 0: asynchronous operation (use global or user event loop).
Packit Service 672cf4
            1: synchronous operation (always use private event loop).
Packit Service 672cf4
            2: asynchronous private operation (use private or user
Packit Service 672cf4
            event loop).
Packit Service 672cf4
            256: Modification flag to suppress the engine reset.
Packit Service 672cf4
*/
Packit Service 672cf4
gpgme_error_t
Packit Service 672cf4
_gpgme_op_reset (gpgme_ctx_t ctx, int type)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_error_t err = 0;
Packit Service 672cf4
  struct gpgme_io_cbs io_cbs;
Packit Service 672cf4
  int no_reset = (type & 256);
Packit Service 672cf4
  int reuse_engine = 0;
Packit Service 672cf4
Packit Service 672cf4
  type &= 255;
Packit Service 672cf4
Packit Service 672cf4
  _gpgme_release_result (ctx);
Packit Service 672cf4
  LOCK (ctx->lock);
Packit Service 672cf4
  ctx->canceled = 0;
Packit Service 672cf4
  ctx->redraw_suggested = 0;
Packit Service 672cf4
  UNLOCK (ctx->lock);
Packit Service 672cf4
Packit Service 672cf4
  if (ctx->engine && no_reset)
Packit Service 672cf4
    reuse_engine = 1;
Packit Service 672cf4
  else if (ctx->engine)
Packit Service 672cf4
    {
Packit Service 672cf4
      /* Attempt to reset an existing engine.  */
Packit Service 672cf4
Packit Service 672cf4
      err = _gpgme_engine_reset (ctx->engine);
Packit Service 672cf4
      if (gpg_err_code (err) == GPG_ERR_NOT_IMPLEMENTED)
Packit Service 672cf4
	{
Packit Service 672cf4
	  _gpgme_engine_release (ctx->engine);
Packit Service 672cf4
	  ctx->engine = NULL;
Packit Service 672cf4
	}
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  if (!ctx->engine)
Packit Service 672cf4
    {
Packit Service 672cf4
      gpgme_engine_info_t info;
Packit Service 672cf4
      info = ctx->engine_info;
Packit Service 672cf4
      while (info && info->protocol != ctx->protocol)
Packit Service 672cf4
	info = info->next;
Packit Service 672cf4
Packit Service 672cf4
      if (!info)
Packit Service 672cf4
	return gpg_error (GPG_ERR_UNSUPPORTED_PROTOCOL);
Packit Service 672cf4
Packit Service 672cf4
      /* Create an engine object.  */
Packit Service 672cf4
      err = _gpgme_engine_new (info, &ctx->engine);
Packit Service 672cf4
      if (err)
Packit Service 672cf4
	return err;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  if (!reuse_engine)
Packit Service 672cf4
    {
Packit Service 672cf4
      err = 0;
Packit Service 672cf4
#ifdef LC_CTYPE
Packit Service 672cf4
      err = _gpgme_engine_set_locale (ctx->engine, LC_CTYPE, ctx->lc_ctype);
Packit Service 672cf4
#endif
Packit Service 672cf4
#ifdef LC_MESSAGES
Packit Service 672cf4
      if (!err)
Packit Service 672cf4
        err = _gpgme_engine_set_locale (ctx->engine,
Packit Service 672cf4
                                        LC_MESSAGES, ctx->lc_messages);
Packit Service 672cf4
#endif
Packit Service 672cf4
      if (gpg_err_code (err) == GPG_ERR_NOT_IMPLEMENTED)
Packit Service 672cf4
	err = 0;
Packit Service 672cf4
Packit Service 672cf4
      if (!err)
Packit Service 672cf4
        {
Packit Service 672cf4
          err = _gpgme_engine_set_pinentry_mode (ctx->engine,
Packit Service 672cf4
                                                 ctx->pinentry_mode);
Packit Service 672cf4
          if (gpg_err_code (err) == GPG_ERR_NOT_IMPLEMENTED)
Packit Service 672cf4
            err = 0;
Packit Service 672cf4
        }
Packit Service 672cf4
Packit Service 672cf4
      if (!err && ctx->status_cb && ctx->full_status)
Packit Service 672cf4
        {
Packit Service 672cf4
          _gpgme_engine_set_status_cb (ctx->engine,
Packit Service 672cf4
                                       ctx->status_cb, ctx->status_cb_value);
Packit Service 672cf4
        }
Packit Service 672cf4
Packit Service 672cf4
      if (err)
Packit Service 672cf4
        {
Packit Service 672cf4
          _gpgme_engine_release (ctx->engine);
Packit Service 672cf4
          ctx->engine = NULL;
Packit Service 672cf4
          return err;
Packit Service 672cf4
        }
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  if (ctx->sub_protocol != GPGME_PROTOCOL_DEFAULT)
Packit Service 672cf4
    {
Packit Service 672cf4
      err = _gpgme_engine_set_protocol (ctx->engine, ctx->sub_protocol);
Packit Service 672cf4
      if (err)
Packit Service 672cf4
	return err;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  if (type == 1 || (type == 2 && !ctx->io_cbs.add))
Packit Service 672cf4
    {
Packit Service 672cf4
      /* Use private event loop.  */
Packit Service 672cf4
      io_cbs.add = _gpgme_add_io_cb;
Packit Service 672cf4
      io_cbs.add_priv = ctx;
Packit Service 672cf4
      io_cbs.remove = _gpgme_remove_io_cb;
Packit Service 672cf4
      io_cbs.event = _gpgme_wait_private_event_cb;
Packit Service 672cf4
      io_cbs.event_priv = ctx;
Packit Service 672cf4
    }
Packit Service 672cf4
  else if (! ctx->io_cbs.add)
Packit Service 672cf4
    {
Packit Service 672cf4
      /* Use global event loop.  */
Packit Service 672cf4
      io_cbs.add = _gpgme_add_io_cb;
Packit Service 672cf4
      io_cbs.add_priv = ctx;
Packit Service 672cf4
      io_cbs.remove = _gpgme_remove_io_cb;
Packit Service 672cf4
      io_cbs.event = _gpgme_wait_global_event_cb;
Packit Service 672cf4
      io_cbs.event_priv = ctx;
Packit Service 672cf4
    }
Packit Service 672cf4
  else
Packit Service 672cf4
    {
Packit Service 672cf4
      /* Use user event loop.  */
Packit Service 672cf4
      io_cbs.add = _gpgme_wait_user_add_io_cb;
Packit Service 672cf4
      io_cbs.add_priv = ctx;
Packit Service 672cf4
      io_cbs.remove = _gpgme_wait_user_remove_io_cb;
Packit Service 672cf4
      io_cbs.event = _gpgme_wait_user_event_cb;
Packit Service 672cf4
      io_cbs.event_priv = ctx;
Packit Service 672cf4
    }
Packit Service 672cf4
  _gpgme_engine_set_io_cbs (ctx->engine, &io_cbs);
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4

Packit Service 672cf4
/* Parse the INV_RECP or INV_SNDR status line in ARGS and return the
Packit Service 672cf4
   result in KEY.  If KC_FPR (from the KEY_CONSIDERED status line) is
Packit Service 672cf4
   not NULL take the KC_FLAGS in account. */
Packit Service 672cf4
gpgme_error_t
Packit Service 672cf4
_gpgme_parse_inv_recp (char *args, int for_signing,
Packit Service 672cf4
                       const char *kc_fpr, unsigned int kc_flags,
Packit Service 672cf4
                       gpgme_invalid_key_t *key)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_invalid_key_t inv_key;
Packit Service 672cf4
  char *tail;
Packit Service 672cf4
  long int reason;
Packit Service 672cf4
Packit Service 672cf4
  (void)for_signing;
Packit Service 672cf4
Packit Service 672cf4
  inv_key = calloc (1, sizeof (*inv_key));
Packit Service 672cf4
  if (!inv_key)
Packit Service 672cf4
    return gpg_error_from_syserror ();
Packit Service 672cf4
  inv_key->next = NULL;
Packit Service 672cf4
  gpg_err_set_errno (0);
Packit Service 672cf4
  reason = strtol (args, &tail, 0);
Packit Service 672cf4
  if (errno || args == tail || (*tail && *tail != ' '))
Packit Service 672cf4
    {
Packit Service 672cf4
      /* The crypto backend does not behave.  */
Packit Service 672cf4
      free (inv_key);
Packit Service 672cf4
      return trace_gpg_error (GPG_ERR_INV_ENGINE);
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  switch (reason)
Packit Service 672cf4
    {
Packit Service 672cf4
    case 0:
Packit Service 672cf4
      if (kc_fpr && (kc_flags & 2))
Packit Service 672cf4
        inv_key->reason = gpg_error (GPG_ERR_SUBKEYS_EXP_OR_REV);
Packit Service 672cf4
      else
Packit Service 672cf4
        inv_key->reason = gpg_error (GPG_ERR_GENERAL);
Packit Service 672cf4
      break;
Packit Service 672cf4
Packit Service 672cf4
    case 1:
Packit Service 672cf4
      inv_key->reason = gpg_error (GPG_ERR_NO_PUBKEY);
Packit Service 672cf4
      break;
Packit Service 672cf4
Packit Service 672cf4
    case 2:
Packit Service 672cf4
      inv_key->reason = gpg_error (GPG_ERR_AMBIGUOUS_NAME);
Packit Service 672cf4
      break;
Packit Service 672cf4
Packit Service 672cf4
    case 3:
Packit Service 672cf4
      inv_key->reason = gpg_error (GPG_ERR_WRONG_KEY_USAGE);
Packit Service 672cf4
      break;
Packit Service 672cf4
Packit Service 672cf4
    case 4:
Packit Service 672cf4
      inv_key->reason = gpg_error (GPG_ERR_CERT_REVOKED);
Packit Service 672cf4
      break;
Packit Service 672cf4
Packit Service 672cf4
    case 5:
Packit Service 672cf4
      inv_key->reason = gpg_error (GPG_ERR_CERT_EXPIRED);
Packit Service 672cf4
      break;
Packit Service 672cf4
Packit Service 672cf4
    case 6:
Packit Service 672cf4
      inv_key->reason = gpg_error (GPG_ERR_NO_CRL_KNOWN);
Packit Service 672cf4
      break;
Packit Service 672cf4
Packit Service 672cf4
    case 7:
Packit Service 672cf4
      inv_key->reason = gpg_error (GPG_ERR_CRL_TOO_OLD);
Packit Service 672cf4
      break;
Packit Service 672cf4
Packit Service 672cf4
    case 8:
Packit Service 672cf4
      inv_key->reason = gpg_error (GPG_ERR_NO_POLICY_MATCH);
Packit Service 672cf4
      break;
Packit Service 672cf4
Packit Service 672cf4
    case 9:
Packit Service 672cf4
      inv_key->reason = gpg_error (GPG_ERR_NO_SECKEY);
Packit Service 672cf4
      break;
Packit Service 672cf4
Packit Service 672cf4
    case 10:
Packit Service 672cf4
      inv_key->reason = gpg_error (GPG_ERR_PUBKEY_NOT_TRUSTED);
Packit Service 672cf4
      break;
Packit Service 672cf4
Packit Service 672cf4
    case 11:
Packit Service 672cf4
      inv_key->reason = gpg_error (GPG_ERR_MISSING_CERT);
Packit Service 672cf4
      break;
Packit Service 672cf4
Packit Service 672cf4
    case 12:
Packit Service 672cf4
      inv_key->reason = gpg_error (GPG_ERR_MISSING_ISSUER_CERT);
Packit Service 672cf4
      break;
Packit Service 672cf4
Packit Service 672cf4
    case 13:
Packit Service 672cf4
      inv_key->reason = gpg_error (252); /*GPG_ERR_KEY_DISABLED*/
Packit Service 672cf4
      break;
Packit Service 672cf4
Packit Service 672cf4
    case 14:
Packit Service 672cf4
      inv_key->reason = gpg_error (GPG_ERR_INV_USER_ID);
Packit Service 672cf4
      break;
Packit Service 672cf4
Packit Service 672cf4
    default:
Packit Service 672cf4
      inv_key->reason = gpg_error (GPG_ERR_GENERAL);
Packit Service 672cf4
      break;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  while (*tail && *tail == ' ')
Packit Service 672cf4
    tail++;
Packit Service 672cf4
  if (*tail)
Packit Service 672cf4
    {
Packit Service 672cf4
      inv_key->fpr = strdup (tail);
Packit Service 672cf4
      if (!inv_key->fpr)
Packit Service 672cf4
	{
Packit Service 672cf4
	  free (inv_key);
Packit Service 672cf4
	  return gpg_error_from_syserror ();
Packit Service 672cf4
	}
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  *key = inv_key;
Packit Service 672cf4
  return 0;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4

Packit Service 672cf4
/* Parse a KEY_CONSIDERED status line in ARGS and store the
Packit Service 672cf4
 * fingerprint and the flags at R_FPR and R_FLAGS.  The caller must
Packit Service 672cf4
 * free the value at R_FPR on success.  */
Packit Service 672cf4
gpgme_error_t
Packit Service 672cf4
_gpgme_parse_key_considered (const char *args,
Packit Service 672cf4
                             char **r_fpr, unsigned int *r_flags)
Packit Service 672cf4
{
Packit Service 672cf4
  char *pend;
Packit Service 672cf4
  size_t n;
Packit Service 672cf4
Packit Service 672cf4
  *r_fpr = NULL;
Packit Service 672cf4
Packit Service 672cf4
  pend = strchr (args, ' ');
Packit Service 672cf4
  if (!pend || pend == args)
Packit Service 672cf4
    return trace_gpg_error (GPG_ERR_INV_ENGINE);  /* Bogus status line.  */
Packit Service 672cf4
  n = pend - args;
Packit Service 672cf4
  *r_fpr = malloc (n + 1);
Packit Service 672cf4
  if (!*r_fpr)
Packit Service 672cf4
    return gpg_error_from_syserror ();
Packit Service 672cf4
  memcpy (*r_fpr, args, n);
Packit Service 672cf4
  (*r_fpr)[n] = 0;
Packit Service 672cf4
  args = pend + 1;
Packit Service 672cf4
Packit Service 672cf4
  gpg_err_set_errno (0);
Packit Service 672cf4
  *r_flags = strtoul (args, &pend, 0);
Packit Service 672cf4
  if (errno || args == pend || (*pend && *pend != ' '))
Packit Service 672cf4
    {
Packit Service 672cf4
      free (*r_fpr);
Packit Service 672cf4
      *r_fpr = NULL;
Packit Service 672cf4
      return trace_gpg_error (GPG_ERR_INV_ENGINE);
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  return 0;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
/* Parse the PLAINTEXT status line in ARGS and return the result in
Packit Service 672cf4
   FILENAMEP.  */
Packit Service 672cf4
gpgme_error_t
Packit Service 6c01f9
_gpgme_parse_plaintext (char *args, char **filenamep)
Packit Service 672cf4
{
Packit Service 672cf4
  char *tail;
Packit Service 672cf4
Packit Service 672cf4
  while (*args == ' ')
Packit Service 672cf4
    args++;
Packit Service 672cf4
  if (*args == '\0')
Packit Service 672cf4
    return 0;
Packit Service 672cf4
Packit Service 6c01f9
  /* First argument is file type.  */
Packit Service 672cf4
  while (*args != ' ' && *args != '\0')
Packit Service 672cf4
    args++;
Packit Service 672cf4
  while (*args == ' ')
Packit Service 672cf4
    args++;
Packit Service 672cf4
  if (*args == '\0')
Packit Service 672cf4
    return 0;
Packit Service 672cf4
Packit Service 672cf4
  /* Second argument is the timestamp.  */
Packit Service 672cf4
  while (*args != ' ' && *args != '\0')
Packit Service 672cf4
    args++;
Packit Service 672cf4
  while (*args == ' ')
Packit Service 672cf4
    args++;
Packit Service 672cf4
  if (*args == '\0')
Packit Service 672cf4
    return 0;
Packit Service 672cf4
Packit Service 672cf4
  tail = args;
Packit Service 672cf4
  while (*tail != ' ' && *tail != '\0')
Packit Service 672cf4
    tail++;
Packit Service 672cf4
  *tail = '\0';
Packit Service 672cf4
  if (filenamep && *args != '\0')
Packit Service 672cf4
    {
Packit Service 672cf4
      char *filename = strdup (args);
Packit Service 672cf4
      if (!filename)
Packit Service 672cf4
	return gpg_error_from_syserror ();
Packit Service 672cf4
Packit Service 672cf4
      *filenamep = filename;
Packit Service 672cf4
    }
Packit Service 672cf4
  return 0;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
/* Parse a FAILURE status line and return the error code.  ARGS is
Packit Service 6c01f9
   modified to contain the location part.  */
Packit Service 672cf4
gpgme_error_t
Packit Service 672cf4
_gpgme_parse_failure (char *args)
Packit Service 672cf4
{
Packit Service 672cf4
  char *where, *which;
Packit Service 672cf4
Packit Service 672cf4
  where = strchr (args, ' ');
Packit Service 672cf4
  if (!where)
Packit Service 672cf4
    return trace_gpg_error (GPG_ERR_INV_ENGINE);
Packit Service 672cf4
Packit Service 672cf4
  *where = '\0';
Packit Service 672cf4
  which = where + 1;
Packit Service 672cf4
Packit Service 672cf4
  where = strchr (which, ' ');
Packit Service 672cf4
  if (where)
Packit Service 672cf4
    *where = '\0';
Packit Service 672cf4
Packit Service 6c01f9
  where = args;
Packit Service 6c01f9
Packit Service 672cf4
  return atoi (which);
Packit Service 672cf4
}