Page MenuHome GnuPG

gpgmeedit.c
No OneTemporary

gpgmeedit.c

/* gpgmetools.c - The GNU Privacy Assistant
* Copyright (C) 2002, Miguel Coca.
*
* This file is part of GPA
*
* GPA is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GPA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include "gpgmeedit.h"
#include "passwddlg.h"
#include <unistd.h>
/* The edit callback for all the edit operations is edit_fnc(). Each
* operation is modelled as a sequential machine (a Moore machine, to be
* precise). Therefore, for each operation you must write two functions.
*
* One of them is "action" or output function, that chooses the right value
* for *result (the next command issued in the edit command line) based on
* the current state. The other is the "transit" function, which chooses
* the next state based on the current state and the input (status code and
* args).
*
* See the comments below for details.
*/
/* Define this macro to 1 to enable debugging of the FSM. */
#define DEBUG_FSM 0
/* Prototype of the action function. Returns the error if there is one */
typedef gpg_error_t (*EditAction) (int state, void *opaque,
char **result);
/* Prototype of the transit function. Returns the next state. If and error
* is found changes *err. If there is no error it should NOT touch it */
typedef int (*EditTransit) (int current_state, gpgme_status_code_t status,
const char *args, void *opaque, gpg_error_t *err);
/* Data to be passed to the edit callback. Must be filled by the caller of
* gpgme_op_edit() */
struct edit_parms_s
{
/* Current state */
int state;
/* Last error: The return code of gpgme_op_edit() is the return value of
* the last invocation of the callback. But returning an error from the
* callback does not abort the edit operation, so we must remember any
* error. In other words, errors from action() or transit() are sticky.
*/
gpg_error_t err;
/* The action function */
EditAction action;
/* The transit function */
EditTransit transit;
/* The output data object */
gpgme_data_t out;
/* Signal attachment id */
gulong signal_id;
/* Data to be passed to the previous functions */
void *opaque;
/* The passwd dialog needs to see GPGME_STATUS_NEED_PASSPHRASE_SYM.
To make thinks easier it is only passed to the FSM if this flag
has been set. */
int need_status_passphrase_sym;
};
/* The edit callback proper */
static gpg_error_t
edit_fnc (void *opaque, gpgme_status_code_t status,
const char *args, int fd)
{
struct edit_parms_s *parms = opaque;
char *result = NULL;
/* Ignore these status lines, as they don't require any response */
if (status == GPGME_STATUS_EOF
|| status == GPGME_STATUS_GOT_IT
|| status == GPGME_STATUS_NEED_PASSPHRASE
|| status == GPGME_STATUS_NEED_PASSPHRASE_SYM
|| status == GPGME_STATUS_GOOD_PASSPHRASE
|| status == GPGME_STATUS_BAD_PASSPHRASE
|| status == GPGME_STATUS_USERID_HINT
|| status == GPGME_STATUS_SIGEXPIRED
|| status == GPGME_STATUS_KEYEXPIRED)
{
return parms->err;
}
else if (!parms->need_status_passphrase_sym
&& status == GPGME_STATUS_NEED_PASSPHRASE_SYM)
{
return parms->err;
}
#if DEBUG_FSM
g_debug ("edit_fnc: state=%d input=%d (%s)", parms->state, status, args);
#endif
/* Choose the next state based on the current one and the input */
parms->state = parms->transit (parms->state, status, args, parms->opaque,
&parms->err);
if (gpg_err_code (parms->err) == GPG_ERR_NO_ERROR)
{
gpg_error_t err;
/* Choose the action based on the state */
err = parms->action (parms->state, parms->opaque, &result);
#if DEBUG_FSM
g_debug ("edit_fnc: newstate=%d err=%s result=%s",
parms->state, gpg_strerror (err), result);
#endif
if (gpg_err_code (err) != GPG_ERR_NO_ERROR)
{
parms->err = err;
}
/* Send the command, if any was provided */
if (result)
{
if (*result)
write (fd, result, strlen (result));
write (fd, "\n", 1);
}
}
else
{
#if DEBUG_FSM
g_debug ("edit_fnc: newstate=%d err=%s transit failed",
parms->state, gpg_strerror (parms->err));
#endif
}
return parms->err;
}
/* Change expiry time */
typedef enum
{
EXPIRE_START,
EXPIRE_COMMAND,
EXPIRE_DATE,
EXPIRE_QUIT,
EXPIRE_SAVE,
EXPIRE_ERROR
} ExpireState;
static gpg_error_t
edit_expire_fnc_action (int state, void *opaque, char **result)
{
gchar *date = opaque;
switch (state)
{
/* Start the operation */
case EXPIRE_COMMAND:
*result = "expire";
break;
/* Send the new expire date */
case EXPIRE_DATE:
*result = date;
break;
/* End the operation */
case EXPIRE_QUIT:
*result = "quit";
break;
/* Save */
case EXPIRE_SAVE:
*result = "Y";
break;
/* Special state: an error ocurred. Do nothing until we can quit */
case EXPIRE_ERROR:
break;
/* Can't happen */
default:
return gpg_error (GPG_ERR_GENERAL);
}
return gpg_error (GPG_ERR_NO_ERROR);
}
static int
edit_expire_fnc_transit (int current_state, gpgme_status_code_t status,
const char *args, void *opaque, gpg_error_t *err)
{
int next_state;
switch (current_state)
{
case EXPIRE_START:
if (status == GPGME_STATUS_GET_LINE &&
g_str_equal (args, "keyedit.prompt"))
{
next_state = EXPIRE_COMMAND;
}
else
{
next_state = EXPIRE_ERROR;
*err = gpg_error (GPG_ERR_GENERAL);
}
break;
case EXPIRE_COMMAND:
if (status == GPGME_STATUS_GET_LINE &&
g_str_equal (args, "keygen.valid"))
{
next_state = EXPIRE_DATE;
}
else
{
next_state = EXPIRE_ERROR;
*err = gpg_error (GPG_ERR_GENERAL);
}
break;
case EXPIRE_DATE:
if (status == GPGME_STATUS_GET_LINE &&
g_str_equal (args, "keyedit.prompt"))
{
next_state = EXPIRE_QUIT;
}
else if (status == GPGME_STATUS_GET_LINE &&
g_str_equal (args, "keygen.valid"))
{
next_state = EXPIRE_ERROR;
*err = gpg_error (GPG_ERR_INV_TIME);
}
else
{
next_state = EXPIRE_ERROR;
*err = gpg_error (GPG_ERR_GENERAL);
}
break;
case EXPIRE_QUIT:
if (status == GPGME_STATUS_GET_BOOL &&
g_str_equal (args, "keyedit.save.okay"))
{
next_state = EXPIRE_SAVE;
}
else
{
next_state = EXPIRE_ERROR;
*err = gpg_error (GPG_ERR_GENERAL);
}
break;
case EXPIRE_ERROR:
if (status == GPGME_STATUS_GET_LINE &&
g_str_equal (args, "keyedit.prompt"))
{
/* Go to quit operation state */
next_state = EXPIRE_QUIT;
}
else
{
next_state = EXPIRE_ERROR;
}
break;
default:
next_state = EXPIRE_ERROR;
*err = gpg_error (GPG_ERR_GENERAL);
}
return next_state;
}
/* Change the key ownertrust */
typedef enum
{
TRUST_START,
TRUST_COMMAND,
TRUST_VALUE,
TRUST_REALLY_ULTIMATE,
TRUST_QUIT,
TRUST_SAVE,
TRUST_ERROR
} TrustState;
static gpg_error_t
edit_trust_fnc_action (int state, void *opaque, char **result)
{
gchar *trust = opaque;
switch (state)
{
/* Start the operation */
case TRUST_COMMAND:
*result = "trust";
break;
/* Send the new trust date */
case TRUST_VALUE:
*result = trust;
break;
/* Really set to ultimate trust */
case TRUST_REALLY_ULTIMATE:
*result = "Y";
break;
/* End the operation */
case TRUST_QUIT:
*result = "quit";
break;
/* Save */
case TRUST_SAVE:
*result = "Y";
break;
/* Special state: an error ocurred. Do nothing until we can quit */
case TRUST_ERROR:
break;
/* Can't happen */
default:
return gpg_error (GPG_ERR_GENERAL);
}
return gpg_error (GPG_ERR_NO_ERROR);
}
static int
edit_trust_fnc_transit (int current_state, gpgme_status_code_t status,
const char *args, void *opaque, gpg_error_t *err)
{
int next_state;
switch (current_state)
{
case TRUST_START:
if (status == GPGME_STATUS_GET_LINE &&
g_str_equal (args, "keyedit.prompt"))
{
next_state = TRUST_COMMAND;
}
else
{
next_state = TRUST_ERROR;
*err = gpg_error (GPG_ERR_GENERAL);
}
break;
case TRUST_COMMAND:
if (status == GPGME_STATUS_GET_LINE &&
g_str_equal (args, "edit_ownertrust.value"))
{
next_state = TRUST_VALUE;
}
else
{
next_state = TRUST_ERROR;
*err = gpg_error (GPG_ERR_GENERAL);
}
break;
case TRUST_VALUE:
if (status == GPGME_STATUS_GET_LINE &&
g_str_equal (args, "keyedit.prompt"))
{
next_state = TRUST_QUIT;
}
else if (status == GPGME_STATUS_GET_BOOL &&
g_str_equal (args, "edit_ownertrust.set_ultimate.okay"))
{
next_state = TRUST_REALLY_ULTIMATE;
}
else
{
next_state = TRUST_ERROR;
*err = gpg_error (GPG_ERR_GENERAL);
}
break;
case TRUST_REALLY_ULTIMATE:
if (status == GPGME_STATUS_GET_LINE &&
g_str_equal (args, "keyedit.prompt"))
{
next_state = TRUST_QUIT;
}
else
{
next_state = TRUST_ERROR;
*err = gpg_error (GPG_ERR_GENERAL);
}
break;
case TRUST_QUIT:
if (status == GPGME_STATUS_GET_BOOL &&
g_str_equal (args, "keyedit.save.okay"))
{
next_state = TRUST_SAVE;
}
else
{
next_state = TRUST_ERROR;
*err = gpg_error (GPG_ERR_GENERAL);
}
break;
case TRUST_ERROR:
if (status == GPGME_STATUS_GET_LINE &&
g_str_equal (args, "keyedit.prompt"))
{
/* Go to quit operation state */
next_state = TRUST_QUIT;
}
else
{
next_state = TRUST_ERROR;
}
break;
default:
next_state = TRUST_ERROR;
*err = gpg_error (GPG_ERR_GENERAL);
}
return next_state;
}
/* Sign a key */
typedef enum
{
SIGN_START,
SIGN_COMMAND,
SIGN_UIDS,
SIGN_SET_EXPIRE,
SIGN_SET_CHECK_LEVEL,
SIGN_CONFIRM,
SIGN_QUIT,
SIGN_SAVE,
SIGN_ERROR
} SignState;
struct sign_parms_s
{
gchar *check_level;
gboolean local;
};
static gpg_error_t
edit_sign_fnc_action (int state, void *opaque, char **result)
{
struct sign_parms_s *parms = opaque;
switch (state)
{
/* Start the operation */
case SIGN_COMMAND:
*result = parms->local ? "lsign" : "sign";
break;
/* Sign all user ID's */
case SIGN_UIDS:
*result = "Y";
break;
/* The signature expires at the same time as the key */
case SIGN_SET_EXPIRE:
*result = "Y";
break;
/* Set the check level on the key */
case SIGN_SET_CHECK_LEVEL:
*result = parms->check_level;
break;
/* Confirm the signature */
case SIGN_CONFIRM:
*result = "Y";
break;
/* End the operation */
case SIGN_QUIT:
*result = "quit";
break;
/* Save */
case SIGN_SAVE:
*result = "Y";
break;
/* Special state: an error ocurred. Do nothing until we can quit */
case SIGN_ERROR:
break;
/* Can't happen */
default:
return gpg_error (GPG_ERR_GENERAL);
}
return gpg_error (GPG_ERR_NO_ERROR);
}
static int
edit_sign_fnc_transit (int current_state, gpgme_status_code_t status,
const char *args, void *opaque, gpg_error_t *err)
{
int next_state;
switch (current_state)
{
case SIGN_START:
if (status == GPGME_STATUS_GET_LINE &&
g_str_equal (args, "keyedit.prompt"))
{
next_state = SIGN_COMMAND;
}
else
{
next_state = SIGN_ERROR;
*err = gpg_error (GPG_ERR_GENERAL);
}
break;
case SIGN_COMMAND:
if (status == GPGME_STATUS_GET_BOOL &&
g_str_equal (args, "keyedit.sign_all.okay"))
{
next_state = SIGN_UIDS;
}
else if (status == GPGME_STATUS_GET_BOOL &&
g_str_equal (args, "sign_uid.okay"))
{
next_state = SIGN_CONFIRM;
}
else if (status == GPGME_STATUS_GET_LINE &&
g_str_equal (args, "sign_uid.expire"))
{
next_state = SIGN_SET_EXPIRE;
break;
}
else if (status == GPGME_STATUS_GET_LINE &&
g_str_equal (args, "sign_uid.class"))
{
next_state = SIGN_SET_CHECK_LEVEL;
}
else if (status == GPGME_STATUS_ALREADY_SIGNED)
{
/* The key has already been signed with this key */
next_state = SIGN_ERROR;
*err = gpg_error (GPG_ERR_CONFLICT);
}
else if (status == GPGME_STATUS_GET_LINE &&
g_str_equal (args, "keyedit.prompt"))
{
/* Failed sign: expired key */
next_state = SIGN_ERROR;
*err = gpg_error (GPG_ERR_UNUSABLE_PUBKEY);
}
else
{
next_state = SIGN_ERROR;
*err = gpg_error (GPG_ERR_GENERAL);
}
break;
case SIGN_UIDS:
if (status == GPGME_STATUS_GET_LINE &&
g_str_equal (args, "sign_uid.expire"))
{
next_state = SIGN_SET_EXPIRE;
break;
}
else if (status == GPGME_STATUS_GET_LINE &&
g_str_equal (args, "sign_uid.class"))
{
next_state = SIGN_SET_CHECK_LEVEL;
}
else if (status == GPGME_STATUS_GET_BOOL &&
g_str_equal (args, "sign_uid.okay"))
{
next_state = SIGN_CONFIRM;
}
else if (status == GPGME_STATUS_GET_LINE &&
g_str_equal (args, "keyedit.prompt"))
{
/* Failed sign: expired key */
next_state = SIGN_ERROR;
*err = gpg_error (GPG_ERR_UNUSABLE_PUBKEY);
}
else
{
next_state = SIGN_ERROR;
*err = gpg_error (GPG_ERR_GENERAL);
}
break;
case SIGN_SET_EXPIRE:
if (status == GPGME_STATUS_GET_LINE &&
g_str_equal (args, "sign_uid.class"))
{
next_state = SIGN_SET_CHECK_LEVEL;
}
else
{
next_state = SIGN_ERROR;
*err = gpg_error (GPG_ERR_GENERAL);
}
break;
case SIGN_SET_CHECK_LEVEL:
if (status == GPGME_STATUS_GET_BOOL &&
g_str_equal (args, "sign_uid.okay"))
{
next_state = SIGN_CONFIRM;
}
else
{
next_state = SIGN_ERROR;
*err = gpg_error (GPG_ERR_GENERAL);
}
break;
case SIGN_CONFIRM:
if (status == GPGME_STATUS_GET_LINE &&
g_str_equal (args, "keyedit.prompt"))
{
next_state = SIGN_QUIT;
}
else
{
next_state = SIGN_ERROR;
*err = gpg_error (GPG_ERR_GENERAL);
}
break;
case SIGN_QUIT:
if (status == GPGME_STATUS_GET_BOOL &&
g_str_equal (args, "keyedit.save.okay"))
{
next_state = SIGN_SAVE;
}
else
{
next_state = SIGN_ERROR;
*err = gpg_error (GPG_ERR_GENERAL);
}
break;
case SIGN_ERROR:
if (status == GPGME_STATUS_GET_LINE &&
g_str_equal (args, "keyedit.prompt"))
{
/* Go to quit operation state */
next_state = SIGN_QUIT;
}
else
{
next_state = SIGN_ERROR;
}
break;
default:
next_state = SIGN_ERROR;
*err = gpg_error (GPG_ERR_GENERAL);
}
return next_state;
}
/* Change passphrase */
typedef enum
{
PASSWD_START,
PASSWD_COMMAND,
PASSWD_ENTERNEW,
PASSWD_QUIT,
PASSWD_SAVE,
PASSWD_ERROR
} PasswdState;
struct passwd_parms_s
{
gpgme_passphrase_cb_t func;
void *opaque;
};
static gpg_error_t
edit_passwd_fnc_action (int state, void *opaque, char **result)
{
switch (state)
{
case PASSWD_COMMAND:
/* Start the operation */
*result = "passwd";
break;
case PASSWD_ENTERNEW:
/* No action required. This state is only used by the
passphrase callback. */
break;
case PASSWD_QUIT:
/* End the operation */
*result = "quit";
break;
case PASSWD_SAVE:
/* Save */
*result = "Y";
break;
case PASSWD_ERROR:
/* Special state: an error ocurred. Do nothing until we can quit */
break;
default:
/* Can't happen */
return gpg_error (GPG_ERR_GENERAL);
}
return gpg_error (GPG_ERR_NO_ERROR);
}
static int
edit_passwd_fnc_transit (int current_state, gpgme_status_code_t status,
const char *args, void *opaque, gpg_error_t *err)
{
int next_state;
switch (current_state)
{
case PASSWD_START:
if (status == GPGME_STATUS_GET_LINE &&
g_str_equal (args, "keyedit.prompt"))
{
next_state = PASSWD_COMMAND;
}
else
{
next_state = PASSWD_ERROR;
*err = gpg_error (GPG_ERR_GENERAL);
}
break;
case PASSWD_COMMAND:
case PASSWD_ENTERNEW:
if (status == GPGME_STATUS_GET_LINE &&
g_str_equal (args, "keyedit.prompt"))
{
next_state = PASSWD_QUIT;
}
else if (status == GPGME_STATUS_NEED_PASSPHRASE_SYM)
{
next_state = PASSWD_ENTERNEW;
}
else
{
next_state = PASSWD_ERROR;
*err = gpg_error (GPG_ERR_GENERAL);
}
break;
case PASSWD_QUIT:
if (status == GPGME_STATUS_GET_BOOL &&
g_str_equal (args, "keyedit.save.okay"))
{
next_state = PASSWD_SAVE;
}
else
{
next_state = PASSWD_ERROR;
*err = gpg_error (GPG_ERR_GENERAL);
}
break;
case PASSWD_ERROR:
if (status == GPGME_STATUS_GET_LINE &&
g_str_equal (args, "keyedit.prompt"))
{
/* Go to quit operation state */
next_state = PASSWD_QUIT;
}
else
{
next_state = PASSWD_ERROR;
}
break;
default:
next_state = PASSWD_ERROR;
*err = gpg_error (GPG_ERR_GENERAL);
}
return next_state;
}
/* Release the edit parameters needed for setting owner trust. The prototype
* is that of a GpaContext's "done" signal handler.
*/
static void
gpa_gpgme_edit_trust_parms_release (GpaContext *ctx, gpg_error_t err,
struct edit_parms_s* parms)
{
gpgme_data_release (parms->out);
if (parms->signal_id != 0)
{
/* Don't run this signal handler again if the context is reused */
g_signal_handler_disconnect (ctx, parms->signal_id);
}
g_free (parms->opaque);
g_free (parms);
}
/* Generate the edit parameters needed for setting owner trust.
*/
static struct edit_parms_s*
gpa_gpgme_edit_trust_parms_new (GpaContext *ctx, const char *trust_string,
gpgme_data_t out)
{
struct edit_parms_s *edit_parms = g_malloc (sizeof (struct edit_parms_s));
edit_parms->state = TRUST_START;
edit_parms->err = gpg_error (GPG_ERR_NO_ERROR);
edit_parms->action = edit_trust_fnc_action;
edit_parms->transit = edit_trust_fnc_transit;
edit_parms->signal_id = 0;
edit_parms->out = out;
edit_parms->opaque = g_strdup (trust_string);
/* Make sure the cleanup is run when the edit completes */
edit_parms->signal_id =
g_signal_connect (G_OBJECT (ctx), "done",
G_CALLBACK (gpa_gpgme_edit_trust_parms_release),
edit_parms);
return edit_parms;
}
/* Change the ownertrust of a key */
gpg_error_t gpa_gpgme_edit_trust_start (GpaContext *ctx, gpgme_key_t key,
gpgme_validity_t ownertrust)
{
const gchar *trust_strings[] = {"1", "1", "2", "3", "4", "5"};
struct edit_parms_s *parms = NULL;
gpg_error_t err;
gpgme_data_t out = NULL;
err = gpgme_data_new (&out);
if (gpg_err_code (err) != GPG_ERR_NO_ERROR)
{
return err;
}
parms = gpa_gpgme_edit_trust_parms_new (ctx, trust_strings[ownertrust], out);
err = gpgme_op_edit_start (ctx->ctx, key, edit_fnc, parms, out);
return err;
}
/* Release the edit parameters needed for changing the expiry date. The
* prototype is that of a GpaContext's "done" signal handler.
*/
static void
gpa_gpgme_edit_expire_parms_release (GpaContext *ctx, gpg_error_t err,
struct edit_parms_s* parms)
{
gpgme_data_release (parms->out);
if (parms->signal_id != 0)
{
/* Don't run this signal handler again if the context is reused */
g_signal_handler_disconnect (ctx, parms->signal_id);
}
g_free (parms->opaque);
g_free (parms);
}
/* Generate the edit parameters needed for changing the expiry date.
*/
static struct edit_parms_s*
gpa_gpgme_edit_expire_parms_new (GpaContext *ctx, GDate *date,
gpgme_data_t out)
{
struct edit_parms_s *edit_parms = g_malloc (sizeof (struct edit_parms_s));
int buf_len = 12;
gchar *buf = g_malloc (buf_len);
edit_parms->state = EXPIRE_START;
edit_parms->err = gpg_error (GPG_ERR_NO_ERROR);
edit_parms->action = edit_expire_fnc_action;
edit_parms->transit = edit_expire_fnc_transit;
edit_parms->signal_id = 0;
edit_parms->out = out;
edit_parms->opaque = buf;
/* The new expiration date */
if (date)
{
g_date_strftime (buf, buf_len, "%Y-%m-%d", date);
}
else
{
strncpy (buf, "0", buf_len);
}
/* Make sure the cleanup is run when the edit completes */
edit_parms->signal_id =
g_signal_connect (G_OBJECT (ctx), "done",
G_CALLBACK (gpa_gpgme_edit_expire_parms_release),
edit_parms);
return edit_parms;
}
/* Change the expire date of a key */
gpg_error_t gpa_gpgme_edit_expire_start (GpaContext *ctx, gpgme_key_t key,
GDate *date)
{
struct edit_parms_s *parms;
gpg_error_t err;
gpgme_data_t out = NULL;
err = gpgme_data_new (&out);
if (gpg_err_code (err) != GPG_ERR_NO_ERROR)
{
return err;
}
parms = gpa_gpgme_edit_expire_parms_new (ctx, date, out);
err = gpgme_op_edit_start (ctx->ctx, key, edit_fnc, parms, out);
return err;
}
/* Release the edit parameters needed for signing. The prototype is that of
* a GpaContext's "done" signal handler.
*/
static void
gpa_gpgme_edit_sign_parms_release (GpaContext *ctx, gpg_error_t err,
struct edit_parms_s* parms)
{
gpgme_data_release (parms->out);
if (parms->signal_id != 0)
{
g_signal_handler_disconnect (ctx, parms->signal_id);
}
g_free (parms->opaque);
g_free (parms);
}
/* Generate the edit parameters needed for signing
*/
static struct edit_parms_s*
gpa_gpgme_edit_sign_parms_new (GpaContext *ctx, char *check_level,
gboolean local, gpgme_data_t out)
{
struct sign_parms_s *sign_parms = g_malloc (sizeof (struct sign_parms_s));
struct edit_parms_s *edit_parms = g_malloc (sizeof (struct edit_parms_s));
edit_parms->state = SIGN_START;
edit_parms->err = gpg_error (GPG_ERR_NO_ERROR);
edit_parms->action = edit_sign_fnc_action;
edit_parms->transit = edit_sign_fnc_transit;
edit_parms->signal_id = 0;
edit_parms->out = out;
edit_parms->opaque = sign_parms;
sign_parms->check_level = check_level;
sign_parms->local = local;
/* Make sure the cleanup is run when the edit completes */
edit_parms->signal_id =
g_signal_connect (G_OBJECT (ctx), "done",
G_CALLBACK (gpa_gpgme_edit_sign_parms_release),
edit_parms);
return edit_parms;
}
/* Sign this key with the given private key */
gpg_error_t gpa_gpgme_edit_sign_start (GpaContext *ctx, gpgme_key_t key,
gpgme_key_t secret_key, gboolean local)
{
struct edit_parms_s *parms = NULL;
gpg_error_t err = gpg_error (GPG_ERR_NO_ERROR);
gpgme_data_t out;
err = gpgme_data_new (&out);
if (gpg_err_code (err) != GPG_ERR_NO_ERROR)
{
return err;
}
gpgme_signers_clear (ctx->ctx);
err = gpgme_signers_add (ctx->ctx, secret_key);
if (gpg_err_code (err) != GPG_ERR_NO_ERROR)
{
return err;
}
parms = gpa_gpgme_edit_sign_parms_new (ctx, "0", local, out);
err = gpgme_op_edit_start (ctx->ctx, key, edit_fnc, parms, out);
return err;
}
/*
* Change the passphrase of the key.
*/
/* Special passphrase callback for use within the passwd command */
gpg_error_t
passwd_passphrase_cb (void *hook, const char *uid_hint,
const char *passphrase_info,
int prev_was_bad, int fd)
{
struct edit_parms_s *parms = hook;
if (parms->state == PASSWD_ENTERNEW)
{
/* Gpg is asking for the new passphrase. Run the dialog to
enter and re-enter the new passphrase. */
return gpa_change_passphrase_dialog_run (hook, uid_hint,
passphrase_info,
prev_was_bad, fd);
}
else
{
/* Gpg is asking for the passphrase to unprotect the key. */
return gpa_passphrase_cb (hook, uid_hint, passphrase_info,
prev_was_bad, fd);
}
}
/* Release the edit parameters needed for changing the passphrase. The
* prototype is that of a GpaContext's "done" signal handler.
*/
static void
gpa_gpgme_edit_passwd_parms_release (GpaContext *ctx, gpg_error_t err,
struct edit_parms_s* parms)
{
struct passwd_parms_s *passwd_parms = parms->opaque;
gpgme_data_release (parms->out);
/* Make sure the normal passphrase callback is used */
gpgme_set_passphrase_cb (ctx->ctx, passwd_parms->func, passwd_parms->opaque);
if (parms->signal_id != 0)
{
/* Don't run this signal handler again if the context is reused */
g_signal_handler_disconnect (ctx, parms->signal_id);
}
g_free (parms);
g_free (parms->opaque);
}
/* Generate the edit parameters needed for changing the passphrase.
*/
static struct edit_parms_s*
gpa_gpgme_edit_passwd_parms_new (GpaContext *ctx, gpgme_data_t out)
{
struct edit_parms_s *edit_parms = g_malloc (sizeof (struct edit_parms_s));
struct passwd_parms_s *passwd_parms = g_malloc (sizeof
(struct passwd_parms_s));
edit_parms->state = PASSWD_START;
edit_parms->err = gpg_error (GPG_ERR_NO_ERROR);
edit_parms->action = edit_passwd_fnc_action;
edit_parms->transit = edit_passwd_fnc_transit;
edit_parms->signal_id = 0;
edit_parms->out = out;
edit_parms->opaque = passwd_parms;
gpgme_get_passphrase_cb (ctx->ctx, &passwd_parms->func,
&passwd_parms->opaque);
/* Make sure the cleanup is run when the edit completes */
edit_parms->signal_id =
g_signal_connect (G_OBJECT (ctx), "done",
G_CALLBACK (gpa_gpgme_edit_passwd_parms_release),
edit_parms);
return edit_parms;
}
gpg_error_t
gpa_gpgme_edit_passwd_start (GpaContext *ctx, gpgme_key_t key)
{
struct edit_parms_s *parms;
gpg_error_t err;
gpgme_data_t out;
err = gpgme_data_new (&out);
if (gpg_err_code (err) != GPG_ERR_NO_ERROR)
{
return err;
}
parms = gpa_gpgme_edit_passwd_parms_new (ctx, out);
/* Use our own passphrase callback: The data are the actual edit
parms. */
gpgme_set_passphrase_cb (ctx->ctx, passwd_passphrase_cb, parms);
err = gpgme_op_edit_start (ctx->ctx, key, edit_fnc, parms, out);
return err;
}

File Metadata

Mime Type
text/x-c
Expires
Mon, Dec 23, 1:25 PM (1 h, 54 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
c6/f3/87c4752bc47342cec5a36fac6143

Event Timeline