-
Notifications
You must be signed in to change notification settings - Fork 0
/
pageant.h
257 lines (235 loc) · 9.84 KB
/
pageant.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
/*
* 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 *key_comment);
};
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 *comment)
{ return pc->vt->ask_passphrase(pc, dlgid, comment); }
/* 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, used by GUI
* Pageant, to count the keys, to delete a key, or to re-encrypt a
* decrypted-on-demand key (SSH-2 only).
*/
int pageant_count_ssh1_keys(void);
int pageant_count_ssh2_keys(void);
bool pageant_delete_nth_ssh1_key(int i);
bool pageant_delete_nth_ssh2_key(int i);
bool pageant_reencrypt_nth_ssh2_key(int i);
void pageant_delete_all(void);
void pageant_reencrypt_all(void);
/*
* 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 *key_comment);
};
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 *comment)
{ return plc->vt->ask_passphrase(plc, dlgid, comment); }
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, char **fingerprints,
const char *comment, uint32_t ext_flags,
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);
/*
* Definitions for agent protocol extensions.
*/
#define PUTTYEXT(base) base "@putty.projects.tartarus.org"
#define KNOWN_EXTENSIONS(X) \
X(EXT_QUERY, "query") \
X(EXT_ADD_PPK, PUTTYEXT("add-ppk")) \
X(EXT_REENCRYPT, PUTTYEXT("reencrypt")) \
X(EXT_REENCRYPT_ALL, PUTTYEXT("reencrypt-all")) \
X(EXT_LIST_EXTENDED, PUTTYEXT("list-extended")) \
/* end of list */
#define LIST_EXTENDED_FLAG_HAS_ENCRYPTED_KEY_FILE 1
#define LIST_EXTENDED_FLAG_HAS_NO_CLEARTEXT_KEY 2