Blame src/passwd.c

Packit Service 672cf4
/* passwd.c - Passphrase changing function
Packit Service 6c01f9
   Copyright (C) 2010 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
Packit Service 672cf4
#include "gpgme.h"
Packit Service 672cf4
#include "debug.h"
Packit Service 672cf4
#include "context.h"
Packit Service 672cf4
#include "ops.h"
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
typedef struct
Packit Service 672cf4
{
Packit Service 672cf4
  /* The error code from a FAILURE status line or 0.  */
Packit Service 672cf4
  gpg_error_t failure_code;
Packit Service 672cf4
Packit Service 672cf4
  int success_seen;
Packit Service 672cf4
  int error_seen;
Packit Service 672cf4
} *op_data_t;
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4

Packit Service 672cf4
/* Parse an error status line and return the error code.  */
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
parse_error (char *args)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
  char *where = strchr (args, ' ');
Packit Service 672cf4
  char *which;
Packit Service 672cf4
Packit Service 672cf4
  if (where)
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 672cf4
      where = args;
Packit Service 672cf4
    }
Packit Service 672cf4
  else
Packit Service 672cf4
    return trace_gpg_error (GPG_ERR_INV_ENGINE);
Packit Service 672cf4
Packit Service 672cf4
  err = atoi (which);
Packit Service 672cf4
Packit Service 672cf4
  if (!strcmp (where, "keyedit.passwd"))
Packit Service 672cf4
    return err;
Packit Service 672cf4
Packit Service 672cf4
  return 0;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
passwd_status_handler (void *priv, gpgme_status_code_t code, char *args)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
  void *hook;
Packit Service 672cf4
  op_data_t opd;
Packit Service 672cf4
Packit Service 672cf4
  err = _gpgme_op_data_lookup (ctx, OPDATA_PASSWD, &hook, -1, NULL);
Packit Service 672cf4
  opd = hook;
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    return err;
Packit Service 672cf4
Packit Service 672cf4
  switch (code)
Packit Service 672cf4
    {
Packit Service 672cf4
    case GPGME_STATUS_ERROR:
Packit Service 672cf4
      err = parse_error (args);
Packit Service 672cf4
      if (err)
Packit Service 672cf4
        opd->error_seen = 1;
Packit Service 672cf4
      break;
Packit Service 672cf4
Packit Service 672cf4
    case GPGME_STATUS_SUCCESS:
Packit Service 672cf4
      opd->success_seen = 1;
Packit Service 672cf4
      break;
Packit Service 672cf4
Packit Service 672cf4
    case GPGME_STATUS_FAILURE:
Packit Service 672cf4
      opd->failure_code = _gpgme_parse_failure (args);
Packit Service 672cf4
      break;
Packit Service 672cf4
Packit Service 672cf4
    case GPGME_STATUS_EOF:
Packit Service 672cf4
      /* In case the OpenPGP engine does not properly implement the
Packit Service 672cf4
         passwd command we won't get a success status back and thus we
Packit Service 672cf4
         conclude that this operation is not supported.  This is for
Packit Service 672cf4
         example the case for GnuPG < 2.0.16.  Note that this test is
Packit Service 672cf4
         obsolete for assuan based engines because they will properly
Packit Service 672cf4
         return an error for an unknown command.  */
Packit Service 672cf4
      if (ctx->protocol == GPGME_PROTOCOL_OpenPGP
Packit Service 672cf4
          && !opd->error_seen && !opd->success_seen)
Packit Service 672cf4
        err = gpg_error (GPG_ERR_NOT_SUPPORTED);
Packit Service 672cf4
      else if (opd->failure_code)
Packit Service 672cf4
        err = opd->failure_code;
Packit Service 672cf4
      break;
Packit Service 672cf4
Packit Service 672cf4
    default:
Packit Service 672cf4
      break;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
passwd_start (gpgme_ctx_t ctx, int synchronous, gpgme_key_t key,
Packit Service 672cf4
              unsigned int flags)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
  void *hook;
Packit Service 672cf4
  op_data_t opd;
Packit Service 672cf4
Packit Service 672cf4
  if (!key)
Packit Service 672cf4
    return gpg_error (GPG_ERR_INV_VALUE);
Packit Service 672cf4
  if (flags)
Packit Service 672cf4
    return gpg_error (GPG_ERR_INV_FLAG);
Packit Service 672cf4
Packit Service 672cf4
  err = _gpgme_op_reset (ctx, synchronous);
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    return err;
Packit Service 672cf4
Packit Service 672cf4
  err = _gpgme_op_data_lookup (ctx, OPDATA_PASSWD, &hook, sizeof (*opd), NULL);
Packit Service 672cf4
  opd = hook;
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    return err;
Packit Service 672cf4
Packit Service 672cf4
  opd->success_seen = 0;
Packit Service 672cf4
  opd->error_seen = 0;
Packit Service 672cf4
Packit Service 672cf4
  _gpgme_engine_set_status_handler (ctx->engine, passwd_status_handler, ctx);
Packit Service 672cf4
Packit Service 672cf4
  if (ctx->passphrase_cb)
Packit Service 672cf4
    {
Packit Service 672cf4
      err = _gpgme_engine_set_command_handler
Packit Service 6c01f9
        (ctx->engine, _gpgme_passphrase_command_handler, ctx, NULL);
Packit Service 672cf4
      if (err)
Packit Service 672cf4
        return err;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  return _gpgme_engine_op_passwd (ctx->engine, key, flags);
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
/* Change the passphrase for KEY.  FLAGS is reserved for future use
Packit Service 672cf4
   and must be passed as 0.  The engine is expected to present a user
Packit Service 672cf4
   interface to enter the old and the new passphrase.  This is the
Packit Service 672cf4
   asynchronous variant.
Packit Service 672cf4
Packit Service 672cf4
   Note that if ever the need arises to supply a passphrase we can do
Packit Service 672cf4
   this with a flag value and the passphrase callback feature.  */
Packit Service 672cf4
gpgme_error_t
Packit Service 672cf4
gpgme_op_passwd_start (gpgme_ctx_t ctx, gpgme_key_t key, unsigned int flags)
Packit Service 672cf4
{
Packit Service 672cf4
  gpg_error_t err;
Packit Service 6c01f9
  TRACE_BEG2 (DEBUG_CTX, "gpgme_op_passwd_start", ctx,
Packit Service 672cf4
	      "key=%p, flags=0x%x", key, flags);
Packit Service 672cf4
Packit Service 672cf4
  if (!ctx)
Packit Service 672cf4
    return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
Packit Service 672cf4
Packit Service 672cf4
  err = passwd_start (ctx, 0, key, flags);
Packit Service 672cf4
  return TRACE_ERR (err);
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
/* Change the passphrase for KEY.  FLAGS is reserved for future use
Packit Service 672cf4
   and must be passed as 0.  This is the synchronous variant.  */
Packit Service 672cf4
gpgme_error_t
Packit Service 672cf4
gpgme_op_passwd (gpgme_ctx_t ctx, gpgme_key_t key, unsigned int flags)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
Packit Service 6c01f9
  TRACE_BEG2 (DEBUG_CTX, "gpgme_op_passwd", ctx,
Packit Service 672cf4
	      "key=%p, flags=0x%x", key, flags);
Packit Service 672cf4
Packit Service 672cf4
  if (!ctx)
Packit Service 672cf4
    return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
Packit Service 672cf4
Packit Service 672cf4
  err = passwd_start (ctx, 1, key, flags);
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = _gpgme_wait_one (ctx);
Packit Service 672cf4
  return TRACE_ERR (err);
Packit Service 672cf4
}
Packit Service 672cf4