]>
Commit | Line | Data |
---|---|---|
91885a4d | 1 | /* |
2 | * Copyright 2002 Niels Provos <provos@citi.umich.edu> | |
3 | * All rights reserved. | |
4 | * | |
5 | * Redistribution and use in source and binary forms, with or without | |
6 | * modification, are permitted provided that the following conditions | |
7 | * are met: | |
8 | * 1. Redistributions of source code must retain the above copyright | |
9 | * notice, this list of conditions and the following disclaimer. | |
10 | * 2. Redistributions in binary form must reproduce the above copyright | |
11 | * notice, this list of conditions and the following disclaimer in the | |
12 | * documentation and/or other materials provided with the distribution. | |
13 | * | |
14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |
15 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |
16 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
17 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
18 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
19 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
20 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
21 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
23 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
24 | */ | |
25 | ||
26 | #include "includes.h" | |
27 | RCSID("$OpenBSD$"); | |
28 | ||
29 | #include <openssl/bn.h> | |
30 | #include <openssl/dh.h> | |
31 | ||
32 | #include "ssh.h" | |
33 | #include "dh.h" | |
34 | #include "kex.h" | |
35 | #include "buffer.h" | |
36 | #include "bufaux.h" | |
37 | #include "packet.h" | |
38 | #include "mac.h" | |
39 | #include "log.h" | |
40 | #include "zlib.h" | |
41 | #include "monitor.h" | |
42 | #include "monitor_wrap.h" | |
43 | #include "xmalloc.h" | |
44 | #include "atomicio.h" | |
45 | #include "monitor_fdpass.h" | |
46 | #include "getput.h" | |
47 | ||
48 | /* Imports */ | |
49 | extern Newkeys *newkeys[]; | |
50 | extern z_stream incoming_stream; | |
51 | extern z_stream outgoing_stream; | |
52 | ||
53 | void | |
54 | mm_request_send(int socket, enum monitor_reqtype type, Buffer *m) | |
55 | { | |
56 | u_char buf[5]; | |
57 | u_int mlen = buffer_len(m); | |
58 | ||
59 | debug3("%s entering: type %d", __FUNCTION__, type); | |
60 | ||
61 | PUT_32BIT(buf, mlen + 1); | |
62 | buf[4] = (u_char) type; /* 1st byte of payload is mesg-type */ | |
63 | if (atomicio(write, socket, buf, sizeof(buf)) != sizeof(buf)) | |
64 | fatal("%s: write", __FUNCTION__); | |
65 | if (atomicio(write, socket, buffer_ptr(m), mlen) != mlen) | |
66 | fatal("%s: write", __FUNCTION__); | |
67 | } | |
68 | ||
69 | void | |
70 | mm_request_receive(int socket, Buffer *m) | |
71 | { | |
72 | u_char buf[4]; | |
73 | ssize_t res; | |
74 | u_int msg_len; | |
75 | ||
76 | debug3("%s entering", __FUNCTION__); | |
77 | ||
78 | res = atomicio(read, socket, buf, sizeof(buf)); | |
79 | if (res != sizeof(buf)) | |
80 | fatal("%s: read: %d", __FUNCTION__, res); | |
81 | msg_len = GET_32BIT(buf); | |
82 | if (msg_len > 256 * 1024) | |
83 | fatal("%s: read: bad msg_len %d", __FUNCTION__, msg_len); | |
84 | buffer_clear(m); | |
85 | buffer_append_space(m, msg_len); | |
86 | res = atomicio(read, socket, buffer_ptr(m), msg_len); | |
87 | if (res != msg_len) | |
88 | fatal("%s: read: %d != msg_len", __FUNCTION__, res); | |
89 | } | |
90 | ||
91 | void | |
92 | mm_request_receive_expect(int socket, enum monitor_reqtype type, Buffer *m) | |
93 | { | |
94 | u_char rtype; | |
95 | ||
96 | debug3("%s entering: type %d", __FUNCTION__, type); | |
97 | ||
98 | mm_request_receive(socket, m); | |
99 | rtype = buffer_get_char(m); | |
100 | if (rtype != type) | |
101 | fatal("%s: read: rtype %d != type %d", __FUNCTION__, | |
102 | rtype, type); | |
103 | } | |
104 | ||
105 | DH * | |
106 | mm_choose_dh(int socket, int min, int nbits, int max) | |
107 | { | |
108 | BIGNUM *p, *g; | |
109 | int success = 0; | |
110 | Buffer m; | |
111 | ||
112 | buffer_init(&m); | |
113 | buffer_put_int(&m, min); | |
114 | buffer_put_int(&m, nbits); | |
115 | buffer_put_int(&m, max); | |
116 | ||
117 | mm_request_send(socket, MONITOR_REQ_MODULI, &m); | |
118 | ||
119 | debug3("%s: waiting for MONITOR_ANS_MODULI", __FUNCTION__); | |
120 | mm_request_receive_expect(socket, MONITOR_ANS_MODULI, &m); | |
121 | ||
122 | success = buffer_get_char(&m); | |
123 | if (success == 0) | |
124 | fatal("%s: MONITOR_ANS_MODULI failed", __FUNCTION__); | |
125 | ||
126 | if ((p = BN_new()) == NULL) | |
127 | fatal("%s: BN_new failed", __FUNCTION__); | |
128 | if ((g = BN_new()) == NULL) | |
129 | fatal("%s: BN_new failed", __FUNCTION__); | |
130 | buffer_get_bignum2(&m, p); | |
131 | buffer_get_bignum2(&m, g); | |
132 | ||
133 | debug3("%s: remaining %d", __FUNCTION__, buffer_len(&m)); | |
134 | buffer_free(&m); | |
135 | ||
136 | return (dh_new_group(g, p)); | |
137 | } | |
138 | ||
139 | int | |
140 | mm_key_sign(int socket, int keyind, u_char **sigp, u_int *lenp, | |
141 | u_char *data, u_int datalen) | |
142 | { | |
143 | Buffer m; | |
144 | ||
145 | debug3("%s entering", __FUNCTION__); | |
146 | ||
147 | buffer_init(&m); | |
148 | buffer_put_int(&m, keyind); | |
149 | buffer_put_string(&m, data, datalen); | |
150 | ||
151 | mm_request_send(socket, MONITOR_REQ_SIGN, &m); | |
152 | ||
153 | debug3("%s: waiting for MONITOR_ANS_SIGN", __FUNCTION__); | |
154 | mm_request_receive_expect(socket, MONITOR_ANS_SIGN, &m); | |
155 | *sigp = buffer_get_string(&m, lenp); | |
156 | buffer_free(&m); | |
157 | ||
158 | return (0); | |
159 | } | |
160 | ||
161 | struct passwd * | |
162 | mm_getpwnamallow(int socket, const char *login, int *allowed) | |
163 | { | |
164 | Buffer m; | |
165 | struct passwd *pw; | |
166 | u_int pwlen; | |
167 | ||
168 | debug3("%s entering", __FUNCTION__); | |
169 | ||
170 | buffer_init(&m); | |
171 | buffer_put_cstring(&m, login); | |
172 | ||
173 | mm_request_send(socket, MONITOR_REQ_PWNAM, &m); | |
174 | ||
175 | debug3("%s: waiting for MONITOR_ANS_PWNAM", __FUNCTION__); | |
176 | mm_request_receive_expect(socket, MONITOR_ANS_PWNAM, &m); | |
177 | ||
178 | *allowed = buffer_get_char(&m); | |
179 | if (*allowed == 0) { | |
180 | buffer_free(&m); | |
181 | return (NULL); | |
182 | } | |
183 | pw = buffer_get_string(&m, &pwlen); | |
184 | if (pwlen != sizeof(struct passwd)) | |
185 | fatal("%s: struct passwd size mismatch", __FUNCTION__); | |
186 | pw->pw_name = buffer_get_string(&m, NULL); | |
187 | pw->pw_passwd = buffer_get_string(&m, NULL); | |
188 | pw->pw_gecos = buffer_get_string(&m, NULL); | |
189 | pw->pw_class = buffer_get_string(&m, NULL); | |
190 | pw->pw_dir = buffer_get_string(&m, NULL); | |
191 | pw->pw_shell = buffer_get_string(&m, NULL); | |
192 | buffer_free(&m); | |
193 | ||
194 | return (pw); | |
195 | } | |
196 | ||
197 | void | |
198 | pwfree(struct passwd *pw) | |
199 | { | |
200 | xfree(pw->pw_name); | |
201 | xfree(pw->pw_passwd); | |
202 | xfree(pw->pw_gecos); | |
203 | xfree(pw->pw_class); | |
204 | xfree(pw->pw_dir); | |
205 | xfree(pw->pw_shell); | |
206 | xfree(pw); | |
207 | } | |
208 | ||
209 | /* Inform the privileged process about service and style */ | |
210 | ||
211 | void | |
212 | mm_inform_authserv(int socket, char *service, char *style) | |
213 | { | |
214 | Buffer m; | |
215 | ||
216 | debug3("%s entering", __FUNCTION__); | |
217 | ||
218 | buffer_init(&m); | |
219 | buffer_put_cstring(&m, service); | |
220 | buffer_put_cstring(&m, style ? style : ""); | |
221 | ||
222 | mm_request_send(socket, MONITOR_REQ_AUTHSERV, &m); | |
223 | ||
224 | buffer_free(&m); | |
225 | } | |
226 | ||
227 | /* Do the password authentication */ | |
228 | int | |
229 | mm_auth_password(int socket, char *password) | |
230 | { | |
231 | Buffer m; | |
232 | int authenticated = 0; | |
233 | ||
234 | debug3("%s entering", __FUNCTION__); | |
235 | ||
236 | buffer_init(&m); | |
237 | buffer_put_cstring(&m, password); | |
238 | mm_request_send(socket, MONITOR_REQ_AUTHPASSWORD, &m); | |
239 | ||
240 | debug3("%s: waiting for MONITOR_ANS_AUTHPASSWORD", __FUNCTION__); | |
241 | mm_request_receive_expect(socket, MONITOR_ANS_AUTHPASSWORD, &m); | |
242 | ||
243 | authenticated = buffer_get_int(&m); | |
244 | ||
245 | buffer_free(&m); | |
246 | ||
247 | debug3("%s: user %sauthenticated", | |
248 | __FUNCTION__, authenticated ? "" : "not "); | |
249 | return (authenticated); | |
250 | } | |
251 | ||
252 | int | |
253 | mm_key_allowed(int socket, enum mm_keytype type, char *user, char *host, | |
254 | Key *key) | |
255 | { | |
256 | Buffer m; | |
257 | u_char *blob; | |
258 | u_int len; | |
259 | int allowed = 0; | |
260 | ||
261 | debug3("%s entering", __FUNCTION__); | |
262 | ||
263 | /* Convert the key to a blob and the pass it over */ | |
264 | if (!key_to_blob(key, &blob, &len)) | |
265 | return (0); | |
266 | ||
267 | buffer_init(&m); | |
268 | buffer_put_int(&m, type); | |
269 | buffer_put_cstring(&m, user ? user : ""); | |
270 | buffer_put_cstring(&m, host ? host : ""); | |
271 | buffer_put_string(&m, blob, len); | |
272 | xfree(blob); | |
273 | ||
274 | mm_request_send(socket, MONITOR_REQ_KEYALLOWED, &m); | |
275 | ||
276 | debug3("%s: waiting for MONITOR_ANS_KEYALLOWED", __FUNCTION__); | |
277 | mm_request_receive_expect(socket, MONITOR_ANS_KEYALLOWED, &m); | |
278 | ||
279 | allowed = buffer_get_int(&m); | |
280 | ||
281 | buffer_free(&m); | |
282 | ||
283 | return (allowed); | |
284 | } | |
285 | ||
286 | /* | |
287 | * This key verify needs to send the key type along, because the | |
288 | * privileged parent makes the decision if the key is allowed | |
289 | * for authentication. | |
290 | */ | |
291 | ||
292 | int | |
293 | mm_key_verify(int socket, enum mm_keytype type, char *user, char *host, | |
294 | Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen) | |
295 | { | |
296 | Buffer m; | |
297 | u_char *blob; | |
298 | u_int len; | |
299 | int verified = 0; | |
300 | ||
301 | debug3("%s entering", __FUNCTION__); | |
302 | ||
303 | /* Convert the key to a blob and the pass it over */ | |
304 | if (!key_to_blob(key, &blob, &len)) | |
305 | return (0); | |
306 | ||
307 | buffer_init(&m); | |
308 | buffer_put_int(&m, type); | |
309 | buffer_put_cstring(&m, user ? user : ""); | |
310 | buffer_put_cstring(&m, host ? host : ""); | |
311 | buffer_put_string(&m, blob, len); | |
312 | buffer_put_string(&m, sig, siglen); | |
313 | buffer_put_string(&m, data, datalen); | |
314 | xfree(blob); | |
315 | ||
316 | mm_request_send(socket, MONITOR_REQ_KEYVERIFY, &m); | |
317 | ||
318 | debug3("%s: waiting for MONITOR_ANS_KEYVERIFY", __FUNCTION__); | |
319 | mm_request_receive_expect(socket, MONITOR_ANS_KEYVERIFY, &m); | |
320 | ||
321 | verified = buffer_get_int(&m); | |
322 | ||
323 | buffer_free(&m); | |
324 | ||
325 | return (verified); | |
326 | } | |
327 | ||
328 | /* Export key state after authentication */ | |
329 | Newkeys * | |
330 | mm_newkeys_from_blob(u_char *blob, int blen) | |
331 | { | |
332 | Buffer b; | |
333 | int rlen; | |
334 | Newkeys *newkey = NULL; | |
335 | Enc *enc; | |
336 | Mac *mac; | |
337 | Comp *comp; | |
338 | ||
339 | debug3("%s: %p(%d)", __FUNCTION__, blob, blen); | |
340 | #ifdef DEBUG_PK | |
341 | dump_base64(stderr, blob, blen); | |
342 | #endif | |
343 | buffer_init(&b); | |
344 | buffer_append(&b, blob, blen); | |
345 | ||
346 | newkey = xmalloc(sizeof(*newkey)); | |
347 | enc = &newkey->enc; | |
348 | mac = &newkey->mac; | |
349 | comp = &newkey->comp; | |
350 | ||
351 | /* Enc structure */ | |
352 | enc->name = buffer_get_string(&b, NULL); | |
353 | buffer_get(&b, &enc->cipher, sizeof(enc->cipher)); | |
354 | enc->enabled = buffer_get_int(&b); | |
355 | enc->key_len = buffer_get_int(&b); | |
356 | enc->block_size = buffer_get_int(&b); | |
357 | enc->key = xmalloc(enc->key_len); | |
358 | buffer_get(&b, enc->key, enc->key_len); | |
359 | enc->iv = xmalloc(enc->block_size); | |
360 | buffer_get(&b, enc->iv, enc->block_size); | |
361 | ||
362 | if (enc->name == NULL || cipher_by_name(enc->name) != enc->cipher) | |
363 | fatal("%s: bad cipher name %s or pointer %p", __FUNCTION__, | |
364 | enc->name, enc->cipher); | |
365 | ||
366 | /* Mac structure */ | |
367 | mac->name = buffer_get_string(&b, NULL); | |
368 | if (mac->name == NULL || mac_init(mac, mac->name) == -1) | |
369 | fatal("%s: can not init mac %s", __FUNCTION__, mac->name); | |
370 | mac->enabled = buffer_get_int(&b); | |
371 | mac->key = xmalloc(mac->key_len); | |
372 | buffer_get(&b, mac->key, mac->key_len); | |
373 | ||
374 | /* Comp structure */ | |
375 | comp->type = buffer_get_int(&b); | |
376 | comp->enabled = buffer_get_int(&b); | |
377 | comp->name = buffer_get_string(&b, NULL); | |
378 | ||
379 | rlen = buffer_len(&b); | |
380 | if (rlen != 0) | |
381 | error("newkeys_from_blob: remaining bytes in blob %d", rlen); | |
382 | buffer_free(&b); | |
383 | return (newkey); | |
384 | } | |
385 | ||
386 | int | |
387 | mm_newkeys_to_blob(int mode, u_char **blobp, u_int *lenp) | |
388 | { | |
389 | Buffer b; | |
390 | int len; | |
391 | u_char *buf; | |
392 | Enc *enc; | |
393 | Mac *mac; | |
394 | Comp *comp; | |
395 | Newkeys *newkey = newkeys[mode]; | |
396 | ||
397 | debug3("%s: converting %p", __FUNCTION__, newkey); | |
398 | ||
399 | if (newkey == NULL) { | |
400 | error("%s: newkey == NULL", __FUNCTION__); | |
401 | return 0; | |
402 | } | |
403 | enc = &newkey->enc; | |
404 | mac = &newkey->mac; | |
405 | comp = &newkey->comp; | |
406 | ||
407 | buffer_init(&b); | |
408 | /* Enc structure */ | |
409 | buffer_put_cstring(&b, enc->name); | |
410 | /* The cipher struct is constant and shared, you export pointer */ | |
411 | buffer_append(&b, &enc->cipher, sizeof(enc->cipher)); | |
412 | buffer_put_int(&b, enc->enabled); | |
413 | buffer_put_int(&b, enc->key_len); | |
414 | buffer_put_int(&b, enc->block_size); | |
415 | buffer_append(&b, enc->key, enc->key_len); | |
416 | packet_get_keyiv(mode, enc->iv, enc->block_size); | |
417 | buffer_append(&b, enc->iv, enc->block_size); | |
418 | ||
419 | /* Mac structure */ | |
420 | buffer_put_cstring(&b, mac->name); | |
421 | buffer_put_int(&b, mac->enabled); | |
422 | buffer_append(&b, mac->key, mac->key_len); | |
423 | ||
424 | /* Comp structure */ | |
425 | buffer_put_int(&b, comp->type); | |
426 | buffer_put_int(&b, comp->enabled); | |
427 | buffer_put_cstring(&b, comp->name); | |
428 | ||
429 | len = buffer_len(&b); | |
430 | buf = xmalloc(len); | |
431 | memcpy(buf, buffer_ptr(&b), len); | |
432 | memset(buffer_ptr(&b), 0, len); | |
433 | buffer_free(&b); | |
434 | if (lenp != NULL) | |
435 | *lenp = len; | |
436 | if (blobp != NULL) | |
437 | *blobp = buf; | |
438 | return len; | |
439 | } | |
440 | ||
441 | void | |
442 | mm_send_keystate(int socket) | |
443 | { | |
444 | Buffer m; | |
445 | u_char *blob, *p; | |
446 | u_int bloblen, plen; | |
447 | ||
448 | debug3("%s: Sending new keys: %p %p", | |
449 | __FUNCTION__, newkeys[MODE_OUT], newkeys[MODE_IN]); | |
450 | ||
451 | buffer_init(&m); | |
452 | ||
453 | /* Keys from Kex */ | |
454 | if (!mm_newkeys_to_blob(MODE_OUT, &blob, &bloblen)) | |
455 | fatal("%s: conversion of newkeys failed", __FUNCTION__); | |
456 | ||
457 | buffer_put_string(&m, blob, bloblen); | |
458 | xfree(blob); | |
459 | ||
460 | if (!mm_newkeys_to_blob(MODE_IN, &blob, &bloblen)) | |
461 | fatal("%s: conversion of newkeys failed", __FUNCTION__); | |
462 | ||
463 | buffer_put_string(&m, blob, bloblen); | |
464 | xfree(blob); | |
465 | ||
466 | buffer_put_int(&m, packet_get_seqnr(MODE_OUT)); | |
467 | buffer_put_int(&m, packet_get_seqnr(MODE_IN)); | |
468 | ||
469 | debug3("%s: New keys have been sent", __FUNCTION__); | |
470 | ||
471 | /* More key context */ | |
472 | plen = packet_get_keycontext(MODE_OUT, NULL); | |
473 | p = xmalloc(plen+1); | |
474 | packet_get_keycontext(MODE_OUT, p); | |
475 | buffer_put_string(&m, p, plen); | |
476 | xfree(p); | |
477 | ||
478 | plen = packet_get_keycontext(MODE_IN, NULL); | |
479 | p = xmalloc(plen+1); | |
480 | packet_get_keycontext(MODE_IN, p); | |
481 | buffer_put_string(&m, p, plen); | |
482 | xfree(p); | |
483 | ||
484 | /* Compression state */ | |
485 | debug3("%s: Sending compression state", __FUNCTION__); | |
486 | buffer_put_string(&m, &outgoing_stream, sizeof(outgoing_stream)); | |
487 | buffer_put_string(&m, &incoming_stream, sizeof(incoming_stream)); | |
488 | ||
489 | mm_request_send(socket, MONITOR_REQ_KEYEXPORT, &m); | |
490 | debug3("%s: Finished sending state", __FUNCTION__); | |
491 | ||
492 | buffer_free(&m); | |
493 | } | |
494 | ||
495 | int | |
496 | mm_pty_allocown(int socket, int *ptyfd, int *ttyfd, | |
497 | char *namebuf, int namebuflen) | |
498 | { | |
499 | Buffer m; | |
500 | u_char *p; | |
501 | int success = 0; | |
502 | ||
503 | buffer_init(&m); | |
504 | mm_request_send(socket, MONITOR_REQ_PTY, &m); | |
505 | ||
506 | debug3("%s: waiting for MONITOR_ANS_PTY", __FUNCTION__); | |
507 | mm_request_receive_expect(socket, MONITOR_ANS_PTY, &m); | |
508 | ||
509 | success = buffer_get_int(&m); | |
510 | if (success == 0) { | |
511 | debug3("%s: pty alloc failed", __FUNCTION__); | |
512 | buffer_free(&m); | |
513 | return (0); | |
514 | } | |
515 | p = buffer_get_string(&m, NULL); | |
516 | buffer_free(&m); | |
517 | ||
518 | strlcpy(namebuf, p, namebuflen); /* Possible truncation */ | |
519 | xfree(p); | |
520 | ||
521 | *ptyfd = mm_receive_fd(socket); | |
522 | *ttyfd = mm_receive_fd(socket); | |
523 | ||
524 | /* Success */ | |
525 | return (1); | |
526 | } | |
527 | ||
528 | /* Request process termination */ | |
529 | ||
530 | void | |
531 | mm_terminate(int socket) | |
532 | { | |
533 | Buffer m; | |
534 | ||
535 | buffer_init(&m); | |
536 | mm_request_send(socket, MONITOR_REQ_TERM, &m); | |
537 | buffer_free(&m); | |
538 | } |