PuTTY 0.76 にアップデート
- 展開して使うソースを PuTTY 0.76 に変更
- コピーして使うソースも PuTTY 0.76 にアップデート
@@ -1,4 +1,3 @@ | ||
1 | -// PuTTY is copyright 1997-2007 Simon Tatham. | |
2 | 1 | /* |
3 | 2 | * Copyright (C) 1994-1998 T. Teranishi |
4 | 3 | * (C) 2004- TeraTerm Project |
@@ -27,31 +26,59 @@ | ||
27 | 26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
28 | 27 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
29 | 28 | */ |
29 | +// PuTTY is copyright 1997-2021 Simon Tatham. | |
30 | 30 | |
31 | 31 | /* |
32 | 32 | * putty プロジェクトは |
33 | - * - PuTTY のソースファイル (プロジェクトに読み込むファイルは最小限) | |
34 | - * - libputty.c/h | |
33 | + * - libputty.c/h | |
35 | 34 | * PuTTY の機能を利用するインターフェース |
36 | - * PuTTY のソースファイルから必要な関数のみをコピー | |
35 | + * PuTTY の内部型との変換 | |
36 | + * - PuTTY のソースコード (プロジェクトに読み込むファイルは最小限) | |
37 | + * -- 展開した PuTTY のソースファイルをそのまま読み込んだもの (Putty Files グループ内) | |
38 | + * -- putty プロジェクト側にコピーしたソースコード (putty-import.c) | |
39 | + * static なために呼び出せない関数の static を外す | |
40 | + * putty で使う部分だけを抜粋 (putty で使わない部分で増えてしまう依存を抑制) | |
37 | 41 | * から静的ライブラリ libputty.lib を生成し、TTXSSH からリンクされて利用される。 |
38 | 42 | * そのため、TTXSSH 側の定義は持ち込まない。 |
39 | 43 | */ |
40 | 44 | |
45 | +#include <stdio.h> | |
41 | 46 | #include <windows.h> |
42 | 47 | #include <assert.h> |
43 | 48 | |
44 | -#include "sshbn.h" | |
45 | - | |
46 | -// from SSHBN.C (ver 0.60) | |
47 | -#define BIGNUM_INTERNAL | |
48 | -typedef BignumInt *Bignum; | |
49 | - | |
50 | 49 | #include "ssh.h" |
50 | +#include "mpint.h" | |
51 | 51 | |
52 | 52 | #include "libputty.h" |
53 | 53 | |
54 | 54 | |
55 | +// pageant.c | |
56 | +typedef struct KeyListEntry { | |
57 | + ptrlen blob, comment; | |
58 | + uint32_t flags; | |
59 | +} KeyListEntry; | |
60 | +typedef struct KeyList { | |
61 | + strbuf *raw_data; | |
62 | + KeyListEntry *keys; | |
63 | + size_t nkeys; | |
64 | + bool broken; | |
65 | +} KeyList; | |
66 | + | |
67 | +// putty.h | |
68 | +// aqsync.c | |
69 | +extern void agent_query_synchronous(strbuf *in, void **out, int *outlen); | |
70 | + | |
71 | +// pageant.c | |
72 | +extern void keylist_free(KeyList *kl); | |
73 | + | |
74 | +// pageant.c | |
75 | +extern KeyList *pageant_get_keylist(unsigned ssh_version); | |
76 | + | |
77 | +// putty.h | |
78 | +// windows/winpgntc.c | |
79 | +extern bool agent_exists(void); | |
80 | + | |
81 | + | |
55 | 82 | /* |
56 | 83 | * for SSH2 |
57 | 84 | * 鍵の一覧を得る |
@@ -58,20 +85,47 @@ | ||
58 | 85 | */ |
59 | 86 | int putty_get_ssh2_keylist(unsigned char **keylist) |
60 | 87 | { |
61 | - int keylistlen; | |
88 | + KeyList *kl; | |
89 | + int keylistlen = 0; | |
90 | + strbuf *sb_keylist = strbuf_new(); | |
91 | + size_t i; | |
62 | 92 | |
63 | - *keylist = get_keylist2(&keylistlen); | |
64 | - if (*keylist == NULL){ | |
65 | - // 取得に失敗 | |
66 | - return 0; | |
93 | + kl = pageant_get_keylist(2); | |
94 | + if (kl) { | |
95 | + if (kl->broken) { | |
96 | + keylist_free(kl); | |
97 | + strbuf_free(sb_keylist); | |
98 | + return 0; | |
99 | + } | |
100 | + | |
101 | + put_uint32(sb_keylist, kl->nkeys); | |
102 | + keylistlen += 4; | |
103 | + for (i = 0; i < kl->nkeys; i++) { | |
104 | + put_uint32(sb_keylist, kl->keys[i].blob.len); | |
105 | + keylistlen += 4; | |
106 | + put_datapl(sb_keylist, kl->keys[i].blob); | |
107 | + keylistlen += kl->keys[i].blob.len; | |
108 | + put_uint32(sb_keylist, kl->keys[i].comment.len); | |
109 | + keylistlen += 4; | |
110 | + put_datapl(sb_keylist, kl->keys[i].comment); | |
111 | + keylistlen += kl->keys[i].comment.len; | |
112 | + } | |
113 | + keylist_free(kl); | |
114 | + | |
115 | + *keylist = strbuf_to_str(sb_keylist); | |
116 | + | |
117 | + return keylistlen; | |
67 | 118 | } |
68 | - return keylistlen; | |
119 | + | |
120 | + strbuf_free(sb_keylist); | |
121 | + return 0; | |
69 | 122 | } |
70 | 123 | |
71 | 124 | /* |
72 | 125 | * for SSH2 |
73 | 126 | * 公開鍵とデータを渡し、 |
74 | - * 秘密鍵によって署名されたデータを得る | |
127 | + * 秘密鍵による署名を得る | |
128 | + * ssh2userauth.c (PuTTY 0.76) から再構成 | |
75 | 129 | */ |
76 | 130 | void *putty_sign_ssh2_key(unsigned char *pubkey /* length(4byte) + data */, |
77 | 131 | unsigned char *data, |
@@ -80,43 +134,34 @@ | ||
80 | 134 | { |
81 | 135 | void *ret; |
82 | 136 | |
83 | - unsigned char *request, *response; | |
137 | + unsigned char *response; | |
84 | 138 | void *vresponse; |
85 | - int resplen; | |
86 | - int pubkeylen, reqlen; | |
87 | - int flags = 0; | |
139 | + int response_len; | |
140 | + int pubkeylen; | |
141 | + strbuf *agentreq = strbuf_new_for_agent_query(); | |
142 | + int signflags = 0; | |
88 | 143 | |
89 | - pubkeylen = GET_32BIT(pubkey); | |
90 | - reqlen = 4 + 1 + (4 + pubkeylen) + (4 + datalen) + 4; | |
91 | - request = (unsigned char *)malloc(reqlen); | |
144 | + put_byte(agentreq, SSH2_AGENTC_SIGN_REQUEST); | |
145 | + pubkeylen = GET_32BIT_MSB_FIRST(pubkey); | |
146 | + put_data(agentreq, pubkey, 4 + pubkeylen); | |
147 | + put_uint32(agentreq, datalen); | |
148 | + put_data(agentreq, data, datalen); | |
149 | + put_uint32(agentreq, signflags); | |
150 | + agent_query_synchronous(agentreq, &vresponse, &response_len); | |
151 | + strbuf_free(agentreq); | |
92 | 152 | |
93 | - // request length | |
94 | - PUT_32BIT(request, reqlen); | |
95 | - // request type | |
96 | - request[4] = SSH2_AGENTC_SIGN_REQUEST; | |
97 | - // public key (length + data) | |
98 | - memcpy(request + 5, pubkey, 4 + pubkeylen); | |
99 | - // sign data length | |
100 | - PUT_32BIT(request + 5 + 4 + pubkeylen, datalen); | |
101 | - // sign data | |
102 | - memcpy(request + 5 + 4 + pubkeylen + 4, data, datalen); | |
103 | - // flags word | |
104 | - PUT_32BIT(request + 5 + 4 + pubkeylen + 4 + datalen, flags); | |
105 | - | |
106 | - agent_query(request, reqlen, &vresponse, &resplen, NULL, NULL); | |
107 | - | |
108 | 153 | response = vresponse; |
109 | - if (resplen < 5 || response[4] != SSH2_AGENT_SIGN_RESPONSE) { | |
154 | + if (response_len < 5 || response[4] != SSH2_AGENT_SIGN_RESPONSE) { | |
110 | 155 | sfree(response); |
111 | 156 | return NULL; |
112 | 157 | } |
113 | 158 | |
114 | - ret = snewn(resplen-5, unsigned char); | |
115 | - memcpy(ret, response+5, resplen-5); | |
159 | + ret = snewn(response_len-5, unsigned char); | |
160 | + memcpy(ret, response+5, response_len-5); | |
116 | 161 | sfree(response); |
117 | 162 | |
118 | 163 | if (outlen) |
119 | - *outlen = resplen-5; | |
164 | + *outlen = response_len-5; | |
120 | 165 | |
121 | 166 | return ret; |
122 | 167 | } |
@@ -127,14 +172,38 @@ | ||
127 | 172 | */ |
128 | 173 | int putty_get_ssh1_keylist(unsigned char **keylist) |
129 | 174 | { |
130 | - int keylistlen; | |
175 | + KeyList *kl; | |
176 | + int keylistlen = 0; | |
177 | + strbuf *sb_keylist = strbuf_new(); | |
178 | + size_t i; | |
131 | 179 | |
132 | - *keylist = get_keylist1(&keylistlen); | |
133 | - if (*keylist == NULL){ | |
134 | - // 取得に失敗 | |
135 | - return 0; | |
180 | + kl = pageant_get_keylist(1); | |
181 | + if (kl) { | |
182 | + if (kl->broken) { | |
183 | + keylist_free(kl); | |
184 | + strbuf_free(sb_keylist); | |
185 | + return 0; | |
186 | + } | |
187 | + | |
188 | + put_uint32(sb_keylist, kl->nkeys); | |
189 | + keylistlen += 4; | |
190 | + for (i = 0; i < kl->nkeys; i++) { | |
191 | + put_data(sb_keylist, kl->keys[i].blob.ptr, kl->keys[i].blob.len); | |
192 | + keylistlen += kl->keys[i].blob.len; | |
193 | + put_uint32(sb_keylist, kl->keys[i].comment.len); | |
194 | + keylistlen += 4; | |
195 | + put_datapl(sb_keylist, kl->keys[i].comment); | |
196 | + keylistlen += kl->keys[i].comment.len; | |
197 | + } | |
198 | + keylist_free(kl); | |
199 | + | |
200 | + *keylist = strbuf_to_str(sb_keylist); | |
201 | + | |
202 | + return keylistlen; | |
136 | 203 | } |
137 | - return keylistlen; | |
204 | + | |
205 | + strbuf_free(sb_keylist); | |
206 | + return 0; | |
138 | 207 | } |
139 | 208 | |
140 | 209 | /* |
@@ -141,6 +210,7 @@ | ||
141 | 210 | * for SSH1 |
142 | 211 | * 公開鍵と暗号化データを渡し |
143 | 212 | * 復号データのハッシュを得る |
213 | + * ssh1login.c (PuTTY 0.76) から再構成 | |
144 | 214 | */ |
145 | 215 | void *putty_hash_ssh1_challenge(unsigned char *pubkey, |
146 | 216 | int pubkeylen, |
@@ -151,47 +221,31 @@ | ||
151 | 221 | { |
152 | 222 | void *ret; |
153 | 223 | |
154 | - unsigned char *request, *response, *p; | |
224 | + unsigned char *response; | |
155 | 225 | void *vresponse; |
156 | - int resplen; | |
157 | - int reqlen; | |
226 | + int response_len; | |
227 | + strbuf *agentreq = strbuf_new_for_agent_query(); | |
158 | 228 | |
159 | - reqlen = 4 + 1 + pubkeylen + datalen + 16 + 4; | |
160 | - request = (unsigned char *)malloc(reqlen); | |
161 | - p = request; | |
229 | + put_byte(agentreq, SSH1_AGENTC_RSA_CHALLENGE); | |
230 | + put_data(agentreq, pubkey, pubkeylen); | |
231 | + put_data(agentreq, data, datalen); | |
232 | + put_data(agentreq, session_id, 16); | |
233 | + put_uint32(agentreq, 1); // response format | |
234 | + agent_query_synchronous(agentreq, &vresponse, &response_len); | |
235 | + strbuf_free(agentreq); | |
162 | 236 | |
163 | - // request length | |
164 | - PUT_32BIT(request, reqlen); | |
165 | - // request type | |
166 | - request[4] = SSH1_AGENTC_RSA_CHALLENGE; | |
167 | - p += 5; | |
168 | - | |
169 | - // public key | |
170 | - memcpy(p, pubkey, pubkeylen); | |
171 | - p += pubkeylen; | |
172 | - // challange from server | |
173 | - memcpy(p, data, datalen); | |
174 | - p += datalen; | |
175 | - // session_id | |
176 | - memcpy(p, session_id, 16); | |
177 | - p += 16; | |
178 | - // response format | |
179 | - PUT_32BIT(p, 1); | |
180 | - | |
181 | - agent_query(request, reqlen, &vresponse, &resplen, NULL, NULL); | |
182 | - | |
183 | 237 | response = vresponse; |
184 | - if (resplen < 5 || response[4] != SSH1_AGENT_RSA_RESPONSE) { | |
238 | + if (response_len < 5+16 || response[4] != SSH1_AGENT_RSA_RESPONSE) { | |
185 | 239 | sfree(response); |
186 | 240 | return NULL; |
187 | 241 | } |
188 | 242 | |
189 | - ret = snewn(resplen-5, unsigned char); | |
190 | - memcpy(ret, response+5, resplen-5); | |
243 | + ret = snewn(response_len-5, unsigned char); | |
244 | + memcpy(ret, response+5, response_len-5); | |
191 | 245 | sfree(response); |
192 | 246 | |
193 | 247 | if (outlen) |
194 | - *outlen = resplen-5; | |
248 | + *outlen = response_len-5; | |
195 | 249 | |
196 | 250 | return ret; |
197 | 251 | } |
@@ -198,7 +252,7 @@ | ||
198 | 252 | |
199 | 253 | int putty_get_ssh1_keylen(unsigned char *key, int maxlen) |
200 | 254 | { |
201 | - return rsa_public_blob_len(key, maxlen); | |
255 | + return rsa_ssh1_public_blob_len(make_ptrlen(key, maxlen)); | |
202 | 256 | } |
203 | 257 | |
204 | 258 | const char *putty_get_version() |
@@ -207,173 +261,15 @@ | ||
207 | 261 | return ver; |
208 | 262 | } |
209 | 263 | |
210 | -/* | |
211 | - * Following functions are copied from putty source. | |
212 | - */ | |
213 | - | |
214 | -// from SSHBN.C (ver 0.63) | |
215 | -static Bignum newbn(int length) | |
264 | +void putty_agent_query_synchronous(void *in, int inlen, void **out, int *outlen) | |
216 | 265 | { |
217 | - Bignum b; | |
266 | + strbuf *buf = strbuf_new(); | |
218 | 267 | |
219 | - assert(length >= 0 && length < INT_MAX / BIGNUM_INT_BITS); | |
220 | - | |
221 | - b = snewn(length + 1, BignumInt); | |
222 | - if (!b) | |
223 | - abort(); /* FIXME */ | |
224 | - memset(b, 0, (length + 1) * sizeof(*b)); | |
225 | - b[0] = length; | |
226 | - return b; | |
268 | + put_data(buf, in, inlen); | |
269 | + agent_query_synchronous(buf, out, outlen); | |
270 | + strbuf_free(buf); | |
227 | 271 | } |
228 | 272 | |
229 | -// from SSHBN.C (ver 0.65) | |
230 | -Bignum bignum_from_bytes(const unsigned char *data, int nbytes) | |
231 | -{ | |
232 | - Bignum result; | |
233 | - int w, i; | |
234 | - | |
235 | - assert(nbytes >= 0 && nbytes < INT_MAX / 8); | |
236 | - | |
237 | - w = (nbytes + BIGNUM_INT_BYTES - 1) / BIGNUM_INT_BYTES; /* bytes->words */ | |
238 | - | |
239 | - result = newbn(w); | |
240 | - for (i = 1; i <= w; i++) | |
241 | - result[i] = 0; | |
242 | - for (i = nbytes; i--;) { | |
243 | - unsigned char byte = *data++; | |
244 | - result[1 + i / BIGNUM_INT_BYTES] |= | |
245 | - (BignumInt)byte << (8 * i % BIGNUM_INT_BITS); | |
246 | - } | |
247 | - | |
248 | - while (result[0] > 1 && result[result[0]] == 0) | |
249 | - result[0]--; | |
250 | - return result; | |
251 | -} | |
252 | - | |
253 | -// from SSHBN.C (ver 0.60) | |
254 | -/* | |
255 | -* Read an SSH-1-format bignum from a data buffer. Return the number | |
256 | -* of bytes consumed, or -1 if there wasn't enough data. | |
257 | -*/ | |
258 | -int ssh1_read_bignum(const unsigned char *data, int len, Bignum * result) | |
259 | -{ | |
260 | - const unsigned char *p = data; | |
261 | - int i; | |
262 | - int w, b; | |
263 | - | |
264 | - if (len < 2) | |
265 | - return -1; | |
266 | - | |
267 | - w = 0; | |
268 | - for (i = 0; i < 2; i++) | |
269 | - w = (w << 8) + *p++; | |
270 | - b = (w + 7) / 8; /* bits -> bytes */ | |
271 | - | |
272 | - if (len < b + 2) | |
273 | - return -1; | |
274 | - | |
275 | - if (!result) /* just return length */ | |
276 | - return b + 2; | |
277 | - | |
278 | - *result = bignum_from_bytes(p, b); | |
279 | - | |
280 | - return p + b - data; | |
281 | -} | |
282 | - | |
283 | -// from SSHRSA.C (putty 0.60) | |
284 | -/* Given a public blob, determine its length. */ | |
285 | -int rsa_public_blob_len(void *data, int maxlen) | |
286 | -{ | |
287 | - unsigned char *p = (unsigned char *)data; | |
288 | - int n; | |
289 | - | |
290 | - if (maxlen < 4) | |
291 | - return -1; | |
292 | - p += 4; /* length word */ | |
293 | - maxlen -= 4; | |
294 | - | |
295 | - n = ssh1_read_bignum(p, maxlen, NULL); /* exponent */ | |
296 | - if (n < 0) | |
297 | - return -1; | |
298 | - p += n; | |
299 | - | |
300 | - n = ssh1_read_bignum(p, maxlen, NULL); /* modulus */ | |
301 | - if (n < 0) | |
302 | - return -1; | |
303 | - p += n; | |
304 | - | |
305 | - return p - (unsigned char *)data; | |
306 | -} | |
307 | - | |
308 | -// from WINDOWS\WINPGNT.C (putty 0.63) | |
309 | -/* | |
310 | - * Acquire a keylist1 from the primary Pageant; this means either | |
311 | - * calling make_keylist1 (if that's us) or sending a message to the | |
312 | - * primary Pageant (if it's not). | |
313 | - */ | |
314 | -static void *get_keylist1(int *length) | |
315 | -{ | |
316 | - void *ret; | |
317 | - | |
318 | - unsigned char request[5], *response; | |
319 | - void *vresponse; | |
320 | - int resplen; | |
321 | - request[4] = SSH1_AGENTC_REQUEST_RSA_IDENTITIES; | |
322 | - PUT_32BIT(request, 1); | |
323 | - | |
324 | - agent_query(request, 5, &vresponse, &resplen, NULL, NULL); | |
325 | - | |
326 | - response = vresponse; | |
327 | - if (resplen < 5 || response[4] != SSH1_AGENT_RSA_IDENTITIES_ANSWER) { | |
328 | - sfree(response); | |
329 | - return NULL; | |
330 | - } | |
331 | - | |
332 | - ret = snewn(resplen-5, unsigned char); | |
333 | - memcpy(ret, response+5, resplen-5); | |
334 | - sfree(response); | |
335 | - | |
336 | - if (length) | |
337 | - *length = resplen-5; | |
338 | - | |
339 | - return ret; | |
340 | -} | |
341 | - | |
342 | -// from WINDOWS\WINPGNT.C (putty 0.63) | |
343 | -/* | |
344 | - * Acquire a keylist2 from the primary Pageant; this means either | |
345 | - * calling make_keylist2 (if that's us) or sending a message to the | |
346 | - * primary Pageant (if it's not). | |
347 | - */ | |
348 | -static void *get_keylist2(int *length) | |
349 | -{ | |
350 | - void *ret; | |
351 | - | |
352 | - unsigned char request[5], *response; | |
353 | - void *vresponse; | |
354 | - int resplen; | |
355 | - | |
356 | - request[4] = SSH2_AGENTC_REQUEST_IDENTITIES; | |
357 | - PUT_32BIT(request, 1); | |
358 | - | |
359 | - agent_query(request, 5, &vresponse, &resplen, NULL, NULL); | |
360 | - | |
361 | - response = vresponse; | |
362 | - if (resplen < 5 || response[4] != SSH2_AGENT_IDENTITIES_ANSWER) { | |
363 | - sfree(response); | |
364 | - return NULL; | |
365 | - } | |
366 | - | |
367 | - ret = snewn(resplen-5, unsigned char); | |
368 | - memcpy(ret, response+5, resplen-5); | |
369 | - sfree(response); | |
370 | - | |
371 | - if (length) | |
372 | - *length = resplen-5; | |
373 | - | |
374 | - return ret; | |
375 | -} | |
376 | - | |
377 | 273 | BOOL putty_agent_exists() |
378 | 274 | { |
379 | 275 | if (agent_exists()) { |
@@ -382,20 +278,3 @@ | ||
382 | 278 | return FALSE; |
383 | 279 | } |
384 | 280 | |
385 | -// from WINDOWS\WINDOW.C (putty 0.60) | |
386 | -/* | |
387 | - * Print a modal (Really Bad) message box and perform a fatal exit. | |
388 | - */ | |
389 | -void modalfatalbox(char *fmt, ...) | |
390 | -{ | |
391 | - va_list ap; | |
392 | - char *stuff, morestuff[100]; | |
393 | - | |
394 | - va_start(ap, fmt); | |
395 | - stuff = dupvprintf(fmt, ap); | |
396 | - va_end(ap); | |
397 | - sprintf(morestuff, "%.70s Fatal Error", "TTSSH"); | |
398 | - MessageBox(NULL, stuff, morestuff, | |
399 | - MB_SYSTEMMODAL | MB_ICONERROR | MB_OK); | |
400 | - sfree(stuff); | |
401 | -} |
@@ -25,24 +25,8 @@ | ||
25 | 25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
26 | 26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | 27 | */ |
28 | -// PuTTY is copyright 1997-2007 Simon Tatham. | |
28 | +// PuTTY is copyright 1997-2021 Simon Tatham. | |
29 | 29 | |
30 | -// pageant.h | |
31 | -// 本当は pageant.h を include 出来るようにする方がいいのかもしれないけれど | |
32 | -// 関数のプロトタイプ宣言もここにあるので取りあえずここで。 | |
33 | -#define AGENT_MAX_MSGLEN 8192 | |
34 | - | |
35 | -// エラー応答用 | |
36 | -#define SSH_AGENT_FAILURE_MSG "\x00\x00\x00\x01\x05" | |
37 | - | |
38 | -// MISC.C | |
39 | -extern void safefree(void *); | |
40 | - | |
41 | -// WINDOWS\WINPGNTC.C | |
42 | -extern int agent_exists(void); | |
43 | -extern void *agent_query(void *in, int inlen, void **out, int *outlen, | |
44 | - void (*callback)(void *, void *, int), void *callback_ctx); | |
45 | - | |
46 | 30 | int putty_get_ssh2_keylist(unsigned char **keylist); |
47 | 31 | void *putty_sign_ssh2_key(unsigned char *pubkey, |
48 | 32 | unsigned char *data, |
@@ -57,7 +41,16 @@ | ||
57 | 41 | int *outlen); |
58 | 42 | int putty_get_ssh1_keylen(unsigned char *key, int maxlen); |
59 | 43 | const char *putty_get_version(); |
44 | +void putty_agent_query_synchronous(void *in, int inlen, void **out, int *outlen); | |
60 | 45 | BOOL putty_agent_exists(); |
61 | 46 | |
62 | -static void *get_keylist1(int *length); | |
63 | -static void *get_keylist2(int *length); | |
47 | +// エラー応答用 | |
48 | +#define SSH_AGENT_FAILURE_MSG "\x00\x00\x00\x01\x05" | |
49 | + | |
50 | +// pageant.h | |
51 | +#define AGENT_MAX_MSGLEN 262144 | |
52 | + | |
53 | +// puttymen.h | |
54 | +// memory.c | |
55 | +extern void safefree(void *); | |
56 | + |
@@ -0,0 +1,446 @@ | ||
1 | +/* | |
2 | + * Copyright (C) 1994-1998 T. Teranishi | |
3 | + * (C) 2004- TeraTerm Project | |
4 | + * All rights reserved. | |
5 | + * | |
6 | + * Redistribution and use in source and binary forms, with or without | |
7 | + * modification, are permitted provided that the following conditions | |
8 | + * are met: | |
9 | + * | |
10 | + * 1. Redistributions of source code must retain the above copyright | |
11 | + * notice, this list of conditions and the following disclaimer. | |
12 | + * 2. Redistributions in binary form must reproduce the above copyright | |
13 | + * notice, this list of conditions and the following disclaimer in the | |
14 | + * documentation and/or other materials provided with the distribution. | |
15 | + * 3. The name of the author may not be used to endorse or promote products | |
16 | + * derived from this software without specific prior written permission. | |
17 | + * | |
18 | + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR | |
19 | + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |
20 | + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
21 | + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
22 | + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
23 | + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
24 | + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
25 | + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
26 | + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
27 | + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
28 | + */ | |
29 | +// PuTTY is copyright 1997-2021 Simon Tatham. | |
30 | + | |
31 | +/* | |
32 | + * ソース全体をそのままプロジェクトに追加すると、 | |
33 | + * 使わない部分で依存先が増え、さらにその依存先が増えたり競合が起きるので、 | |
34 | + * PuTTY のソースからコピーしてきたコード | |
35 | + */ | |
36 | + | |
37 | +#include <stdio.h> | |
38 | +#include <stdlib.h> | |
39 | +#include <string.h> | |
40 | +#include <assert.h> | |
41 | + | |
42 | +#include "ssh.h" | |
43 | +#include "mpint.h" | |
44 | +#include "putty.h" | |
45 | +#include "network.h" | |
46 | +#include "sshcr.h" | |
47 | +#include "pageant.h" | |
48 | + | |
49 | + | |
50 | +// from pageant.c (PuTTY 0.76) | |
51 | +#define DECL_EXT_ENUM(id, name) id, | |
52 | +enum Extension { KNOWN_EXTENSIONS(DECL_EXT_ENUM) EXT_UNKNOWN }; | |
53 | +#define DEF_EXT_NAMES(id, name) PTRLEN_DECL_LITERAL(name), | |
54 | +static const ptrlen extension_names[] = { KNOWN_EXTENSIONS(DEF_EXT_NAMES) }; | |
55 | + | |
56 | +// from pageant.c (PuTTY 0.76) | |
57 | +typedef struct PageantClientOp { | |
58 | + strbuf *buf; | |
59 | + bool request_made; | |
60 | + BinarySink_DELEGATE_IMPLEMENTATION; | |
61 | + BinarySource_IMPLEMENTATION; | |
62 | +} PageantClientOp; | |
63 | + | |
64 | +// from pageant.c (PuTTY 0.76) | |
65 | +typedef struct KeyListEntry { | |
66 | + ptrlen blob, comment; | |
67 | + uint32_t flags; | |
68 | +} KeyListEntry; | |
69 | + | |
70 | +// from pageant.c (PuTTY 0.76) | |
71 | +typedef struct KeyList { | |
72 | + strbuf *raw_data; | |
73 | + KeyListEntry *keys; | |
74 | + size_t nkeys; | |
75 | + bool broken; | |
76 | +} KeyList; | |
77 | + | |
78 | +// from pageant.c (PuTTY 0.76) | |
79 | +static PageantClientOp *pageant_client_op_new(void) | |
80 | +{ | |
81 | + PageantClientOp *pco = snew(PageantClientOp); | |
82 | + pco->buf = strbuf_new_for_agent_query(); | |
83 | + pco->request_made = false; | |
84 | + BinarySink_DELEGATE_INIT(pco, pco->buf); | |
85 | + BinarySource_INIT(pco, "", 0); | |
86 | + return pco; | |
87 | +} | |
88 | + | |
89 | +// from pageant.c (PuTTY 0.76) | |
90 | +static void pageant_client_op_free(PageantClientOp *pco) | |
91 | +{ | |
92 | + if (pco->buf) | |
93 | + strbuf_free(pco->buf); | |
94 | + sfree(pco); | |
95 | +} | |
96 | + | |
97 | +// from pageant.c (PuTTY 0.76) | |
98 | +static unsigned pageant_client_op_query(PageantClientOp *pco) | |
99 | +{ | |
100 | + /* Since we use the same strbuf for the request and the response, | |
101 | + * check by assertion that we aren't embarrassingly sending a | |
102 | + * previous response back to the agent */ | |
103 | + assert(!pco->request_made); | |
104 | + pco->request_made = true; | |
105 | + | |
106 | + void *response_raw; | |
107 | + int resplen_raw; | |
108 | + agent_query_synchronous(pco->buf, &response_raw, &resplen_raw); | |
109 | + strbuf_clear(pco->buf); | |
110 | + put_data(pco->buf, response_raw, resplen_raw); | |
111 | + sfree(response_raw); | |
112 | + | |
113 | + /* The data coming back from agent_query_synchronous will have | |
114 | + * its length field prepended. So we start by parsing it as an | |
115 | + * SSH-formatted string, and then reinitialise our | |
116 | + * BinarySource with the interior of that string. */ | |
117 | + BinarySource_INIT_PL(pco, ptrlen_from_strbuf(pco->buf)); | |
118 | + BinarySource_INIT_PL(pco, get_string(pco)); | |
119 | + | |
120 | + /* Strip off and directly return the type byte, which every client | |
121 | + * will need, to save a boilerplate get_byte at each call site */ | |
122 | + unsigned reply_type = get_byte(pco); | |
123 | + if (get_err(pco)) | |
124 | + reply_type = 256; /* out-of-range code */ | |
125 | + return reply_type; | |
126 | +} | |
127 | + | |
128 | +// from pageant.c (PuTTY 0.76) | |
129 | +void keylist_free(KeyList *kl) | |
130 | +{ | |
131 | + sfree(kl->keys); | |
132 | + strbuf_free(kl->raw_data); | |
133 | + sfree(kl); | |
134 | +} | |
135 | + | |
136 | +// from pageant.c (PuTTY 0.76) | |
137 | +static PageantClientOp *pageant_request_keylist_1(void) | |
138 | +{ | |
139 | + PageantClientOp *pco = pageant_client_op_new(); | |
140 | + put_byte(pco, SSH1_AGENTC_REQUEST_RSA_IDENTITIES); | |
141 | + if (pageant_client_op_query(pco) == SSH1_AGENT_RSA_IDENTITIES_ANSWER) | |
142 | + return pco; | |
143 | + pageant_client_op_free(pco); | |
144 | + return NULL; | |
145 | +} | |
146 | + | |
147 | +// from pageant.c (PuTTY 0.76) | |
148 | +static PageantClientOp *pageant_request_keylist_2(void) | |
149 | +{ | |
150 | + PageantClientOp *pco = pageant_client_op_new(); | |
151 | + put_byte(pco, SSH2_AGENTC_REQUEST_IDENTITIES); | |
152 | + if (pageant_client_op_query(pco) == SSH2_AGENT_IDENTITIES_ANSWER) | |
153 | + return pco; | |
154 | + pageant_client_op_free(pco); | |
155 | + return NULL; | |
156 | +} | |
157 | + | |
158 | +// from pageant.c (PuTTY 0.76) | |
159 | +static PageantClientOp *pageant_request_keylist_extended(void) | |
160 | +{ | |
161 | + PageantClientOp *pco = pageant_client_op_new(); | |
162 | + put_byte(pco, SSH2_AGENTC_EXTENSION); | |
163 | + put_stringpl(pco, extension_names[EXT_LIST_EXTENDED]); | |
164 | + if (pageant_client_op_query(pco) == SSH_AGENT_SUCCESS) | |
165 | + return pco; | |
166 | + pageant_client_op_free(pco); | |
167 | + return NULL; | |
168 | +} | |
169 | + | |
170 | +// from pageant.c (PuTTY 0.76) | |
171 | +KeyList *pageant_get_keylist(unsigned ssh_version) | |
172 | +{ | |
173 | + PageantClientOp *pco; | |
174 | + bool list_is_extended = false; | |
175 | + | |
176 | + if (ssh_version == 1) { | |
177 | + pco = pageant_request_keylist_1(); | |
178 | + } else { | |
179 | + if ((pco = pageant_request_keylist_extended()) != NULL) | |
180 | + list_is_extended = true; | |
181 | + else | |
182 | + pco = pageant_request_keylist_2(); | |
183 | + } | |
184 | + | |
185 | + if (!pco) | |
186 | + return NULL; | |
187 | + | |
188 | + KeyList *kl = snew(KeyList); | |
189 | + kl->nkeys = get_uint32(pco); | |
190 | + kl->keys = snewn(kl->nkeys, struct KeyListEntry); | |
191 | + kl->broken = false; | |
192 | + | |
193 | + for (size_t i = 0; i < kl->nkeys && !get_err(pco); i++) { | |
194 | + if (ssh_version == 1) { | |
195 | + int bloblen = rsa_ssh1_public_blob_len( | |
196 | + make_ptrlen(get_ptr(pco), get_avail(pco))); | |
197 | + if (bloblen < 0) { | |
198 | + kl->broken = true; | |
199 | + bloblen = 0; | |
200 | + } | |
201 | + kl->keys[i].blob = get_data(pco, bloblen); | |
202 | + } else { | |
203 | + kl->keys[i].blob = get_string(pco); | |
204 | + } | |
205 | + kl->keys[i].comment = get_string(pco); | |
206 | + | |
207 | + if (list_is_extended) { | |
208 | + ptrlen key_ext_info = get_string(pco); | |
209 | + BinarySource src[1]; | |
210 | + BinarySource_BARE_INIT_PL(src, key_ext_info); | |
211 | + | |
212 | + kl->keys[i].flags = get_uint32(src); | |
213 | + } else { | |
214 | + kl->keys[i].flags = 0; | |
215 | + } | |
216 | + } | |
217 | + | |
218 | + if (get_err(pco)) | |
219 | + kl->broken = true; | |
220 | + kl->raw_data = pco->buf; | |
221 | + pco->buf = NULL; | |
222 | + pageant_client_op_free(pco); | |
223 | + return kl; | |
224 | +} | |
225 | + | |
226 | +// from sshrsa.c (PuTTY 0.76) | |
227 | +/* Given an SSH-1 public key blob, determine its length. */ | |
228 | +int rsa_ssh1_public_blob_len(ptrlen data) | |
229 | +{ | |
230 | + BinarySource src[1]; | |
231 | + | |
232 | + BinarySource_BARE_INIT_PL(src, data); | |
233 | + | |
234 | + /* Expect a length word, then exponent and modulus. (It doesn't | |
235 | + * even matter which order.) */ | |
236 | + get_uint32(src); | |
237 | + mp_free(get_mp_ssh1(src)); | |
238 | + mp_free(get_mp_ssh1(src)); | |
239 | + | |
240 | + if (get_err(src)) | |
241 | + return -1; | |
242 | + | |
243 | + /* Return the number of bytes consumed. */ | |
244 | + return src->pos; | |
245 | +} | |
246 | + | |
247 | +// from windows/winmiscs.c (PuTTY 0.76) | |
248 | +/* | |
249 | + * Windows implementation of smemclr (see misc.c) using SecureZeroMemory. | |
250 | + */ | |
251 | +void smemclr(void *b, size_t n) { | |
252 | + if (b && n > 0) | |
253 | + SecureZeroMemory(b, n); | |
254 | +} | |
255 | + | |
256 | +// from be_misc.c (PuTTY 0.76) | |
257 | +void log_proxy_stderr(Plug *plug, ProxyStderrBuf *psb, | |
258 | + const void *vdata, size_t len) | |
259 | +{ | |
260 | + const char *data = (const char *)vdata; | |
261 | + | |
262 | + /* | |
263 | + * This helper function allows us to collect the data written to a | |
264 | + * local proxy command's standard error in whatever size chunks we | |
265 | + * happen to get from its pipe, and whenever we have a complete | |
266 | + * line, we pass it to plug_log. | |
267 | + * | |
268 | + * (We also do this when the buffer in psb fills up, to avoid just | |
269 | + * allocating more and more memory forever, and also to keep Event | |
270 | + * Log lines reasonably bounded in size.) | |
271 | + * | |
272 | + * Prerequisites: a plug to log to, and a ProxyStderrBuf stored | |
273 | + * somewhere to collect any not-yet-output partial line. | |
274 | + */ | |
275 | + | |
276 | + while (len > 0) { | |
277 | + /* | |
278 | + * Copy as much data into psb->buf as will fit. | |
279 | + */ | |
280 | + assert(psb->size < lenof(psb->buf)); | |
281 | + size_t to_consume = lenof(psb->buf) - psb->size; | |
282 | + if (to_consume > len) | |
283 | + to_consume = len; | |
284 | + memcpy(psb->buf + psb->size, data, to_consume); | |
285 | + data += to_consume; | |
286 | + len -= to_consume; | |
287 | + psb->size += to_consume; | |
288 | + | |
289 | + /* | |
290 | + * Output any full lines in psb->buf. | |
291 | + */ | |
292 | + size_t pos = 0; | |
293 | + while (pos < psb->size) { | |
294 | + char *nlpos = memchr(psb->buf + pos, '\n', psb->size - pos); | |
295 | + if (!nlpos) | |
296 | + break; | |
297 | + | |
298 | + /* | |
299 | + * Found a newline in the buffer, so we can output a line. | |
300 | + */ | |
301 | + size_t endpos = nlpos - psb->buf; | |
302 | + while (endpos > pos && (psb->buf[endpos-1] == '\n' || | |
303 | + psb->buf[endpos-1] == '\r')) | |
304 | + endpos--; | |
305 | + char *msg = dupprintf( | |
306 | + "proxy: %.*s", (int)(endpos - pos), psb->buf + pos); | |
307 | + plug_log(plug, PLUGLOG_PROXY_MSG, NULL, 0, msg, 0); | |
308 | + sfree(msg); | |
309 | + | |
310 | + pos = nlpos - psb->buf + 1; | |
311 | + assert(pos <= psb->size); | |
312 | + } | |
313 | + | |
314 | + /* | |
315 | + * If the buffer is completely full and we didn't output | |
316 | + * anything, then output the whole thing, flagging it as a | |
317 | + * truncated line. | |
318 | + */ | |
319 | + if (pos == 0 && psb->size == lenof(psb->buf)) { | |
320 | + char *msg = dupprintf( | |
321 | + "proxy (partial line): %.*s", (int)psb->size, psb->buf); | |
322 | + plug_log(plug, PLUGLOG_PROXY_MSG, NULL, 0, msg, 0); | |
323 | + sfree(msg); | |
324 | + | |
325 | + pos = psb->size = 0; | |
326 | + } | |
327 | + | |
328 | + /* | |
329 | + * Now move any remaining data up to the front of the buffer. | |
330 | + */ | |
331 | + size_t newsize = psb->size - pos; | |
332 | + if (newsize) | |
333 | + memmove(psb->buf, psb->buf + pos, newsize); | |
334 | + psb->size = newsize; | |
335 | + | |
336 | + /* | |
337 | + * And loop round again if there's more data to be read from | |
338 | + * our input. | |
339 | + */ | |
340 | + } | |
341 | +} | |
342 | + | |
343 | +// from be_misc.c (PuTTY 0.76) | |
344 | +void psb_init(ProxyStderrBuf *psb) | |
345 | +{ | |
346 | + psb->size = 0; | |
347 | +} | |
348 | + | |
349 | +// from windows/winpgnt.c (PuTTY 0.76) | |
350 | +void noise_ultralight(NoiseSourceId id, unsigned long data) | |
351 | +{ | |
352 | + /* Pageant doesn't use random numbers, so we ignore this */ | |
353 | +} | |
354 | + | |
355 | +// from windows/window.c (PuTTY 0.76) | |
356 | +/* | |
357 | + * Print a modal (Really Bad) message box and perform a fatal exit. | |
358 | + */ | |
359 | +void modalfatalbox(const char *fmt, ...) | |
360 | +{ | |
361 | + va_list ap; | |
362 | + char *message, *title; | |
363 | + | |
364 | + va_start(ap, fmt); | |
365 | + message = dupvprintf(fmt, ap); | |
366 | + va_end(ap); | |
367 | + title = dupprintf("%s Fatal Error", "TTSSH"); | |
368 | + MessageBox(NULL, message, title, | |
369 | + MB_SYSTEMMODAL | MB_ICONERROR | MB_OK); | |
370 | + sfree(message); | |
371 | + sfree(title); | |
372 | +} | |
373 | + | |
374 | +// from misc.c (PuTTY 0.76) | |
375 | +void out_of_memory(void) | |
376 | +{ | |
377 | + modalfatalbox("Out of memory"); | |
378 | +} | |
379 | + | |
380 | + | |
381 | +/* | |
382 | +putty_get_ssh1_keylen()@libputty.c | |
383 | + rsa_ssh1_public_blob_len()@sshrsa.c ... import | |
384 | + | |
385 | +memory.c / mpint.c / utils.c | |
386 | + smemclr()@windows/winmiscs.c ... import | |
387 | + | |
388 | +safemalloc()@memory.c | |
389 | + out_of_memory()@misc.c ... import | |
390 | + modalfatalbox()@windows/window.c ... import | |
391 | + | |
392 | +wm_copydata_agent_query()@windows\winpgnt.c | |
393 | + got_advapi()@windows\winsecur.c ... include winsecur.c | |
394 | + | |
395 | +agent_named_pipe_name()@windows\winpgnt.c | |
396 | + get_username()@windows\winmisc.c ... include winmisc.c | |
397 | + | |
398 | +agent_connect()@windows\winpgnt.c | |
399 | + new_named_pipe_client()@winnpc.c ... include winnpc.c | |
400 | + connect_to_named_pipe()@winnpc.c | |
401 | + new_error_socket_consume_string()@errsock.c ... include errsock.c | |
402 | + make_handle_socket()@winsocket.c ... include winsocket.c | |
403 | + handle_input_new()@winhandl.c ... include winhandl.c | |
404 | + handle_output_new()@winhandl.c | |
405 | + psb_init()@be_misc.c ... import | |
406 | + handle_stderr()@winhsock.c | |
407 | + log_proxy_stderr()@be_misc.c ... import | |
408 | + | |
409 | +agent_named_pipe_name()@windows\winpgnt.c | |
410 | + capi_obfuscate_string()@windows\wincapi.c ... include wincapi.c | |
411 | + ssh_sha256@sshsh256.c ... include sshsh256.c | |
412 | + | |
413 | +handle_got_event()@windows\winhandl.c | |
414 | + noise_ultralight()@windows/winpgnt.c | |
415 | + | |
416 | +sk_handle_set_frozen()@windows\winhsock.c | |
417 | + queue_toplevel_callback()@callback.c ... include callback.c | |
418 | +sk_handle_close()@windows\winhsock.c | |
419 | + delete_callbacks_for_context()@callback.c | |
420 | + | |
421 | +winmisc.c refers to tree234 ... include tree234.c | |
422 | + | |
423 | + | |
424 | + | |
425 | +if include be_misc.c ... | |
426 | +backend_socket_log()@be_misc.c | |
427 | + sk_getaddr()@windows\winnet.c | |
428 | + sk_addr_needs_port()@windows\winnet.c | |
429 | + conf_get_int()@conf.c | |
430 | + logevent()@logging.c | |
431 | + | |
432 | +if include sshrsa.c ... | |
433 | +rsa_components()@sshrsa.c | |
434 | + key_components_new()@sshpubk.c | |
435 | + key_components_add_text()@sshpubk.c | |
436 | + key_components_add_mp()@sshpubk.c | |
437 | +ssh_rsakex_encrypt()@sshrsa.c | |
438 | + hash_simple()@sshauxcrypt.c | |
439 | +ssh_rsakex_decrypt()@sshrsa.c | |
440 | + hash_simple()@sshauxcrypt.c | |
441 | +rsa_ssh1_encrypt()@sshrsa.c | |
442 | + random_read()@sshrand.c | |
443 | + | |
444 | +if include sshauxcropt.c ... | |
445 | +mac_simple()@sshauxcropt.c coflicts mac_simple()@keyfiles-putty.c | |
446 | +*/ |
@@ -9503,9 +9503,9 @@ | ||
9503 | 9503 | data = agent_msg->buf; |
9504 | 9504 | } |
9505 | 9505 | |
9506 | - agent_query(data, *agent_request_len, &response, &resplen, NULL, NULL); | |
9506 | + putty_agent_query_synchronous(data, *agent_request_len, &response, &resplen); | |
9507 | 9507 | if (response == NULL || resplen < 5) { |
9508 | - logprintf(LOG_LEVEL_NOTICE, "%s Agent Forwarding Error: agent_query is failed.", __FUNCTION__); | |
9508 | + logprintf(LOG_LEVEL_NOTICE, "%s Agent Forwarding Error: putty_agent_query_synchronous is failed.", __FUNCTION__); | |
9509 | 9509 | goto error; |
9510 | 9510 | } |
9511 | 9511 |