View | Details | Raw Unified | Return to bug 1330 | Differences between
and this patch

Collapse All | Expand All

(-)clientloop.c (-3 / +63 lines)
Lines 141-146 Link Here
141
/* Flag indicating whether the user's terminal is in non-blocking mode. */
141
/* Flag indicating whether the user's terminal is in non-blocking mode. */
142
static int in_non_blocking_mode = 0;
142
static int in_non_blocking_mode = 0;
143
143
144
/* Time when backgrounded control master using ControlPersist should exit */
145
static time_t control_persist_exit_time = 0;
146
144
/* Common data for the client loop code. */
147
/* Common data for the client loop code. */
145
static volatile sig_atomic_t quit_pending; /* Set non-zero to quit the loop. */
148
static volatile sig_atomic_t quit_pending; /* Set non-zero to quit the loop. */
146
static int escape_char;		/* Escape character. */
149
static int escape_char;		/* Escape character. */
Lines 235-240 Link Here
235
	return (double) tv.tv_sec + (double) tv.tv_usec / 1000000.0;
238
	return (double) tv.tv_sec + (double) tv.tv_usec / 1000000.0;
236
}
239
}
237
240
241
/*
242
 * Sets control_persist_exit_time to the absolute time when the
243
 * backgrounded control master should exit due to expiry of the
244
 * ControlPersist timeout.  Sets it to 0 if we are not a backgrounded
245
 * control master process, or if there is no ControlPersist timeout.
246
 */
247
static void
248
set_control_persist_exit_time(void)
249
{
250
	if (control_fd == -1 || !options.control_persist
251
	    || options.control_persist_timeout == 0)
252
		/* not using a ControlPersist timeout */
253
		control_persist_exit_time = 0;
254
	else if (channel_still_open())
255
		/* some client connections are still open */
256
		control_persist_exit_time = 0;
257
	else if (control_persist_exit_time <= 0) {
258
		/* a client connection has recently closed */
259
		time_t now = time(NULL);
260
261
		control_persist_exit_time = now +
262
			(time_t)options.control_persist_timeout;
263
	}
264
	/* else we are already counting down to the timeout */
265
}
266
238
#define SSH_X11_PROTO "MIT-MAGIC-COOKIE-1"
267
#define SSH_X11_PROTO "MIT-MAGIC-COOKIE-1"
239
void
268
void
240
client_x11_get_proto(const char *display, const char *xauth_path,
269
client_x11_get_proto(const char *display, const char *xauth_path,
Lines 483-488 Link Here
483
    int *maxfdp, u_int *nallocp, int rekeying)
512
    int *maxfdp, u_int *nallocp, int rekeying)
484
{
513
{
485
	struct timeval tv, *tvp;
514
	struct timeval tv, *tvp;
515
	time_t now;
516
	int timeout_secs;
486
	int ret;
517
	int ret;
487
518
488
	/* Add any selections by the channel mechanism. */
519
	/* Add any selections by the channel mechanism. */
Lines 529-541 Link Here
529
	/*
560
	/*
530
	 * Wait for something to happen.  This will suspend the process until
561
	 * Wait for something to happen.  This will suspend the process until
531
	 * some selected descriptor can be read, written, or has some other
562
	 * some selected descriptor can be read, written, or has some other
532
	 * event pending.
563
	 * event pending, or a timeout expires.
533
	 */
564
	 */
534
565
535
	if (options.server_alive_interval == 0 || !compat20)
566
	now = time(NULL);
567
	timeout_secs = INT_MAX; /* we use INT_MAX to mean no timeout */
568
	if (options.server_alive_interval > 0 && compat20)
569
		timeout_secs = MIN(timeout_secs,
570
			options.server_alive_interval);
571
	set_control_persist_exit_time();
572
	if (control_persist_exit_time > 0) {
573
		timeout_secs = MIN(timeout_secs,
574
			control_persist_exit_time - now);
575
		if (timeout_secs < 0)
576
			timeout_secs = 0;
577
	}
578
	if (timeout_secs == INT_MAX)
536
		tvp = NULL;
579
		tvp = NULL;
537
	else {
580
	else {
538
		tv.tv_sec = options.server_alive_interval;
581
		tv.tv_sec = timeout_secs;
539
		tv.tv_usec = 0;
582
		tv.tv_usec = 0;
540
		tvp = &tv;
583
		tvp = &tv;
541
	}
584
	}
Lines 1514-1519 Link Here
1514
		/* Send as much buffered packet data as possible to the sender. */
1557
		/* Send as much buffered packet data as possible to the sender. */
1515
		if (FD_ISSET(connection_out, writeset))
1558
		if (FD_ISSET(connection_out, writeset))
1516
			packet_write_poll();
1559
			packet_write_poll();
1560
1561
		/*
1562
		 * If we are a backgrounded control master, and the
1563
		 * timeout has expired without any active client
1564
		 * connections, then quit.
1565
		 */
1566
		if (control_fd != -1 && options.control_persist
1567
		    && options.control_persist_timeout > 0
1568
		    && control_persist_exit_time > 0)
1569
		{
1570
			time_t now = time(NULL);
1571
1572
			if (now >= control_persist_exit_time) {
1573
				debug("ControlPersist timeout expired");
1574
				break;
1575
			}
1576
		}
1517
	}
1577
	}
1518
	if (readset)
1578
	if (readset)
1519
		xfree(readset);
1579
		xfree(readset);
(-)readconf.c (-1 / +33 lines)
Lines 128-134 Link Here
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
	oDeprecated, oUnsupported
134
	oDeprecated, oUnsupported
134
} OpCodes;
135
} OpCodes;
Lines 221-226 Link Here
221
	{ "sendenv", oSendEnv },
222
	{ "sendenv", oSendEnv },
222
	{ "controlpath", oControlPath },
223
	{ "controlpath", oControlPath },
223
	{ "controlmaster", oControlMaster },
224
	{ "controlmaster", oControlMaster },
225
	{ "controlpersist", oControlPersist },
224
	{ "hashknownhosts", oHashKnownHosts },
226
	{ "hashknownhosts", oHashKnownHosts },
225
	{ "tunnel", oTunnel },
227
	{ "tunnel", oTunnel },
226
	{ "tunneldevice", oTunnelDevice },
228
	{ "tunneldevice", oTunnelDevice },
Lines 868-873 Link Here
868
			*intptr = value;
870
			*intptr = value;
869
		break;
871
		break;
870
872
873
	case oControlPersist:
874
		/* no/false/yes/true, or a time spec */
875
		intptr = &options->control_persist;
876
		arg = strdelim(&s);
877
		if (!arg || *arg == '\0')
878
			fatal("%.200s line %d: Missing ControlPersist"
879
			    " argument.", filename, linenum);
880
		value = 0;	/* To avoid compiler warning... */
881
		value2 = 0;	/* timeout */
882
		if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
883
			value = 0;
884
		else if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
885
			value = 1;
886
		else if ((value2 = convtime(arg)) > 0)
887
			value = 1;
888
		else
889
			fatal("%.200s line %d: Bad ControlPersist argument.",
890
			    filename, linenum);
891
		if (*activep && *intptr == -1) {
892
			*intptr = value;
893
			options->control_persist_timeout = value2;
894
		}
895
		break;
896
871
	case oHashKnownHosts:
897
	case oHashKnownHosts:
872
		intptr = &options->hash_known_hosts;
898
		intptr = &options->hash_known_hosts;
873
		goto parse_flag;
899
		goto parse_flag;
Lines 1059-1064 Link Here
1059
	options->num_send_env = 0;
1085
	options->num_send_env = 0;
1060
	options->control_path = NULL;
1086
	options->control_path = NULL;
1061
	options->control_master = -1;
1087
	options->control_master = -1;
1088
	options->control_persist = -1;
1089
	options->control_persist_timeout = 0;
1062
	options->hash_known_hosts = -1;
1090
	options->hash_known_hosts = -1;
1063
	options->tun_open = -1;
1091
	options->tun_open = -1;
1064
	options->tun_local = -1;
1092
	options->tun_local = -1;
Lines 1189-1194 Link Here
1189
		options->server_alive_count_max = 3;
1217
		options->server_alive_count_max = 3;
1190
	if (options->control_master == -1)
1218
	if (options->control_master == -1)
1191
		options->control_master = 0;
1219
		options->control_master = 0;
1220
	if (options->control_persist == -1) {
1221
		options->control_persist = 0;
1222
		options->control_persist_timeout = 0;
1223
	}
1192
	if (options->hash_known_hosts == -1)
1224
	if (options->hash_known_hosts == -1)
1193
		options->hash_known_hosts = 0;
1225
		options->hash_known_hosts = 0;
1194
	if (options->tun_open == -1)
1226
	if (options->tun_open == -1)
(-)readconf.h (+2 lines)
Lines 111-116 Link Here
111
111
112
	char	*control_path;
112
	char	*control_path;
113
	int	control_master;
113
	int	control_master;
114
	int     control_persist; /* ControlPersist flag */
115
	int     control_persist_timeout; /* ControlPersist timeout (seconds) */
114
116
115
	int	hash_known_hosts;
117
	int	hash_known_hosts;
116
118
(-)ssh.c (-3 / +42 lines)
Lines 680-685 Link Here
680
		fatal("No ControlPath specified for \"-O\" command");
680
		fatal("No ControlPath specified for \"-O\" command");
681
	if (options.control_path != NULL)
681
	if (options.control_path != NULL)
682
		control_client(options.control_path);
682
		control_client(options.control_path);
683
		/* If control_client() can connect to a master socket,
684
		 * then it doesn't return. */
683
685
684
	/* Open a connection to the remote host. */
686
	/* Open a connection to the remote host. */
685
	if (ssh_connect(host, &hostaddr, options.port,
687
	if (ssh_connect(host, &hostaddr, options.port,
Lines 1190-1195 Link Here
1190
	/* XXX should be pre-session */
1192
	/* XXX should be pre-session */
1191
	ssh_init_forwarding();
1193
	ssh_init_forwarding();
1192
1194
1195
	/* Start listening for multiplex clients */
1196
	ssh_control_listener();
1197
1198
 	/*
1199
 	 * If we are the control master, and if control_persist is set,
1200
 	 * then move the master into the background, and make the
1201
 	 * foreground process a client of the backgrounded master.
1202
 	 */
1203
 	if (options.control_persist && control_fd != -1) {
1204
 		pid_t childpid;
1205
 
1206
 		childpid = fork();
1207
		if (childpid < 0) {
1208
 			fatal("fork() failed");
1209
 		} else if (childpid == 0) {
1210
 			/*
1211
 			 * This is the child.  Set some variables to let
1212
 			 * it continue continue operating as the control
1213
 			 * master in the background.
1214
 			 */
1215
 			debug("backgrounding control master");
1216
 			fork_after_authentication_flag = 1;
1217
 			stdin_null_flag = 1;
1218
 			no_shell_flag = 1;
1219
 			no_tty_flag = 1;
1220
 			tty_flag = 0;
1221
 		} else {
1222
 			/*
1223
 			 * This is the foreground process.  Make it a
1224
 			 * client of the newly-backgrounded control
1225
 			 * master.  control_client() doesn't return
1226
 			 * unless it fails.
1227
 			 */
1228
 			close(control_fd);
1229
 			control_fd = -1;
1230
 			control_client(options.control_path);
1231
 			fatal("Failed to connect to new control master");
1232
 		}
1233
 	}
1234
1193
	if (!no_shell_flag || (datafellows & SSH_BUG_DUMMYCHAN))
1235
	if (!no_shell_flag || (datafellows & SSH_BUG_DUMMYCHAN))
1194
		id = ssh_session2_open();
1236
		id = ssh_session2_open();
1195
1237
Lines 1197-1205 Link Here
1197
	if (options.local_command != NULL &&
1239
	if (options.local_command != NULL &&
1198
	    options.permit_local_command)
1240
	    options.permit_local_command)
1199
		ssh_local_cmd(options.local_command);
1241
		ssh_local_cmd(options.local_command);
1200
1201
	/* Start listening for multiplex clients */
1202
	ssh_control_listener();
1203
1242
1204
	/* If requested, let ssh continue in the background. */
1243
	/* If requested, let ssh continue in the background. */
1205
	if (fork_after_authentication_flag)
1244
	if (fork_after_authentication_flag)
(-)ssh_config.5 (+22 lines)
Lines 318-323 Link Here
318
used for opportunistic connection sharing include
318
used for opportunistic connection sharing include
319
at least %h, %p, and %r.
319
at least %h, %p, and %r.
320
This ensures that shared connections are uniquely identified.
320
This ensures that shared connections are uniquely identified.
321
.It Cm ControlPersist
322
When used in conjunction with
323
.Cm ControlMaster ,
324
specifies that the master connection should remain open
325
in the background (waiting for future client connections)
326
after the initial client connection has been closed.
327
If set to
328
.Dq no ,
329
then the master connection will not be placed into the background,
330
and will close as soon as the initial client connection is closed.
331
If set to
332
.Dq yes ,
333
then the master connection will remain in the background indefinitely
334
(until killed or closed via a mechanism such as the
335
.Xr ssh 1
336
.Dq Fl O No exit
337
option).
338
If set to a time in seconds, or a time in any of the formats documented in
339
.Xr sshd_config 5 ,
340
then the backgrounded master connection will automatically terminate
341
after it has remained idle (with no client connections) for the
342
specified time.
321
.It Cm DynamicForward
343
.It Cm DynamicForward
322
Specifies that a TCP port on the local machine be forwarded
344
Specifies that a TCP port on the local machine be forwarded
323
over the secure channel, and the application
345
over the secure channel, and the application

Return to bug 1330