зеркало из https://github.com/github/putty.git
245 строки
9.5 KiB
C
245 строки
9.5 KiB
C
/*
|
|
* pageant.h: header for pageant.c.
|
|
*/
|
|
|
|
#include <stdarg.h>
|
|
|
|
/*
|
|
* Upper limit on length of any agent message. Used as a basic sanity
|
|
* check on messages' length fields, and used by the Windows Pageant
|
|
* client IPC to decide how large a file mapping to allocate.
|
|
*/
|
|
#define AGENT_MAX_MSGLEN 262144
|
|
|
|
typedef struct PageantClientVtable PageantClientVtable;
|
|
typedef struct PageantClient PageantClient;
|
|
typedef struct PageantClientInfo PageantClientInfo;
|
|
typedef struct PageantClientRequestId PageantClientRequestId;
|
|
typedef struct PageantClientDialogId PageantClientDialogId;
|
|
struct PageantClient {
|
|
const struct PageantClientVtable *vt;
|
|
PageantClientInfo *info; /* used by the central Pageant code */
|
|
|
|
/* Setting this flag prevents the 'log' vtable entry from ever
|
|
* being called, so that it's safe to make it NULL. This also
|
|
* allows optimisations in the core code (it can avoid entire
|
|
* loops that are only used for logging purposes). So you can also
|
|
* set it dynamically if you find out at run time that you're not
|
|
* doing logging. */
|
|
bool suppress_logging;
|
|
};
|
|
struct PageantClientVtable {
|
|
void (*log)(PageantClient *pc, PageantClientRequestId *reqid,
|
|
const char *fmt, va_list ap);
|
|
void (*got_response)(PageantClient *pc, PageantClientRequestId *reqid,
|
|
ptrlen response);
|
|
bool (*ask_passphrase)(PageantClient *pc, PageantClientDialogId *dlgid,
|
|
const char *msg);
|
|
};
|
|
|
|
static inline void pageant_client_log_v(
|
|
PageantClient *pc, PageantClientRequestId *reqid,
|
|
const char *fmt, va_list ap)
|
|
{
|
|
if (!pc->suppress_logging)
|
|
pc->vt->log(pc, reqid, fmt, ap);
|
|
}
|
|
static inline PRINTF_LIKE(3, 4) void pageant_client_log(
|
|
PageantClient *pc, PageantClientRequestId *reqid, const char *fmt, ...)
|
|
{
|
|
if (!pc->suppress_logging) {
|
|
va_list ap;
|
|
va_start(ap, fmt);
|
|
pc->vt->log(pc, reqid, fmt, ap);
|
|
va_end(ap);
|
|
}
|
|
}
|
|
static inline void pageant_client_got_response(
|
|
PageantClient *pc, PageantClientRequestId *reqid, ptrlen response)
|
|
{ pc->vt->got_response(pc, reqid, response); }
|
|
static inline bool pageant_client_ask_passphrase(
|
|
PageantClient *pc, PageantClientDialogId *dlgid, const char *msg)
|
|
{ return pc->vt->ask_passphrase(pc, dlgid, msg); }
|
|
|
|
/* PageantClientRequestId is used to match up responses to the agent
|
|
* requests they refer to. A client may allocate one of these for each
|
|
* call to pageant_handle_request, (probably as a subfield of some
|
|
* larger struct on the client side) and expect the same pointer to be
|
|
* passed back in pageant_client_got_response. */
|
|
struct PageantClientRequestId { int unused_; };
|
|
|
|
/*
|
|
* Initial setup.
|
|
*/
|
|
void pageant_init(void);
|
|
|
|
/*
|
|
* Register and unregister PageantClients. This is necessary so that
|
|
* when a PageantClient goes away, any unfinished asynchronous
|
|
* requests can be cleaned up.
|
|
*
|
|
* pageant_register_client will fill in pc->id. The client itself
|
|
* should not touch that field.
|
|
*/
|
|
void pageant_register_client(PageantClient *pc);
|
|
void pageant_unregister_client(PageantClient *pc);
|
|
|
|
/*
|
|
* The main agent function that answers messages.
|
|
*
|
|
* Expects a message/length pair as input, minus its initial length
|
|
* field but still with its type code on the front.
|
|
*
|
|
* When a response is ready, the got_response method in the
|
|
* PageantClient vtable will be passed it in the form of a ptrlen,
|
|
* again minus its length field.
|
|
*/
|
|
void pageant_handle_msg(PageantClient *pc, PageantClientRequestId *reqid,
|
|
ptrlen msg);
|
|
|
|
/*
|
|
* Send the core Pageant code a response to a passphrase request.
|
|
*/
|
|
void pageant_passphrase_request_success(PageantClientDialogId *dlgid,
|
|
ptrlen passphrase);
|
|
void pageant_passphrase_request_refused(PageantClientDialogId *dlgid);
|
|
|
|
/*
|
|
* Construct a list of public keys, just as the two LIST_IDENTITIES
|
|
* requests would have returned them.
|
|
*/
|
|
void pageant_make_keylist1(BinarySink *);
|
|
void pageant_make_keylist2(BinarySink *);
|
|
|
|
/*
|
|
* Accessor functions for Pageant's internal key lists. Fetch the nth
|
|
* key; count the keys; attempt to add a key (returning true on
|
|
* success, in which case the ownership of the key structure has been
|
|
* taken over by pageant.c); attempt to delete a key (returning true
|
|
* on success, in which case the ownership of the key structure is
|
|
* passed back to the client).
|
|
*/
|
|
RSAKey *pageant_nth_ssh1_key(int i);
|
|
ssh2_userkey *pageant_nth_ssh2_key(int i);
|
|
int pageant_count_ssh1_keys(void);
|
|
int pageant_count_ssh2_keys(void);
|
|
bool pageant_add_ssh1_key(RSAKey *rkey);
|
|
bool pageant_add_ssh2_key(ssh2_userkey *skey);
|
|
bool pageant_delete_ssh1_key(RSAKey *rkey);
|
|
bool pageant_delete_ssh2_key(ssh2_userkey *skey);
|
|
|
|
/*
|
|
* This callback must be provided by the Pageant front end code.
|
|
* pageant_handle_msg calls it to indicate that the message it's just
|
|
* handled has changed the list of keys held by the agent. Front ends
|
|
* which expose that key list through dedicated UI may need to refresh
|
|
* that UI's state in this function; other front ends can leave it
|
|
* empty.
|
|
*/
|
|
void keylist_update(void);
|
|
|
|
/*
|
|
* Functions to establish a listening socket speaking the SSH agent
|
|
* protocol. Call pageant_listener_new() to set up a state; then
|
|
* create a socket using the returned Plug; then call
|
|
* pageant_listener_got_socket() to give the listening state its own
|
|
* socket pointer. Also, provide a logging function later if you want
|
|
* to.
|
|
*/
|
|
typedef struct PageantListenerClientVtable PageantListenerClientVtable;
|
|
typedef struct PageantListenerClient PageantListenerClient;
|
|
struct PageantListenerClient {
|
|
const PageantListenerClientVtable *vt;
|
|
/* suppress_logging flag works similarly to the one in
|
|
* PageantClient, but it is only read when a new connection comes
|
|
* in. So if you do need to change it in mid-run, expect existing
|
|
* agent connections to still use the old value. */
|
|
bool suppress_logging;
|
|
};
|
|
struct PageantListenerClientVtable {
|
|
void (*log)(PageantListenerClient *, const char *fmt, va_list ap);
|
|
bool (*ask_passphrase)(PageantListenerClient *pc,
|
|
PageantClientDialogId *dlgid, const char *msg);
|
|
};
|
|
|
|
static inline void pageant_listener_client_log_v(
|
|
PageantListenerClient *plc, const char *fmt, va_list ap)
|
|
{
|
|
if (!plc->suppress_logging)
|
|
plc->vt->log(plc, fmt, ap);
|
|
}
|
|
static inline PRINTF_LIKE(2, 3) void pageant_listener_client_log(
|
|
PageantListenerClient *plc, const char *fmt, ...)
|
|
{
|
|
if (!plc->suppress_logging) {
|
|
va_list ap;
|
|
va_start(ap, fmt);
|
|
plc->vt->log(plc, fmt, ap);
|
|
va_end(ap);
|
|
}
|
|
}
|
|
static inline bool pageant_listener_client_ask_passphrase(
|
|
PageantListenerClient *plc, PageantClientDialogId *dlgid, const char *msg)
|
|
{ return plc->vt->ask_passphrase(plc, dlgid, msg); }
|
|
|
|
struct pageant_listen_state;
|
|
struct pageant_listen_state *pageant_listener_new(
|
|
Plug **plug, PageantListenerClient *plc);
|
|
void pageant_listener_got_socket(struct pageant_listen_state *pl, Socket *);
|
|
void pageant_listener_free(struct pageant_listen_state *pl);
|
|
|
|
/*
|
|
* Functions to perform specific key actions, either as a client of an
|
|
* ssh-agent running elsewhere, or directly on the agent state in this
|
|
* process. (On at least one platform we want to do this in an
|
|
* agnostic way between the two situations.)
|
|
*
|
|
* 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
|
|
* whether a passphrase is required. Return values are given in the
|
|
* enum below. On return, *retstr will either be NULL, or a
|
|
* dynamically allocated string containing a key comment or an error
|
|
* message.
|
|
*
|
|
* pageant_add_keyfile() also remembers passphrases with which it's
|
|
* successfully decrypted keys (because if you try to add multiple
|
|
* keys in one go, you might very well have used the same passphrase
|
|
* for keys that have the same trust properties). Call
|
|
* pageant_forget_passphrases() to get rid of them all.
|
|
*/
|
|
enum {
|
|
PAGEANT_ACTION_OK, /* success; no further action needed */
|
|
PAGEANT_ACTION_FAILURE, /* failure; *retstr is error message */
|
|
PAGEANT_ACTION_NEED_PP, /* need passphrase: *retstr is key comment */
|
|
PAGEANT_ACTION_WARNING, /* success but with a warning message;
|
|
* *retstr is warning message */
|
|
};
|
|
int pageant_add_keyfile(Filename *filename, const char *passphrase,
|
|
char **retstr, bool add_encrypted);
|
|
void pageant_forget_passphrases(void);
|
|
|
|
struct pageant_pubkey {
|
|
/* Everything needed to identify a public key found by
|
|
* pageant_enum_keys and pass it back to the agent or other code
|
|
* later */
|
|
strbuf *blob;
|
|
char *comment;
|
|
int ssh_version;
|
|
};
|
|
struct pageant_pubkey *pageant_pubkey_copy(struct pageant_pubkey *key);
|
|
void pageant_pubkey_free(struct pageant_pubkey *key);
|
|
|
|
typedef void (*pageant_key_enum_fn_t)(void *ctx,
|
|
const char *fingerprint,
|
|
const char *comment,
|
|
struct pageant_pubkey *key);
|
|
int pageant_enum_keys(pageant_key_enum_fn_t callback, void *callback_ctx,
|
|
char **retstr);
|
|
int pageant_delete_key(struct pageant_pubkey *key, char **retstr);
|
|
int pageant_delete_all_keys(char **retstr);
|
|
int pageant_reencrypt_key(struct pageant_pubkey *key, char **retstr);
|
|
int pageant_reencrypt_all_keys(char **retstr);
|
|
int pageant_sign(struct pageant_pubkey *key, ptrlen message, strbuf *out,
|
|
uint32_t flags, char **retstr);
|