diff options
author | Damien Miller <djm@mindrot.org> | 2004-06-15 10:34:08 +1000 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2004-06-15 10:34:08 +1000 |
commit | 0e220dbfbcc9fe252e8f1f4890dbfa415aad35db (patch) | |
tree | b78bab0c628cd5bdb0ec95340f533a1be2fae75f | |
parent | 05202ffe214115afa24bf6e7a6d8c8457e6759bb (diff) |
- djm@cvs.openbsd.org 2004/06/13 15:03:02
[channels.c channels.h clientloop.c clientloop.h includes.h readconf.c]
[readconf.h scp.1 sftp.1 ssh.1 ssh.c ssh_config.5]
implement session multiplexing in the client (the server has supported
this since 2.0); ok markus@
-rw-r--r-- | ChangeLog | 7 | ||||
-rw-r--r-- | channels.c | 76 | ||||
-rw-r--r-- | channels.h | 7 | ||||
-rw-r--r-- | clientloop.c | 327 | ||||
-rw-r--r-- | clientloop.h | 4 | ||||
-rw-r--r-- | defines.h | 5 | ||||
-rw-r--r-- | includes.h | 3 | ||||
-rw-r--r-- | readconf.c | 18 | ||||
-rw-r--r-- | readconf.h | 5 | ||||
-rw-r--r-- | scp.1 | 4 | ||||
-rw-r--r-- | sftp.1 | 4 | ||||
-rw-r--r-- | ssh-rand-helper.c | 6 | ||||
-rw-r--r-- | ssh.1 | 26 | ||||
-rw-r--r-- | ssh.c | 276 | ||||
-rw-r--r-- | ssh_config.5 | 24 |
15 files changed, 650 insertions, 142 deletions
@@ -24,6 +24,11 @@ | |||
24 | [ssh.1 ssh_config.5 sshd_config.5] | 24 | [ssh.1 ssh_config.5 sshd_config.5] |
25 | List supported ciphers in man pages, tidy up ssh -c; | 25 | List supported ciphers in man pages, tidy up ssh -c; |
26 | "looks fine" jmc@, ok markus@ | 26 | "looks fine" jmc@, ok markus@ |
27 | - djm@cvs.openbsd.org 2004/06/13 15:03:02 | ||
28 | [channels.c channels.h clientloop.c clientloop.h includes.h readconf.c] | ||
29 | [readconf.h scp.1 sftp.1 ssh.1 ssh.c ssh_config.5] | ||
30 | implement session multiplexing in the client (the server has supported | ||
31 | this since 2.0); ok markus@ | ||
27 | 32 | ||
28 | 20040603 | 33 | 20040603 |
29 | - (dtucker) [auth-pam.c] Don't use pam_* namespace for sshd's PAM functions. | 34 | - (dtucker) [auth-pam.c] Don't use pam_* namespace for sshd's PAM functions. |
@@ -1208,4 +1213,4 @@ | |||
1208 | - (djm) Trim deprecated options from INSTALL. Mention UsePAM | 1213 | - (djm) Trim deprecated options from INSTALL. Mention UsePAM |
1209 | - (djm) Fix quote handling in sftp; Patch from admorten AT umich.edu | 1214 | - (djm) Fix quote handling in sftp; Patch from admorten AT umich.edu |
1210 | 1215 | ||
1211 | $Id: ChangeLog,v 1.3381 2004/06/15 00:30:39 djm Exp $ | 1216 | $Id: ChangeLog,v 1.3382 2004/06/15 00:34:08 djm Exp $ |
diff --git a/channels.c b/channels.c index 437befa34..1fb1092c8 100644 --- a/channels.c +++ b/channels.c | |||
@@ -39,7 +39,7 @@ | |||
39 | */ | 39 | */ |
40 | 40 | ||
41 | #include "includes.h" | 41 | #include "includes.h" |
42 | RCSID("$OpenBSD: channels.c,v 1.203 2004/05/26 23:02:39 markus Exp $"); | 42 | RCSID("$OpenBSD: channels.c,v 1.204 2004/06/13 15:03:02 djm Exp $"); |
43 | 43 | ||
44 | #include "ssh.h" | 44 | #include "ssh.h" |
45 | #include "ssh1.h" | 45 | #include "ssh1.h" |
@@ -172,6 +172,7 @@ channel_register_fds(Channel *c, int rfd, int wfd, int efd, | |||
172 | c->rfd = rfd; | 172 | c->rfd = rfd; |
173 | c->wfd = wfd; | 173 | c->wfd = wfd; |
174 | c->sock = (rfd == wfd) ? rfd : -1; | 174 | c->sock = (rfd == wfd) ? rfd : -1; |
175 | c->ctl_fd = -1; /* XXX: set elsewhere */ | ||
175 | c->efd = efd; | 176 | c->efd = efd; |
176 | c->extended_usage = extusage; | 177 | c->extended_usage = extusage; |
177 | 178 | ||
@@ -263,6 +264,7 @@ channel_new(char *ctype, int type, int rfd, int wfd, int efd, | |||
263 | c->single_connection = 0; | 264 | c->single_connection = 0; |
264 | c->detach_user = NULL; | 265 | c->detach_user = NULL; |
265 | c->confirm = NULL; | 266 | c->confirm = NULL; |
267 | c->confirm_ctx = NULL; | ||
266 | c->input_filter = NULL; | 268 | c->input_filter = NULL; |
267 | debug("channel %d: new [%s]", found, remote_name); | 269 | debug("channel %d: new [%s]", found, remote_name); |
268 | return c; | 270 | return c; |
@@ -304,10 +306,11 @@ channel_close_fd(int *fdp) | |||
304 | static void | 306 | static void |
305 | channel_close_fds(Channel *c) | 307 | channel_close_fds(Channel *c) |
306 | { | 308 | { |
307 | debug3("channel %d: close_fds r %d w %d e %d", | 309 | debug3("channel %d: close_fds r %d w %d e %d c %d", |
308 | c->self, c->rfd, c->wfd, c->efd); | 310 | c->self, c->rfd, c->wfd, c->efd, c->ctl_fd); |
309 | 311 | ||
310 | channel_close_fd(&c->sock); | 312 | channel_close_fd(&c->sock); |
313 | channel_close_fd(&c->ctl_fd); | ||
311 | channel_close_fd(&c->rfd); | 314 | channel_close_fd(&c->rfd); |
312 | channel_close_fd(&c->wfd); | 315 | channel_close_fd(&c->wfd); |
313 | channel_close_fd(&c->efd); | 316 | channel_close_fd(&c->efd); |
@@ -333,6 +336,8 @@ channel_free(Channel *c) | |||
333 | 336 | ||
334 | if (c->sock != -1) | 337 | if (c->sock != -1) |
335 | shutdown(c->sock, SHUT_RDWR); | 338 | shutdown(c->sock, SHUT_RDWR); |
339 | if (c->ctl_fd != -1) | ||
340 | shutdown(c->ctl_fd, SHUT_RDWR); | ||
336 | channel_close_fds(c); | 341 | channel_close_fds(c); |
337 | buffer_free(&c->input); | 342 | buffer_free(&c->input); |
338 | buffer_free(&c->output); | 343 | buffer_free(&c->output); |
@@ -550,12 +555,13 @@ channel_open_message(void) | |||
550 | case SSH_CHANNEL_X11_OPEN: | 555 | case SSH_CHANNEL_X11_OPEN: |
551 | case SSH_CHANNEL_INPUT_DRAINING: | 556 | case SSH_CHANNEL_INPUT_DRAINING: |
552 | case SSH_CHANNEL_OUTPUT_DRAINING: | 557 | case SSH_CHANNEL_OUTPUT_DRAINING: |
553 | snprintf(buf, sizeof buf, " #%d %.300s (t%d r%d i%d/%d o%d/%d fd %d/%d)\r\n", | 558 | snprintf(buf, sizeof buf, |
559 | " #%d %.300s (t%d r%d i%d/%d o%d/%d fd %d/%d cfd %d)\r\n", | ||
554 | c->self, c->remote_name, | 560 | c->self, c->remote_name, |
555 | c->type, c->remote_id, | 561 | c->type, c->remote_id, |
556 | c->istate, buffer_len(&c->input), | 562 | c->istate, buffer_len(&c->input), |
557 | c->ostate, buffer_len(&c->output), | 563 | c->ostate, buffer_len(&c->output), |
558 | c->rfd, c->wfd); | 564 | c->rfd, c->wfd, c->ctl_fd); |
559 | buffer_append(&buffer, buf, strlen(buf)); | 565 | buffer_append(&buffer, buf, strlen(buf)); |
560 | continue; | 566 | continue; |
561 | default: | 567 | default: |
@@ -596,14 +602,14 @@ channel_request_start(int id, char *service, int wantconfirm) | |||
596 | logit("channel_request_start: %d: unknown channel id", id); | 602 | logit("channel_request_start: %d: unknown channel id", id); |
597 | return; | 603 | return; |
598 | } | 604 | } |
599 | debug2("channel %d: request %s", id, service) ; | 605 | debug2("channel %d: request %s confirm %d", id, service, wantconfirm); |
600 | packet_start(SSH2_MSG_CHANNEL_REQUEST); | 606 | packet_start(SSH2_MSG_CHANNEL_REQUEST); |
601 | packet_put_int(c->remote_id); | 607 | packet_put_int(c->remote_id); |
602 | packet_put_cstring(service); | 608 | packet_put_cstring(service); |
603 | packet_put_char(wantconfirm); | 609 | packet_put_char(wantconfirm); |
604 | } | 610 | } |
605 | void | 611 | void |
606 | channel_register_confirm(int id, channel_callback_fn *fn) | 612 | channel_register_confirm(int id, channel_callback_fn *fn, void *ctx) |
607 | { | 613 | { |
608 | Channel *c = channel_lookup(id); | 614 | Channel *c = channel_lookup(id); |
609 | 615 | ||
@@ -612,6 +618,7 @@ channel_register_confirm(int id, channel_callback_fn *fn) | |||
612 | return; | 618 | return; |
613 | } | 619 | } |
614 | c->confirm = fn; | 620 | c->confirm = fn; |
621 | c->confirm_ctx = ctx; | ||
615 | } | 622 | } |
616 | void | 623 | void |
617 | channel_register_cleanup(int id, channel_callback_fn *fn) | 624 | channel_register_cleanup(int id, channel_callback_fn *fn) |
@@ -729,6 +736,10 @@ channel_pre_open(Channel *c, fd_set * readset, fd_set * writeset) | |||
729 | buffer_len(&c->extended) < c->remote_window) | 736 | buffer_len(&c->extended) < c->remote_window) |
730 | FD_SET(c->efd, readset); | 737 | FD_SET(c->efd, readset); |
731 | } | 738 | } |
739 | /* XXX: What about efd? races? */ | ||
740 | if (compat20 && c->ctl_fd != -1 && | ||
741 | c->istate == CHAN_INPUT_OPEN && c->ostate == CHAN_OUTPUT_OPEN) | ||
742 | FD_SET(c->ctl_fd, readset); | ||
732 | } | 743 | } |
733 | 744 | ||
734 | static void | 745 | static void |
@@ -1482,6 +1493,33 @@ channel_handle_efd(Channel *c, fd_set * readset, fd_set * writeset) | |||
1482 | return 1; | 1493 | return 1; |
1483 | } | 1494 | } |
1484 | static int | 1495 | static int |
1496 | channel_handle_ctl(Channel *c, fd_set * readset, fd_set * writeset) | ||
1497 | { | ||
1498 | char buf[16]; | ||
1499 | int len; | ||
1500 | |||
1501 | /* Monitor control fd to detect if the slave client exits */ | ||
1502 | if (c->ctl_fd != -1 && FD_ISSET(c->ctl_fd, readset)) { | ||
1503 | len = read(c->ctl_fd, buf, sizeof(buf)); | ||
1504 | if (len < 0 && (errno == EINTR || errno == EAGAIN)) | ||
1505 | return 1; | ||
1506 | if (len <= 0) { | ||
1507 | debug2("channel %d: ctl read<=0", c->self); | ||
1508 | if (c->type != SSH_CHANNEL_OPEN) { | ||
1509 | debug2("channel %d: not open", c->self); | ||
1510 | chan_mark_dead(c); | ||
1511 | return -1; | ||
1512 | } else { | ||
1513 | chan_read_failed(c); | ||
1514 | chan_write_failed(c); | ||
1515 | } | ||
1516 | return -1; | ||
1517 | } else | ||
1518 | fatal("%s: unexpected data on ctl fd", __func__); | ||
1519 | } | ||
1520 | return 1; | ||
1521 | } | ||
1522 | static int | ||
1485 | channel_check_window(Channel *c) | 1523 | channel_check_window(Channel *c) |
1486 | { | 1524 | { |
1487 | if (c->type == SSH_CHANNEL_OPEN && | 1525 | if (c->type == SSH_CHANNEL_OPEN && |
@@ -1511,6 +1549,7 @@ channel_post_open(Channel *c, fd_set * readset, fd_set * writeset) | |||
1511 | if (!compat20) | 1549 | if (!compat20) |
1512 | return; | 1550 | return; |
1513 | channel_handle_efd(c, readset, writeset); | 1551 | channel_handle_efd(c, readset, writeset); |
1552 | channel_handle_ctl(c, readset, writeset); | ||
1514 | channel_check_window(c); | 1553 | channel_check_window(c); |
1515 | } | 1554 | } |
1516 | 1555 | ||
@@ -2011,7 +2050,7 @@ channel_input_open_confirmation(int type, u_int32_t seq, void *ctxt) | |||
2011 | c->remote_maxpacket = packet_get_int(); | 2050 | c->remote_maxpacket = packet_get_int(); |
2012 | if (c->confirm) { | 2051 | if (c->confirm) { |
2013 | debug2("callback start"); | 2052 | debug2("callback start"); |
2014 | c->confirm(c->self, NULL); | 2053 | c->confirm(c->self, c->confirm_ctx); |
2015 | debug2("callback done"); | 2054 | debug2("callback done"); |
2016 | } | 2055 | } |
2017 | debug2("channel %d: open confirm rwindow %u rmax %u", c->self, | 2056 | debug2("channel %d: open confirm rwindow %u rmax %u", c->self, |
@@ -2531,6 +2570,27 @@ channel_connect_to(const char *host, u_short port) | |||
2531 | return connect_to(host, port); | 2570 | return connect_to(host, port); |
2532 | } | 2571 | } |
2533 | 2572 | ||
2573 | void | ||
2574 | channel_send_window_changes(void) | ||
2575 | { | ||
2576 | int i; | ||
2577 | struct winsize ws; | ||
2578 | |||
2579 | for (i = 0; i < channels_alloc; i++) { | ||
2580 | if (channels[i] == NULL || | ||
2581 | channels[i]->type != SSH_CHANNEL_OPEN) | ||
2582 | continue; | ||
2583 | if (ioctl(channels[i]->rfd, TIOCGWINSZ, &ws) < 0) | ||
2584 | continue; | ||
2585 | channel_request_start(i, "window-change", 0); | ||
2586 | packet_put_int(ws.ws_col); | ||
2587 | packet_put_int(ws.ws_row); | ||
2588 | packet_put_int(ws.ws_xpixel); | ||
2589 | packet_put_int(ws.ws_ypixel); | ||
2590 | packet_send(); | ||
2591 | } | ||
2592 | } | ||
2593 | |||
2534 | /* -- X11 forwarding */ | 2594 | /* -- X11 forwarding */ |
2535 | 2595 | ||
2536 | /* | 2596 | /* |
diff --git a/channels.h b/channels.h index 0a49c55ea..41f3cedd3 100644 --- a/channels.h +++ b/channels.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: channels.h,v 1.72 2004/05/21 11:33:11 djm Exp $ */ | 1 | /* $OpenBSD: channels.h,v 1.73 2004/06/13 15:03:02 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
@@ -76,6 +76,7 @@ struct Channel { | |||
76 | int wfd; /* write fd */ | 76 | int wfd; /* write fd */ |
77 | int efd; /* extended fd */ | 77 | int efd; /* extended fd */ |
78 | int sock; /* sock fd */ | 78 | int sock; /* sock fd */ |
79 | int ctl_fd; /* control fd (client sharing) */ | ||
79 | int isatty; /* rfd is a tty */ | 80 | int isatty; /* rfd is a tty */ |
80 | int wfd_isatty; /* wfd is a tty */ | 81 | int wfd_isatty; /* wfd is a tty */ |
81 | int force_drain; /* force close on iEOF */ | 82 | int force_drain; /* force close on iEOF */ |
@@ -105,6 +106,7 @@ struct Channel { | |||
105 | /* callback */ | 106 | /* callback */ |
106 | channel_callback_fn *confirm; | 107 | channel_callback_fn *confirm; |
107 | channel_callback_fn *detach_user; | 108 | channel_callback_fn *detach_user; |
109 | void *confirm_ctx; | ||
108 | 110 | ||
109 | /* filter */ | 111 | /* filter */ |
110 | channel_filter_fn *input_filter; | 112 | channel_filter_fn *input_filter; |
@@ -161,10 +163,11 @@ void channel_stop_listening(void); | |||
161 | void channel_send_open(int); | 163 | void channel_send_open(int); |
162 | void channel_request_start(int, char *, int); | 164 | void channel_request_start(int, char *, int); |
163 | void channel_register_cleanup(int, channel_callback_fn *); | 165 | void channel_register_cleanup(int, channel_callback_fn *); |
164 | void channel_register_confirm(int, channel_callback_fn *); | 166 | void channel_register_confirm(int, channel_callback_fn *, void *); |
165 | void channel_register_filter(int, channel_filter_fn *); | 167 | void channel_register_filter(int, channel_filter_fn *); |
166 | void channel_cancel_cleanup(int); | 168 | void channel_cancel_cleanup(int); |
167 | int channel_close_fd(int *); | 169 | int channel_close_fd(int *); |
170 | void channel_send_window_changes(void); | ||
168 | 171 | ||
169 | /* protocol handler */ | 172 | /* protocol handler */ |
170 | 173 | ||
diff --git a/clientloop.c b/clientloop.c index 31e604180..6401588a9 100644 --- a/clientloop.c +++ b/clientloop.c | |||
@@ -59,7 +59,7 @@ | |||
59 | */ | 59 | */ |
60 | 60 | ||
61 | #include "includes.h" | 61 | #include "includes.h" |
62 | RCSID("$OpenBSD: clientloop.c,v 1.122 2004/05/22 06:32:12 djm Exp $"); | 62 | RCSID("$OpenBSD: clientloop.c,v 1.123 2004/06/13 15:03:02 djm Exp $"); |
63 | 63 | ||
64 | #include "ssh.h" | 64 | #include "ssh.h" |
65 | #include "ssh1.h" | 65 | #include "ssh1.h" |
@@ -81,6 +81,9 @@ RCSID("$OpenBSD: clientloop.c,v 1.122 2004/05/22 06:32:12 djm Exp $"); | |||
81 | #include "atomicio.h" | 81 | #include "atomicio.h" |
82 | #include "sshpty.h" | 82 | #include "sshpty.h" |
83 | #include "misc.h" | 83 | #include "misc.h" |
84 | #include "monitor_fdpass.h" | ||
85 | #include "match.h" | ||
86 | #include "msg.h" | ||
84 | 87 | ||
85 | /* import options */ | 88 | /* import options */ |
86 | extern Options options; | 89 | extern Options options; |
@@ -91,6 +94,9 @@ extern int stdin_null_flag; | |||
91 | /* Flag indicating that no shell has been requested */ | 94 | /* Flag indicating that no shell has been requested */ |
92 | extern int no_shell_flag; | 95 | extern int no_shell_flag; |
93 | 96 | ||
97 | /* Control socket */ | ||
98 | extern int control_fd; | ||
99 | |||
94 | /* | 100 | /* |
95 | * Name of the host we are connecting to. This is the name given on the | 101 | * Name of the host we are connecting to. This is the name given on the |
96 | * command line, or the HostName specified for the user-supplied name in a | 102 | * command line, or the HostName specified for the user-supplied name in a |
@@ -131,9 +137,19 @@ static int server_alive_timeouts = 0; | |||
131 | static void client_init_dispatch(void); | 137 | static void client_init_dispatch(void); |
132 | int session_ident = -1; | 138 | int session_ident = -1; |
133 | 139 | ||
140 | struct confirm_ctx { | ||
141 | int want_tty; | ||
142 | int want_subsys; | ||
143 | Buffer cmd; | ||
144 | char *term; | ||
145 | struct termios tio; | ||
146 | }; | ||
147 | |||
134 | /*XXX*/ | 148 | /*XXX*/ |
135 | extern Kex *xxx_kex; | 149 | extern Kex *xxx_kex; |
136 | 150 | ||
151 | void ssh_process_session2_setup(int, int, int, Buffer *); | ||
152 | |||
137 | /* Restores stdin to blocking mode. */ | 153 | /* Restores stdin to blocking mode. */ |
138 | 154 | ||
139 | static void | 155 | static void |
@@ -291,19 +307,13 @@ client_check_window_change(void) | |||
291 | /** XXX race */ | 307 | /** XXX race */ |
292 | received_window_change_signal = 0; | 308 | received_window_change_signal = 0; |
293 | 309 | ||
294 | if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0) | ||
295 | return; | ||
296 | |||
297 | debug2("client_check_window_change: changed"); | 310 | debug2("client_check_window_change: changed"); |
298 | 311 | ||
299 | if (compat20) { | 312 | if (compat20) { |
300 | channel_request_start(session_ident, "window-change", 0); | 313 | channel_send_window_changes(); |
301 | packet_put_int(ws.ws_col); | ||
302 | packet_put_int(ws.ws_row); | ||
303 | packet_put_int(ws.ws_xpixel); | ||
304 | packet_put_int(ws.ws_ypixel); | ||
305 | packet_send(); | ||
306 | } else { | 314 | } else { |
315 | if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0) | ||
316 | return; | ||
307 | packet_start(SSH_CMSG_WINDOW_SIZE); | 317 | packet_start(SSH_CMSG_WINDOW_SIZE); |
308 | packet_put_int(ws.ws_row); | 318 | packet_put_int(ws.ws_row); |
309 | packet_put_int(ws.ws_col); | 319 | packet_put_int(ws.ws_col); |
@@ -335,7 +345,6 @@ server_alive_check(void) | |||
335 | * Waits until the client can do something (some data becomes available on | 345 | * Waits until the client can do something (some data becomes available on |
336 | * one of the file descriptors). | 346 | * one of the file descriptors). |
337 | */ | 347 | */ |
338 | |||
339 | static void | 348 | static void |
340 | client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, | 349 | client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, |
341 | int *maxfdp, int *nallocp, int rekeying) | 350 | int *maxfdp, int *nallocp, int rekeying) |
@@ -381,6 +390,9 @@ client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, | |||
381 | if (packet_have_data_to_write()) | 390 | if (packet_have_data_to_write()) |
382 | FD_SET(connection_out, *writesetp); | 391 | FD_SET(connection_out, *writesetp); |
383 | 392 | ||
393 | if (control_fd != -1) | ||
394 | FD_SET(control_fd, *readsetp); | ||
395 | |||
384 | /* | 396 | /* |
385 | * Wait for something to happen. This will suspend the process until | 397 | * Wait for something to happen. This will suspend the process until |
386 | * some selected descriptor can be read, written, or has some other | 398 | * some selected descriptor can be read, written, or has some other |
@@ -500,6 +512,176 @@ client_process_net_input(fd_set * readset) | |||
500 | } | 512 | } |
501 | 513 | ||
502 | static void | 514 | static void |
515 | client_subsystem_reply(int type, u_int32_t seq, void *ctxt) | ||
516 | { | ||
517 | int id; | ||
518 | Channel *c; | ||
519 | |||
520 | id = packet_get_int(); | ||
521 | packet_check_eom(); | ||
522 | |||
523 | if ((c = channel_lookup(id)) == NULL) { | ||
524 | error("%s: no channel for id %d", __func__, id); | ||
525 | return; | ||
526 | } | ||
527 | |||
528 | if (type == SSH2_MSG_CHANNEL_SUCCESS) | ||
529 | debug2("Request suceeded on channel %d", id); | ||
530 | else if (type == SSH2_MSG_CHANNEL_FAILURE) { | ||
531 | error("Request failed on channel %d", id); | ||
532 | channel_free(c); | ||
533 | } | ||
534 | } | ||
535 | |||
536 | static void | ||
537 | client_extra_session2_setup(int id, void *arg) | ||
538 | { | ||
539 | struct confirm_ctx *cctx = arg; | ||
540 | Channel *c; | ||
541 | |||
542 | if (cctx == NULL) | ||
543 | fatal("%s: cctx == NULL", __func__); | ||
544 | if ((c = channel_lookup(id)) == NULL) | ||
545 | fatal("%s: no channel for id %d", __func__, id); | ||
546 | |||
547 | client_session2_setup(id, cctx->want_tty, cctx->want_subsys, | ||
548 | cctx->term, &cctx->tio, c->rfd, &cctx->cmd, | ||
549 | client_subsystem_reply); | ||
550 | |||
551 | c->confirm_ctx = NULL; | ||
552 | buffer_free(&cctx->cmd); | ||
553 | free(cctx->term); | ||
554 | free(cctx); | ||
555 | } | ||
556 | |||
557 | static void | ||
558 | client_process_control(fd_set * readset) | ||
559 | { | ||
560 | Buffer m; | ||
561 | Channel *c; | ||
562 | int client_fd, new_fd[3], ver; | ||
563 | socklen_t addrlen; | ||
564 | struct sockaddr_storage addr; | ||
565 | struct confirm_ctx *cctx; | ||
566 | char *cmd; | ||
567 | u_int len; | ||
568 | uid_t euid; | ||
569 | gid_t egid; | ||
570 | |||
571 | /* | ||
572 | * Accept connection on control socket | ||
573 | */ | ||
574 | if (control_fd == -1 || !FD_ISSET(control_fd, readset)) | ||
575 | return; | ||
576 | |||
577 | memset(&addr, 0, sizeof(addr)); | ||
578 | addrlen = sizeof(addr); | ||
579 | if ((client_fd = accept(control_fd, | ||
580 | (struct sockaddr*)&addr, &addrlen)) == -1) { | ||
581 | error("%s accept: %s", __func__, strerror(errno)); | ||
582 | return; | ||
583 | } | ||
584 | |||
585 | if (getpeereid(client_fd, &euid, &egid) < 0) { | ||
586 | error("%s getpeereid failed: %s", __func__, strerror(errno)); | ||
587 | close(client_fd); | ||
588 | return; | ||
589 | } | ||
590 | if ((euid != 0) && (getuid() != euid)) { | ||
591 | error("control mode uid mismatch: peer euid %u != uid %u", | ||
592 | (u_int) euid, (u_int) getuid()); | ||
593 | close(client_fd); | ||
594 | return; | ||
595 | } | ||
596 | /* XXX: implement use of ssh-askpass to confirm additional channels */ | ||
597 | |||
598 | unset_nonblock(client_fd); | ||
599 | |||
600 | buffer_init(&m); | ||
601 | |||
602 | buffer_put_int(&m, getpid()); | ||
603 | if (ssh_msg_send(client_fd, /* version */0, &m) == -1) { | ||
604 | error("%s: client msg_send failed", __func__); | ||
605 | close(client_fd); | ||
606 | return; | ||
607 | } | ||
608 | buffer_clear(&m); | ||
609 | |||
610 | if (ssh_msg_recv(client_fd, &m) == -1) { | ||
611 | error("%s: client msg_recv failed", __func__); | ||
612 | close(client_fd); | ||
613 | return; | ||
614 | } | ||
615 | |||
616 | if ((ver = buffer_get_char(&m)) != 0) { | ||
617 | error("%s: wrong client version %d", __func__, ver); | ||
618 | buffer_free(&m); | ||
619 | close(client_fd); | ||
620 | return; | ||
621 | } | ||
622 | |||
623 | cctx = xmalloc(sizeof(*cctx)); | ||
624 | memset(cctx, 0, sizeof(*cctx)); | ||
625 | |||
626 | cctx->want_tty = buffer_get_int(&m); | ||
627 | cctx->want_subsys = buffer_get_int(&m); | ||
628 | cctx->term = buffer_get_string(&m, &len); | ||
629 | |||
630 | cmd = buffer_get_string(&m, &len); | ||
631 | buffer_init(&cctx->cmd); | ||
632 | buffer_append(&cctx->cmd, cmd, strlen(cmd)); | ||
633 | |||
634 | debug2("%s: accepted tty %d, subsys %d, cmd %s", __func__, | ||
635 | cctx->want_tty, cctx->want_subsys, cmd); | ||
636 | |||
637 | /* Gather fds from client */ | ||
638 | new_fd[0] = mm_receive_fd(client_fd); | ||
639 | new_fd[1] = mm_receive_fd(client_fd); | ||
640 | new_fd[2] = mm_receive_fd(client_fd); | ||
641 | |||
642 | debug2("%s: got fds stdin %d, stdout %d, stderr %d", __func__, | ||
643 | new_fd[0], new_fd[1], new_fd[2]); | ||
644 | |||
645 | /* Try to pick up ttymodes from client before it goes raw */ | ||
646 | if (cctx->want_tty && tcgetattr(new_fd[0], &cctx->tio) == -1) | ||
647 | error("%s: tcgetattr: %s", __func__, strerror(errno)); | ||
648 | |||
649 | buffer_clear(&m); | ||
650 | if (ssh_msg_send(client_fd, /* version */0, &m) == -1) { | ||
651 | error("%s: client msg_send failed", __func__); | ||
652 | close(client_fd); | ||
653 | close(new_fd[0]); | ||
654 | close(new_fd[1]); | ||
655 | close(new_fd[2]); | ||
656 | return; | ||
657 | } | ||
658 | buffer_free(&m); | ||
659 | |||
660 | /* enable nonblocking unless tty */ | ||
661 | if (!isatty(new_fd[0])) | ||
662 | set_nonblock(new_fd[0]); | ||
663 | if (!isatty(new_fd[1])) | ||
664 | set_nonblock(new_fd[1]); | ||
665 | if (!isatty(new_fd[2])) | ||
666 | set_nonblock(new_fd[2]); | ||
667 | |||
668 | set_nonblock(client_fd); | ||
669 | |||
670 | c = channel_new("session", SSH_CHANNEL_OPENING, | ||
671 | new_fd[0], new_fd[1], new_fd[2], | ||
672 | CHAN_SES_WINDOW_DEFAULT, CHAN_SES_PACKET_DEFAULT, | ||
673 | CHAN_EXTENDED_WRITE, "client-session", /*nonblock*/0); | ||
674 | |||
675 | /* XXX */ | ||
676 | c->ctl_fd = client_fd; | ||
677 | |||
678 | debug3("%s: channel_new: %d", __func__, c->self); | ||
679 | |||
680 | channel_send_open(c->self); | ||
681 | channel_register_confirm(c->self, client_extra_session2_setup, cctx); | ||
682 | } | ||
683 | |||
684 | static void | ||
503 | process_cmdline(void) | 685 | process_cmdline(void) |
504 | { | 686 | { |
505 | void (*handler)(int); | 687 | void (*handler)(int); |
@@ -901,9 +1083,6 @@ simple_escape_filter(Channel *c, char *buf, int len) | |||
901 | static void | 1083 | static void |
902 | client_channel_closed(int id, void *arg) | 1084 | client_channel_closed(int id, void *arg) |
903 | { | 1085 | { |
904 | if (id != session_ident) | ||
905 | error("client_channel_closed: id %d != session_ident %d", | ||
906 | id, session_ident); | ||
907 | channel_cancel_cleanup(id); | 1086 | channel_cancel_cleanup(id); |
908 | session_closed = 1; | 1087 | session_closed = 1; |
909 | leave_raw_mode(); | 1088 | leave_raw_mode(); |
@@ -937,6 +1116,8 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
937 | connection_in = packet_get_connection_in(); | 1116 | connection_in = packet_get_connection_in(); |
938 | connection_out = packet_get_connection_out(); | 1117 | connection_out = packet_get_connection_out(); |
939 | max_fd = MAX(connection_in, connection_out); | 1118 | max_fd = MAX(connection_in, connection_out); |
1119 | if (control_fd != -1) | ||
1120 | max_fd = MAX(max_fd, control_fd); | ||
940 | 1121 | ||
941 | if (!compat20) { | 1122 | if (!compat20) { |
942 | /* enable nonblocking unless tty */ | 1123 | /* enable nonblocking unless tty */ |
@@ -1054,6 +1235,9 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1054 | /* Buffer input from the connection. */ | 1235 | /* Buffer input from the connection. */ |
1055 | client_process_net_input(readset); | 1236 | client_process_net_input(readset); |
1056 | 1237 | ||
1238 | /* Accept control connections. */ | ||
1239 | client_process_control(readset); | ||
1240 | |||
1057 | if (quit_pending) | 1241 | if (quit_pending) |
1058 | break; | 1242 | break; |
1059 | 1243 | ||
@@ -1385,7 +1569,7 @@ static void | |||
1385 | client_input_channel_req(int type, u_int32_t seq, void *ctxt) | 1569 | client_input_channel_req(int type, u_int32_t seq, void *ctxt) |
1386 | { | 1570 | { |
1387 | Channel *c = NULL; | 1571 | Channel *c = NULL; |
1388 | int id, reply, success = 0; | 1572 | int exitval, id, reply, success = 0; |
1389 | char *rtype; | 1573 | char *rtype; |
1390 | 1574 | ||
1391 | id = packet_get_int(); | 1575 | id = packet_get_int(); |
@@ -1395,18 +1579,21 @@ client_input_channel_req(int type, u_int32_t seq, void *ctxt) | |||
1395 | debug("client_input_channel_req: channel %d rtype %s reply %d", | 1579 | debug("client_input_channel_req: channel %d rtype %s reply %d", |
1396 | id, rtype, reply); | 1580 | id, rtype, reply); |
1397 | 1581 | ||
1398 | if (session_ident == -1) { | ||
1399 | error("client_input_channel_req: no channel %d", session_ident); | ||
1400 | } else if (id != session_ident) { | ||
1401 | error("client_input_channel_req: channel %d: wrong channel: %d", | ||
1402 | session_ident, id); | ||
1403 | } | ||
1404 | c = channel_lookup(id); | 1582 | c = channel_lookup(id); |
1405 | if (c == NULL) { | 1583 | if (c == NULL) { |
1406 | error("client_input_channel_req: channel %d: unknown channel", id); | 1584 | error("client_input_channel_req: channel %d: unknown channel", id); |
1407 | } else if (strcmp(rtype, "exit-status") == 0) { | 1585 | } else if (strcmp(rtype, "exit-status") == 0) { |
1408 | success = 1; | 1586 | exitval = packet_get_int(); |
1409 | exit_status = packet_get_int(); | 1587 | if (id == session_ident) { |
1588 | success = 1; | ||
1589 | exit_status = exitval; | ||
1590 | } else if (c->ctl_fd == -1) { | ||
1591 | error("client_input_channel_req: unexpected channel %d", | ||
1592 | session_ident); | ||
1593 | } else { | ||
1594 | atomicio(vwrite, c->ctl_fd, &exitval, sizeof(exitval)); | ||
1595 | success = 1; | ||
1596 | } | ||
1410 | packet_check_eom(); | 1597 | packet_check_eom(); |
1411 | } | 1598 | } |
1412 | if (reply) { | 1599 | if (reply) { |
@@ -1437,6 +1624,98 @@ client_input_global_request(int type, u_int32_t seq, void *ctxt) | |||
1437 | xfree(rtype); | 1624 | xfree(rtype); |
1438 | } | 1625 | } |
1439 | 1626 | ||
1627 | void | ||
1628 | client_session2_setup(int id, int want_tty, int want_subsystem, | ||
1629 | const char *term, struct termios *tiop, int in_fd, Buffer *cmd, | ||
1630 | dispatch_fn *subsys_repl) | ||
1631 | { | ||
1632 | int len; | ||
1633 | |||
1634 | debug2("%s: id %d", __func__, id); | ||
1635 | |||
1636 | if (want_tty) { | ||
1637 | struct winsize ws; | ||
1638 | struct termios tio; | ||
1639 | |||
1640 | /* Store window size in the packet. */ | ||
1641 | if (ioctl(in_fd, TIOCGWINSZ, &ws) < 0) | ||
1642 | memset(&ws, 0, sizeof(ws)); | ||
1643 | |||
1644 | channel_request_start(id, "pty-req", 0); | ||
1645 | packet_put_cstring(term != NULL ? term : ""); | ||
1646 | packet_put_int(ws.ws_col); | ||
1647 | packet_put_int(ws.ws_row); | ||
1648 | packet_put_int(ws.ws_xpixel); | ||
1649 | packet_put_int(ws.ws_ypixel); | ||
1650 | tio = get_saved_tio(); | ||
1651 | tty_make_modes(-1, tiop != NULL ? tiop : &tio); | ||
1652 | packet_send(); | ||
1653 | /* XXX wait for reply */ | ||
1654 | } | ||
1655 | |||
1656 | /* Transfer any environment variables from client to server */ | ||
1657 | if (options.num_send_env != 0) { | ||
1658 | int i, j, matched; | ||
1659 | extern char **environ; | ||
1660 | char *name, *val; | ||
1661 | |||
1662 | debug("Sending environment."); | ||
1663 | for (i = 0; environ && environ[i] != NULL; i++) { | ||
1664 | /* Split */ | ||
1665 | name = xstrdup(environ[i]); | ||
1666 | if ((val = strchr(name, '=')) == NULL) { | ||
1667 | free(name); | ||
1668 | continue; | ||
1669 | } | ||
1670 | *val++ = '\0'; | ||
1671 | |||
1672 | matched = 0; | ||
1673 | for (j = 0; j < options.num_send_env; j++) { | ||
1674 | if (match_pattern(name, options.send_env[j])) { | ||
1675 | matched = 1; | ||
1676 | break; | ||
1677 | } | ||
1678 | } | ||
1679 | if (!matched) { | ||
1680 | debug3("Ignored env %s", name); | ||
1681 | free(name); | ||
1682 | continue; | ||
1683 | } | ||
1684 | |||
1685 | debug("Sending env %s = %s", name, val); | ||
1686 | channel_request_start(id, "env", 0); | ||
1687 | packet_put_cstring(name); | ||
1688 | packet_put_cstring(val); | ||
1689 | packet_send(); | ||
1690 | free(name); | ||
1691 | } | ||
1692 | } | ||
1693 | |||
1694 | len = buffer_len(cmd); | ||
1695 | if (len > 0) { | ||
1696 | if (len > 900) | ||
1697 | len = 900; | ||
1698 | if (want_subsystem) { | ||
1699 | debug("Sending subsystem: %.*s", len, (u_char*)buffer_ptr(cmd)); | ||
1700 | channel_request_start(id, "subsystem", subsys_repl != NULL); | ||
1701 | if (subsys_repl != NULL) { | ||
1702 | /* register callback for reply */ | ||
1703 | /* XXX we assume that client_loop has already been called */ | ||
1704 | dispatch_set(SSH2_MSG_CHANNEL_FAILURE, subsys_repl); | ||
1705 | dispatch_set(SSH2_MSG_CHANNEL_SUCCESS, subsys_repl); | ||
1706 | } | ||
1707 | } else { | ||
1708 | debug("Sending command: %.*s", len, (u_char*)buffer_ptr(cmd)); | ||
1709 | channel_request_start(id, "exec", 0); | ||
1710 | } | ||
1711 | packet_put_string(buffer_ptr(cmd), buffer_len(cmd)); | ||
1712 | packet_send(); | ||
1713 | } else { | ||
1714 | channel_request_start(id, "shell", 0); | ||
1715 | packet_send(); | ||
1716 | } | ||
1717 | } | ||
1718 | |||
1440 | static void | 1719 | static void |
1441 | client_init_dispatch_20(void) | 1720 | client_init_dispatch_20(void) |
1442 | { | 1721 | { |
@@ -1503,5 +1782,7 @@ cleanup_exit(int i) | |||
1503 | { | 1782 | { |
1504 | leave_raw_mode(); | 1783 | leave_raw_mode(); |
1505 | leave_non_blocking(); | 1784 | leave_non_blocking(); |
1785 | if (options.control_path != NULL && control_fd != -1) | ||
1786 | unlink(options.control_path); | ||
1506 | _exit(i); | 1787 | _exit(i); |
1507 | } | 1788 | } |
diff --git a/clientloop.h b/clientloop.h index 56af06bc1..f1e13ac3a 100644 --- a/clientloop.h +++ b/clientloop.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: clientloop.h,v 1.8 2003/12/16 15:49:51 markus Exp $ */ | 1 | /* $OpenBSD: clientloop.h,v 1.9 2004/06/13 15:03:02 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
@@ -38,3 +38,5 @@ | |||
38 | /* Client side main loop for the interactive session. */ | 38 | /* Client side main loop for the interactive session. */ |
39 | int client_loop(int, int, int); | 39 | int client_loop(int, int, int); |
40 | void client_global_request_reply_fwd(int, u_int32_t, void *); | 40 | void client_global_request_reply_fwd(int, u_int32_t, void *); |
41 | void client_session2_setup(int, int, int, const char *, struct termios *, | ||
42 | int, Buffer *, dispatch_fn *); | ||
@@ -25,7 +25,7 @@ | |||
25 | #ifndef _DEFINES_H | 25 | #ifndef _DEFINES_H |
26 | #define _DEFINES_H | 26 | #define _DEFINES_H |
27 | 27 | ||
28 | /* $Id: defines.h,v 1.115 2004/04/14 07:24:30 dtucker Exp $ */ | 28 | /* $Id: defines.h,v 1.116 2004/06/15 00:34:08 djm Exp $ */ |
29 | 29 | ||
30 | 30 | ||
31 | /* Constants */ | 31 | /* Constants */ |
@@ -462,6 +462,9 @@ struct winsize { | |||
462 | (struct cmsghdr *)NULL) | 462 | (struct cmsghdr *)NULL) |
463 | #endif /* CMSG_FIRSTHDR */ | 463 | #endif /* CMSG_FIRSTHDR */ |
464 | 464 | ||
465 | #ifndef offsetof | ||
466 | # define offsetof(type, member) ((size_t) &((type *)0)->member) | ||
467 | #endif | ||
465 | 468 | ||
466 | /* Function replacement / compatibility hacks */ | 469 | /* Function replacement / compatibility hacks */ |
467 | 470 | ||
diff --git a/includes.h b/includes.h index ca943c7e6..99b70502c 100644 --- a/includes.h +++ b/includes.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: includes.h,v 1.17 2002/01/26 16:44:22 stevesk Exp $ */ | 1 | /* $OpenBSD: includes.h,v 1.18 2004/06/13 15:03:02 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
@@ -33,6 +33,7 @@ static /**/const char *const rcsid[] = { (char *)rcsid, "\100(#)" msg } | |||
33 | #include <grp.h> | 33 | #include <grp.h> |
34 | #include <time.h> | 34 | #include <time.h> |
35 | #include <dirent.h> | 35 | #include <dirent.h> |
36 | #include <stddef.h> | ||
36 | 37 | ||
37 | #ifdef HAVE_LIMITS_H | 38 | #ifdef HAVE_LIMITS_H |
38 | # include <limits.h> /* For PATH_MAX */ | 39 | # include <limits.h> /* For PATH_MAX */ |
diff --git a/readconf.c b/readconf.c index 5aa371ed9..2b1d7cc46 100644 --- a/readconf.c +++ b/readconf.c | |||
@@ -12,7 +12,7 @@ | |||
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include "includes.h" | 14 | #include "includes.h" |
15 | RCSID("$OpenBSD: readconf.c,v 1.131 2004/05/27 00:50:13 dtucker Exp $"); | 15 | RCSID("$OpenBSD: readconf.c,v 1.132 2004/06/13 15:03:02 djm Exp $"); |
16 | 16 | ||
17 | #include "ssh.h" | 17 | #include "ssh.h" |
18 | #include "xmalloc.h" | 18 | #include "xmalloc.h" |
@@ -106,7 +106,7 @@ typedef enum { | |||
106 | oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, | 106 | oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, |
107 | oAddressFamily, oGssAuthentication, oGssDelegateCreds, | 107 | oAddressFamily, oGssAuthentication, oGssDelegateCreds, |
108 | oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, | 108 | oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, |
109 | oSendEnv, | 109 | oSendEnv, oControlPath, oControlMaster, |
110 | oDeprecated, oUnsupported | 110 | oDeprecated, oUnsupported |
111 | } OpCodes; | 111 | } OpCodes; |
112 | 112 | ||
@@ -195,6 +195,8 @@ static struct { | |||
195 | { "serveraliveinterval", oServerAliveInterval }, | 195 | { "serveraliveinterval", oServerAliveInterval }, |
196 | { "serveralivecountmax", oServerAliveCountMax }, | 196 | { "serveralivecountmax", oServerAliveCountMax }, |
197 | { "sendenv", oSendEnv }, | 197 | { "sendenv", oSendEnv }, |
198 | { "controlpath", oControlPath }, | ||
199 | { "controlmaster", oControlMaster }, | ||
198 | { NULL, oBadOption } | 200 | { NULL, oBadOption } |
199 | }; | 201 | }; |
200 | 202 | ||
@@ -764,6 +766,14 @@ parse_int: | |||
764 | } | 766 | } |
765 | break; | 767 | break; |
766 | 768 | ||
769 | case oControlPath: | ||
770 | charptr = &options->control_path; | ||
771 | goto parse_string; | ||
772 | |||
773 | case oControlMaster: | ||
774 | intptr = &options->control_master; | ||
775 | goto parse_flag; | ||
776 | |||
767 | case oDeprecated: | 777 | case oDeprecated: |
768 | debug("%s line %d: Deprecated option \"%s\"", | 778 | debug("%s line %d: Deprecated option \"%s\"", |
769 | filename, linenum, keyword); | 779 | filename, linenum, keyword); |
@@ -905,6 +915,8 @@ initialize_options(Options * options) | |||
905 | options->server_alive_interval = -1; | 915 | options->server_alive_interval = -1; |
906 | options->server_alive_count_max = -1; | 916 | options->server_alive_count_max = -1; |
907 | options->num_send_env = 0; | 917 | options->num_send_env = 0; |
918 | options->control_path = NULL; | ||
919 | options->control_master = -1; | ||
908 | } | 920 | } |
909 | 921 | ||
910 | /* | 922 | /* |
@@ -1025,6 +1037,8 @@ fill_default_options(Options * options) | |||
1025 | options->server_alive_interval = 0; | 1037 | options->server_alive_interval = 0; |
1026 | if (options->server_alive_count_max == -1) | 1038 | if (options->server_alive_count_max == -1) |
1027 | options->server_alive_count_max = 3; | 1039 | options->server_alive_count_max = 3; |
1040 | if (options->control_master == -1) | ||
1041 | options->control_master = 0; | ||
1028 | /* options->proxy_command should not be set by default */ | 1042 | /* options->proxy_command should not be set by default */ |
1029 | /* options->user will be set in the main program if appropriate */ | 1043 | /* options->user will be set in the main program if appropriate */ |
1030 | /* options->hostname will be set in the main program if appropriate */ | 1044 | /* options->hostname will be set in the main program if appropriate */ |
diff --git a/readconf.h b/readconf.h index 668055943..5e504bece 100644 --- a/readconf.h +++ b/readconf.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: readconf.h,v 1.62 2004/04/27 09:46:37 djm Exp $ */ | 1 | /* $OpenBSD: readconf.h,v 1.63 2004/06/13 15:03:02 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
@@ -108,6 +108,9 @@ typedef struct { | |||
108 | 108 | ||
109 | int num_send_env; | 109 | int num_send_env; |
110 | char *send_env[MAX_SEND_ENV]; | 110 | char *send_env[MAX_SEND_ENV]; |
111 | |||
112 | char *control_path; | ||
113 | int control_master; | ||
111 | } Options; | 114 | } Options; |
112 | 115 | ||
113 | 116 | ||
@@ -9,7 +9,7 @@ | |||
9 | .\" | 9 | .\" |
10 | .\" Created: Sun May 7 00:14:37 1995 ylo | 10 | .\" Created: Sun May 7 00:14:37 1995 ylo |
11 | .\" | 11 | .\" |
12 | .\" $OpenBSD: scp.1,v 1.35 2004/05/04 18:36:07 jmc Exp $ | 12 | .\" $OpenBSD: scp.1,v 1.36 2004/06/13 15:03:02 djm Exp $ |
13 | .\" | 13 | .\" |
14 | .Dd September 25, 1999 | 14 | .Dd September 25, 1999 |
15 | .Dt SCP 1 | 15 | .Dt SCP 1 |
@@ -128,6 +128,8 @@ For full details of the options listed below, and their possible values, see | |||
128 | .It CompressionLevel | 128 | .It CompressionLevel |
129 | .It ConnectionAttempts | 129 | .It ConnectionAttempts |
130 | .It ConnectTimeout | 130 | .It ConnectTimeout |
131 | .It ControlMaster | ||
132 | .It ControlPath | ||
131 | .It GlobalKnownHostsFile | 133 | .It GlobalKnownHostsFile |
132 | .It GSSAPIAuthentication | 134 | .It GSSAPIAuthentication |
133 | .It GSSAPIDelegateCredentials | 135 | .It GSSAPIDelegateCredentials |
@@ -1,4 +1,4 @@ | |||
1 | .\" $OpenBSD: sftp.1,v 1.54 2004/05/02 23:02:17 dtucker Exp $ | 1 | .\" $OpenBSD: sftp.1,v 1.55 2004/06/13 15:03:02 djm Exp $ |
2 | .\" | 2 | .\" |
3 | .\" Copyright (c) 2001 Damien Miller. All rights reserved. | 3 | .\" Copyright (c) 2001 Damien Miller. All rights reserved. |
4 | .\" | 4 | .\" |
@@ -154,6 +154,8 @@ For full details of the options listed below, and their possible values, see | |||
154 | .It CompressionLevel | 154 | .It CompressionLevel |
155 | .It ConnectionAttempts | 155 | .It ConnectionAttempts |
156 | .It ConnectTimeout | 156 | .It ConnectTimeout |
157 | .It ControlMaster | ||
158 | .It ControlPath | ||
157 | .It GlobalKnownHostsFile | 159 | .It GlobalKnownHostsFile |
158 | .It GSSAPIAuthentication | 160 | .It GSSAPIAuthentication |
159 | .It GSSAPIDelegateCredentials | 161 | .It GSSAPIDelegateCredentials |
diff --git a/ssh-rand-helper.c b/ssh-rand-helper.c index 8a320a71e..471e7295b 100644 --- a/ssh-rand-helper.c +++ b/ssh-rand-helper.c | |||
@@ -39,7 +39,7 @@ | |||
39 | #include "pathnames.h" | 39 | #include "pathnames.h" |
40 | #include "log.h" | 40 | #include "log.h" |
41 | 41 | ||
42 | RCSID("$Id: ssh-rand-helper.c,v 1.16 2003/11/21 12:56:47 djm Exp $"); | 42 | RCSID("$Id: ssh-rand-helper.c,v 1.17 2004/06/15 00:34:08 djm Exp $"); |
43 | 43 | ||
44 | /* Number of bytes we write out */ | 44 | /* Number of bytes we write out */ |
45 | #define OUTPUT_SEED_SIZE 48 | 45 | #define OUTPUT_SEED_SIZE 48 |
@@ -69,10 +69,6 @@ extern char *__progname; | |||
69 | char *__progname; | 69 | char *__progname; |
70 | #endif | 70 | #endif |
71 | 71 | ||
72 | #ifndef offsetof | ||
73 | # define offsetof(type, member) ((size_t) &((type *)0)->member) | ||
74 | #endif | ||
75 | |||
76 | #define WHITESPACE " \t\n" | 72 | #define WHITESPACE " \t\n" |
77 | 73 | ||
78 | #ifndef RUSAGE_SELF | 74 | #ifndef RUSAGE_SELF |
@@ -34,7 +34,7 @@ | |||
34 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 34 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
35 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 35 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
36 | .\" | 36 | .\" |
37 | .\" $OpenBSD: ssh.1,v 1.189 2004/06/13 14:01:42 dtucker Exp $ | 37 | .\" $OpenBSD: ssh.1,v 1.190 2004/06/13 15:03:02 djm Exp $ |
38 | .Dd September 25, 1999 | 38 | .Dd September 25, 1999 |
39 | .Dt SSH 1 | 39 | .Dt SSH 1 |
40 | .Os | 40 | .Os |
@@ -43,7 +43,7 @@ | |||
43 | .Nd OpenSSH SSH client (remote login program) | 43 | .Nd OpenSSH SSH client (remote login program) |
44 | .Sh SYNOPSIS | 44 | .Sh SYNOPSIS |
45 | .Nm ssh | 45 | .Nm ssh |
46 | .Op Fl 1246AaCfgkNnqsTtVvXxY | 46 | .Op Fl 1246AaCfgkMNnqSsTtVvXxY |
47 | .Op Fl b Ar bind_address | 47 | .Op Fl b Ar bind_address |
48 | .Op Fl c Ar cipher_spec | 48 | .Op Fl c Ar cipher_spec |
49 | .Op Fl D Ar port | 49 | .Op Fl D Ar port |
@@ -605,6 +605,17 @@ be specified in order of preference. | |||
605 | See the | 605 | See the |
606 | .Cm MACs | 606 | .Cm MACs |
607 | keyword for more information. | 607 | keyword for more information. |
608 | .It Fl M | ||
609 | Places the | ||
610 | .Nm | ||
611 | client into | ||
612 | .Dq master | ||
613 | mode for connection sharing. | ||
614 | Refer to the description of | ||
615 | .Cm ControlMaster | ||
616 | in | ||
617 | .Xr ssh_config 5 | ||
618 | for details. | ||
608 | .It Fl N | 619 | .It Fl N |
609 | Do not execute a remote command. | 620 | Do not execute a remote command. |
610 | This is useful for just forwarding ports | 621 | This is useful for just forwarding ports |
@@ -649,6 +660,8 @@ For full details of the options listed below, and their possible values, see | |||
649 | .It CompressionLevel | 660 | .It CompressionLevel |
650 | .It ConnectionAttempts | 661 | .It ConnectionAttempts |
651 | .It ConnectTimeout | 662 | .It ConnectTimeout |
663 | .It ControlMaster | ||
664 | .It ControlPath | ||
652 | .It DynamicForward | 665 | .It DynamicForward |
653 | .It EscapeChar | 666 | .It EscapeChar |
654 | .It ForwardAgent | 667 | .It ForwardAgent |
@@ -724,6 +737,15 @@ IPv6 addresses can be specified with an alternative syntax: | |||
724 | .Ar hostport . | 737 | .Ar hostport . |
725 | .Xc | 738 | .Xc |
726 | .Sm on | 739 | .Sm on |
740 | .It Fl S | ||
741 | Places the | ||
742 | .Nm | ||
743 | client into slave mode for connection sharing. | ||
744 | Refer to the description of | ||
745 | .Cm ControlMaster | ||
746 | in | ||
747 | .Xr ssh_config 5 | ||
748 | for details. | ||
727 | .It Fl s | 749 | .It Fl s |
728 | May be used to request invocation of a subsystem on the remote system. | 750 | May be used to request invocation of a subsystem on the remote system. |
729 | Subsystems are a feature of the SSH2 protocol which facilitate the use | 751 | Subsystems are a feature of the SSH2 protocol which facilitate the use |
@@ -40,7 +40,7 @@ | |||
40 | */ | 40 | */ |
41 | 41 | ||
42 | #include "includes.h" | 42 | #include "includes.h" |
43 | RCSID("$OpenBSD: ssh.c,v 1.213 2004/05/08 00:01:37 deraadt Exp $"); | 43 | RCSID("$OpenBSD: ssh.c,v 1.214 2004/06/13 15:03:02 djm Exp $"); |
44 | 44 | ||
45 | #include <openssl/evp.h> | 45 | #include <openssl/evp.h> |
46 | #include <openssl/err.h> | 46 | #include <openssl/err.h> |
@@ -53,21 +53,24 @@ RCSID("$OpenBSD: ssh.c,v 1.213 2004/05/08 00:01:37 deraadt Exp $"); | |||
53 | #include "xmalloc.h" | 53 | #include "xmalloc.h" |
54 | #include "packet.h" | 54 | #include "packet.h" |
55 | #include "buffer.h" | 55 | #include "buffer.h" |
56 | #include "bufaux.h" | ||
56 | #include "channels.h" | 57 | #include "channels.h" |
57 | #include "key.h" | 58 | #include "key.h" |
58 | #include "authfd.h" | 59 | #include "authfd.h" |
59 | #include "authfile.h" | 60 | #include "authfile.h" |
60 | #include "pathnames.h" | 61 | #include "pathnames.h" |
62 | #include "dispatch.h" | ||
61 | #include "clientloop.h" | 63 | #include "clientloop.h" |
62 | #include "log.h" | 64 | #include "log.h" |
63 | #include "readconf.h" | 65 | #include "readconf.h" |
64 | #include "sshconnect.h" | 66 | #include "sshconnect.h" |
65 | #include "dispatch.h" | ||
66 | #include "misc.h" | 67 | #include "misc.h" |
67 | #include "kex.h" | 68 | #include "kex.h" |
68 | #include "mac.h" | 69 | #include "mac.h" |
69 | #include "sshpty.h" | 70 | #include "sshpty.h" |
70 | #include "match.h" | 71 | #include "match.h" |
72 | #include "msg.h" | ||
73 | #include "monitor_fdpass.h" | ||
71 | 74 | ||
72 | #ifdef SMARTCARD | 75 | #ifdef SMARTCARD |
73 | #include "scard.h" | 76 | #include "scard.h" |
@@ -141,6 +144,13 @@ static int client_global_request_id = 0; | |||
141 | /* pid of proxycommand child process */ | 144 | /* pid of proxycommand child process */ |
142 | pid_t proxy_command_pid = 0; | 145 | pid_t proxy_command_pid = 0; |
143 | 146 | ||
147 | /* fd to control socket */ | ||
148 | int control_fd = -1; | ||
149 | |||
150 | /* Only used in control client mode */ | ||
151 | volatile sig_atomic_t control_client_terminate = 0; | ||
152 | u_int control_server_pid = 0; | ||
153 | |||
144 | /* Prints a help message to the user. This function never returns. */ | 154 | /* Prints a help message to the user. This function never returns. */ |
145 | 155 | ||
146 | static void | 156 | static void |
@@ -158,6 +168,7 @@ usage(void) | |||
158 | static int ssh_session(void); | 168 | static int ssh_session(void); |
159 | static int ssh_session2(void); | 169 | static int ssh_session2(void); |
160 | static void load_public_identity_files(void); | 170 | static void load_public_identity_files(void); |
171 | static void control_client(const char *path); | ||
161 | 172 | ||
162 | /* | 173 | /* |
163 | * Main program for the ssh client. | 174 | * Main program for the ssh client. |
@@ -228,7 +239,7 @@ main(int ac, char **av) | |||
228 | 239 | ||
229 | again: | 240 | again: |
230 | while ((opt = getopt(ac, av, | 241 | while ((opt = getopt(ac, av, |
231 | "1246ab:c:e:fgi:kl:m:no:p:qstvxACD:F:I:L:NPR:TVXY")) != -1) { | 242 | "1246ab:c:e:fgi:kl:m:no:p:qstvxACD:F:I:L:MNPR:S:TVXY")) != -1) { |
232 | switch (opt) { | 243 | switch (opt) { |
233 | case '1': | 244 | case '1': |
234 | options.protocol = SSH_PROTO_1; | 245 | options.protocol = SSH_PROTO_1; |
@@ -364,6 +375,9 @@ again: | |||
364 | exit(1); | 375 | exit(1); |
365 | } | 376 | } |
366 | break; | 377 | break; |
378 | case 'M': | ||
379 | options.control_master = 1; | ||
380 | break; | ||
367 | case 'p': | 381 | case 'p': |
368 | options.port = a2port(optarg); | 382 | options.port = a2port(optarg); |
369 | if (options.port == 0) { | 383 | if (options.port == 0) { |
@@ -432,6 +446,13 @@ again: | |||
432 | case 's': | 446 | case 's': |
433 | subsystem_flag = 1; | 447 | subsystem_flag = 1; |
434 | break; | 448 | break; |
449 | case 'S': | ||
450 | if (options.control_path != NULL) | ||
451 | free(options.control_path); | ||
452 | options.control_path = xstrdup(optarg); | ||
453 | if (options.control_master == -1) | ||
454 | options.control_master = 0; | ||
455 | break; | ||
435 | case 'b': | 456 | case 'b': |
436 | options.bind_address = optarg; | 457 | options.bind_address = optarg; |
437 | break; | 458 | break; |
@@ -566,6 +587,13 @@ again: | |||
566 | strcmp(options.proxy_command, "none") == 0) | 587 | strcmp(options.proxy_command, "none") == 0) |
567 | options.proxy_command = NULL; | 588 | options.proxy_command = NULL; |
568 | 589 | ||
590 | if (options.control_path != NULL) { | ||
591 | options.control_path = tilde_expand_filename( | ||
592 | options.control_path, original_real_uid); | ||
593 | } | ||
594 | if (options.control_path != NULL && options.control_master == 0) | ||
595 | control_client(options.control_path); /* This doesn't return */ | ||
596 | |||
569 | /* Open a connection to the remote host. */ | 597 | /* Open a connection to the remote host. */ |
570 | if (ssh_connect(host, &hostaddr, options.port, | 598 | if (ssh_connect(host, &hostaddr, options.port, |
571 | options.address_family, options.connection_attempts, | 599 | options.address_family, options.connection_attempts, |
@@ -678,6 +706,9 @@ again: | |||
678 | exit_status = compat20 ? ssh_session2() : ssh_session(); | 706 | exit_status = compat20 ? ssh_session2() : ssh_session(); |
679 | packet_close(); | 707 | packet_close(); |
680 | 708 | ||
709 | if (options.control_path != NULL && control_fd != -1) | ||
710 | unlink(options.control_path); | ||
711 | |||
681 | /* | 712 | /* |
682 | * Send SIGHUP to proxy command if used. We don't wait() in | 713 | * Send SIGHUP to proxy command if used. We don't wait() in |
683 | * case it hangs and instead rely on init to reap the child | 714 | * case it hangs and instead rely on init to reap the child |
@@ -974,7 +1005,7 @@ ssh_session(void) | |||
974 | } | 1005 | } |
975 | 1006 | ||
976 | static void | 1007 | static void |
977 | client_subsystem_reply(int type, u_int32_t seq, void *ctxt) | 1008 | ssh_subsystem_reply(int type, u_int32_t seq, void *ctxt) |
978 | { | 1009 | { |
979 | int id, len; | 1010 | int id, len; |
980 | 1011 | ||
@@ -1006,40 +1037,50 @@ client_global_request_reply_fwd(int type, u_int32_t seq, void *ctxt) | |||
1006 | options.remote_forwards[i].port); | 1037 | options.remote_forwards[i].port); |
1007 | } | 1038 | } |
1008 | 1039 | ||
1009 | /* request pty/x11/agent/tcpfwd/shell for channel */ | ||
1010 | static void | 1040 | static void |
1011 | ssh_session2_setup(int id, void *arg) | 1041 | ssh_control_listener(void) |
1012 | { | 1042 | { |
1013 | int len; | 1043 | struct sockaddr_un addr; |
1014 | int interactive = 0; | 1044 | mode_t old_umask; |
1015 | struct termios tio; | 1045 | |
1046 | if (options.control_path == NULL || options.control_master != 1) | ||
1047 | return; | ||
1016 | 1048 | ||
1017 | debug2("ssh_session2_setup: id %d", id); | 1049 | memset(&addr, '\0', sizeof(addr)); |
1050 | addr.sun_family = AF_UNIX; | ||
1051 | addr.sun_len = offsetof(struct sockaddr_un, sun_path) + | ||
1052 | strlen(options.control_path) + 1; | ||
1018 | 1053 | ||
1019 | if (tty_flag) { | 1054 | if (strlcpy(addr.sun_path, options.control_path, |
1020 | struct winsize ws; | 1055 | sizeof(addr.sun_path)) >= sizeof(addr.sun_path)) |
1021 | char *cp; | 1056 | fatal("ControlPath too long"); |
1022 | cp = getenv("TERM"); | ||
1023 | if (!cp) | ||
1024 | cp = ""; | ||
1025 | /* Store window size in the packet. */ | ||
1026 | if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0) | ||
1027 | memset(&ws, 0, sizeof(ws)); | ||
1028 | 1057 | ||
1029 | channel_request_start(id, "pty-req", 0); | 1058 | if ((control_fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) |
1030 | packet_put_cstring(cp); | 1059 | fatal("%s socket(): %s\n", __func__, strerror(errno)); |
1031 | packet_put_int(ws.ws_col); | 1060 | |
1032 | packet_put_int(ws.ws_row); | 1061 | old_umask = umask(0177); |
1033 | packet_put_int(ws.ws_xpixel); | 1062 | if (bind(control_fd, (struct sockaddr*)&addr, addr.sun_len) == -1) { |
1034 | packet_put_int(ws.ws_ypixel); | 1063 | control_fd = -1; |
1035 | tio = get_saved_tio(); | 1064 | if (errno == EINVAL) |
1036 | tty_make_modes(/*ignored*/ 0, &tio); | 1065 | fatal("ControlSocket %s already exists", |
1037 | packet_send(); | 1066 | options.control_path); |
1038 | interactive = 1; | 1067 | else |
1039 | /* XXX wait for reply */ | 1068 | fatal("%s bind(): %s\n", __func__, strerror(errno)); |
1040 | } | 1069 | } |
1041 | if (options.forward_x11 && | 1070 | umask(old_umask); |
1042 | getenv("DISPLAY") != NULL) { | 1071 | |
1072 | if (listen(control_fd, 64) == -1) | ||
1073 | fatal("%s listen(): %s\n", __func__, strerror(errno)); | ||
1074 | |||
1075 | set_nonblock(control_fd); | ||
1076 | } | ||
1077 | |||
1078 | /* request pty/x11/agent/tcpfwd/shell for channel */ | ||
1079 | static void | ||
1080 | ssh_session2_setup(int id, void *arg) | ||
1081 | { | ||
1082 | int interactive = tty_flag; | ||
1083 | if (options.forward_x11 && getenv("DISPLAY") != NULL) { | ||
1043 | char *proto, *data; | 1084 | char *proto, *data; |
1044 | /* Get reasonable local authentication information. */ | 1085 | /* Get reasonable local authentication information. */ |
1045 | x11_get_proto(&proto, &data); | 1086 | x11_get_proto(&proto, &data); |
@@ -1057,65 +1098,8 @@ ssh_session2_setup(int id, void *arg) | |||
1057 | packet_send(); | 1098 | packet_send(); |
1058 | } | 1099 | } |
1059 | 1100 | ||
1060 | /* Transfer any environment variables from client to server */ | 1101 | client_session2_setup(id, tty_flag, subsystem_flag, getenv("TERM"), |
1061 | if (options.num_send_env != 0) { | 1102 | NULL, fileno(stdin), &command, &ssh_subsystem_reply); |
1062 | int i, j, matched; | ||
1063 | extern char **environ; | ||
1064 | char *name, *val; | ||
1065 | |||
1066 | debug("Sending environment."); | ||
1067 | for (i = 0; environ && environ[i] != NULL; i++) { | ||
1068 | /* Split */ | ||
1069 | name = xstrdup(environ[i]); | ||
1070 | if ((val = strchr(name, '=')) == NULL) { | ||
1071 | free(name); | ||
1072 | continue; | ||
1073 | } | ||
1074 | *val++ = '\0'; | ||
1075 | |||
1076 | matched = 0; | ||
1077 | for (j = 0; j < options.num_send_env; j++) { | ||
1078 | if (match_pattern(name, options.send_env[j])) { | ||
1079 | matched = 1; | ||
1080 | break; | ||
1081 | } | ||
1082 | } | ||
1083 | if (!matched) { | ||
1084 | debug3("Ignored env %s", name); | ||
1085 | free(name); | ||
1086 | continue; | ||
1087 | } | ||
1088 | |||
1089 | debug("Sending env %s = %s", name, val); | ||
1090 | channel_request_start(id, "env", 0); | ||
1091 | packet_put_cstring(name); | ||
1092 | packet_put_cstring(val); | ||
1093 | packet_send(); | ||
1094 | free(name); | ||
1095 | } | ||
1096 | } | ||
1097 | |||
1098 | len = buffer_len(&command); | ||
1099 | if (len > 0) { | ||
1100 | if (len > 900) | ||
1101 | len = 900; | ||
1102 | if (subsystem_flag) { | ||
1103 | debug("Sending subsystem: %.*s", len, (u_char *)buffer_ptr(&command)); | ||
1104 | channel_request_start(id, "subsystem", /*want reply*/ 1); | ||
1105 | /* register callback for reply */ | ||
1106 | /* XXX we assume that client_loop has already been called */ | ||
1107 | dispatch_set(SSH2_MSG_CHANNEL_FAILURE, &client_subsystem_reply); | ||
1108 | dispatch_set(SSH2_MSG_CHANNEL_SUCCESS, &client_subsystem_reply); | ||
1109 | } else { | ||
1110 | debug("Sending command: %.*s", len, (u_char *)buffer_ptr(&command)); | ||
1111 | channel_request_start(id, "exec", 0); | ||
1112 | } | ||
1113 | packet_put_string(buffer_ptr(&command), buffer_len(&command)); | ||
1114 | packet_send(); | ||
1115 | } else { | ||
1116 | channel_request_start(id, "shell", 0); | ||
1117 | packet_send(); | ||
1118 | } | ||
1119 | 1103 | ||
1120 | packet_set_interactive(interactive); | 1104 | packet_set_interactive(interactive); |
1121 | } | 1105 | } |
@@ -1161,7 +1145,7 @@ ssh_session2_open(void) | |||
1161 | 1145 | ||
1162 | channel_send_open(c->self); | 1146 | channel_send_open(c->self); |
1163 | if (!no_shell_flag) | 1147 | if (!no_shell_flag) |
1164 | channel_register_confirm(c->self, ssh_session2_setup); | 1148 | channel_register_confirm(c->self, ssh_session2_setup, NULL); |
1165 | 1149 | ||
1166 | return c->self; | 1150 | return c->self; |
1167 | } | 1151 | } |
@@ -1173,6 +1157,7 @@ ssh_session2(void) | |||
1173 | 1157 | ||
1174 | /* XXX should be pre-session */ | 1158 | /* XXX should be pre-session */ |
1175 | ssh_init_forwarding(); | 1159 | ssh_init_forwarding(); |
1160 | ssh_control_listener(); | ||
1176 | 1161 | ||
1177 | if (!no_shell_flag || (datafellows & SSH_BUG_DUMMYCHAN)) | 1162 | if (!no_shell_flag || (datafellows & SSH_BUG_DUMMYCHAN)) |
1178 | id = ssh_session2_open(); | 1163 | id = ssh_session2_open(); |
@@ -1226,3 +1211,110 @@ load_public_identity_files(void) | |||
1226 | options.identity_keys[i] = public; | 1211 | options.identity_keys[i] = public; |
1227 | } | 1212 | } |
1228 | } | 1213 | } |
1214 | |||
1215 | static void | ||
1216 | control_client_sighandler(int signo) | ||
1217 | { | ||
1218 | control_client_terminate = signo; | ||
1219 | } | ||
1220 | |||
1221 | static void | ||
1222 | control_client_sigrelay(int signo) | ||
1223 | { | ||
1224 | if (control_server_pid > 1) | ||
1225 | kill(control_server_pid, signo); | ||
1226 | } | ||
1227 | |||
1228 | static void | ||
1229 | control_client(const char *path) | ||
1230 | { | ||
1231 | struct sockaddr_un addr; | ||
1232 | int r, sock, exitval; | ||
1233 | Buffer m; | ||
1234 | char *cp; | ||
1235 | |||
1236 | memset(&addr, '\0', sizeof(addr)); | ||
1237 | addr.sun_family = AF_UNIX; | ||
1238 | addr.sun_len = offsetof(struct sockaddr_un, sun_path) + | ||
1239 | strlen(path) + 1; | ||
1240 | |||
1241 | if (strlcpy(addr.sun_path, path, | ||
1242 | sizeof(addr.sun_path)) >= sizeof(addr.sun_path)) | ||
1243 | fatal("ControlPath too long"); | ||
1244 | |||
1245 | if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) | ||
1246 | fatal("%s socket(): %s", __func__, strerror(errno)); | ||
1247 | |||
1248 | if (connect(sock, (struct sockaddr*)&addr, addr.sun_len) == -1) | ||
1249 | fatal("Couldn't connect to %s: %s", path, strerror(errno)); | ||
1250 | |||
1251 | if ((cp = getenv("TERM")) == NULL) | ||
1252 | cp = ""; | ||
1253 | |||
1254 | signal(SIGINT, control_client_sighandler); | ||
1255 | signal(SIGTERM, control_client_sighandler); | ||
1256 | signal(SIGWINCH, control_client_sigrelay); | ||
1257 | |||
1258 | buffer_init(&m); | ||
1259 | |||
1260 | /* Get PID of controlee */ | ||
1261 | if (ssh_msg_recv(sock, &m) == -1) | ||
1262 | fatal("%s: msg_recv", __func__); | ||
1263 | if (buffer_get_char(&m) != 0) | ||
1264 | fatal("%s: wrong version", __func__); | ||
1265 | control_server_pid = buffer_get_int(&m); | ||
1266 | |||
1267 | /* XXX: env passing */ | ||
1268 | |||
1269 | buffer_clear(&m); | ||
1270 | buffer_put_int(&m, tty_flag); | ||
1271 | buffer_put_int(&m, subsystem_flag); | ||
1272 | buffer_put_cstring(&m, cp); | ||
1273 | |||
1274 | buffer_append(&command, "\0", 1); | ||
1275 | buffer_put_cstring(&m, buffer_ptr(&command)); | ||
1276 | |||
1277 | if (ssh_msg_send(sock, /* version */0, &m) == -1) | ||
1278 | fatal("%s: msg_send", __func__); | ||
1279 | |||
1280 | mm_send_fd(sock, STDIN_FILENO); | ||
1281 | mm_send_fd(sock, STDOUT_FILENO); | ||
1282 | mm_send_fd(sock, STDERR_FILENO); | ||
1283 | |||
1284 | /* Wait for reply, so master has a chance to gather ttymodes */ | ||
1285 | buffer_clear(&m); | ||
1286 | if (ssh_msg_recv(sock, &m) == -1) | ||
1287 | fatal("%s: msg_recv", __func__); | ||
1288 | if (buffer_get_char(&m) != 0) | ||
1289 | fatal("%s: master returned error", __func__); | ||
1290 | buffer_free(&m); | ||
1291 | |||
1292 | if (tty_flag) | ||
1293 | enter_raw_mode(); | ||
1294 | |||
1295 | /* Stick around until the controlee closes the client_fd */ | ||
1296 | exitval = 0; | ||
1297 | for (;!control_client_terminate;) { | ||
1298 | r = read(sock, &exitval, sizeof(exitval)); | ||
1299 | if (r == 0) { | ||
1300 | debug2("Received EOF from master"); | ||
1301 | break; | ||
1302 | } | ||
1303 | if (r > 0) | ||
1304 | debug2("Received exit status from master %d", exitval); | ||
1305 | if (r == -1 && errno != EINTR) | ||
1306 | fatal("%s: read %s", __func__, strerror(errno)); | ||
1307 | } | ||
1308 | |||
1309 | if (control_client_terminate) | ||
1310 | debug2("Exiting on signal %d", control_client_terminate); | ||
1311 | |||
1312 | close(sock); | ||
1313 | |||
1314 | leave_raw_mode(); | ||
1315 | |||
1316 | if (tty_flag && options.log_level != SYSLOG_LEVEL_QUIET) | ||
1317 | fprintf(stderr, "Connection to master closed.\r\n"); | ||
1318 | |||
1319 | exit(exitval); | ||
1320 | } | ||
diff --git a/ssh_config.5 b/ssh_config.5 index 46d3012c8..bab11d313 100644 --- a/ssh_config.5 +++ b/ssh_config.5 | |||
@@ -34,7 +34,7 @@ | |||
34 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 34 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
35 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 35 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
36 | .\" | 36 | .\" |
37 | .\" $OpenBSD: ssh_config.5,v 1.35 2004/06/13 14:01:42 dtucker Exp $ | 37 | .\" $OpenBSD: ssh_config.5,v 1.36 2004/06/13 15:03:02 djm Exp $ |
38 | .Dd September 25, 1999 | 38 | .Dd September 25, 1999 |
39 | .Dt SSH_CONFIG 5 | 39 | .Dt SSH_CONFIG 5 |
40 | .Os | 40 | .Os |
@@ -256,6 +256,28 @@ will act as a SOCKS server. | |||
256 | Multiple forwardings may be specified, and | 256 | Multiple forwardings may be specified, and |
257 | additional forwardings can be given on the command line. | 257 | additional forwardings can be given on the command line. |
258 | Only the superuser can forward privileged ports. | 258 | Only the superuser can forward privileged ports. |
259 | .It Cm ControlMaster | ||
260 | Enables the sharing of multiple sessions over a single network connection. | ||
261 | When set to | ||
262 | .Dq yes | ||
263 | .Nm ssh | ||
264 | will listen for connections on a control socket specified using the | ||
265 | .Cm ControlPath | ||
266 | argument. | ||
267 | Additional sessions can connect to this socket using the same | ||
268 | .Cm ControlPath | ||
269 | with | ||
270 | .Cm ControlMaster | ||
271 | set to | ||
272 | .Dq no | ||
273 | (the default.) | ||
274 | These sessions will reuse the master instance's network connection rather | ||
275 | than initiating new ones. | ||
276 | .It Cm ControlPath | ||
277 | Specify a the path to the control socket used for connection sharing. | ||
278 | See | ||
279 | .Cm ControlMaster | ||
280 | above. | ||
259 | .It Cm EnableSSHKeysign | 281 | .It Cm EnableSSHKeysign |
260 | Setting this option to | 282 | Setting this option to |
261 | .Dq yes | 283 | .Dq yes |