1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 17:38:00 +00:00

Rework the Pageant client code to use BinarySource.

There was a lot of ugly, repetitive, error-prone code that decoded
agent responses in raw data buffers. Now my internal client query
function is returning something that works as a BinarySource, so we
can decode agent responses using the marshal.h system like any other
SSH-formatted message in this code base.

While I'm at it, I've centralised more of the parsing of key lists
(saving repetition in pageant_add_key and pageant_enum_keys),
including merging most of the logic between SSH-1 and SSH-2. The old
functions pageant_get_keylist1 and pageant_get_keylist2 aren't exposed
in pageant.h any more, because they no longer exist in that form, and
also because nothing was using them anyway. (Windows Pageant was using
the separate pageant_nth_ssh2_key() functions that talk directly to
the core, and Unix Pageant was using the more cooked client function
pageant_enum_keys.)
This commit is contained in:
Simon Tatham 2020-02-15 07:30:19 +00:00
parent 891bf36600
commit 2e479fabad
2 changed files with 229 additions and 325 deletions

548
pageant.c
View File

@ -1559,6 +1559,7 @@ static void internal_client_got_response(
PageantClient *pc, PageantClientRequestId *reqid, ptrlen response)
{
PageantInternalClient *pic = container_of(pc, PageantInternalClient, pc);
strbuf_clear(pic->response);
put_datapl(pic->response, response);
pic->got_response = true;
}
@ -1576,32 +1577,79 @@ static const struct PageantClientVtable internal_clientvt = {
internal_client_ask_passphrase,
};
void pageant_client_query(strbuf *request, void **resp_p, int *resplen_p)
typedef struct PageantClientOp {
strbuf *buf;
bool request_made;
BinarySink_DELEGATE_IMPLEMENTATION;
BinarySource_IMPLEMENTATION;
} PageantClientOp;
static PageantClientOp *pageant_client_op_new(void)
{
PageantClientOp *pco = snew(PageantClientOp);
pco->buf = strbuf_new_for_agent_query();
pco->request_made = false;
BinarySink_DELEGATE_INIT(pco, pco->buf);
BinarySource_INIT(pco, "", 0);
return pco;
}
static void pageant_client_op_free(PageantClientOp *pco)
{
if (pco->buf)
strbuf_free(pco->buf);
sfree(pco);
}
static unsigned pageant_client_op_query(PageantClientOp *pco)
{
/* Since we use the same strbuf for the request and the response,
* check by assertion that we aren't embarrassingly sending a
* previous response back to the agent */
assert(!pco->request_made);
pco->request_made = true;
if (!pageant_local) {
agent_query_synchronous(request, resp_p, resplen_p);
void *response_raw;
int resplen_raw;
agent_query_synchronous(pco->buf, &response_raw, &resplen_raw);
strbuf_clear(pco->buf);
put_data(pco->buf, response_raw, resplen_raw);
sfree(response_raw);
/* The data coming back from agent_query_synchronous will have
* its length field prepended. So we start by parsing it as an
* SSH-formatted string, and then reinitialise our
* BinarySource with the interior of that string. */
BinarySource_INIT_PL(pco, ptrlen_from_strbuf(pco->buf));
BinarySource_INIT_PL(pco, get_string(pco));
} else {
PageantInternalClient pic;
PageantClientRequestId reqid;
pic.pc.vt = &internal_clientvt;
pic.pc.suppress_logging = true;
pic.response = strbuf_new_for_agent_query();
pic.response = pco->buf;
pic.got_response = false;
pageant_register_client(&pic.pc);
assert(request->len > 4);
assert(pco->buf->len > 4);
PageantAsyncOp *pao = pageant_make_op(
&pic.pc, &reqid, make_ptrlen(request->s + 4, request->len - 4));
&pic.pc, &reqid, make_ptrlen(pco->buf->s + 4, pco->buf->len - 4));
while (!pic.got_response)
pageant_async_op_coroutine(pao);
pageant_unregister_client(&pic.pc);
strbuf_finalise_agent_query(pic.response);
*resplen_p = pic.response->len;
*resp_p = strbuf_to_str(pic.response);
BinarySource_INIT_PL(pco, ptrlen_from_strbuf(pco->buf));
}
/* Strip off and directly return the type byte, which every client
* will need, to save a boilerplate get_byte at each call site */
unsigned reply_type = get_byte(pco);
if (get_err(pco))
reply_type = 256; /* out-of-range code */
return reply_type;
}
/*
@ -1621,64 +1669,59 @@ void pageant_forget_passphrases(void)
}
}
void *pageant_get_keylist1(int *length)
typedef struct KeyListEntry {
ptrlen blob, comment;
} KeyListEntry;
typedef struct KeyList {
strbuf *raw_data;
KeyListEntry *keys;
size_t nkeys;
bool broken;
} KeyList;
static void keylist_free(KeyList *kl)
{
void *ret;
strbuf *request;
unsigned char *response;
void *vresponse;
int resplen;
request = strbuf_new_for_agent_query();
put_byte(request, SSH1_AGENTC_REQUEST_RSA_IDENTITIES);
pageant_client_query(request, &vresponse, &resplen);
strbuf_free(request);
response = vresponse;
if (resplen < 5 || response[4] != SSH1_AGENT_RSA_IDENTITIES_ANSWER) {
sfree(response);
return NULL;
}
ret = snewn(resplen-5, unsigned char);
memcpy(ret, response+5, resplen-5);
sfree(response);
if (length)
*length = resplen-5;
return ret;
sfree(kl->keys);
strbuf_free(kl->raw_data);
sfree(kl);
}
void *pageant_get_keylist2(int *length)
static KeyList *pageant_get_keylist(unsigned ssh_version)
{
void *ret;
static const unsigned char requests[] = {
0, SSH1_AGENTC_REQUEST_RSA_IDENTITIES, SSH2_AGENTC_REQUEST_IDENTITIES
}, responses[] = {
0, SSH1_AGENT_RSA_IDENTITIES_ANSWER, SSH2_AGENT_IDENTITIES_ANSWER
};
strbuf *request;
unsigned char *response;
void *vresponse;
int resplen;
PageantClientOp *pco = pageant_client_op_new();
put_byte(pco, requests[ssh_version]);
unsigned reply = pageant_client_op_query(pco);
request = strbuf_new_for_agent_query();
put_byte(request, SSH2_AGENTC_REQUEST_IDENTITIES);
pageant_client_query(request, &vresponse, &resplen);
strbuf_free(request);
response = vresponse;
if (resplen < 5 || response[4] != SSH2_AGENT_IDENTITIES_ANSWER) {
sfree(response);
if (reply != responses[ssh_version]) {
pageant_client_op_free(pco);
return NULL;
}
ret = snewn(resplen-5, unsigned char);
memcpy(ret, response+5, resplen-5);
sfree(response);
KeyList *kl = snew(KeyList);
kl->nkeys = get_uint32(pco);
kl->keys = snewn(kl->nkeys, struct KeyListEntry);
if (length)
*length = resplen-5;
for (size_t i = 0; i < kl->nkeys && !get_err(pco); i++) {
if (ssh_version == 1) {
kl->keys[i].blob = get_data(pco, rsa_ssh1_public_blob_len(
make_ptrlen(get_ptr(pco), get_avail(pco))));
} else {
kl->keys[i].blob = get_string(pco);
}
kl->keys[i].comment = get_string(pco);
}
return ret;
kl->broken = get_err(pco);
kl->raw_data = pco->buf;
pco->buf = NULL;
pageant_client_op_free(pco);
return kl;
}
int pageant_add_keyfile(Filename *filename, const char *passphrase,
@ -1718,8 +1761,7 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase,
*/
{
strbuf *blob = strbuf_new();
unsigned char *keylist, *p;
int i, nkeys, keylistlen;
KeyList *kl;
if (type == SSH_KEYTYPE_SSH1) {
if (!rsa1_loadpub_f(filename, BinarySink_UPCAST(blob),
@ -1728,103 +1770,36 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase,
strbuf_free(blob);
return PAGEANT_ACTION_FAILURE;
}
keylist = pageant_get_keylist1(&keylistlen);
kl = pageant_get_keylist(1);
} else {
/* For our purposes we want the blob prefixed with its
* length, so add a placeholder here to fill in
* afterwards */
put_uint32(blob, 0);
if (!ppk_loadpub_f(filename, NULL, BinarySink_UPCAST(blob),
NULL, &error)) {
*retstr = dupprintf("Couldn't load private key (%s)", error);
strbuf_free(blob);
return PAGEANT_ACTION_FAILURE;
}
PUT_32BIT_MSB_FIRST(blob->s, blob->len - 4);
keylist = pageant_get_keylist2(&keylistlen);
kl = pageant_get_keylist(2);
}
if (keylist) {
if (keylistlen < 4) {
*retstr = dupstr("Received broken key list from agent");
sfree(keylist);
strbuf_free(blob);
return PAGEANT_ACTION_FAILURE;
}
nkeys = toint(GET_32BIT_MSB_FIRST(keylist));
if (nkeys < 0) {
*retstr = dupstr("Received broken key list from agent");
sfree(keylist);
strbuf_free(blob);
return PAGEANT_ACTION_FAILURE;
}
p = keylist + 4;
keylistlen -= 4;
for (i = 0; i < nkeys; i++) {
if (!memcmp(blob->s, p, blob->len)) {
if (kl) {
if (kl->broken) {
*retstr = dupstr("Received broken key list from agent");
keylist_free(kl);
strbuf_free(blob);
return PAGEANT_ACTION_FAILURE;
}
for (size_t i = 0; i < kl->nkeys; i++) {
if (ptrlen_eq_ptrlen(ptrlen_from_strbuf(blob),
kl->keys[i].blob)) {
/* Key is already present; we can now leave. */
sfree(keylist);
keylist_free(kl);
strbuf_free(blob);
return PAGEANT_ACTION_OK;
}
/* Now skip over public blob */
if (type == SSH_KEYTYPE_SSH1) {
int n = rsa_ssh1_public_blob_len(
make_ptrlen(p, keylistlen));
if (n < 0) {
*retstr = dupstr("Received broken key list from agent");
sfree(keylist);
strbuf_free(blob);
return PAGEANT_ACTION_FAILURE;
}
p += n;
keylistlen -= n;
} else {
int n;
if (keylistlen < 4) {
*retstr = dupstr("Received broken key list from agent");
sfree(keylist);
strbuf_free(blob);
return PAGEANT_ACTION_FAILURE;
}
n = GET_32BIT_MSB_FIRST(p);
p += 4;
keylistlen -= 4;
if (n < 0 || n > keylistlen) {
*retstr = dupstr("Received broken key list from agent");
sfree(keylist);
strbuf_free(blob);
return PAGEANT_ACTION_FAILURE;
}
p += n;
keylistlen -= n;
}
/* Now skip over comment field */
{
int n;
if (keylistlen < 4) {
*retstr = dupstr("Received broken key list from agent");
sfree(keylist);
strbuf_free(blob);
return PAGEANT_ACTION_FAILURE;
}
n = GET_32BIT_MSB_FIRST(p);
p += 4;
keylistlen -= 4;
if (n < 0 || n > keylistlen) {
*retstr = dupstr("Received broken key list from agent");
sfree(keylist);
strbuf_free(blob);
return PAGEANT_ACTION_FAILURE;
}
p += n;
keylistlen -= n;
}
}
sfree(keylist);
keylist_free(kl);
}
strbuf_free(blob);
@ -1838,27 +1813,22 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase,
return PAGEANT_ACTION_FAILURE;
}
strbuf *request = strbuf_new_for_agent_query();
put_byte(request, SSH2_AGENTC_EXTENSION);
put_stringpl(request, extension_names[EXT_ADD_PPK]);
put_string(request, lf->data, lf->len);
PageantClientOp *pco = pageant_client_op_new();
put_byte(pco, SSH2_AGENTC_EXTENSION);
put_stringpl(pco, extension_names[EXT_ADD_PPK]);
put_string(pco, lf->data, lf->len);
lf_free(lf);
void *vresponse;
int resplen;
pageant_client_query(request, &vresponse, &resplen);
strbuf_free(request);
unsigned reply = pageant_client_op_query(pco);
pageant_client_op_free(pco);
unsigned char *response = vresponse;
if (resplen < 5 || response[4] != SSH_AGENT_SUCCESS) {
if (reply != SSH_AGENT_SUCCESS) {
*retstr = dupstr("The already running Pageant "
"refused to add the key.");
sfree(response);
return PAGEANT_ACTION_FAILURE;
}
sfree(response);
return PAGEANT_ACTION_OK;
}
@ -1958,56 +1928,39 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase,
sfree(comment);
if (type == SSH_KEYTYPE_SSH1) {
strbuf *request;
unsigned char *response;
void *vresponse;
int resplen;
PageantClientOp *pco = pageant_client_op_new();
put_byte(pco, SSH1_AGENTC_ADD_RSA_IDENTITY);
rsa_ssh1_private_blob_agent(BinarySink_UPCAST(pco), rkey);
put_stringz(pco, rkey->comment);
unsigned reply = pageant_client_op_query(pco);
pageant_client_op_free(pco);
request = strbuf_new_for_agent_query();
put_byte(request, SSH1_AGENTC_ADD_RSA_IDENTITY);
rsa_ssh1_private_blob_agent(BinarySink_UPCAST(request), rkey);
put_stringz(request, rkey->comment);
pageant_client_query(request, &vresponse, &resplen);
strbuf_free(request);
response = vresponse;
if (resplen < 5 || response[4] != SSH_AGENT_SUCCESS) {
*retstr = dupstr("The already running Pageant "
"refused to add the key.");
freersakey(rkey);
sfree(rkey);
sfree(response);
return PAGEANT_ACTION_FAILURE;
}
freersakey(rkey);
sfree(rkey);
sfree(response);
} else {
strbuf *request;
unsigned char *response;
void *vresponse;
int resplen;
request = strbuf_new_for_agent_query();
put_byte(request, SSH2_AGENTC_ADD_IDENTITY);
put_stringz(request, ssh_key_ssh_id(skey->key));
ssh_key_openssh_blob(skey->key, BinarySink_UPCAST(request));
put_stringz(request, skey->comment);
pageant_client_query(request, &vresponse, &resplen);
strbuf_free(request);
response = vresponse;
if (resplen < 5 || response[4] != SSH_AGENT_SUCCESS) {
if (reply != SSH_AGENT_SUCCESS) {
*retstr = dupstr("The already running Pageant "
"refused to add the key.");
sfree(response);
return PAGEANT_ACTION_FAILURE;
}
} else {
PageantClientOp *pco = pageant_client_op_new();
put_byte(pco, SSH2_AGENTC_ADD_IDENTITY);
put_stringz(pco, ssh_key_ssh_id(skey->key));
ssh_key_openssh_blob(skey->key, BinarySink_UPCAST(pco));
put_stringz(pco, skey->comment);
unsigned reply = pageant_client_op_query(pco);
pageant_client_op_free(pco);
sfree(skey->comment);
ssh_key_free(skey->key);
sfree(skey);
sfree(response);
if (reply != SSH_AGENT_SUCCESS) {
*retstr = dupstr("The already running Pageant "
"refused to add the key.");
return PAGEANT_ACTION_FAILURE;
}
}
return PAGEANT_ACTION_OK;
}
@ -2015,158 +1968,124 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase,
int pageant_enum_keys(pageant_key_enum_fn_t callback, void *callback_ctx,
char **retstr)
{
unsigned char *keylist;
int i, nkeys, keylistlen;
ptrlen comment;
KeyList *kl1 = NULL, *kl2 = NULL;
struct pageant_pubkey cbkey;
BinarySource src[1];
int toret = PAGEANT_ACTION_FAILURE;
keylist = pageant_get_keylist1(&keylistlen);
if (!keylist) {
kl1 = pageant_get_keylist(1);
if (!kl1) {
*retstr = dupstr("Did not receive an SSH-1 key list from agent");
return PAGEANT_ACTION_FAILURE;
goto out;
}
BinarySource_BARE_INIT(src, keylist, keylistlen);
nkeys = toint(get_uint32(src));
for (i = 0; i < nkeys; i++) {
RSAKey rkey;
char *fingerprint;
/* public blob and fingerprint */
memset(&rkey, 0, sizeof(rkey));
get_rsa_ssh1_pub(src, &rkey, RSA_SSH1_EXPONENT_FIRST);
comment = get_string(src);
if (get_err(src)) {
*retstr = dupstr("Received broken SSH-1 key list from agent");
freersakey(&rkey);
sfree(keylist);
return PAGEANT_ACTION_FAILURE;
}
fingerprint = rsa_ssh1_fingerprint(&rkey);
cbkey.blob = makeblob1(&rkey);
cbkey.comment = mkstr(comment);
cbkey.ssh_version = 1;
callback(callback_ctx, fingerprint, cbkey.comment, &cbkey);
strbuf_free(cbkey.blob);
freersakey(&rkey);
sfree(cbkey.comment);
sfree(fingerprint);
}
sfree(keylist);
if (get_err(src) || get_avail(src) != 0) {
if (kl1->broken) {
*retstr = dupstr("Received broken SSH-1 key list from agent");
return PAGEANT_ACTION_FAILURE;
goto out;
}
keylist = pageant_get_keylist2(&keylistlen);
if (!keylist) {
kl2 = pageant_get_keylist(2);
if (!kl2) {
*retstr = dupstr("Did not receive an SSH-2 key list from agent");
return PAGEANT_ACTION_FAILURE;
goto out;
}
if (kl2->broken) {
*retstr = dupstr("Received broken SSH-2 key list from agent");
goto out;
}
BinarySource_BARE_INIT(src, keylist, keylistlen);
nkeys = toint(get_uint32(src));
for (i = 0; i < nkeys; i++) {
ptrlen pubblob;
char *fingerprint;
pubblob = get_string(src);
comment = get_string(src);
if (get_err(src)) {
*retstr = dupstr("Received broken SSH-2 key list from agent");
sfree(keylist);
return PAGEANT_ACTION_FAILURE;
}
fingerprint = ssh2_fingerprint_blob(pubblob);
for (size_t i = 0; i < kl1->nkeys; i++) {
cbkey.blob = strbuf_new();
put_datapl(cbkey.blob, pubblob);
put_datapl(cbkey.blob, kl1->keys[i].blob);
cbkey.comment = mkstr(kl1->keys[i].comment);
cbkey.ssh_version = 1;
/* Decode public blob into a key in order to fingerprint it */
RSAKey rkey;
memset(&rkey, 0, sizeof(rkey));
{
BinarySource src[1];
BinarySource_BARE_INIT_PL(src, kl1->keys[i].blob);
get_rsa_ssh1_pub(src, &rkey, RSA_SSH1_EXPONENT_FIRST);
if (get_err(src)) {
*retstr = dupstr("Received an invalid SSH-1 key from agent");
goto out;
}
}
char *fingerprint = rsa_ssh1_fingerprint(&rkey);
freersakey(&rkey);
callback(callback_ctx, fingerprint, cbkey.comment, &cbkey);
strbuf_free(cbkey.blob);
sfree(cbkey.comment);
sfree(fingerprint);
}
for (size_t i = 0; i < kl2->nkeys; i++) {
cbkey.blob = strbuf_new();
put_datapl(cbkey.blob, kl2->keys[i].blob);
cbkey.comment = mkstr(kl2->keys[i].comment);
cbkey.ssh_version = 2;
cbkey.comment = mkstr(comment);
char *fingerprint = ssh2_fingerprint_blob(kl2->keys[i].blob);
callback(callback_ctx, fingerprint, cbkey.comment, &cbkey);
sfree(fingerprint);
sfree(cbkey.comment);
strbuf_free(cbkey.blob);
}
sfree(keylist);
if (get_err(src) || get_avail(src) != 0) {
*retstr = dupstr("Received broken SSH-2 key list from agent");
return PAGEANT_ACTION_FAILURE;
}
return PAGEANT_ACTION_OK;
*retstr = NULL;
toret = PAGEANT_ACTION_OK;
out:
if (kl1)
keylist_free(kl1);
if (kl2)
keylist_free(kl2);
return toret;
}
int pageant_delete_key(struct pageant_pubkey *key, char **retstr)
{
strbuf *request;
unsigned char *response;
int resplen, ret;
void *vresponse;
request = strbuf_new_for_agent_query();
PageantClientOp *pco = pageant_client_op_new();
if (key->ssh_version == 1) {
put_byte(request, SSH1_AGENTC_REMOVE_RSA_IDENTITY);
put_data(request, key->blob->s, key->blob->len);
put_byte(pco, SSH1_AGENTC_REMOVE_RSA_IDENTITY);
put_data(pco, key->blob->s, key->blob->len);
} else {
put_byte(request, SSH2_AGENTC_REMOVE_IDENTITY);
put_string(request, key->blob->s, key->blob->len);
put_byte(pco, SSH2_AGENTC_REMOVE_IDENTITY);
put_string(pco, key->blob->s, key->blob->len);
}
pageant_client_query(request, &vresponse, &resplen);
strbuf_free(request);
unsigned reply = pageant_client_op_query(pco);
pageant_client_op_free(pco);
response = vresponse;
if (resplen < 5 || response[4] != SSH_AGENT_SUCCESS) {
if (reply != SSH_AGENT_SUCCESS) {
*retstr = dupstr("Agent failed to delete key");
ret = PAGEANT_ACTION_FAILURE;
return PAGEANT_ACTION_FAILURE;
} else {
*retstr = NULL;
ret = PAGEANT_ACTION_OK;
return PAGEANT_ACTION_OK;
}
sfree(response);
return ret;
}
int pageant_delete_all_keys(char **retstr)
{
strbuf *request;
unsigned char *response;
int resplen;
bool success;
void *vresponse;
PageantClientOp *pco;
unsigned reply;
request = strbuf_new_for_agent_query();
put_byte(request, SSH2_AGENTC_REMOVE_ALL_IDENTITIES);
pageant_client_query(request, &vresponse, &resplen);
strbuf_free(request);
response = vresponse;
success = (resplen >= 4 && response[4] == SSH_AGENT_SUCCESS);
sfree(response);
if (!success) {
pco = pageant_client_op_new();
put_byte(pco, SSH2_AGENTC_REMOVE_ALL_IDENTITIES);
reply = pageant_client_op_query(pco);
pageant_client_op_free(pco);
if (reply != SSH_AGENT_SUCCESS) {
*retstr = dupstr("Agent failed to delete SSH-2 keys");
return PAGEANT_ACTION_FAILURE;
}
request = strbuf_new_for_agent_query();
put_byte(request, SSH1_AGENTC_REMOVE_ALL_RSA_IDENTITIES);
pageant_client_query(request, &vresponse, &resplen);
strbuf_free(request);
response = vresponse;
success = (resplen >= 4 && response[4] == SSH_AGENT_SUCCESS);
sfree(response);
if (!success) {
pco = pageant_client_op_new();
put_byte(pco, SSH1_AGENTC_REMOVE_ALL_RSA_IDENTITIES);
reply = pageant_client_op_query(pco);
pageant_client_op_free(pco);
if (reply != SSH_AGENT_SUCCESS) {
*retstr = dupstr("Agent failed to delete SSH-1 keys");
return PAGEANT_ACTION_FAILURE;
}
@ -2178,31 +2097,22 @@ int pageant_delete_all_keys(char **retstr)
int pageant_sign(struct pageant_pubkey *key, ptrlen message, strbuf *out,
uint32_t flags, char **retstr)
{
strbuf *request;
void *response;
int resplen;
BinarySource src[1];
PageantClientOp *pco = pageant_client_op_new();
put_byte(pco, SSH2_AGENTC_SIGN_REQUEST);
put_string(pco, key->blob->s, key->blob->len);
put_stringpl(pco, message);
put_uint32(pco, flags);
unsigned reply = pageant_client_op_query(pco);
ptrlen signature = get_string(pco);
request = strbuf_new_for_agent_query();
put_byte(request, SSH2_AGENTC_SIGN_REQUEST);
put_string(request, key->blob->s, key->blob->len);
put_stringpl(request, message);
put_uint32(request, flags);
pageant_client_query(request, &response, &resplen);
strbuf_free(request);
BinarySource_BARE_INIT(src, response, resplen);
BinarySource_BARE_INIT_PL(src, get_string(src));
int type = get_byte(src);
ptrlen signature = get_string(src);
put_datapl(out, signature);
sfree(response);
if (type == SSH2_AGENT_SIGN_RESPONSE && !get_err(src)) {
if (reply == SSH2_AGENT_SIGN_RESPONSE && !get_err(pco)) {
*retstr = NULL;
put_datapl(out, signature);
pageant_client_op_free(pco);
return PAGEANT_ACTION_OK;
} else {
*retstr = dupstr("Agent failed to create signature");
pageant_client_op_free(pco);
return PAGEANT_ACTION_FAILURE;
}
}

View File

@ -194,10 +194,6 @@ void pageant_listener_free(struct pageant_listen_state *pl);
* process. (On at least one platform we want to do this in an
* agnostic way between the two situations.)
*
* pageant_get_keylist{1,2} work just like pageant_make_keylist{1,2}
* above, except that they can also cope if they have to contact an
* external agent.
*
* pageant_add_keyfile() is used to load a private key from a file and
* add it to the agent. Initially, you should call it with passphrase
* NULL, and it will check if the key is already in the agent, and
@ -212,8 +208,6 @@ void pageant_listener_free(struct pageant_listen_state *pl);
* for keys that have the same trust properties). Call
* pageant_forget_passphrases() to get rid of them all.
*/
void *pageant_get_keylist1(int *length);
void *pageant_get_keylist2(int *length);
enum {
PAGEANT_ACTION_OK, /* success; no further action needed */
PAGEANT_ACTION_FAILURE, /* failure; *retstr is error message */