diff options
author | Damien Miller <djm@mindrot.org> | 2008-05-19 15:05:07 +1000 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2008-05-19 15:05:07 +1000 |
commit | b84886ba3e362f54b70aefcbe1aa10606309b7d7 (patch) | |
tree | 9346734369c4e527eca83c87a89c05df0ffe4a18 /channels.c | |
parent | db255cad0531047a3e35a95af74ad2e03b054412 (diff) |
- djm@cvs.openbsd.org 2008/05/08 12:02:23
[auth-options.c auth1.c channels.c channels.h clientloop.c gss-serv.c]
[monitor.c monitor_wrap.c nchan.c servconf.c serverloop.c session.c]
[ssh.c sshd.c]
Implement a channel success/failure status confirmation callback
mechanism. Each channel maintains a queue of callbacks, which will
be drained in order (RFC4253 guarantees confirm messages are not
reordered within an channel).
Also includes a abandonment callback to clean up if a channel is
closed without sending confirmation messages. This probably
shouldn't happen in compliant implementations, but it could be
abused to leak memory.
ok markus@ (as part of a larger diff)
Diffstat (limited to 'channels.c')
-rw-r--r-- | channels.c | 73 |
1 files changed, 64 insertions, 9 deletions
diff --git a/channels.c b/channels.c index 05c23e59c..b5e28dabf 100644 --- a/channels.c +++ b/channels.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: channels.c,v 1.274 2008/05/08 06:59:01 markus Exp $ */ | 1 | /* $OpenBSD: channels.c,v 1.275 2008/05/08 12:02:23 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -61,6 +61,7 @@ | |||
61 | #include <unistd.h> | 61 | #include <unistd.h> |
62 | #include <stdarg.h> | 62 | #include <stdarg.h> |
63 | 63 | ||
64 | #include "openbsd-compat/sys-queue.h" | ||
64 | #include "xmalloc.h" | 65 | #include "xmalloc.h" |
65 | #include "ssh.h" | 66 | #include "ssh.h" |
66 | #include "ssh1.h" | 67 | #include "ssh1.h" |
@@ -319,10 +320,11 @@ channel_new(char *ctype, int type, int rfd, int wfd, int efd, | |||
319 | c->single_connection = 0; | 320 | c->single_connection = 0; |
320 | c->detach_user = NULL; | 321 | c->detach_user = NULL; |
321 | c->detach_close = 0; | 322 | c->detach_close = 0; |
322 | c->confirm = NULL; | 323 | c->open_confirm = NULL; |
323 | c->confirm_ctx = NULL; | 324 | c->open_confirm_ctx = NULL; |
324 | c->input_filter = NULL; | 325 | c->input_filter = NULL; |
325 | c->output_filter = NULL; | 326 | c->output_filter = NULL; |
327 | TAILQ_INIT(&c->status_confirms); | ||
326 | debug("channel %d: new [%s]", found, remote_name); | 328 | debug("channel %d: new [%s]", found, remote_name); |
327 | return c; | 329 | return c; |
328 | } | 330 | } |
@@ -379,6 +381,7 @@ channel_free(Channel *c) | |||
379 | { | 381 | { |
380 | char *s; | 382 | char *s; |
381 | u_int i, n; | 383 | u_int i, n; |
384 | struct channel_confirm *cc; | ||
382 | 385 | ||
383 | for (n = 0, i = 0; i < channels_alloc; i++) | 386 | for (n = 0, i = 0; i < channels_alloc; i++) |
384 | if (channels[i]) | 387 | if (channels[i]) |
@@ -402,6 +405,13 @@ channel_free(Channel *c) | |||
402 | xfree(c->remote_name); | 405 | xfree(c->remote_name); |
403 | c->remote_name = NULL; | 406 | c->remote_name = NULL; |
404 | } | 407 | } |
408 | while ((cc = TAILQ_FIRST(&c->status_confirms)) != NULL) { | ||
409 | if (cc->abandon_cb != NULL) | ||
410 | cc->abandon_cb(c, cc->ctx); | ||
411 | TAILQ_REMOVE(&c->status_confirms, cc, entry); | ||
412 | bzero(cc, sizeof(*cc)); | ||
413 | xfree(cc); | ||
414 | } | ||
405 | channels[c->self] = NULL; | 415 | channels[c->self] = NULL; |
406 | xfree(c); | 416 | xfree(c); |
407 | } | 417 | } |
@@ -660,16 +670,33 @@ channel_request_start(int id, char *service, int wantconfirm) | |||
660 | } | 670 | } |
661 | 671 | ||
662 | void | 672 | void |
663 | channel_register_confirm(int id, channel_callback_fn *fn, void *ctx) | 673 | channel_register_status_confirm(int id, channel_confirm_cb *cb, |
674 | channel_confirm_abandon_cb *abandon_cb, void *ctx) | ||
675 | { | ||
676 | struct channel_confirm *cc; | ||
677 | Channel *c; | ||
678 | |||
679 | if ((c = channel_lookup(id)) == NULL) | ||
680 | fatal("channel_register_expect: %d: bad id", id); | ||
681 | |||
682 | cc = xmalloc(sizeof(*cc)); | ||
683 | cc->cb = cb; | ||
684 | cc->abandon_cb = abandon_cb; | ||
685 | cc->ctx = ctx; | ||
686 | TAILQ_INSERT_TAIL(&c->status_confirms, cc, entry); | ||
687 | } | ||
688 | |||
689 | void | ||
690 | channel_register_open_confirm(int id, channel_callback_fn *fn, void *ctx) | ||
664 | { | 691 | { |
665 | Channel *c = channel_lookup(id); | 692 | Channel *c = channel_lookup(id); |
666 | 693 | ||
667 | if (c == NULL) { | 694 | if (c == NULL) { |
668 | logit("channel_register_comfirm: %d: bad id", id); | 695 | logit("channel_register_open_comfirm: %d: bad id", id); |
669 | return; | 696 | return; |
670 | } | 697 | } |
671 | c->confirm = fn; | 698 | c->open_confirm = fn; |
672 | c->confirm_ctx = ctx; | 699 | c->open_confirm_ctx = ctx; |
673 | } | 700 | } |
674 | 701 | ||
675 | void | 702 | void |
@@ -2209,9 +2236,9 @@ channel_input_open_confirmation(int type, u_int32_t seq, void *ctxt) | |||
2209 | if (compat20) { | 2236 | if (compat20) { |
2210 | c->remote_window = packet_get_int(); | 2237 | c->remote_window = packet_get_int(); |
2211 | c->remote_maxpacket = packet_get_int(); | 2238 | c->remote_maxpacket = packet_get_int(); |
2212 | if (c->confirm) { | 2239 | if (c->open_confirm) { |
2213 | debug2("callback start"); | 2240 | debug2("callback start"); |
2214 | c->confirm(c->self, c->confirm_ctx); | 2241 | c->open_confirm(c->self, c->open_confirm_ctx); |
2215 | debug2("callback done"); | 2242 | debug2("callback done"); |
2216 | } | 2243 | } |
2217 | debug2("channel %d: open confirm rwindow %u rmax %u", c->self, | 2244 | debug2("channel %d: open confirm rwindow %u rmax %u", c->self, |
@@ -2328,6 +2355,34 @@ channel_input_port_open(int type, u_int32_t seq, void *ctxt) | |||
2328 | xfree(host); | 2355 | xfree(host); |
2329 | } | 2356 | } |
2330 | 2357 | ||
2358 | /* ARGSUSED */ | ||
2359 | void | ||
2360 | channel_input_status_confirm(int type, u_int32_t seq, void *ctxt) | ||
2361 | { | ||
2362 | Channel *c; | ||
2363 | struct channel_confirm *cc; | ||
2364 | int remote_id; | ||
2365 | |||
2366 | /* Reset keepalive timeout */ | ||
2367 | keep_alive_timeouts = 0; | ||
2368 | |||
2369 | remote_id = packet_get_int(); | ||
2370 | packet_check_eom(); | ||
2371 | |||
2372 | debug2("channel_input_confirm: type %d id %d", type, remote_id); | ||
2373 | |||
2374 | if ((c = channel_lookup(remote_id)) == NULL) { | ||
2375 | logit("channel_input_success_failure: %d: unknown", remote_id); | ||
2376 | return; | ||
2377 | } | ||
2378 | ; | ||
2379 | if ((cc = TAILQ_FIRST(&c->status_confirms)) == NULL) | ||
2380 | return; | ||
2381 | cc->cb(type, c, cc->ctx); | ||
2382 | TAILQ_REMOVE(&c->status_confirms, cc, entry); | ||
2383 | bzero(cc, sizeof(*cc)); | ||
2384 | xfree(cc); | ||
2385 | } | ||
2331 | 2386 | ||
2332 | /* -- tcp forwarding */ | 2387 | /* -- tcp forwarding */ |
2333 | 2388 | ||