summaryrefslogtreecommitdiff
path: root/ssh.c
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2010-08-03 16:04:46 +1000
committerDamien Miller <djm@mindrot.org>2010-08-03 16:04:46 +1000
commite11e1ea5d475ee8be0038d64aa3e47c776295ac2 (patch)
tree88fa00ef41babbec7cb33e68f400e3a1ff787230 /ssh.c
parentc4bb91c79c0a05d2bbf2ac68b7be8421fb4957bf (diff)
- djm@cvs.openbsd.org 2010/07/19 09:15:12
[clientloop.c readconf.c readconf.h ssh.c ssh_config.5] add a "ControlPersist" option that automatically starts a background ssh(1) multiplex master when connecting. This connection can stay alive indefinitely, or can be set to automatically close after a user-specified duration of inactivity. bz#1330 - patch by dwmw2 AT infradead.org, but further hacked on by wmertens AT cisco.com, apb AT cequrux.com, martin-mindrot-bugzilla AT earth.li and myself; "looks ok" markus@
Diffstat (limited to 'ssh.c')
-rw-r--r--ssh.c117
1 files changed, 95 insertions, 22 deletions
diff --git a/ssh.c b/ssh.c
index 61fe10df0..249be2db8 100644
--- a/ssh.c
+++ b/ssh.c
@@ -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;
128int stdin_null_flag = 0; 128int 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 */
134int need_controlpersist_detach = 0;
135
136/* Copies of flags for ControlPersist foreground slave */
137int 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
889static void
890control_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" */
922static void
923fork_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 */
881static void 934static void
882ssh_confirm_remote_forward(int type, u_int32_t seq, void *ctxt) 935ssh_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)