diff options
-rw-r--r-- | ChangeLog | 8 | ||||
-rw-r--r-- | clientloop.c | 63 | ||||
-rw-r--r-- | readconf.c | 36 | ||||
-rw-r--r-- | readconf.h | 4 | ||||
-rw-r--r-- | ssh.c | 117 | ||||
-rw-r--r-- | ssh_config.5 | 26 |
6 files changed, 223 insertions, 31 deletions
@@ -16,6 +16,14 @@ | |||
16 | bz#1797: fix swapped args in upload_dir_internal(), breaking recursive | 16 | bz#1797: fix swapped args in upload_dir_internal(), breaking recursive |
17 | upload depth checks and causing verbose printing of transfers to always | 17 | upload depth checks and causing verbose printing of transfers to always |
18 | be turned on; patch from imorgan AT nas.nasa.gov | 18 | be turned on; patch from imorgan AT nas.nasa.gov |
19 | - djm@cvs.openbsd.org 2010/07/19 09:15:12 | ||
20 | [clientloop.c readconf.c readconf.h ssh.c ssh_config.5] | ||
21 | add a "ControlPersist" option that automatically starts a background | ||
22 | ssh(1) multiplex master when connecting. This connection can stay alive | ||
23 | indefinitely, or can be set to automatically close after a user-specified | ||
24 | duration of inactivity. bz#1330 - patch by dwmw2 AT infradead.org, but | ||
25 | further hacked on by wmertens AT cisco.com, apb AT cequrux.com, | ||
26 | martin-mindrot-bugzilla AT earth.li and myself; "looks ok" markus@ | ||
19 | 27 | ||
20 | 20100819 | 28 | 20100819 |
21 | - (dtucker) [contrib/ssh-copy-ud.1] Bug #1786: update ssh-copy-id.1 with more | 29 | - (dtucker) [contrib/ssh-copy-ud.1] Bug #1786: update ssh-copy-id.1 with more |
diff --git a/clientloop.c b/clientloop.c index 5608bcc2e..de7979366 100644 --- a/clientloop.c +++ b/clientloop.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: clientloop.c,v 1.221 2010/06/25 23:15:36 djm Exp $ */ | 1 | /* $OpenBSD: clientloop.c,v 1.222 2010/07/19 09:15:12 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 |
@@ -145,6 +145,9 @@ static volatile sig_atomic_t received_signal = 0; | |||
145 | /* Flag indicating whether the user's terminal is in non-blocking mode. */ | 145 | /* Flag indicating whether the user's terminal is in non-blocking mode. */ |
146 | static int in_non_blocking_mode = 0; | 146 | static int in_non_blocking_mode = 0; |
147 | 147 | ||
148 | /* Time when backgrounded control master using ControlPersist should exit */ | ||
149 | static time_t control_persist_exit_time = 0; | ||
150 | |||
148 | /* Common data for the client loop code. */ | 151 | /* Common data for the client loop code. */ |
149 | volatile sig_atomic_t quit_pending; /* Set non-zero to quit the loop. */ | 152 | volatile sig_atomic_t quit_pending; /* Set non-zero to quit the loop. */ |
150 | static int escape_char1; /* Escape character. (proto1 only) */ | 153 | static int escape_char1; /* Escape character. (proto1 only) */ |
@@ -252,6 +255,34 @@ get_current_time(void) | |||
252 | return (double) tv.tv_sec + (double) tv.tv_usec / 1000000.0; | 255 | return (double) tv.tv_sec + (double) tv.tv_usec / 1000000.0; |
253 | } | 256 | } |
254 | 257 | ||
258 | /* | ||
259 | * Sets control_persist_exit_time to the absolute time when the | ||
260 | * backgrounded control master should exit due to expiry of the | ||
261 | * ControlPersist timeout. Sets it to 0 if we are not a backgrounded | ||
262 | * control master process, or if there is no ControlPersist timeout. | ||
263 | */ | ||
264 | static void | ||
265 | set_control_persist_exit_time(void) | ||
266 | { | ||
267 | if (muxserver_sock == -1 || !options.control_persist | ||
268 | || options.control_persist_timeout == 0) | ||
269 | /* not using a ControlPersist timeout */ | ||
270 | control_persist_exit_time = 0; | ||
271 | else if (channel_still_open()) { | ||
272 | /* some client connections are still open */ | ||
273 | if (control_persist_exit_time > 0) | ||
274 | debug2("%s: cancel scheduled exit", __func__); | ||
275 | control_persist_exit_time = 0; | ||
276 | } else if (control_persist_exit_time <= 0) { | ||
277 | /* a client connection has recently closed */ | ||
278 | control_persist_exit_time = time(NULL) + | ||
279 | (time_t)options.control_persist_timeout; | ||
280 | debug2("%s: schedule exit in %d seconds", __func__, | ||
281 | options.control_persist_timeout); | ||
282 | } | ||
283 | /* else we are already counting down to the timeout */ | ||
284 | } | ||
285 | |||
255 | #define SSH_X11_PROTO "MIT-MAGIC-COOKIE-1" | 286 | #define SSH_X11_PROTO "MIT-MAGIC-COOKIE-1" |
256 | void | 287 | void |
257 | client_x11_get_proto(const char *display, const char *xauth_path, | 288 | client_x11_get_proto(const char *display, const char *xauth_path, |
@@ -533,6 +564,7 @@ client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, | |||
533 | int *maxfdp, u_int *nallocp, int rekeying) | 564 | int *maxfdp, u_int *nallocp, int rekeying) |
534 | { | 565 | { |
535 | struct timeval tv, *tvp; | 566 | struct timeval tv, *tvp; |
567 | int timeout_secs; | ||
536 | int ret; | 568 | int ret; |
537 | 569 | ||
538 | /* Add any selections by the channel mechanism. */ | 570 | /* Add any selections by the channel mechanism. */ |
@@ -576,16 +608,27 @@ client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, | |||
576 | /* | 608 | /* |
577 | * Wait for something to happen. This will suspend the process until | 609 | * Wait for something to happen. This will suspend the process until |
578 | * some selected descriptor can be read, written, or has some other | 610 | * some selected descriptor can be read, written, or has some other |
579 | * event pending. | 611 | * event pending, or a timeout expires. |
580 | */ | 612 | */ |
581 | 613 | ||
582 | if (options.server_alive_interval == 0 || !compat20) | 614 | timeout_secs = INT_MAX; /* we use INT_MAX to mean no timeout */ |
615 | if (options.server_alive_interval > 0 && compat20) | ||
616 | timeout_secs = options.server_alive_interval; | ||
617 | set_control_persist_exit_time(); | ||
618 | if (control_persist_exit_time > 0) { | ||
619 | timeout_secs = MIN(timeout_secs, | ||
620 | control_persist_exit_time - time(NULL)); | ||
621 | if (timeout_secs < 0) | ||
622 | timeout_secs = 0; | ||
623 | } | ||
624 | if (timeout_secs == INT_MAX) | ||
583 | tvp = NULL; | 625 | tvp = NULL; |
584 | else { | 626 | else { |
585 | tv.tv_sec = options.server_alive_interval; | 627 | tv.tv_sec = timeout_secs; |
586 | tv.tv_usec = 0; | 628 | tv.tv_usec = 0; |
587 | tvp = &tv; | 629 | tvp = &tv; |
588 | } | 630 | } |
631 | |||
589 | ret = select((*maxfdp)+1, *readsetp, *writesetp, NULL, tvp); | 632 | ret = select((*maxfdp)+1, *readsetp, *writesetp, NULL, tvp); |
590 | if (ret < 0) { | 633 | if (ret < 0) { |
591 | char buf[100]; | 634 | char buf[100]; |
@@ -1478,6 +1521,18 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1478 | */ | 1521 | */ |
1479 | if (FD_ISSET(connection_out, writeset)) | 1522 | if (FD_ISSET(connection_out, writeset)) |
1480 | packet_write_poll(); | 1523 | packet_write_poll(); |
1524 | |||
1525 | /* | ||
1526 | * If we are a backgrounded control master, and the | ||
1527 | * timeout has expired without any active client | ||
1528 | * connections, then quit. | ||
1529 | */ | ||
1530 | if (control_persist_exit_time > 0) { | ||
1531 | if (time(NULL) >= control_persist_exit_time) { | ||
1532 | debug("ControlPersist timeout expired"); | ||
1533 | break; | ||
1534 | } | ||
1535 | } | ||
1481 | } | 1536 | } |
1482 | if (readset) | 1537 | if (readset) |
1483 | xfree(readset); | 1538 | xfree(readset); |
diff --git a/readconf.c b/readconf.c index da48ae7da..0296590e2 100644 --- a/readconf.c +++ b/readconf.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: readconf.c,v 1.186 2010/06/25 23:15:36 djm Exp $ */ | 1 | /* $OpenBSD: readconf.c,v 1.187 2010/07/19 09:15:12 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 |
@@ -128,7 +128,8 @@ typedef enum { | |||
128 | oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, | 128 | oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, |
129 | oAddressFamily, oGssAuthentication, oGssDelegateCreds, | 129 | oAddressFamily, oGssAuthentication, oGssDelegateCreds, |
130 | oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, | 130 | oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, |
131 | oSendEnv, oControlPath, oControlMaster, oHashKnownHosts, | 131 | oSendEnv, oControlPath, oControlMaster, oControlPersist, |
132 | oHashKnownHosts, | ||
132 | oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand, | 133 | oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand, |
133 | oVisualHostKey, oUseRoaming, oZeroKnowledgePasswordAuthentication, | 134 | oVisualHostKey, oUseRoaming, oZeroKnowledgePasswordAuthentication, |
134 | oDeprecated, oUnsupported | 135 | oDeprecated, oUnsupported |
@@ -225,6 +226,7 @@ static struct { | |||
225 | { "sendenv", oSendEnv }, | 226 | { "sendenv", oSendEnv }, |
226 | { "controlpath", oControlPath }, | 227 | { "controlpath", oControlPath }, |
227 | { "controlmaster", oControlMaster }, | 228 | { "controlmaster", oControlMaster }, |
229 | { "controlpersist", oControlPersist }, | ||
228 | { "hashknownhosts", oHashKnownHosts }, | 230 | { "hashknownhosts", oHashKnownHosts }, |
229 | { "tunnel", oTunnel }, | 231 | { "tunnel", oTunnel }, |
230 | { "tunneldevice", oTunnelDevice }, | 232 | { "tunneldevice", oTunnelDevice }, |
@@ -882,6 +884,30 @@ parse_int: | |||
882 | *intptr = value; | 884 | *intptr = value; |
883 | break; | 885 | break; |
884 | 886 | ||
887 | case oControlPersist: | ||
888 | /* no/false/yes/true, or a time spec */ | ||
889 | intptr = &options->control_persist; | ||
890 | arg = strdelim(&s); | ||
891 | if (!arg || *arg == '\0') | ||
892 | fatal("%.200s line %d: Missing ControlPersist" | ||
893 | " argument.", filename, linenum); | ||
894 | value = 0; | ||
895 | value2 = 0; /* timeout */ | ||
896 | if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0) | ||
897 | value = 0; | ||
898 | else if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0) | ||
899 | value = 1; | ||
900 | else if ((value2 = convtime(arg)) >= 0) | ||
901 | value = 1; | ||
902 | else | ||
903 | fatal("%.200s line %d: Bad ControlPersist argument.", | ||
904 | filename, linenum); | ||
905 | if (*activep && *intptr == -1) { | ||
906 | *intptr = value; | ||
907 | options->control_persist_timeout = value2; | ||
908 | } | ||
909 | break; | ||
910 | |||
885 | case oHashKnownHosts: | 911 | case oHashKnownHosts: |
886 | intptr = &options->hash_known_hosts; | 912 | intptr = &options->hash_known_hosts; |
887 | goto parse_flag; | 913 | goto parse_flag; |
@@ -1083,6 +1109,8 @@ initialize_options(Options * options) | |||
1083 | options->num_send_env = 0; | 1109 | options->num_send_env = 0; |
1084 | options->control_path = NULL; | 1110 | options->control_path = NULL; |
1085 | options->control_master = -1; | 1111 | options->control_master = -1; |
1112 | options->control_persist = -1; | ||
1113 | options->control_persist_timeout = 0; | ||
1086 | options->hash_known_hosts = -1; | 1114 | options->hash_known_hosts = -1; |
1087 | options->tun_open = -1; | 1115 | options->tun_open = -1; |
1088 | options->tun_local = -1; | 1116 | options->tun_local = -1; |
@@ -1218,6 +1246,10 @@ fill_default_options(Options * options) | |||
1218 | options->server_alive_count_max = 3; | 1246 | options->server_alive_count_max = 3; |
1219 | if (options->control_master == -1) | 1247 | if (options->control_master == -1) |
1220 | options->control_master = 0; | 1248 | options->control_master = 0; |
1249 | if (options->control_persist == -1) { | ||
1250 | options->control_persist = 0; | ||
1251 | options->control_persist_timeout = 0; | ||
1252 | } | ||
1221 | if (options->hash_known_hosts == -1) | 1253 | if (options->hash_known_hosts == -1) |
1222 | options->hash_known_hosts = 0; | 1254 | options->hash_known_hosts = 0; |
1223 | if (options->tun_open == -1) | 1255 | if (options->tun_open == -1) |
diff --git a/readconf.h b/readconf.h index 66acafdef..95d104674 100644 --- a/readconf.h +++ b/readconf.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: readconf.h,v 1.85 2010/06/25 23:15:36 djm Exp $ */ | 1 | /* $OpenBSD: readconf.h,v 1.86 2010/07/19 09:15:12 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
@@ -114,6 +114,8 @@ typedef struct { | |||
114 | 114 | ||
115 | char *control_path; | 115 | char *control_path; |
116 | int control_master; | 116 | int control_master; |
117 | int control_persist; /* ControlPersist flag */ | ||
118 | int control_persist_timeout; /* ControlPersist timeout (seconds) */ | ||
117 | 119 | ||
118 | int hash_known_hosts; | 120 | int hash_known_hosts; |
119 | 121 | ||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh.c,v 1.343 2010/07/12 22:41:13 djm Exp $ */ | 1 | /* $OpenBSD: ssh.c,v 1.344 2010/07/19 09:15:12 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 |
@@ -128,6 +128,15 @@ int no_shell_flag = 0; | |||
128 | int stdin_null_flag = 0; | 128 | int stdin_null_flag = 0; |
129 | 129 | ||
130 | /* | 130 | /* |
131 | * Flag indicating that the current process should be backgrounded and | ||
132 | * a new slave launched in the foreground for ControlPersist. | ||
133 | */ | ||
134 | int need_controlpersist_detach = 0; | ||
135 | |||
136 | /* Copies of flags for ControlPersist foreground slave */ | ||
137 | int ostdin_null_flag, ono_shell_flag, ono_tty_flag, otty_flag; | ||
138 | |||
139 | /* | ||
131 | * Flag indicating that ssh should fork after authentication. This is useful | 140 | * Flag indicating that ssh should fork after authentication. This is useful |
132 | * so that the passphrase can be entered manually, and then ssh goes to the | 141 | * so that the passphrase can be entered manually, and then ssh goes to the |
133 | * background. | 142 | * background. |
@@ -877,6 +886,50 @@ main(int ac, char **av) | |||
877 | return exit_status; | 886 | return exit_status; |
878 | } | 887 | } |
879 | 888 | ||
889 | static void | ||
890 | control_persist_detach(void) | ||
891 | { | ||
892 | pid_t pid; | ||
893 | |||
894 | debug("%s: backgrounding master process", __func__); | ||
895 | |||
896 | /* | ||
897 | * master (current process) into the background, and make the | ||
898 | * foreground process a client of the backgrounded master. | ||
899 | */ | ||
900 | switch ((pid = fork())) { | ||
901 | case -1: | ||
902 | fatal("%s: fork: %s", __func__, strerror(errno)); | ||
903 | case 0: | ||
904 | /* Child: master process continues mainloop */ | ||
905 | break; | ||
906 | default: | ||
907 | /* Parent: set up mux slave to connect to backgrounded master */ | ||
908 | debug2("%s: background process is %ld", __func__, (long)pid); | ||
909 | stdin_null_flag = ostdin_null_flag; | ||
910 | no_shell_flag = ono_shell_flag; | ||
911 | no_tty_flag = ono_tty_flag; | ||
912 | tty_flag = otty_flag; | ||
913 | close(muxserver_sock); | ||
914 | muxserver_sock = -1; | ||
915 | muxclient(options.control_path); | ||
916 | /* muxclient() doesn't return on success. */ | ||
917 | fatal("Failed to connect to new control master"); | ||
918 | } | ||
919 | } | ||
920 | |||
921 | /* Do fork() after authentication. Used by "ssh -f" */ | ||
922 | static void | ||
923 | fork_postauth(void) | ||
924 | { | ||
925 | if (need_controlpersist_detach) | ||
926 | control_persist_detach(); | ||
927 | debug("forking to background"); | ||
928 | fork_after_authentication_flag = 0; | ||
929 | if (daemon(1, 1) < 0) | ||
930 | fatal("daemon() failed: %.200s", strerror(errno)); | ||
931 | } | ||
932 | |||
880 | /* Callback for remote forward global requests */ | 933 | /* Callback for remote forward global requests */ |
881 | static void | 934 | static void |
882 | ssh_confirm_remote_forward(int type, u_int32_t seq, void *ctxt) | 935 | ssh_confirm_remote_forward(int type, u_int32_t seq, void *ctxt) |
@@ -904,12 +957,8 @@ ssh_confirm_remote_forward(int type, u_int32_t seq, void *ctxt) | |||
904 | } | 957 | } |
905 | if (++remote_forward_confirms_received == options.num_remote_forwards) { | 958 | if (++remote_forward_confirms_received == options.num_remote_forwards) { |
906 | debug("All remote forwarding requests processed"); | 959 | debug("All remote forwarding requests processed"); |
907 | if (fork_after_authentication_flag) { | 960 | if (fork_after_authentication_flag) |
908 | fork_after_authentication_flag = 0; | 961 | fork_postauth(); |
909 | if (daemon(1, 1) < 0) | ||
910 | fatal("daemon() failed: %.200s", | ||
911 | strerror(errno)); | ||
912 | } | ||
913 | } | 962 | } |
914 | } | 963 | } |
915 | 964 | ||
@@ -1153,12 +1202,13 @@ ssh_session(void) | |||
1153 | * If requested and we are not interested in replies to remote | 1202 | * If requested and we are not interested in replies to remote |
1154 | * forwarding requests, then let ssh continue in the background. | 1203 | * forwarding requests, then let ssh continue in the background. |
1155 | */ | 1204 | */ |
1156 | if (fork_after_authentication_flag && | 1205 | if (fork_after_authentication_flag) { |
1157 | (!options.exit_on_forward_failure || | 1206 | if (options.exit_on_forward_failure && |
1158 | options.num_remote_forwards == 0)) { | 1207 | options.num_remote_forwards > 0) { |
1159 | fork_after_authentication_flag = 0; | 1208 | debug("deferring postauth fork until remote forward " |
1160 | if (daemon(1, 1) < 0) | 1209 | "confirmation received"); |
1161 | fatal("daemon() failed: %.200s", strerror(errno)); | 1210 | } else |
1211 | fork_postauth(); | ||
1162 | } | 1212 | } |
1163 | 1213 | ||
1164 | /* | 1214 | /* |
@@ -1281,6 +1331,31 @@ ssh_session2(void) | |||
1281 | /* XXX should be pre-session */ | 1331 | /* XXX should be pre-session */ |
1282 | ssh_init_forwarding(); | 1332 | ssh_init_forwarding(); |
1283 | 1333 | ||
1334 | /* Start listening for multiplex clients */ | ||
1335 | muxserver_listen(); | ||
1336 | |||
1337 | /* | ||
1338 | * If we are in control persist mode, then prepare to background | ||
1339 | * ourselves and have a foreground client attach as a control | ||
1340 | * slave. NB. we must save copies of the flags that we override for | ||
1341 | * the backgrounding, since we defer attachment of the slave until | ||
1342 | * after the connection is fully established (in particular, | ||
1343 | * async rfwd replies have been received for ExitOnForwardFailure). | ||
1344 | */ | ||
1345 | if (options.control_persist && muxserver_sock != -1) { | ||
1346 | ostdin_null_flag = stdin_null_flag; | ||
1347 | ono_shell_flag = no_shell_flag; | ||
1348 | ono_tty_flag = no_tty_flag; | ||
1349 | otty_flag = tty_flag; | ||
1350 | stdin_null_flag = 1; | ||
1351 | no_shell_flag = 1; | ||
1352 | no_tty_flag = 1; | ||
1353 | tty_flag = 0; | ||
1354 | if (!fork_after_authentication_flag) | ||
1355 | need_controlpersist_detach = 1; | ||
1356 | fork_after_authentication_flag = 1; | ||
1357 | } | ||
1358 | |||
1284 | if (!no_shell_flag || (datafellows & SSH_BUG_DUMMYCHAN)) | 1359 | if (!no_shell_flag || (datafellows & SSH_BUG_DUMMYCHAN)) |
1285 | id = ssh_session2_open(); | 1360 | id = ssh_session2_open(); |
1286 | 1361 | ||
@@ -1299,19 +1374,17 @@ ssh_session2(void) | |||
1299 | options.permit_local_command) | 1374 | options.permit_local_command) |
1300 | ssh_local_cmd(options.local_command); | 1375 | ssh_local_cmd(options.local_command); |
1301 | 1376 | ||
1302 | /* Start listening for multiplex clients */ | ||
1303 | muxserver_listen(); | ||
1304 | |||
1305 | /* | 1377 | /* |
1306 | * If requested and we are not interested in replies to remote | 1378 | * If requested and we are not interested in replies to remote |
1307 | * forwarding requests, then let ssh continue in the background. | 1379 | * forwarding requests, then let ssh continue in the background. |
1308 | */ | 1380 | */ |
1309 | if (fork_after_authentication_flag && | 1381 | if (fork_after_authentication_flag) { |
1310 | (!options.exit_on_forward_failure || | 1382 | if (options.exit_on_forward_failure && |
1311 | options.num_remote_forwards == 0)) { | 1383 | options.num_remote_forwards > 0) { |
1312 | fork_after_authentication_flag = 0; | 1384 | debug("deferring postauth fork until remote forward " |
1313 | if (daemon(1, 1) < 0) | 1385 | "confirmation received"); |
1314 | fatal("daemon() failed: %.200s", strerror(errno)); | 1386 | } else |
1387 | fork_postauth(); | ||
1315 | } | 1388 | } |
1316 | 1389 | ||
1317 | if (options.use_roaming) | 1390 | if (options.use_roaming) |
diff --git a/ssh_config.5 b/ssh_config.5 index e7bb21ebb..04df8184c 100644 --- a/ssh_config.5 +++ b/ssh_config.5 | |||
@@ -34,8 +34,8 @@ | |||
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.136 2010/07/12 22:41:13 djm Exp $ | 37 | .\" $OpenBSD: ssh_config.5,v 1.137 2010/07/19 09:15:12 djm Exp $ |
38 | .Dd $Mdocdate: July 12 2010 $ | 38 | .Dd $Mdocdate: July 19 2010 $ |
39 | .Dt SSH_CONFIG 5 | 39 | .Dt SSH_CONFIG 5 |
40 | .Os | 40 | .Os |
41 | .Sh NAME | 41 | .Sh NAME |
@@ -319,6 +319,28 @@ It is recommended that any | |||
319 | used for opportunistic connection sharing include | 319 | used for opportunistic connection sharing include |
320 | at least %h, %p, and %r. | 320 | at least %h, %p, and %r. |
321 | This ensures that shared connections are uniquely identified. | 321 | This ensures that shared connections are uniquely identified. |
322 | .It Cm ControlPersist | ||
323 | When used in conjunction with | ||
324 | .Cm ControlMaster , | ||
325 | specifies that the master connection should remain open | ||
326 | in the background (waiting for future client connections) | ||
327 | after the initial client connection has been closed. | ||
328 | If set to | ||
329 | .Dq no , | ||
330 | then the master connection will not be placed into the background, | ||
331 | and will close as soon as the initial client connection is closed. | ||
332 | If set to | ||
333 | .Dq yes , | ||
334 | then the master connection will remain in the background indefinitely | ||
335 | (until killed or closed via a mechanism such as the | ||
336 | .Xr ssh 1 | ||
337 | .Dq Fl O No exit | ||
338 | option). | ||
339 | If set to a time in seconds, or a time in any of the formats documented in | ||
340 | .Xr sshd_config 5 , | ||
341 | then the backgrounded master connection will automatically terminate | ||
342 | after it has remained idle (with no client connections) for the | ||
343 | specified time. | ||
322 | .It Cm DynamicForward | 344 | .It Cm DynamicForward |
323 | Specifies that a TCP port on the local machine be forwarded | 345 | Specifies that a TCP port on the local machine be forwarded |
324 | over the secure channel, and the application | 346 | over the secure channel, and the application |