1 /*	$NetBSD: readconf.c,v 1.41 2023/07/26 17:58:15 christos Exp $	*/
2 /* $OpenBSD: readconf.c,v 1.375 2023/03/10 02:24:56 dtucker Exp $ */
3 /*
4  * Author: Tatu Ylonen <ylo@cs.hut.fi>
5  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
6  *                    All rights reserved
7  * Functions for reading the configuration files.
8  *
9  * As far as I am concerned, the code I have written for this software
10  * can be used freely for any purpose.  Any derived versions of this
11  * software must be clearly marked as such, and if the derived work is
12  * incompatible with the protocol description in the RFC file, it must be
13  * called by a name other than "ssh" or "Secure Shell".
14  */
15 
16 #include "includes.h"
17 __RCSID("$NetBSD: readconf.c,v 1.41 2023/07/26 17:58:15 christos Exp $");
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <sys/socket.h>
21 #include <sys/wait.h>
22 #include <sys/un.h>
23 
24 #include <netinet/in.h>
25 #include <netinet/ip.h>
26 
27 #include <ctype.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <glob.h>
31 #include <netdb.h>
32 #include <paths.h>
33 #include <pwd.h>
34 #include <signal.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include <stdarg.h>
38 #include <unistd.h>
39 #include <limits.h>
40 #include <util.h>
41 #include <vis.h>
42 
43 #include "xmalloc.h"
44 #include "ssh.h"
45 #include "sshbuf.h"
46 #include "ssherr.h"
47 #include "cipher.h"
48 #include "pathnames.h"
49 #include "log.h"
50 #include "sshkey.h"
51 #include "misc.h"
52 #include "readconf.h"
53 #include "match.h"
54 #include "kex.h"
55 #include "mac.h"
56 #include "fmt_scaled.h"
57 #include "uidswap.h"
58 #include "myproposal.h"
59 #include "digest.h"
60 
61 /* Format of the configuration file:
62 
63    # Configuration data is parsed as follows:
64    #  1. command line options
65    #  2. user-specific file
66    #  3. system-wide file
67    # Any configuration value is only changed the first time it is set.
68    # Thus, host-specific definitions should be at the beginning of the
69    # configuration file, and defaults at the end.
70 
71    # Host-specific declarations.  These may override anything above.  A single
72    # host may match multiple declarations; these are processed in the order
73    # that they are given in.
74 
75    Host *.ngs.fi ngs.fi
76      User foo
77 
78    Host fake.com
79      Hostname another.host.name.real.org
80      User blaah
81      Port 34289
82      ForwardX11 no
83      ForwardAgent no
84 
85    Host books.com
86      RemoteForward 9999 shadows.cs.hut.fi:9999
87      Ciphers 3des-cbc
88 
89    Host fascist.blob.com
90      Port 23123
91      User tylonen
92      PasswordAuthentication no
93 
94    Host puukko.hut.fi
95      User t35124p
96      ProxyCommand ssh-proxy %h %p
97 
98    Host *.fr
99      PublicKeyAuthentication no
100 
101    Host *.su
102      Ciphers aes128-ctr
103      PasswordAuthentication no
104 
105    Host vpn.fake.com
106      Tunnel yes
107      TunnelDevice 3
108 
109    # Defaults for various options
110    Host *
111      ForwardAgent no
112      ForwardX11 no
113      PasswordAuthentication yes
114      StrictHostKeyChecking yes
115      TcpKeepAlive no
116      IdentityFile ~/.ssh/identity
117      Port 22
118      EscapeChar ~
119 
120 */
121 
122 static int read_config_file_depth(const char *filename, struct passwd *pw,
123     const char *host, const char *original_host, Options *options,
124     int flags, int *activep, int *want_final_pass, int depth);
125 static int process_config_line_depth(Options *options, struct passwd *pw,
126     const char *host, const char *original_host, char *line,
127     const char *filename, int linenum, int *activep, int flags,
128     int *want_final_pass, int depth);
129 
130 /* Keyword tokens. */
131 
132 typedef enum {
133 	oBadOption,
134 	oHost, oMatch, oInclude,
135 	oForwardAgent, oForwardX11, oForwardX11Trusted, oForwardX11Timeout,
136 	oGatewayPorts, oExitOnForwardFailure,
137 	oPasswordAuthentication,
138 	oXAuthLocation,
139 #if defined(KRB4) || defined(KRB5)
140 	oKerberosAuthentication,
141 #endif
142 #if defined(AFS) || defined(KRB5)
143 	oKerberosTgtPassing,
144 #endif
145 #ifdef AFS
146 	oAFSTokenPassing,
147 #endif
148 	oIdentityFile, oHostname, oPort, oRemoteForward, oLocalForward,
149 	oPermitRemoteOpen,
150 	oCertificateFile, oAddKeysToAgent, oIdentityAgent,
151 	oUser, oEscapeChar, oProxyCommand,
152 	oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
153 	oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
154 	oTCPKeepAlive, oNumberOfPasswordPrompts,
155 	oLogFacility, oLogLevel, oLogVerbose, oCiphers, oMacs,
156 	oPubkeyAuthentication,
157 	oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
158 	oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
159 	oHostKeyAlgorithms, oBindAddress, oBindInterface, oPKCS11Provider,
160 	oClearAllForwardings, oNoHostAuthenticationForLocalhost,
161 	oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
162 	oAddressFamily, oGssAuthentication, oGssDelegateCreds,
163 	oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
164 	oSendEnv, oSetEnv, oControlPath, oControlMaster, oControlPersist,
165 	oHashKnownHosts,
166 	oTunnel, oTunnelDevice,
167 	oLocalCommand, oPermitLocalCommand, oRemoteCommand,
168 	oVisualHostKey,
169 	oKexAlgorithms, oIPQoS, oRequestTTY, oSessionType, oStdinNull,
170 	oForkAfterAuthentication, oIgnoreUnknown, oProxyUseFdpass,
171 	oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots,
172 	oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs,
173 	oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys,
174 	oFingerprintHash, oUpdateHostkeys, oHostbasedAcceptedAlgorithms,
175 	oPubkeyAcceptedAlgorithms, oCASignatureAlgorithms, oProxyJump,
176 	oSecurityKeyProvider, oKnownHostsCommand, oRequiredRSASize,
177 	oEnableEscapeCommandline,
178 	oNoneEnabled, oTcpRcvBufPoll, oTcpRcvBuf, oNoneSwitch, oHPNDisabled,
179 	oHPNBufferSize,
180 	oSendVersionFirst,
181 	oIgnore, oIgnoredUnknownOption, oDeprecated, oUnsupported
182 } OpCodes;
183 
184 /* Textual representations of the tokens. */
185 
186 static struct {
187 	const char *name;
188 	OpCodes opcode;
189 } keywords[] = {
190 	/* Deprecated options */
191 	{ "protocol", oIgnore }, /* NB. silently ignored */
192 	{ "cipher", oDeprecated },
193 	{ "fallbacktorsh", oDeprecated },
194 	{ "globalknownhostsfile2", oDeprecated },
195 	{ "rhostsauthentication", oDeprecated },
196 	{ "userknownhostsfile2", oDeprecated },
197 	{ "useroaming", oDeprecated },
198 	{ "usersh", oDeprecated },
199 	{ "useprivilegedport", oDeprecated },
200 
201 	/* Unsupported options */
202 #ifdef AFS
203 	{ "afstokenpassing", oAFSTokenPassing },
204 #else
205 	{ "afstokenpassing", oUnsupported },
206 #endif
207 #if defined(KRB4) || defined(KRB5)
208 	{ "kerberosauthentication", oKerberosAuthentication },
209 #else
210 	{ "kerberosauthentication", oUnsupported },
211 #endif
212 #if defined(AFS) || defined(KRB5)
213 	{ "kerberostgtpassing", oKerberosTgtPassing },
214 	{ "kerberos5tgtpassing", oKerberosTgtPassing },		/* alias */
215 	{ "kerberos4tgtpassing", oKerberosTgtPassing },		/* alias */
216 #else
217 	{ "kerberostgtpassing", oUnsupported },
218 	{ "kerberos5tgtpassing", oUnsupported },
219 	{ "kerberos4tgtpassing", oUnsupported },
220 #endif
221 	{ "rsaauthentication", oUnsupported },
222 	{ "rhostsrsaauthentication", oUnsupported },
223 	{ "compressionlevel", oUnsupported },
224 
225 	/* Sometimes-unsupported options */
226 #if defined(GSSAPI)
227 	{ "gssapiauthentication", oGssAuthentication },
228 	{ "gssapidelegatecredentials", oGssDelegateCreds },
229 # else
230 	{ "gssapiauthentication", oUnsupported },
231 	{ "gssapidelegatecredentials", oUnsupported },
232 #endif
233 #ifdef ENABLE_PKCS11
234 	{ "pkcs11provider", oPKCS11Provider },
235 	{ "smartcarddevice", oPKCS11Provider },
236 # else
237 	{ "smartcarddevice", oUnsupported },
238 	{ "pkcs11provider", oUnsupported },
239 #endif
240 
241 	{ "forwardagent", oForwardAgent },
242 	{ "forwardx11", oForwardX11 },
243 	{ "forwardx11trusted", oForwardX11Trusted },
244 	{ "forwardx11timeout", oForwardX11Timeout },
245 	{ "exitonforwardfailure", oExitOnForwardFailure },
246 	{ "xauthlocation", oXAuthLocation },
247 	{ "gatewayports", oGatewayPorts },
248 	{ "passwordauthentication", oPasswordAuthentication },
249 	{ "kbdinteractiveauthentication", oKbdInteractiveAuthentication },
250 	{ "kbdinteractivedevices", oKbdInteractiveDevices },
251 	{ "challengeresponseauthentication", oKbdInteractiveAuthentication }, /* alias */
252 	{ "skeyauthentication", oKbdInteractiveAuthentication }, /* alias */
253 	{ "tisauthentication", oKbdInteractiveAuthentication },  /* alias */
254 	{ "pubkeyauthentication", oPubkeyAuthentication },
255 	{ "dsaauthentication", oPubkeyAuthentication },		    /* alias */
256 	{ "hostbasedauthentication", oHostbasedAuthentication },
257 #if defined(GSSAPI)
258 	{ "gssapiauthentication", oGssAuthentication },
259 	{ "gssapidelegatecredentials", oGssDelegateCreds },
260 #else
261 	{ "gssapiauthentication", oUnsupported },
262 	{ "gssapidelegatecredentials", oUnsupported },
263 #endif
264 	{ "identityfile", oIdentityFile },
265 	{ "identityfile2", oIdentityFile },			/* obsolete */
266 	{ "identitiesonly", oIdentitiesOnly },
267 	{ "certificatefile", oCertificateFile },
268 	{ "addkeystoagent", oAddKeysToAgent },
269 	{ "identityagent", oIdentityAgent },
270 	{ "hostname", oHostname },
271 	{ "hostkeyalias", oHostKeyAlias },
272 	{ "proxycommand", oProxyCommand },
273 	{ "port", oPort },
274 	{ "ciphers", oCiphers },
275 	{ "macs", oMacs },
276 	{ "remoteforward", oRemoteForward },
277 	{ "localforward", oLocalForward },
278 	{ "permitremoteopen", oPermitRemoteOpen },
279 	{ "user", oUser },
280 	{ "host", oHost },
281 	{ "match", oMatch },
282 	{ "escapechar", oEscapeChar },
283 	{ "globalknownhostsfile", oGlobalKnownHostsFile },
284 	{ "userknownhostsfile", oUserKnownHostsFile },
285 	{ "connectionattempts", oConnectionAttempts },
286 	{ "batchmode", oBatchMode },
287 	{ "checkhostip", oCheckHostIP },
288 	{ "stricthostkeychecking", oStrictHostKeyChecking },
289 	{ "compression", oCompression },
290 	{ "tcpkeepalive", oTCPKeepAlive },
291 	{ "keepalive", oTCPKeepAlive },				/* obsolete */
292 	{ "numberofpasswordprompts", oNumberOfPasswordPrompts },
293 	{ "syslogfacility", oLogFacility },
294 	{ "loglevel", oLogLevel },
295 	{ "logverbose", oLogVerbose },
296 	{ "dynamicforward", oDynamicForward },
297 	{ "preferredauthentications", oPreferredAuthentications },
298 	{ "hostkeyalgorithms", oHostKeyAlgorithms },
299 	{ "casignaturealgorithms", oCASignatureAlgorithms },
300 	{ "bindaddress", oBindAddress },
301 	{ "bindinterface", oBindInterface },
302 	{ "clearallforwardings", oClearAllForwardings },
303 	{ "enablesshkeysign", oEnableSSHKeysign },
304 	{ "verifyhostkeydns", oVerifyHostKeyDNS },
305 	{ "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
306 	{ "rekeylimit", oRekeyLimit },
307 	{ "connecttimeout", oConnectTimeout },
308 	{ "addressfamily", oAddressFamily },
309 	{ "serveraliveinterval", oServerAliveInterval },
310 	{ "serveralivecountmax", oServerAliveCountMax },
311 	{ "sendenv", oSendEnv },
312 	{ "setenv", oSetEnv },
313 	{ "controlpath", oControlPath },
314 	{ "controlmaster", oControlMaster },
315 	{ "controlpersist", oControlPersist },
316 	{ "hashknownhosts", oHashKnownHosts },
317 	{ "include", oInclude },
318 	{ "tunnel", oTunnel },
319 	{ "tunneldevice", oTunnelDevice },
320 	{ "localcommand", oLocalCommand },
321 	{ "permitlocalcommand", oPermitLocalCommand },
322 	{ "remotecommand", oRemoteCommand },
323 	{ "visualhostkey", oVisualHostKey },
324 	{ "kexalgorithms", oKexAlgorithms },
325 	{ "ipqos", oIPQoS },
326 	{ "requesttty", oRequestTTY },
327 	{ "sessiontype", oSessionType },
328 	{ "stdinnull", oStdinNull },
329 	{ "forkafterauthentication", oForkAfterAuthentication },
330 	{ "proxyusefdpass", oProxyUseFdpass },
331 	{ "canonicaldomains", oCanonicalDomains },
332 	{ "canonicalizefallbacklocal", oCanonicalizeFallbackLocal },
333 	{ "canonicalizehostname", oCanonicalizeHostname },
334 	{ "canonicalizemaxdots", oCanonicalizeMaxDots },
335 	{ "canonicalizepermittedcnames", oCanonicalizePermittedCNAMEs },
336 	{ "streamlocalbindmask", oStreamLocalBindMask },
337 	{ "streamlocalbindunlink", oStreamLocalBindUnlink },
338 	{ "revokedhostkeys", oRevokedHostKeys },
339 	{ "fingerprinthash", oFingerprintHash },
340 	{ "updatehostkeys", oUpdateHostkeys },
341 	{ "hostbasedacceptedalgorithms", oHostbasedAcceptedAlgorithms },
342 	{ "hostbasedkeytypes", oHostbasedAcceptedAlgorithms }, /* obsolete */
343 	{ "pubkeyacceptedalgorithms", oPubkeyAcceptedAlgorithms },
344 	{ "pubkeyacceptedkeytypes", oPubkeyAcceptedAlgorithms }, /* obsolete */
345 	{ "proxyjump", oProxyJump },
346 	{ "noneenabled", oNoneEnabled },
347 	{ "tcprcvbufpoll", oTcpRcvBufPoll },
348 	{ "tcprcvbuf", oTcpRcvBuf },
349 	{ "noneswitch", oNoneSwitch },
350 	{ "hpndisabled", oHPNDisabled },
351 	{ "hpnbuffersize", oHPNBufferSize },
352 	{ "sendversionfirst", oSendVersionFirst },
353 	{ "ignoreunknown", oIgnoreUnknown },
354 	{ "proxyjump", oProxyJump },
355 	{ "securitykeyprovider", oSecurityKeyProvider },
356 	{ "knownhostscommand", oKnownHostsCommand },
357 	{ "requiredrsasize", oRequiredRSASize },
358 	{ "enableescapecommandline", oEnableEscapeCommandline },
359 
360 	{ NULL, oBadOption }
361 };
362 
363 static const char *lookup_opcode_name(OpCodes code);
364 
365 const char *
kex_default_pk_alg(void)366 kex_default_pk_alg(void)
367 {
368 	static char *pkalgs;
369 
370 	if (pkalgs == NULL) {
371 		char *all_key;
372 
373 		all_key = sshkey_alg_list(0, 0, 1, ',');
374 		pkalgs = match_filter_allowlist(KEX_DEFAULT_PK_ALG, all_key);
375 		free(all_key);
376 	}
377 	return pkalgs;
378 }
379 
380 char *
ssh_connection_hash(const char * thishost,const char * host,const char * portstr,const char * user)381 ssh_connection_hash(const char *thishost, const char *host, const char *portstr,
382     const char *user)
383 {
384 	struct ssh_digest_ctx *md;
385 	u_char conn_hash[SSH_DIGEST_MAX_LENGTH];
386 
387 	if ((md = ssh_digest_start(SSH_DIGEST_SHA1)) == NULL ||
388 	    ssh_digest_update(md, thishost, strlen(thishost)) < 0 ||
389 	    ssh_digest_update(md, host, strlen(host)) < 0 ||
390 	    ssh_digest_update(md, portstr, strlen(portstr)) < 0 ||
391 	    ssh_digest_update(md, user, strlen(user)) < 0 ||
392 	    ssh_digest_final(md, conn_hash, sizeof(conn_hash)) < 0)
393 		fatal_f("mux digest failed");
394 	ssh_digest_free(md);
395 	return tohex(conn_hash, ssh_digest_bytes(SSH_DIGEST_SHA1));
396 }
397 
398 /*
399  * Adds a local TCP/IP port forward to options.  Never returns if there is an
400  * error.
401  */
402 
403 void
add_local_forward(Options * options,const struct Forward * newfwd)404 add_local_forward(Options *options, const struct Forward *newfwd)
405 {
406 	struct Forward *fwd;
407 	int i;
408 
409 	/* Don't add duplicates */
410 	for (i = 0; i < options->num_local_forwards; i++) {
411 		if (forward_equals(newfwd, options->local_forwards + i))
412 			return;
413 	}
414 	options->local_forwards = xreallocarray(options->local_forwards,
415 	    options->num_local_forwards + 1,
416 	    sizeof(*options->local_forwards));
417 	fwd = &options->local_forwards[options->num_local_forwards++];
418 
419 	fwd->listen_host = newfwd->listen_host;
420 	fwd->listen_port = newfwd->listen_port;
421 	fwd->listen_path = newfwd->listen_path;
422 	fwd->connect_host = newfwd->connect_host;
423 	fwd->connect_port = newfwd->connect_port;
424 	fwd->connect_path = newfwd->connect_path;
425 }
426 
427 /*
428  * Adds a remote TCP/IP port forward to options.  Never returns if there is
429  * an error.
430  */
431 
432 void
add_remote_forward(Options * options,const struct Forward * newfwd)433 add_remote_forward(Options *options, const struct Forward *newfwd)
434 {
435 	struct Forward *fwd;
436 	int i;
437 
438 	/* Don't add duplicates */
439 	for (i = 0; i < options->num_remote_forwards; i++) {
440 		if (forward_equals(newfwd, options->remote_forwards + i))
441 			return;
442 	}
443 	options->remote_forwards = xreallocarray(options->remote_forwards,
444 	    options->num_remote_forwards + 1,
445 	    sizeof(*options->remote_forwards));
446 	fwd = &options->remote_forwards[options->num_remote_forwards++];
447 
448 	fwd->listen_host = newfwd->listen_host;
449 	fwd->listen_port = newfwd->listen_port;
450 	fwd->listen_path = newfwd->listen_path;
451 	fwd->connect_host = newfwd->connect_host;
452 	fwd->connect_port = newfwd->connect_port;
453 	fwd->connect_path = newfwd->connect_path;
454 	fwd->handle = newfwd->handle;
455 	fwd->allocated_port = 0;
456 }
457 
458 static void
clear_forwardings(Options * options)459 clear_forwardings(Options *options)
460 {
461 	int i;
462 
463 	for (i = 0; i < options->num_local_forwards; i++) {
464 		free(options->local_forwards[i].listen_host);
465 		free(options->local_forwards[i].listen_path);
466 		free(options->local_forwards[i].connect_host);
467 		free(options->local_forwards[i].connect_path);
468 	}
469 	if (options->num_local_forwards > 0) {
470 		free(options->local_forwards);
471 		options->local_forwards = NULL;
472 	}
473 	options->num_local_forwards = 0;
474 	for (i = 0; i < options->num_remote_forwards; i++) {
475 		free(options->remote_forwards[i].listen_host);
476 		free(options->remote_forwards[i].listen_path);
477 		free(options->remote_forwards[i].connect_host);
478 		free(options->remote_forwards[i].connect_path);
479 	}
480 	if (options->num_remote_forwards > 0) {
481 		free(options->remote_forwards);
482 		options->remote_forwards = NULL;
483 	}
484 	options->num_remote_forwards = 0;
485 	options->tun_open = SSH_TUNMODE_NO;
486 }
487 
488 void
add_certificate_file(Options * options,const char * path,int userprovided)489 add_certificate_file(Options *options, const char *path, int userprovided)
490 {
491 	int i;
492 
493 	if (options->num_certificate_files >= SSH_MAX_CERTIFICATE_FILES)
494 		fatal("Too many certificate files specified (max %d)",
495 		    SSH_MAX_CERTIFICATE_FILES);
496 
497 	/* Avoid registering duplicates */
498 	for (i = 0; i < options->num_certificate_files; i++) {
499 		if (options->certificate_file_userprovided[i] == userprovided &&
500 		    strcmp(options->certificate_files[i], path) == 0) {
501 			debug2_f("ignoring duplicate key %s", path);
502 			return;
503 		}
504 	}
505 
506 	options->certificate_file_userprovided[options->num_certificate_files] =
507 	    userprovided;
508 	options->certificate_files[options->num_certificate_files++] =
509 	    xstrdup(path);
510 }
511 
512 void
add_identity_file(Options * options,const char * dir,const char * filename,int userprovided)513 add_identity_file(Options *options, const char *dir, const char *filename,
514     int userprovided)
515 {
516 	char *path;
517 	int i;
518 
519 	if (options->num_identity_files >= SSH_MAX_IDENTITY_FILES)
520 		fatal("Too many identity files specified (max %d)",
521 		    SSH_MAX_IDENTITY_FILES);
522 
523 	if (dir == NULL) /* no dir, filename is absolute */
524 		path = xstrdup(filename);
525 	else if (xasprintf(&path, "%s%s", dir, filename) >= PATH_MAX)
526 		fatal("Identity file path %s too long", path);
527 
528 	/* Avoid registering duplicates */
529 	for (i = 0; i < options->num_identity_files; i++) {
530 		if (options->identity_file_userprovided[i] == userprovided &&
531 		    strcmp(options->identity_files[i], path) == 0) {
532 			debug2_f("ignoring duplicate key %s", path);
533 			free(path);
534 			return;
535 		}
536 	}
537 
538 	options->identity_file_userprovided[options->num_identity_files] =
539 	    userprovided;
540 	options->identity_files[options->num_identity_files++] = path;
541 }
542 
543 int
default_ssh_port(void)544 default_ssh_port(void)
545 {
546 	static int port;
547 	struct servent *sp;
548 
549 	if (port == 0) {
550 		sp = getservbyname(SSH_SERVICE_NAME, "tcp");
551 		port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT;
552 	}
553 	return port;
554 }
555 
556 /*
557  * Execute a command in a shell.
558  * Return its exit status or -1 on abnormal exit.
559  */
560 static int
execute_in_shell(const char * cmd)561 execute_in_shell(const char *cmd)
562 {
563 	const char *shell;
564 	pid_t pid;
565 	int status;
566 
567 	if ((shell = getenv("SHELL")) == NULL)
568 		shell = _PATH_BSHELL;
569 
570 	if (access(shell, X_OK) == -1) {
571 		fatal("Shell \"%s\" is not executable: %s",
572 		    shell, strerror(errno));
573 	}
574 
575 	debug("Executing command: '%.500s'", cmd);
576 
577 	/* Fork and execute the command. */
578 	if ((pid = fork()) == 0) {
579 		char *argv[4];
580 
581 		if (stdfd_devnull(1, 1, 0) == -1)
582 			fatal_f("stdfd_devnull failed");
583 		closefrom(STDERR_FILENO + 1);
584 
585 		argv[0] = __UNCONST(shell);
586 		argv[1] = __UNCONST("-c");
587 		argv[2] = xstrdup(cmd);
588 		argv[3] = NULL;
589 
590 		execv(argv[0], argv);
591 		error("Unable to execute '%.100s': %s", cmd, strerror(errno));
592 		/* Die with signal to make this error apparent to parent. */
593 		ssh_signal(SIGTERM, SIG_DFL);
594 		kill(getpid(), SIGTERM);
595 		_exit(1);
596 	}
597 	/* Parent. */
598 	if (pid == -1)
599 		fatal_f("fork: %.100s", strerror(errno));
600 
601 	while (waitpid(pid, &status, 0) == -1) {
602 		if (errno != EINTR && errno != EAGAIN)
603 			fatal_f("waitpid: %s", strerror(errno));
604 	}
605 	if (!WIFEXITED(status)) {
606 		error("command '%.100s' exited abnormally", cmd);
607 		return -1;
608 	}
609 	debug3("command returned status %d", WEXITSTATUS(status));
610 	return WEXITSTATUS(status);
611 }
612 
613 /*
614  * Parse and execute a Match directive.
615  */
616 static int
match_cfg_line(Options * options,char ** condition,struct passwd * pw,const char * host_arg,const char * original_host,int final_pass,int * want_final_pass,const char * filename,int linenum)617 match_cfg_line(Options *options, char **condition, struct passwd *pw,
618     const char *host_arg, const char *original_host, int final_pass,
619     int *want_final_pass, const char *filename, int linenum)
620 {
621 	char *arg, *oattrib, *attrib, *cmd, *cp = *condition, *host, *criteria;
622 	const char *ruser;
623 	int r, port, this_result, result = 1, attributes = 0, negate;
624 	char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV];
625 	char uidstr[32];
626 
627 	/*
628 	 * Configuration is likely to be incomplete at this point so we
629 	 * must be prepared to use default values.
630 	 */
631 	port = options->port <= 0 ? default_ssh_port() : options->port;
632 	ruser = options->user == NULL ? pw->pw_name : options->user;
633 	if (final_pass) {
634 		host = xstrdup(options->hostname);
635 	} else if (options->hostname != NULL) {
636 		/* NB. Please keep in sync with ssh.c:main() */
637 		host = percent_expand(options->hostname,
638 		    "h", host_arg, (char *)NULL);
639 	} else {
640 		host = xstrdup(host_arg);
641 	}
642 
643 	debug2("checking match for '%s' host %s originally %s",
644 	    cp, host, original_host);
645 	while ((oattrib = attrib = strdelim(&cp)) && *attrib != '\0') {
646 		/* Terminate on comment */
647 		if (*attrib == '#') {
648 			cp = NULL; /* mark all arguments consumed */
649 			break;
650 		}
651 		arg = criteria = NULL;
652 		this_result = 1;
653 		if ((negate = (attrib[0] == '!')))
654 			attrib++;
655 		/* Criterion "all" has no argument and must appear alone */
656 		if (strcasecmp(attrib, "all") == 0) {
657 			if (attributes > 1 || ((arg = strdelim(&cp)) != NULL &&
658 			    *arg != '\0' && *arg != '#')) {
659 				error("%.200s line %d: '%s' cannot be combined "
660 				    "with other Match attributes",
661 				    filename, linenum, oattrib);
662 				result = -1;
663 				goto out;
664 			}
665 			if (arg != NULL && *arg == '#')
666 				cp = NULL; /* mark all arguments consumed */
667 			if (result)
668 				result = negate ? 0 : 1;
669 			goto out;
670 		}
671 		attributes++;
672 		/* criteria "final" and "canonical" have no argument */
673 		if (strcasecmp(attrib, "canonical") == 0 ||
674 		    strcasecmp(attrib, "final") == 0) {
675 			/*
676 			 * If the config requests "Match final" then remember
677 			 * this so we can perform a second pass later.
678 			 */
679 			if (strcasecmp(attrib, "final") == 0 &&
680 			    want_final_pass != NULL)
681 				*want_final_pass = 1;
682 			r = !!final_pass;  /* force bitmask member to boolean */
683 			if (r == (negate ? 1 : 0))
684 				this_result = result = 0;
685 			debug3("%.200s line %d: %smatched '%s'",
686 			    filename, linenum,
687 			    this_result ? "" : "not ", oattrib);
688 			continue;
689 		}
690 		/* All other criteria require an argument */
691 		if ((arg = strdelim(&cp)) == NULL ||
692 		    *arg == '\0' || *arg == '#') {
693 			error("Missing Match criteria for %s", attrib);
694 			result = -1;
695 			goto out;
696 		}
697 		if (strcasecmp(attrib, "host") == 0) {
698 			criteria = xstrdup(host);
699 			r = match_hostname(host, arg) == 1;
700 			if (r == (negate ? 1 : 0))
701 				this_result = result = 0;
702 		} else if (strcasecmp(attrib, "originalhost") == 0) {
703 			criteria = xstrdup(original_host);
704 			r = match_hostname(original_host, arg) == 1;
705 			if (r == (negate ? 1 : 0))
706 				this_result = result = 0;
707 		} else if (strcasecmp(attrib, "user") == 0) {
708 			criteria = xstrdup(ruser);
709 			r = match_pattern_list(ruser, arg, 0) == 1;
710 			if (r == (negate ? 1 : 0))
711 				this_result = result = 0;
712 		} else if (strcasecmp(attrib, "localuser") == 0) {
713 			criteria = xstrdup(pw->pw_name);
714 			r = match_pattern_list(pw->pw_name, arg, 0) == 1;
715 			if (r == (negate ? 1 : 0))
716 				this_result = result = 0;
717 		} else if (strcasecmp(attrib, "exec") == 0) {
718 			char *conn_hash_hex, *keyalias;
719 
720 			if (gethostname(thishost, sizeof(thishost)) == -1)
721 				fatal("gethostname: %s", strerror(errno));
722 			strlcpy(shorthost, thishost, sizeof(shorthost));
723 			shorthost[strcspn(thishost, ".")] = '\0';
724 			snprintf(portstr, sizeof(portstr), "%d", port);
725 			snprintf(uidstr, sizeof(uidstr), "%llu",
726 			    (unsigned long long)pw->pw_uid);
727 			conn_hash_hex = ssh_connection_hash(thishost, host,
728 			    portstr, ruser);
729 			keyalias = options->host_key_alias ?
730 			    options->host_key_alias : host;
731 
732 			cmd = percent_expand(arg,
733 			    "C", conn_hash_hex,
734 			    "L", shorthost,
735 			    "d", pw->pw_dir,
736 			    "h", host,
737 			    "k", keyalias,
738 			    "l", thishost,
739 			    "n", original_host,
740 			    "p", portstr,
741 			    "r", ruser,
742 			    "u", pw->pw_name,
743 			    "i", uidstr,
744 			    (char *)NULL);
745 			free(conn_hash_hex);
746 			if (result != 1) {
747 				/* skip execution if prior predicate failed */
748 				debug3("%.200s line %d: skipped exec "
749 				    "\"%.100s\"", filename, linenum, cmd);
750 				free(cmd);
751 				continue;
752 			}
753 			r = execute_in_shell(cmd);
754 			if (r == -1) {
755 				fatal("%.200s line %d: match exec "
756 				    "'%.100s' error", filename,
757 				    linenum, cmd);
758 			}
759 			criteria = xstrdup(cmd);
760 			free(cmd);
761 			/* Force exit status to boolean */
762 			r = r == 0;
763 			if (r == (negate ? 1 : 0))
764 				this_result = result = 0;
765 		} else {
766 			error("Unsupported Match attribute %s", attrib);
767 			result = -1;
768 			goto out;
769 		}
770 		debug3("%.200s line %d: %smatched '%s \"%.100s\"' ",
771 		    filename, linenum, this_result ? "": "not ",
772 		    oattrib, criteria);
773 		free(criteria);
774 	}
775 	if (attributes == 0) {
776 		error("One or more attributes required for Match");
777 		result = -1;
778 		goto out;
779 	}
780  out:
781 	if (result != -1)
782 		debug2("match %sfound", result ? "" : "not ");
783 	*condition = cp;
784 	free(host);
785 	return result;
786 }
787 
788 /* Remove environment variable by pattern */
789 static void
rm_env(Options * options,const char * arg,const char * filename,int linenum)790 rm_env(Options *options, const char *arg, const char *filename, int linenum)
791 {
792 	u_int i, j, onum_send_env = options->num_send_env;
793 
794 	/* Remove an environment variable */
795 	for (i = 0; i < options->num_send_env; ) {
796 		if (!match_pattern(options->send_env[i], arg + 1)) {
797 			i++;
798 			continue;
799 		}
800 		debug3("%s line %d: removing environment %s",
801 		    filename, linenum, options->send_env[i]);
802 		free(options->send_env[i]);
803 		options->send_env[i] = NULL;
804 		for (j = i; j < options->num_send_env - 1; j++) {
805 			options->send_env[j] = options->send_env[j + 1];
806 			options->send_env[j + 1] = NULL;
807 		}
808 		options->num_send_env--;
809 		/* NB. don't increment i */
810 	}
811 	if (onum_send_env != options->num_send_env) {
812 		options->send_env = xrecallocarray(options->send_env,
813 		    onum_send_env, options->num_send_env,
814 		    sizeof(*options->send_env));
815 	}
816 }
817 
818 /*
819  * Returns the number of the token pointed to by cp or oBadOption.
820  */
821 static OpCodes
parse_token(const char * cp,const char * filename,int linenum,const char * ignored_unknown)822 parse_token(const char *cp, const char *filename, int linenum,
823     const char *ignored_unknown)
824 {
825 	int i;
826 
827 	for (i = 0; keywords[i].name; i++)
828 		if (strcmp(cp, keywords[i].name) == 0)
829 			return keywords[i].opcode;
830 	if (ignored_unknown != NULL &&
831 	    match_pattern_list(cp, ignored_unknown, 1) == 1)
832 		return oIgnoredUnknownOption;
833 	error("%s: line %d: Bad configuration option: %s",
834 	    filename, linenum, cp);
835 	return oBadOption;
836 }
837 
838 /* Multistate option parsing */
839 struct multistate {
840 	const char *key;
841 	int value;
842 };
843 static const struct multistate multistate_flag[] = {
844 	{ "true",			1 },
845 	{ "false",			0 },
846 	{ "yes",			1 },
847 	{ "no",				0 },
848 	{ NULL, -1 }
849 };
850 static const struct multistate multistate_yesnoask[] = {
851 	{ "true",			1 },
852 	{ "false",			0 },
853 	{ "yes",			1 },
854 	{ "no",				0 },
855 	{ "ask",			2 },
856 	{ NULL, -1 }
857 };
858 static const struct multistate multistate_strict_hostkey[] = {
859 	{ "true",			SSH_STRICT_HOSTKEY_YES },
860 	{ "false",			SSH_STRICT_HOSTKEY_OFF },
861 	{ "yes",			SSH_STRICT_HOSTKEY_YES },
862 	{ "no",				SSH_STRICT_HOSTKEY_OFF },
863 	{ "ask",			SSH_STRICT_HOSTKEY_ASK },
864 	{ "off",			SSH_STRICT_HOSTKEY_OFF },
865 	{ "accept-new",			SSH_STRICT_HOSTKEY_NEW },
866 	{ NULL, -1 }
867 };
868 static const struct multistate multistate_yesnoaskconfirm[] = {
869 	{ "true",			1 },
870 	{ "false",			0 },
871 	{ "yes",			1 },
872 	{ "no",				0 },
873 	{ "ask",			2 },
874 	{ "confirm",			3 },
875 	{ NULL, -1 }
876 };
877 static const struct multistate multistate_addressfamily[] = {
878 	{ "inet",			AF_INET },
879 	{ "inet6",			AF_INET6 },
880 	{ "any",			AF_UNSPEC },
881 	{ NULL, -1 }
882 };
883 static const struct multistate multistate_controlmaster[] = {
884 	{ "true",			SSHCTL_MASTER_YES },
885 	{ "yes",			SSHCTL_MASTER_YES },
886 	{ "false",			SSHCTL_MASTER_NO },
887 	{ "no",				SSHCTL_MASTER_NO },
888 	{ "auto",			SSHCTL_MASTER_AUTO },
889 	{ "ask",			SSHCTL_MASTER_ASK },
890 	{ "autoask",			SSHCTL_MASTER_AUTO_ASK },
891 	{ NULL, -1 }
892 };
893 static const struct multistate multistate_tunnel[] = {
894 	{ "ethernet",			SSH_TUNMODE_ETHERNET },
895 	{ "point-to-point",		SSH_TUNMODE_POINTOPOINT },
896 	{ "true",			SSH_TUNMODE_DEFAULT },
897 	{ "yes",			SSH_TUNMODE_DEFAULT },
898 	{ "false",			SSH_TUNMODE_NO },
899 	{ "no",				SSH_TUNMODE_NO },
900 	{ NULL, -1 }
901 };
902 static const struct multistate multistate_requesttty[] = {
903 	{ "true",			REQUEST_TTY_YES },
904 	{ "yes",			REQUEST_TTY_YES },
905 	{ "false",			REQUEST_TTY_NO },
906 	{ "no",				REQUEST_TTY_NO },
907 	{ "force",			REQUEST_TTY_FORCE },
908 	{ "auto",			REQUEST_TTY_AUTO },
909 	{ NULL, -1 }
910 };
911 static const struct multistate multistate_sessiontype[] = {
912 	{ "none",			SESSION_TYPE_NONE },
913 	{ "subsystem",			SESSION_TYPE_SUBSYSTEM },
914 	{ "default",			SESSION_TYPE_DEFAULT },
915 	{ NULL, -1 }
916 };
917 static const struct multistate multistate_canonicalizehostname[] = {
918 	{ "true",			SSH_CANONICALISE_YES },
919 	{ "false",			SSH_CANONICALISE_NO },
920 	{ "yes",			SSH_CANONICALISE_YES },
921 	{ "no",				SSH_CANONICALISE_NO },
922 	{ "always",			SSH_CANONICALISE_ALWAYS },
923 	{ NULL, -1 }
924 };
925 static const struct multistate multistate_pubkey_auth[] = {
926 	{ "true",			SSH_PUBKEY_AUTH_ALL },
927 	{ "false",			SSH_PUBKEY_AUTH_NO },
928 	{ "yes",			SSH_PUBKEY_AUTH_ALL },
929 	{ "no",				SSH_PUBKEY_AUTH_NO },
930 	{ "unbound",			SSH_PUBKEY_AUTH_UNBOUND },
931 	{ "host-bound",			SSH_PUBKEY_AUTH_HBOUND },
932 	{ NULL, -1 }
933 };
934 static const struct multistate multistate_compression[] = {
935 #ifdef WITH_ZLIB
936 	{ "yes",			COMP_ZLIB },
937 #endif
938 	{ "no",				COMP_NONE },
939 	{ NULL, -1 }
940 };
941 
942 static int
parse_multistate_value(const char * arg,const char * filename,int linenum,const struct multistate * multistate_ptr)943 parse_multistate_value(const char *arg, const char *filename, int linenum,
944     const struct multistate *multistate_ptr)
945 {
946 	int i;
947 
948 	if (!arg || *arg == '\0') {
949 		error("%s line %d: missing argument.", filename, linenum);
950 		return -1;
951 	}
952 	for (i = 0; multistate_ptr[i].key != NULL; i++) {
953 		if (strcasecmp(arg, multistate_ptr[i].key) == 0)
954 			return multistate_ptr[i].value;
955 	}
956 	return -1;
957 }
958 
959 /*
960  * Processes a single option line as used in the configuration files. This
961  * only sets those values that have not already been set.
962  */
963 int
process_config_line(Options * options,struct passwd * pw,const char * host,const char * original_host,char * line,const char * filename,int linenum,int * activep,int flags)964 process_config_line(Options *options, struct passwd *pw, const char *host,
965     const char *original_host, char *line, const char *filename,
966     int linenum, int *activep, int flags)
967 {
968 	return process_config_line_depth(options, pw, host, original_host,
969 	    line, filename, linenum, activep, flags, NULL, 0);
970 }
971 
972 #define WHITESPACE " \t\r\n"
973 static int
process_config_line_depth(Options * options,struct passwd * pw,const char * host,const char * original_host,char * line,const char * filename,int linenum,int * activep,int flags,int * want_final_pass,int depth)974 process_config_line_depth(Options *options, struct passwd *pw, const char *host,
975     const char *original_host, char *line, const char *filename,
976     int linenum, int *activep, int flags, int *want_final_pass, int depth)
977 {
978 	char *str, **charptr, *endofnumber, *keyword, *arg, *arg2, *p;
979 	char **cpptr, ***cppptr, fwdarg[256];
980 	u_int i, *uintptr, uvalue, max_entries = 0;
981 	int r, oactive, negated, opcode, *intptr, value, value2, cmdline = 0;
982 	int remotefwd, dynamicfwd;
983 	LogLevel *log_level_ptr;
984 	SyslogFacility *log_facility_ptr;
985 	long long val64;
986 	size_t len;
987 	struct Forward fwd;
988 	const struct multistate *multistate_ptr;
989 	struct allowed_cname *cname;
990 	glob_t gl;
991 	const char *errstr;
992 	char **oav = NULL, **av;
993 	int oac = 0, ac;
994 	int ret = -1;
995 
996 	if (activep == NULL) { /* We are processing a command line directive */
997 		cmdline = 1;
998 		activep = &cmdline;
999 	}
1000 
1001 	/* Strip trailing whitespace. Allow \f (form feed) at EOL only */
1002 	if ((len = strlen(line)) == 0)
1003 		return 0;
1004 	for (len--; len > 0; len--) {
1005 		if (strchr(WHITESPACE "\f", line[len]) == NULL)
1006 			break;
1007 		line[len] = '\0';
1008 	}
1009 
1010 	str = line;
1011 	/* Get the keyword. (Each line is supposed to begin with a keyword). */
1012 	if ((keyword = strdelim(&str)) == NULL)
1013 		return 0;
1014 	/* Ignore leading whitespace. */
1015 	if (*keyword == '\0')
1016 		keyword = strdelim(&str);
1017 	if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#')
1018 		return 0;
1019 	/* Match lowercase keyword */
1020 	lowercase(keyword);
1021 
1022 	/* Prepare to parse remainder of line */
1023 	if (str != NULL)
1024 		str += strspn(str, WHITESPACE);
1025 	if (str == NULL || *str == '\0') {
1026 		error("%s line %d: no argument after keyword \"%s\"",
1027 		    filename, linenum, keyword);
1028 		return -1;
1029 	}
1030 	opcode = parse_token(keyword, filename, linenum,
1031 	    options->ignored_unknown);
1032 	if (argv_split(str, &oac, &oav, 1) != 0) {
1033 		error("%s line %d: invalid quotes", filename, linenum);
1034 		return -1;
1035 	}
1036 	ac = oac;
1037 	av = oav;
1038 
1039 	switch (opcode) {
1040 	case oBadOption:
1041 		/* don't panic, but count bad options */
1042 		goto out;
1043 	case oIgnore:
1044 		argv_consume(&ac);
1045 		break;
1046 	case oIgnoredUnknownOption:
1047 		debug("%s line %d: Ignored unknown option \"%s\"",
1048 		    filename, linenum, keyword);
1049 		argv_consume(&ac);
1050 		break;
1051 	case oConnectTimeout:
1052 		intptr = &options->connection_timeout;
1053 parse_time:
1054 		arg = argv_next(&ac, &av);
1055 		if (!arg || *arg == '\0') {
1056 			error("%s line %d: missing time value.",
1057 			    filename, linenum);
1058 			goto out;
1059 		}
1060 		if (strcmp(arg, "none") == 0)
1061 			value = -1;
1062 		else if ((value = convtime(arg)) == -1) {
1063 			error("%s line %d: invalid time value.",
1064 			    filename, linenum);
1065 			goto out;
1066 		}
1067 		if (*activep && *intptr == -1)
1068 			*intptr = value;
1069 		break;
1070 
1071 	case oForwardAgent:
1072 		intptr = &options->forward_agent;
1073 
1074 		arg = argv_next(&ac, &av);
1075 		if (!arg || *arg == '\0') {
1076 			error("%s line %d: missing argument.",
1077 			    filename, linenum);
1078 			goto out;
1079 		}
1080 
1081 		value = -1;
1082 		multistate_ptr = multistate_flag;
1083 		for (i = 0; multistate_ptr[i].key != NULL; i++) {
1084 			if (strcasecmp(arg, multistate_ptr[i].key) == 0) {
1085 				value = multistate_ptr[i].value;
1086 				break;
1087 			}
1088 		}
1089 		if (value != -1) {
1090 			if (*activep && *intptr == -1)
1091 				*intptr = value;
1092 			break;
1093 		}
1094 		/* ForwardAgent wasn't 'yes' or 'no', assume a path */
1095 		if (*activep && *intptr == -1)
1096 			*intptr = 1;
1097 
1098 		charptr = &options->forward_agent_sock_path;
1099 		goto parse_agent_path;
1100 
1101 	case oForwardX11:
1102 		intptr = &options->forward_x11;
1103  parse_flag:
1104 		multistate_ptr = multistate_flag;
1105  parse_multistate:
1106 		arg = argv_next(&ac, &av);
1107 		if ((value = parse_multistate_value(arg, filename, linenum,
1108 		    multistate_ptr)) == -1) {
1109 			error("%s line %d: unsupported option \"%s\".",
1110 			    filename, linenum, arg);
1111 			goto out;
1112 		}
1113 		if (*activep && *intptr == -1)
1114 			*intptr = value;
1115 		break;
1116 
1117 	case oForwardX11Trusted:
1118 		intptr = &options->forward_x11_trusted;
1119 		goto parse_flag;
1120 
1121 	case oForwardX11Timeout:
1122 		intptr = &options->forward_x11_timeout;
1123 		goto parse_time;
1124 
1125 	case oGatewayPorts:
1126 		intptr = &options->fwd_opts.gateway_ports;
1127 		goto parse_flag;
1128 
1129 	case oExitOnForwardFailure:
1130 		intptr = &options->exit_on_forward_failure;
1131 		goto parse_flag;
1132 
1133 	case oPasswordAuthentication:
1134 		intptr = &options->password_authentication;
1135 		goto parse_flag;
1136 
1137 	case oKbdInteractiveAuthentication:
1138 		intptr = &options->kbd_interactive_authentication;
1139 		goto parse_flag;
1140 
1141 	case oKbdInteractiveDevices:
1142 		charptr = &options->kbd_interactive_devices;
1143 		goto parse_string;
1144 
1145 	case oPubkeyAuthentication:
1146 		multistate_ptr = multistate_pubkey_auth;
1147 		intptr = &options->pubkey_authentication;
1148 		goto parse_multistate;
1149 
1150 	case oHostbasedAuthentication:
1151 		intptr = &options->hostbased_authentication;
1152 		goto parse_flag;
1153 
1154 #if defined(KRB4) || defined(KRB5)
1155 	case oKerberosAuthentication:
1156 		intptr = &options->kerberos_authentication;
1157 		goto parse_flag;
1158 #endif
1159 #if defined(AFS) || defined(KRB5)
1160 	case oKerberosTgtPassing:
1161 		intptr = &options->kerberos_tgt_passing;
1162 		goto parse_flag;
1163 #endif
1164 
1165 	case oGssAuthentication:
1166 		intptr = &options->gss_authentication;
1167 		goto parse_flag;
1168 
1169 #ifdef AFS
1170 	case oAFSTokenPassing:
1171 		intptr = &options->afs_token_passing;
1172  		goto parse_flag;
1173 #endif
1174 
1175 	case oGssDelegateCreds:
1176 		intptr = &options->gss_deleg_creds;
1177 		goto parse_flag;
1178 
1179 	case oBatchMode:
1180 		intptr = &options->batch_mode;
1181 		goto parse_flag;
1182 
1183 	case oCheckHostIP:
1184 		intptr = &options->check_host_ip;
1185 		goto parse_flag;
1186 
1187 	case oNoneEnabled:
1188 		intptr = &options->none_enabled;
1189 		goto parse_flag;
1190 
1191 	/* we check to see if the command comes from the */
1192 	/* command line or not. If it does then enable it */
1193 	/* otherwise fail. NONE should never be a default configuration */
1194 	case oNoneSwitch:
1195 		if(strcmp(filename,"command-line")==0)
1196 		{
1197 		    intptr = &options->none_switch;
1198 		    goto parse_flag;
1199 		} else {
1200 		    error("NoneSwitch is found in %.200s.\nYou may only use this configuration option from the command line", filename);
1201 		    error("Continuing...");
1202 		    debug("NoneSwitch directive found in %.200s.", filename);
1203 		    return 0;
1204 	        }
1205 
1206 	case oHPNDisabled:
1207 		intptr = &options->hpn_disabled;
1208 		goto parse_flag;
1209 
1210 	case oHPNBufferSize:
1211 		intptr = &options->hpn_buffer_size;
1212 		goto parse_int;
1213 
1214 	case oTcpRcvBufPoll:
1215 		intptr = &options->tcp_rcv_buf_poll;
1216 		goto parse_flag;
1217 
1218 	case oVerifyHostKeyDNS:
1219 		intptr = &options->verify_host_key_dns;
1220 		multistate_ptr = multistate_yesnoask;
1221 		goto parse_multistate;
1222 
1223 	case oStrictHostKeyChecking:
1224 		intptr = &options->strict_host_key_checking;
1225 		multistate_ptr = multistate_strict_hostkey;
1226 		goto parse_multistate;
1227 
1228 	case oCompression:
1229 		intptr = &options->compression;
1230 		multistate_ptr = multistate_compression;
1231 		goto parse_multistate;
1232 
1233 	case oTCPKeepAlive:
1234 		intptr = &options->tcp_keep_alive;
1235 		goto parse_flag;
1236 
1237 	case oNoHostAuthenticationForLocalhost:
1238 		intptr = &options->no_host_authentication_for_localhost;
1239 		goto parse_flag;
1240 
1241 	case oNumberOfPasswordPrompts:
1242 		intptr = &options->number_of_password_prompts;
1243 		goto parse_int;
1244 
1245 	case oRekeyLimit:
1246 		arg = argv_next(&ac, &av);
1247 		if (!arg || *arg == '\0') {
1248 			error("%.200s line %d: Missing argument.", filename,
1249 			    linenum);
1250 			goto out;
1251 		}
1252 		if (strcmp(arg, "default") == 0) {
1253 			val64 = 0;
1254 		} else {
1255 			if (scan_scaled(arg, &val64) == -1) {
1256 				error("%.200s line %d: Bad number '%s': %s",
1257 				    filename, linenum, arg, strerror(errno));
1258 				goto out;
1259 			}
1260 			if (val64 != 0 && val64 < 16) {
1261 				error("%.200s line %d: RekeyLimit too small",
1262 				    filename, linenum);
1263 				goto out;
1264 			}
1265 		}
1266 		if (*activep && options->rekey_limit == -1)
1267 			options->rekey_limit = val64;
1268 		if (ac != 0) { /* optional rekey interval present */
1269 			if (strcmp(av[0], "none") == 0) {
1270 				(void)argv_next(&ac, &av);	/* discard */
1271 				break;
1272 			}
1273 			intptr = &options->rekey_interval;
1274 			goto parse_time;
1275 		}
1276 		break;
1277 
1278 	case oIdentityFile:
1279 		arg = argv_next(&ac, &av);
1280 		if (!arg || *arg == '\0') {
1281 			error("%.200s line %d: Missing argument.",
1282 			    filename, linenum);
1283 			goto out;
1284 		}
1285 		if (*activep) {
1286 			intptr = &options->num_identity_files;
1287 			if (*intptr >= SSH_MAX_IDENTITY_FILES) {
1288 				error("%.200s line %d: Too many identity files "
1289 				    "specified (max %d).", filename, linenum,
1290 				    SSH_MAX_IDENTITY_FILES);
1291 				goto out;
1292 			}
1293 			add_identity_file(options, NULL,
1294 			    arg, flags & SSHCONF_USERCONF);
1295 		}
1296 		break;
1297 
1298 	case oCertificateFile:
1299 		arg = argv_next(&ac, &av);
1300 		if (!arg || *arg == '\0') {
1301 			error("%.200s line %d: Missing argument.",
1302 			    filename, linenum);
1303 			goto out;
1304 		}
1305 		if (*activep) {
1306 			intptr = &options->num_certificate_files;
1307 			if (*intptr >= SSH_MAX_CERTIFICATE_FILES) {
1308 				error("%.200s line %d: Too many certificate "
1309 				    "files specified (max %d).",
1310 				    filename, linenum,
1311 				    SSH_MAX_CERTIFICATE_FILES);
1312 				goto out;
1313 			}
1314 			add_certificate_file(options, arg,
1315 			    flags & SSHCONF_USERCONF);
1316 		}
1317 		break;
1318 
1319 	case oXAuthLocation:
1320 		charptr=&options->xauth_location;
1321 		goto parse_string;
1322 
1323 	case oUser:
1324 		charptr = &options->user;
1325 parse_string:
1326 		arg = argv_next(&ac, &av);
1327 		if (!arg || *arg == '\0') {
1328 			error("%.200s line %d: Missing argument.",
1329 			    filename, linenum);
1330 			goto out;
1331 		}
1332 		if (*activep && *charptr == NULL)
1333 			*charptr = xstrdup(arg);
1334 		break;
1335 
1336 	case oGlobalKnownHostsFile:
1337 		cpptr = (char **)&options->system_hostfiles;
1338 		uintptr = &options->num_system_hostfiles;
1339 		max_entries = SSH_MAX_HOSTS_FILES;
1340 parse_char_array:
1341 		i = 0;
1342 		value = *uintptr == 0; /* was array empty when we started? */
1343 		while ((arg = argv_next(&ac, &av)) != NULL) {
1344 			if (*arg == '\0') {
1345 				error("%s line %d: keyword %s empty argument",
1346 				    filename, linenum, keyword);
1347 				goto out;
1348 			}
1349 			/* Allow "none" only in first position */
1350 			if (strcasecmp(arg, "none") == 0) {
1351 				if (i > 0 || ac > 0) {
1352 					error("%s line %d: keyword %s \"none\" "
1353 					    "argument must appear alone.",
1354 					    filename, linenum, keyword);
1355 					goto out;
1356 				}
1357 			}
1358 			i++;
1359 			if (*activep && value) {
1360 				if ((*uintptr) >= max_entries) {
1361 					error("%s line %d: too many %s "
1362 					    "entries.", filename, linenum,
1363 					    keyword);
1364 					goto out;
1365 				}
1366 				cpptr[(*uintptr)++] = xstrdup(arg);
1367 			}
1368 		}
1369 		break;
1370 
1371 	case oUserKnownHostsFile:
1372 		cpptr = (char **)&options->user_hostfiles;
1373 		uintptr = &options->num_user_hostfiles;
1374 		max_entries = SSH_MAX_HOSTS_FILES;
1375 		goto parse_char_array;
1376 
1377 	case oHostname:
1378 		charptr = &options->hostname;
1379 		goto parse_string;
1380 
1381 	case oHostKeyAlias:
1382 		charptr = &options->host_key_alias;
1383 		goto parse_string;
1384 
1385 	case oPreferredAuthentications:
1386 		charptr = &options->preferred_authentications;
1387 		goto parse_string;
1388 
1389 	case oBindAddress:
1390 		charptr = &options->bind_address;
1391 		goto parse_string;
1392 
1393 	case oBindInterface:
1394 		charptr = &options->bind_interface;
1395 		goto parse_string;
1396 
1397 	case oPKCS11Provider:
1398 		charptr = &options->pkcs11_provider;
1399 		goto parse_string;
1400 
1401 	case oSecurityKeyProvider:
1402 		charptr = &options->sk_provider;
1403 		goto parse_string;
1404 
1405 	case oKnownHostsCommand:
1406 		charptr = &options->known_hosts_command;
1407 		goto parse_command;
1408 
1409 	case oProxyCommand:
1410 		charptr = &options->proxy_command;
1411 		/* Ignore ProxyCommand if ProxyJump already specified */
1412 		if (options->jump_host != NULL)
1413 			charptr = &options->jump_host; /* Skip below */
1414 parse_command:
1415 		if (str == NULL) {
1416 			error("%.200s line %d: Missing argument.",
1417 			    filename, linenum);
1418 			goto out;
1419 		}
1420 		len = strspn(str, WHITESPACE "=");
1421 		if (*activep && *charptr == NULL)
1422 			*charptr = xstrdup(str + len);
1423 		argv_consume(&ac);
1424 		break;
1425 
1426 	case oProxyJump:
1427 		if (str == NULL) {
1428 			error("%.200s line %d: Missing argument.",
1429 			    filename, linenum);
1430 			goto out;
1431 		}
1432 		len = strspn(str, WHITESPACE "=");
1433 		/* XXX use argv? */
1434 		if (parse_jump(str + len, options, *activep) == -1) {
1435 			error("%.200s line %d: Invalid ProxyJump \"%s\"",
1436 			    filename, linenum, str + len);
1437 			goto out;
1438 		}
1439 		argv_consume(&ac);
1440 		break;
1441 
1442 	case oPort:
1443 		arg = argv_next(&ac, &av);
1444 		if (!arg || *arg == '\0') {
1445 			error("%.200s line %d: Missing argument.",
1446 			    filename, linenum);
1447 			goto out;
1448 		}
1449 		value = a2port(arg);
1450 		if (value <= 0) {
1451 			error("%.200s line %d: Bad port '%s'.",
1452 			    filename, linenum, arg);
1453 			goto out;
1454 		}
1455 		if (*activep && options->port == -1)
1456 			options->port = value;
1457 		break;
1458 
1459 	case oConnectionAttempts:
1460 		intptr = &options->connection_attempts;
1461 parse_int:
1462 		arg = argv_next(&ac, &av);
1463 		if ((errstr = atoi_err(arg, &value)) != NULL) {
1464 			error("%s line %d: integer value %s.",
1465 			    filename, linenum, errstr);
1466 			goto out;
1467 		}
1468 		if (*activep && *intptr == -1)
1469 			*intptr = value;
1470 		break;
1471 
1472 	case oTcpRcvBuf:
1473 		intptr = &options->tcp_rcv_buf;
1474 		goto parse_int;
1475 
1476 	case oCiphers:
1477 		arg = argv_next(&ac, &av);
1478 		if (!arg || *arg == '\0') {
1479 			error("%.200s line %d: Missing argument.",
1480 			    filename, linenum);
1481 			goto out;
1482 		}
1483 		if (*arg != '-' &&
1484 		    !ciphers_valid(*arg == '+' || *arg == '^' ? arg + 1 : arg)){
1485 			error("%.200s line %d: Bad SSH2 cipher spec '%s'.",
1486 			    filename, linenum, arg ? arg : "<NONE>");
1487 			goto out;
1488 		}
1489 		if (*activep && options->ciphers == NULL)
1490 			options->ciphers = xstrdup(arg);
1491 		break;
1492 
1493 	case oMacs:
1494 		arg = argv_next(&ac, &av);
1495 		if (!arg || *arg == '\0') {
1496 			error("%.200s line %d: Missing argument.",
1497 			    filename, linenum);
1498 			goto out;
1499 		}
1500 		if (*arg != '-' &&
1501 		    !mac_valid(*arg == '+' || *arg == '^' ? arg + 1 : arg)) {
1502 			error("%.200s line %d: Bad SSH2 MAC spec '%s'.",
1503 			    filename, linenum, arg ? arg : "<NONE>");
1504 			goto out;
1505 		}
1506 		if (*activep && options->macs == NULL)
1507 			options->macs = xstrdup(arg);
1508 		break;
1509 
1510 	case oKexAlgorithms:
1511 		arg = argv_next(&ac, &av);
1512 		if (!arg || *arg == '\0') {
1513 			error("%.200s line %d: Missing argument.",
1514 			    filename, linenum);
1515 			goto out;
1516 		}
1517 		if (*arg != '-' &&
1518 		    !kex_names_valid(*arg == '+' || *arg == '^' ?
1519 		    arg + 1 : arg)) {
1520 			error("%.200s line %d: Bad SSH2 KexAlgorithms '%s'.",
1521 			    filename, linenum, arg ? arg : "<NONE>");
1522 			goto out;
1523 		}
1524 		if (*activep && options->kex_algorithms == NULL)
1525 			options->kex_algorithms = xstrdup(arg);
1526 		break;
1527 
1528 	case oHostKeyAlgorithms:
1529 		charptr = &options->hostkeyalgorithms;
1530 parse_pubkey_algos:
1531 		arg = argv_next(&ac, &av);
1532 		if (!arg || *arg == '\0') {
1533 			error("%.200s line %d: Missing argument.",
1534 			    filename, linenum);
1535 			goto out;
1536 		}
1537 		if (*arg != '-' &&
1538 		    !sshkey_names_valid2(*arg == '+' || *arg == '^' ?
1539 		    arg + 1 : arg, 1)) {
1540 			error("%s line %d: Bad key types '%s'.",
1541 			    filename, linenum, arg ? arg : "<NONE>");
1542 			goto out;
1543 		}
1544 		if (*activep && *charptr == NULL)
1545 			*charptr = xstrdup(arg);
1546 		break;
1547 
1548 	case oCASignatureAlgorithms:
1549 		charptr = &options->ca_sign_algorithms;
1550 		goto parse_pubkey_algos;
1551 
1552 	case oLogLevel:
1553 		log_level_ptr = &options->log_level;
1554 		arg = argv_next(&ac, &av);
1555 		value = log_level_number(arg);
1556 		if (value == SYSLOG_LEVEL_NOT_SET) {
1557 			error("%.200s line %d: unsupported log level '%s'",
1558 			    filename, linenum, arg ? arg : "<NONE>");
1559 			goto out;
1560 		}
1561 		if (*activep && *log_level_ptr == SYSLOG_LEVEL_NOT_SET)
1562 			*log_level_ptr = (LogLevel) value;
1563 		break;
1564 
1565 	case oLogFacility:
1566 		log_facility_ptr = &options->log_facility;
1567 		arg = argv_next(&ac, &av);
1568 		value = log_facility_number(arg);
1569 		if (value == SYSLOG_FACILITY_NOT_SET) {
1570 			error("%.200s line %d: unsupported log facility '%s'",
1571 			    filename, linenum, arg ? arg : "<NONE>");
1572 			goto out;
1573 		}
1574 		if (*log_facility_ptr == -1)
1575 			*log_facility_ptr = (SyslogFacility) value;
1576 		break;
1577 
1578 	case oLogVerbose:
1579 		cppptr = &options->log_verbose;
1580 		uintptr = &options->num_log_verbose;
1581 		i = 0;
1582 		while ((arg = argv_next(&ac, &av)) != NULL) {
1583 			if (*arg == '\0') {
1584 				error("%s line %d: keyword %s empty argument",
1585 				    filename, linenum, keyword);
1586 				goto out;
1587 			}
1588 			/* Allow "none" only in first position */
1589 			if (strcasecmp(arg, "none") == 0) {
1590 				if (i > 0 || ac > 0) {
1591 					error("%s line %d: keyword %s \"none\" "
1592 					    "argument must appear alone.",
1593 					    filename, linenum, keyword);
1594 					goto out;
1595 				}
1596 			}
1597 			i++;
1598 			if (*activep && *uintptr == 0) {
1599 				*cppptr = xrecallocarray(*cppptr, *uintptr,
1600 				    *uintptr + 1, sizeof(**cppptr));
1601 				(*cppptr)[(*uintptr)++] = xstrdup(arg);
1602 			}
1603 		}
1604 		break;
1605 
1606 	case oLocalForward:
1607 	case oRemoteForward:
1608 	case oDynamicForward:
1609 		arg = argv_next(&ac, &av);
1610 		if (!arg || *arg == '\0') {
1611 			error("%.200s line %d: Missing argument.",
1612 			    filename, linenum);
1613 			goto out;
1614 		}
1615 
1616 		remotefwd = (opcode == oRemoteForward);
1617 		dynamicfwd = (opcode == oDynamicForward);
1618 
1619 		if (!dynamicfwd) {
1620 			arg2 = argv_next(&ac, &av);
1621 			if (arg2 == NULL || *arg2 == '\0') {
1622 				if (remotefwd)
1623 					dynamicfwd = 1;
1624 				else {
1625 					error("%.200s line %d: Missing target "
1626 					    "argument.", filename, linenum);
1627 					goto out;
1628 				}
1629 			} else {
1630 				/* construct a string for parse_forward */
1631 				snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg,
1632 				    arg2);
1633 			}
1634 		}
1635 		if (dynamicfwd)
1636 			strlcpy(fwdarg, arg, sizeof(fwdarg));
1637 
1638 		if (parse_forward(&fwd, fwdarg, dynamicfwd, remotefwd) == 0) {
1639 			error("%.200s line %d: Bad forwarding specification.",
1640 			    filename, linenum);
1641 			goto out;
1642 		}
1643 
1644 		if (*activep) {
1645 			if (remotefwd) {
1646 				add_remote_forward(options, &fwd);
1647 			} else {
1648 				add_local_forward(options, &fwd);
1649 			}
1650 		}
1651 		break;
1652 
1653 	case oPermitRemoteOpen:
1654 		uintptr = &options->num_permitted_remote_opens;
1655 		cppptr = &options->permitted_remote_opens;
1656 		uvalue = *uintptr;	/* modified later */
1657 		i = 0;
1658 		while ((arg = argv_next(&ac, &av)) != NULL) {
1659 			arg2 = xstrdup(arg);
1660 			/* Allow any/none only in first position */
1661 			if (strcasecmp(arg, "none") == 0 ||
1662 			    strcasecmp(arg, "any") == 0) {
1663 				if (i > 0 || ac > 0) {
1664 					error("%s line %d: keyword %s \"%s\" "
1665 					    "argument must appear alone.",
1666 					    filename, linenum, keyword, arg);
1667 					goto out;
1668 				}
1669 			} else {
1670 				p = hpdelim(&arg);
1671 				if (p == NULL) {
1672 					fatal("%s line %d: missing host in %s",
1673 					    filename, linenum,
1674 					    lookup_opcode_name(opcode));
1675 				}
1676 				p = cleanhostname(p);
1677 				/*
1678 				 * don't want to use permitopen_port to avoid
1679 				 * dependency on channels.[ch] here.
1680 				 */
1681 				if (arg == NULL || (strcmp(arg, "*") != 0 &&
1682 				    a2port(arg) <= 0)) {
1683 					fatal("%s line %d: bad port number "
1684 					    "in %s", filename, linenum,
1685 					    lookup_opcode_name(opcode));
1686 				}
1687 			}
1688 			if (*activep && uvalue == 0) {
1689 				opt_array_append(filename, linenum,
1690 				    lookup_opcode_name(opcode),
1691 				    cppptr, uintptr, arg2);
1692 			}
1693 			free(arg2);
1694 			i++;
1695 		}
1696 		if (i == 0)
1697 			fatal("%s line %d: missing %s specification",
1698 			    filename, linenum, lookup_opcode_name(opcode));
1699 		break;
1700 
1701 	case oClearAllForwardings:
1702 		intptr = &options->clear_forwardings;
1703 		goto parse_flag;
1704 
1705 	case oHost:
1706 		if (cmdline) {
1707 			error("Host directive not supported as a command-line "
1708 			    "option");
1709 			goto out;
1710 		}
1711 		*activep = 0;
1712 		arg2 = NULL;
1713 		while ((arg = argv_next(&ac, &av)) != NULL) {
1714 			if (*arg == '\0') {
1715 				error("%s line %d: keyword %s empty argument",
1716 				    filename, linenum, keyword);
1717 				goto out;
1718 			}
1719 			if ((flags & SSHCONF_NEVERMATCH) != 0) {
1720 				argv_consume(&ac);
1721 				break;
1722 			}
1723 			negated = *arg == '!';
1724 			if (negated)
1725 				arg++;
1726 			if (match_pattern(host, arg)) {
1727 				if (negated) {
1728 					debug("%.200s line %d: Skipping Host "
1729 					    "block because of negated match "
1730 					    "for %.100s", filename, linenum,
1731 					    arg);
1732 					*activep = 0;
1733 					argv_consume(&ac);
1734 					break;
1735 				}
1736 				if (!*activep)
1737 					arg2 = arg; /* logged below */
1738 				*activep = 1;
1739 			}
1740 		}
1741 		if (*activep)
1742 			debug("%.200s line %d: Applying options for %.100s",
1743 			    filename, linenum, arg2);
1744 		break;
1745 
1746 	case oMatch:
1747 		if (cmdline) {
1748 			error("Host directive not supported as a command-line "
1749 			    "option");
1750 			goto out;
1751 		}
1752 		value = match_cfg_line(options, &str, pw, host, original_host,
1753 		    flags & SSHCONF_FINAL, want_final_pass,
1754 		    filename, linenum);
1755 		if (value < 0) {
1756 			error("%.200s line %d: Bad Match condition", filename,
1757 			    linenum);
1758 			goto out;
1759 		}
1760 		*activep = (flags & SSHCONF_NEVERMATCH) ? 0 : value;
1761 		/*
1762 		 * If match_cfg_line() didn't consume all its arguments then
1763 		 * arrange for the extra arguments check below to fail.
1764 		 */
1765 
1766 		if (str == NULL || *str == '\0')
1767 			argv_consume(&ac);
1768 		break;
1769 
1770 	case oEscapeChar:
1771 		intptr = &options->escape_char;
1772 		arg = argv_next(&ac, &av);
1773 		if (!arg || *arg == '\0') {
1774 			error("%.200s line %d: Missing argument.",
1775 			    filename, linenum);
1776 			goto out;
1777 		}
1778 		if (strcmp(arg, "none") == 0)
1779 			value = SSH_ESCAPECHAR_NONE;
1780 		else if (arg[1] == '\0')
1781 			value = (u_char) arg[0];
1782 		else if (arg[0] == '^' && arg[2] == 0 &&
1783 		    (u_char) arg[1] >= 64 && (u_char) arg[1] < 128)
1784 			value = (u_char) arg[1] & 31;
1785 		else {
1786 			error("%.200s line %d: Bad escape character.",
1787 			    filename, linenum);
1788 			goto out;
1789 		}
1790 		if (*activep && *intptr == -1)
1791 			*intptr = value;
1792 		break;
1793 
1794 	case oAddressFamily:
1795 		intptr = &options->address_family;
1796 		multistate_ptr = multistate_addressfamily;
1797 		goto parse_multistate;
1798 
1799 	case oEnableSSHKeysign:
1800 		intptr = &options->enable_ssh_keysign;
1801 		goto parse_flag;
1802 
1803 	case oIdentitiesOnly:
1804 		intptr = &options->identities_only;
1805 		goto parse_flag;
1806 
1807 	case oServerAliveInterval:
1808 		intptr = &options->server_alive_interval;
1809 		goto parse_time;
1810 
1811 	case oServerAliveCountMax:
1812 		intptr = &options->server_alive_count_max;
1813 		goto parse_int;
1814 
1815 	case oSendEnv:
1816 		while ((arg = argv_next(&ac, &av)) != NULL) {
1817 			if (*arg == '\0' || strchr(arg, '=') != NULL) {
1818 				error("%s line %d: Invalid environment name.",
1819 				    filename, linenum);
1820 				goto out;
1821 			}
1822 			if (!*activep)
1823 				continue;
1824 			if (*arg == '-') {
1825 				/* Removing an env var */
1826 				rm_env(options, arg, filename, linenum);
1827 				continue;
1828 			}
1829 			opt_array_append(filename, linenum,
1830 			    lookup_opcode_name(opcode),
1831 			    &options->send_env, &options->num_send_env, arg);
1832 		}
1833 		break;
1834 
1835 	case oSetEnv:
1836 		value = options->num_setenv;
1837 		while ((arg = argv_next(&ac, &av)) != NULL) {
1838 			if (strchr(arg, '=') == NULL) {
1839 				error("%s line %d: Invalid SetEnv.",
1840 				    filename, linenum);
1841 				goto out;
1842 			}
1843 			if (!*activep || value != 0)
1844 				continue;
1845 			if (lookup_setenv_in_list(arg, options->setenv,
1846 			    options->num_setenv) != NULL) {
1847 				debug2("%s line %d: ignoring duplicate env "
1848 				    "name \"%.64s\"", filename, linenum, arg);
1849 				continue;
1850 			}
1851 			opt_array_append(filename, linenum,
1852 			    lookup_opcode_name(opcode),
1853 			    &options->setenv, &options->num_setenv, arg);
1854 		}
1855 		break;
1856 
1857 	case oControlPath:
1858 		charptr = &options->control_path;
1859 		goto parse_string;
1860 
1861 	case oControlMaster:
1862 		intptr = &options->control_master;
1863 		multistate_ptr = multistate_controlmaster;
1864 		goto parse_multistate;
1865 
1866 	case oControlPersist:
1867 		/* no/false/yes/true, or a time spec */
1868 		intptr = &options->control_persist;
1869 		arg = argv_next(&ac, &av);
1870 		if (!arg || *arg == '\0') {
1871 			error("%.200s line %d: Missing ControlPersist"
1872 			    " argument.", filename, linenum);
1873 			goto out;
1874 		}
1875 		value = 0;
1876 		value2 = 0;	/* timeout */
1877 		if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
1878 			value = 0;
1879 		else if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
1880 			value = 1;
1881 		else if ((value2 = convtime(arg)) >= 0)
1882 			value = 1;
1883 		else {
1884 			error("%.200s line %d: Bad ControlPersist argument.",
1885 			    filename, linenum);
1886 			goto out;
1887 		}
1888 		if (*activep && *intptr == -1) {
1889 			*intptr = value;
1890 			options->control_persist_timeout = value2;
1891 		}
1892 		break;
1893 
1894 	case oHashKnownHosts:
1895 		intptr = &options->hash_known_hosts;
1896 		goto parse_flag;
1897 
1898 	case oTunnel:
1899 		intptr = &options->tun_open;
1900 		multistate_ptr = multistate_tunnel;
1901 		goto parse_multistate;
1902 
1903 	case oTunnelDevice:
1904 		arg = argv_next(&ac, &av);
1905 		if (!arg || *arg == '\0') {
1906 			error("%.200s line %d: Missing argument.",
1907 			    filename, linenum);
1908 			goto out;
1909 		}
1910 		value = a2tun(arg, &value2);
1911 		if (value == SSH_TUNID_ERR) {
1912 			error("%.200s line %d: Bad tun device.",
1913 			    filename, linenum);
1914 			goto out;
1915 		}
1916 		if (*activep && options->tun_local == -1) {
1917 			options->tun_local = value;
1918 			options->tun_remote = value2;
1919 		}
1920 		break;
1921 
1922 	case oLocalCommand:
1923 		charptr = &options->local_command;
1924 		goto parse_command;
1925 
1926 	case oPermitLocalCommand:
1927 		intptr = &options->permit_local_command;
1928 		goto parse_flag;
1929 
1930 	case oRemoteCommand:
1931 		charptr = &options->remote_command;
1932 		goto parse_command;
1933 
1934 	case oVisualHostKey:
1935 		intptr = &options->visual_host_key;
1936 		goto parse_flag;
1937 
1938 	case oInclude:
1939 		if (cmdline) {
1940 			error("Include directive not supported as a "
1941 			    "command-line option");
1942 			goto out;
1943 		}
1944 		value = 0;
1945 		while ((arg = argv_next(&ac, &av)) != NULL) {
1946 			if (*arg == '\0') {
1947 				error("%s line %d: keyword %s empty argument",
1948 				    filename, linenum, keyword);
1949 				goto out;
1950 			}
1951 			/*
1952 			 * Ensure all paths are anchored. User configuration
1953 			 * files may begin with '~/' but system configurations
1954 			 * must not. If the path is relative, then treat it
1955 			 * as living in ~/.ssh for user configurations or
1956 			 * /etc/ssh for system ones.
1957 			 */
1958 			if (*arg == '~' && (flags & SSHCONF_USERCONF) == 0) {
1959 				error("%.200s line %d: bad include path %s.",
1960 				    filename, linenum, arg);
1961 				goto out;
1962 			}
1963 			if (!path_absolute(arg) && *arg != '~') {
1964 				xasprintf(&arg2, "%s/%s",
1965 				    (flags & SSHCONF_USERCONF) ?
1966 				    "~/" _PATH_SSH_USER_DIR : SSHDIR, arg);
1967 			} else
1968 				arg2 = xstrdup(arg);
1969 			memset(&gl, 0, sizeof(gl));
1970 			r = glob(arg2, GLOB_TILDE | GLOB_LIMIT, NULL, &gl);
1971 			if (r == GLOB_NOMATCH) {
1972 				debug("%.200s line %d: include %s matched no "
1973 				    "files",filename, linenum, arg2);
1974 				free(arg2);
1975 				continue;
1976 			} else if (r != 0) {
1977 				error("%.200s line %d: glob failed for %s.",
1978 				    filename, linenum, arg2);
1979 				goto out;
1980 			}
1981 			free(arg2);
1982 			oactive = *activep;
1983 			for (i = 0; i < gl.gl_pathc; i++) {
1984 				debug3("%.200s line %d: Including file %s "
1985 				    "depth %d%s", filename, linenum,
1986 				    gl.gl_pathv[i], depth,
1987 				    oactive ? "" : " (parse only)");
1988 				r = read_config_file_depth(gl.gl_pathv[i],
1989 				    pw, host, original_host, options,
1990 				    flags | SSHCONF_CHECKPERM |
1991 				    (oactive ? 0 : SSHCONF_NEVERMATCH),
1992 				    activep, want_final_pass, depth + 1);
1993 				if (r != 1 && errno != ENOENT) {
1994 					error("Can't open user config file "
1995 					    "%.100s: %.100s", gl.gl_pathv[i],
1996 					    strerror(errno));
1997 					globfree(&gl);
1998 					goto out;
1999 				}
2000 				/*
2001 				 * don't let Match in includes clobber the
2002 				 * containing file's Match state.
2003 				 */
2004 				*activep = oactive;
2005 				if (r != 1)
2006 					value = -1;
2007 			}
2008 			globfree(&gl);
2009 		}
2010 		if (value != 0)
2011 			ret = value;
2012 		break;
2013 
2014 	case oIPQoS:
2015 		arg = argv_next(&ac, &av);
2016 		if ((value = parse_ipqos(arg)) == -1) {
2017 			error("%s line %d: Bad IPQoS value: %s",
2018 			    filename, linenum, arg);
2019 			goto out;
2020 		}
2021 		arg = argv_next(&ac, &av);
2022 		if (arg == NULL)
2023 			value2 = value;
2024 		else if ((value2 = parse_ipqos(arg)) == -1) {
2025 			error("%s line %d: Bad IPQoS value: %s",
2026 			    filename, linenum, arg);
2027 			goto out;
2028 		}
2029 		if (*activep && options->ip_qos_interactive == -1) {
2030 			options->ip_qos_interactive = value;
2031 			options->ip_qos_bulk = value2;
2032 		}
2033 		break;
2034 
2035 	case oRequestTTY:
2036 		intptr = &options->request_tty;
2037 		multistate_ptr = multistate_requesttty;
2038 		goto parse_multistate;
2039 
2040 	case oSendVersionFirst:
2041 		intptr = &options->send_version_first;
2042 		goto parse_flag;
2043 
2044 	case oSessionType:
2045 		intptr = &options->session_type;
2046 		multistate_ptr = multistate_sessiontype;
2047 		goto parse_multistate;
2048 
2049 	case oStdinNull:
2050 		intptr = &options->stdin_null;
2051 		goto parse_flag;
2052 
2053 	case oForkAfterAuthentication:
2054 		intptr = &options->fork_after_authentication;
2055 		goto parse_flag;
2056 
2057 	case oIgnoreUnknown:
2058 		charptr = &options->ignored_unknown;
2059 		goto parse_string;
2060 
2061 	case oProxyUseFdpass:
2062 		intptr = &options->proxy_use_fdpass;
2063 		goto parse_flag;
2064 
2065 	case oCanonicalDomains:
2066 		value = options->num_canonical_domains != 0;
2067 		i = 0;
2068 		while ((arg = argv_next(&ac, &av)) != NULL) {
2069 			if (*arg == '\0') {
2070 				error("%s line %d: keyword %s empty argument",
2071 				    filename, linenum, keyword);
2072 				goto out;
2073 			}
2074 			/* Allow "none" only in first position */
2075 			if (strcasecmp(arg, "none") == 0) {
2076 				if (i > 0 || ac > 0) {
2077 					error("%s line %d: keyword %s \"none\" "
2078 					    "argument must appear alone.",
2079 					    filename, linenum, keyword);
2080 					goto out;
2081 				}
2082 			}
2083 			i++;
2084 			if (!valid_domain(arg, 1, &errstr)) {
2085 				error("%s line %d: %s", filename, linenum,
2086 				    errstr);
2087 				goto out;
2088 			}
2089 			if (!*activep || value)
2090 				continue;
2091 			if (options->num_canonical_domains >=
2092 			    MAX_CANON_DOMAINS) {
2093 				error("%s line %d: too many hostname suffixes.",
2094 				    filename, linenum);
2095 				goto out;
2096 			}
2097 			options->canonical_domains[
2098 			    options->num_canonical_domains++] = xstrdup(arg);
2099 		}
2100 		break;
2101 
2102 	case oCanonicalizePermittedCNAMEs:
2103 		value = options->num_permitted_cnames != 0;
2104 		i = 0;
2105 		while ((arg = argv_next(&ac, &av)) != NULL) {
2106 			char empty[] = "";
2107 			/*
2108 			 * Either 'none' (only in first position), '*' for
2109 			 * everything or 'list:list'
2110 			 */
2111 			if (strcasecmp(arg, "none") == 0) {
2112 				if (i > 0 || ac > 0) {
2113 					error("%s line %d: keyword %s \"none\" "
2114 					    "argument must appear alone.",
2115 					    filename, linenum, keyword);
2116 					goto out;
2117 				}
2118 				arg2 = empty;
2119 			} else if (strcmp(arg, "*") == 0) {
2120 				arg2 = arg;
2121 			} else {
2122 				lowercase(arg);
2123 				if ((arg2 = strchr(arg, ':')) == NULL ||
2124 				    arg2[1] == '\0') {
2125 					error("%s line %d: "
2126 					    "Invalid permitted CNAME \"%s\"",
2127 					    filename, linenum, arg);
2128 					goto out;
2129 				}
2130 				*arg2 = '\0';
2131 				arg2++;
2132 			}
2133 			i++;
2134 			if (!*activep || value)
2135 				continue;
2136 			if (options->num_permitted_cnames >=
2137 			    MAX_CANON_DOMAINS) {
2138 				error("%s line %d: too many permitted CNAMEs.",
2139 				    filename, linenum);
2140 				goto out;
2141 			}
2142 			cname = options->permitted_cnames +
2143 			    options->num_permitted_cnames++;
2144 			cname->source_list = xstrdup(arg);
2145 			cname->target_list = xstrdup(arg2);
2146 		}
2147 		break;
2148 
2149 	case oCanonicalizeHostname:
2150 		intptr = &options->canonicalize_hostname;
2151 		multistate_ptr = multistate_canonicalizehostname;
2152 		goto parse_multistate;
2153 
2154 	case oCanonicalizeMaxDots:
2155 		intptr = &options->canonicalize_max_dots;
2156 		goto parse_int;
2157 
2158 	case oCanonicalizeFallbackLocal:
2159 		intptr = &options->canonicalize_fallback_local;
2160 		goto parse_flag;
2161 
2162 	case oStreamLocalBindMask:
2163 		arg = argv_next(&ac, &av);
2164 		if (!arg || *arg == '\0') {
2165 			error("%.200s line %d: Missing StreamLocalBindMask "
2166 			    "argument.", filename, linenum);
2167 			goto out;
2168 		}
2169 		/* Parse mode in octal format */
2170 		value = strtol(arg, &endofnumber, 8);
2171 		if (arg == endofnumber || value < 0 || value > 0777) {
2172 			error("%.200s line %d: Bad mask.", filename, linenum);
2173 			goto out;
2174 		}
2175 		options->fwd_opts.streamlocal_bind_mask = (mode_t)value;
2176 		break;
2177 
2178 	case oStreamLocalBindUnlink:
2179 		intptr = &options->fwd_opts.streamlocal_bind_unlink;
2180 		goto parse_flag;
2181 
2182 	case oRevokedHostKeys:
2183 		charptr = &options->revoked_host_keys;
2184 		goto parse_string;
2185 
2186 	case oFingerprintHash:
2187 		intptr = &options->fingerprint_hash;
2188 		arg = argv_next(&ac, &av);
2189 		if (!arg || *arg == '\0') {
2190 			error("%.200s line %d: Missing argument.",
2191 			    filename, linenum);
2192 			goto out;
2193 		}
2194 		if ((value = ssh_digest_alg_by_name(arg)) == -1) {
2195 			error("%.200s line %d: Invalid hash algorithm \"%s\".",
2196 			    filename, linenum, arg);
2197 			goto out;
2198 		}
2199 		if (*activep && *intptr == -1)
2200 			*intptr = value;
2201 		break;
2202 
2203 	case oUpdateHostkeys:
2204 		intptr = &options->update_hostkeys;
2205 		multistate_ptr = multistate_yesnoask;
2206 		goto parse_multistate;
2207 
2208 	case oHostbasedAcceptedAlgorithms:
2209 		charptr = &options->hostbased_accepted_algos;
2210 		goto parse_pubkey_algos;
2211 
2212 	case oPubkeyAcceptedAlgorithms:
2213 		charptr = &options->pubkey_accepted_algos;
2214 		goto parse_pubkey_algos;
2215 
2216 	case oAddKeysToAgent:
2217 		arg = argv_next(&ac, &av);
2218 		arg2 = argv_next(&ac, &av);
2219 		value = parse_multistate_value(arg, filename, linenum,
2220 		    multistate_yesnoaskconfirm);
2221 		value2 = 0; /* unlimited lifespan by default */
2222 		if (value == 3 && arg2 != NULL) {
2223 			/* allow "AddKeysToAgent confirm 5m" */
2224 			if ((value2 = convtime(arg2)) == -1) {
2225 				error("%s line %d: invalid time value.",
2226 				    filename, linenum);
2227 				goto out;
2228 			}
2229 		} else if (value == -1 && arg2 == NULL) {
2230 			if ((value2 = convtime(arg)) == -1) {
2231 				error("%s line %d: unsupported option",
2232 				    filename, linenum);
2233 				goto out;
2234 			}
2235 			value = 1; /* yes */
2236 		} else if (value == -1 || arg2 != NULL) {
2237 			error("%s line %d: unsupported option",
2238 			    filename, linenum);
2239 			goto out;
2240 		}
2241 		if (*activep && options->add_keys_to_agent == -1) {
2242 			options->add_keys_to_agent = value;
2243 			options->add_keys_to_agent_lifespan = value2;
2244 		}
2245 		break;
2246 
2247 	case oIdentityAgent:
2248 		charptr = &options->identity_agent;
2249 		arg = argv_next(&ac, &av);
2250 		if (!arg || *arg == '\0') {
2251 			error("%.200s line %d: Missing argument.",
2252 			    filename, linenum);
2253 			goto out;
2254 		}
2255   parse_agent_path:
2256 		/* Extra validation if the string represents an env var. */
2257 		if ((arg2 = dollar_expand(&r, arg)) == NULL || r) {
2258 			error("%.200s line %d: Invalid environment expansion "
2259 			    "%s.", filename, linenum, arg);
2260 			goto out;
2261 		}
2262 		free(arg2);
2263 		/* check for legacy environment format */
2264 		if (arg[0] == '$' && arg[1] != '{' &&
2265 		    !valid_env_name(arg + 1)) {
2266 			error("%.200s line %d: Invalid environment name %s.",
2267 			    filename, linenum, arg);
2268 			goto out;
2269 		}
2270 		if (*activep && *charptr == NULL)
2271 			*charptr = xstrdup(arg);
2272 		break;
2273 
2274 	case oEnableEscapeCommandline:
2275 		intptr = &options->enable_escape_commandline;
2276 		goto parse_flag;
2277 
2278 	case oRequiredRSASize:
2279 		intptr = &options->required_rsa_size;
2280 		goto parse_int;
2281 
2282 	case oDeprecated:
2283 		debug("%s line %d: Deprecated option \"%s\"",
2284 		    filename, linenum, keyword);
2285 		argv_consume(&ac);
2286 		break;
2287 
2288 	case oUnsupported:
2289 		error("%s line %d: Unsupported option \"%s\"",
2290 		    filename, linenum, keyword);
2291 		argv_consume(&ac);
2292 		break;
2293 
2294 	default:
2295 		error("%s line %d: Unimplemented opcode %d",
2296 		    filename, linenum, opcode);
2297 		goto out;
2298 	}
2299 
2300 	/* Check that there is no garbage at end of line. */
2301 	if (ac > 0) {
2302 		error("%.200s line %d: keyword %s extra arguments "
2303 		    "at end of line", filename, linenum, keyword);
2304 		goto out;
2305 	}
2306 
2307 	/* success */
2308 	ret = 0;
2309  out:
2310 	argv_free(oav, oac);
2311 	return ret;
2312 }
2313 
2314 /*
2315  * Reads the config file and modifies the options accordingly.  Options
2316  * should already be initialized before this call.  This never returns if
2317  * there is an error.  If the file does not exist, this returns 0.
2318  */
2319 int
read_config_file(const char * filename,struct passwd * pw,const char * host,const char * original_host,Options * options,int flags,int * want_final_pass)2320 read_config_file(const char *filename, struct passwd *pw, const char *host,
2321     const char *original_host, Options *options, int flags,
2322     int *want_final_pass)
2323 {
2324 	int active = 1;
2325 
2326 	return read_config_file_depth(filename, pw, host, original_host,
2327 	    options, flags, &active, want_final_pass, 0);
2328 }
2329 
2330 #define READCONF_MAX_DEPTH	16
2331 static int
read_config_file_depth(const char * filename,struct passwd * pw,const char * host,const char * original_host,Options * options,int flags,int * activep,int * want_final_pass,int depth)2332 read_config_file_depth(const char *filename, struct passwd *pw,
2333     const char *host, const char *original_host, Options *options,
2334     int flags, int *activep, int *want_final_pass, int depth)
2335 {
2336 	FILE *f;
2337 	char *line = NULL;
2338 	size_t linesize = 0;
2339 	int linenum;
2340 	int bad_options = 0;
2341 
2342 	if (depth < 0 || depth > READCONF_MAX_DEPTH)
2343 		fatal("Too many recursive configuration includes");
2344 
2345 	if ((f = fopen(filename, "r")) == NULL)
2346 		return 0;
2347 
2348 	if (flags & SSHCONF_CHECKPERM) {
2349 		struct stat sb;
2350 
2351 		if (fstat(fileno(f), &sb) == -1)
2352 			fatal("fstat %s: %s", filename, strerror(errno));
2353 		if (((sb.st_uid != 0 && sb.st_uid != getuid()) ||
2354 		    (sb.st_mode & 022) != 0))
2355 			fatal("Bad owner or permissions on %s", filename);
2356 	}
2357 
2358 	debug("Reading configuration data %.200s", filename);
2359 
2360 	/*
2361 	 * Mark that we are now processing the options.  This flag is turned
2362 	 * on/off by Host specifications.
2363 	 */
2364 	linenum = 0;
2365 	while (getline(&line, &linesize, f) != -1) {
2366 		/* Update line number counter. */
2367 		linenum++;
2368 		/*
2369 		 * Trim out comments and strip whitespace.
2370 		 * NB - preserve newlines, they are needed to reproduce
2371 		 * line numbers later for error messages.
2372 		 */
2373 		if (process_config_line_depth(options, pw, host, original_host,
2374 		    line, filename, linenum, activep, flags, want_final_pass,
2375 		    depth) != 0)
2376 			bad_options++;
2377 	}
2378 	free(line);
2379 	fclose(f);
2380 	if (bad_options > 0)
2381 		fatal("%s: terminating, %d bad configuration options",
2382 		    filename, bad_options);
2383 	return 1;
2384 }
2385 
2386 /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */
2387 int
option_clear_or_none(const char * o)2388 option_clear_or_none(const char *o)
2389 {
2390 	return o == NULL || strcasecmp(o, "none") == 0;
2391 }
2392 
2393 /*
2394  * Returns 1 if CanonicalizePermittedCNAMEs have been specified, 0 otherwise.
2395  * Allowed to be called on non-final configuration.
2396  */
2397 int
config_has_permitted_cnames(Options * options)2398 config_has_permitted_cnames(Options *options)
2399 {
2400 	if (options->num_permitted_cnames == 1 &&
2401 	    strcasecmp(options->permitted_cnames[0].source_list, "none") == 0 &&
2402 	    strcmp(options->permitted_cnames[0].target_list, "") == 0)
2403 		return 0;
2404 	return options->num_permitted_cnames > 0;
2405 }
2406 
2407 /*
2408  * Initializes options to special values that indicate that they have not yet
2409  * been set.  Read_config_file will only set options with this value. Options
2410  * are processed in the following order: command line, user config file,
2411  * system config file.  Last, fill_default_options is called.
2412  */
2413 
2414 void
initialize_options(Options * options)2415 initialize_options(Options * options)
2416 {
2417 	memset(options, 'X', sizeof(*options));
2418 	options->host_arg = NULL;
2419 	options->forward_agent = -1;
2420 	options->forward_agent_sock_path = NULL;
2421 	options->forward_x11 = -1;
2422 	options->forward_x11_trusted = -1;
2423 	options->forward_x11_timeout = -1;
2424 	options->stdio_forward_host = NULL;
2425 	options->stdio_forward_port = 0;
2426 	options->clear_forwardings = -1;
2427 	options->exit_on_forward_failure = -1;
2428 	options->xauth_location = NULL;
2429 	options->fwd_opts.gateway_ports = -1;
2430 	options->fwd_opts.streamlocal_bind_mask = (mode_t)-1;
2431 	options->fwd_opts.streamlocal_bind_unlink = -1;
2432 	options->pubkey_authentication = -1;
2433 #if defined(KRB4) || defined(KRB5)
2434 	options->kerberos_authentication = -1;
2435 #endif
2436 #if defined(AFS) || defined(KRB5)
2437 	options->kerberos_tgt_passing = -1;
2438 #endif
2439 #ifdef AFS
2440 	options->afs_token_passing = -1;
2441 #endif
2442 	options->gss_authentication = -1;
2443 	options->gss_deleg_creds = -1;
2444 	options->password_authentication = -1;
2445 	options->kbd_interactive_authentication = -1;
2446 	options->kbd_interactive_devices = NULL;
2447 	options->hostbased_authentication = -1;
2448 	options->batch_mode = -1;
2449 	options->check_host_ip = -1;
2450 	options->strict_host_key_checking = -1;
2451 	options->compression = -1;
2452 	options->tcp_keep_alive = -1;
2453 	options->port = -1;
2454 	options->address_family = -1;
2455 	options->connection_attempts = -1;
2456 	options->connection_timeout = -1;
2457 	options->number_of_password_prompts = -1;
2458 	options->ciphers = NULL;
2459 	options->macs = NULL;
2460 	options->kex_algorithms = NULL;
2461 	options->hostkeyalgorithms = NULL;
2462 	options->ca_sign_algorithms = NULL;
2463 	options->num_identity_files = 0;
2464 	memset(options->identity_keys, 0, sizeof(options->identity_keys));
2465 	options->num_certificate_files = 0;
2466 	memset(options->certificates, 0, sizeof(options->certificates));
2467 	options->hostname = NULL;
2468 	options->host_key_alias = NULL;
2469 	options->proxy_command = NULL;
2470 	options->jump_user = NULL;
2471 	options->jump_host = NULL;
2472 	options->jump_port = -1;
2473 	options->jump_extra = NULL;
2474 	options->user = NULL;
2475 	options->escape_char = -1;
2476 	options->num_system_hostfiles = 0;
2477 	options->num_user_hostfiles = 0;
2478 	options->local_forwards = NULL;
2479 	options->num_local_forwards = 0;
2480 	options->remote_forwards = NULL;
2481 	options->num_remote_forwards = 0;
2482 	options->permitted_remote_opens = NULL;
2483 	options->num_permitted_remote_opens = 0;
2484 	options->log_facility = SYSLOG_FACILITY_NOT_SET;
2485 	options->log_level = SYSLOG_LEVEL_NOT_SET;
2486 	options->num_log_verbose = 0;
2487 	options->log_verbose = NULL;
2488 	options->preferred_authentications = NULL;
2489 	options->bind_address = NULL;
2490 	options->bind_interface = NULL;
2491 	options->pkcs11_provider = NULL;
2492 	options->sk_provider = NULL;
2493 	options->enable_ssh_keysign = - 1;
2494 	options->no_host_authentication_for_localhost = - 1;
2495 	options->identities_only = - 1;
2496 	options->rekey_limit = - 1;
2497 	options->rekey_interval = -1;
2498 	options->verify_host_key_dns = -1;
2499 	options->server_alive_interval = -1;
2500 	options->server_alive_count_max = -1;
2501 	options->send_env = NULL;
2502 	options->num_send_env = 0;
2503 	options->setenv = NULL;
2504 	options->num_setenv = 0;
2505 	options->control_path = NULL;
2506 	options->control_master = -1;
2507 	options->control_persist = -1;
2508 	options->control_persist_timeout = 0;
2509 	options->hash_known_hosts = -1;
2510 	options->tun_open = -1;
2511 	options->tun_local = -1;
2512 	options->tun_remote = -1;
2513 	options->local_command = NULL;
2514 	options->permit_local_command = -1;
2515 	options->remote_command = NULL;
2516 	options->add_keys_to_agent = -1;
2517 	options->add_keys_to_agent_lifespan = -1;
2518 	options->identity_agent = NULL;
2519 	options->visual_host_key = -1;
2520 	options->ip_qos_interactive = -1;
2521 	options->ip_qos_bulk = -1;
2522 	options->request_tty = -1;
2523 	options->session_type = -1;
2524 	options->stdin_null = -1;
2525 	options->fork_after_authentication = -1;
2526 	options->proxy_use_fdpass = -1;
2527 	options->ignored_unknown = NULL;
2528 	options->num_canonical_domains = 0;
2529 	options->num_permitted_cnames = 0;
2530 	options->canonicalize_max_dots = -1;
2531 	options->canonicalize_fallback_local = -1;
2532 	options->canonicalize_hostname = -1;
2533 	options->revoked_host_keys = NULL;
2534 	options->fingerprint_hash = -1;
2535 	options->update_hostkeys = -1;
2536 	options->hostbased_accepted_algos = NULL;
2537 	options->pubkey_accepted_algos = NULL;
2538 	options->known_hosts_command = NULL;
2539 	options->required_rsa_size = -1;
2540 	options->enable_escape_commandline = -1;
2541 	options->none_switch = -1;
2542 	options->none_enabled = -1;
2543 	options->hpn_disabled = -1;
2544 	options->hpn_buffer_size = -1;
2545 	options->tcp_rcv_buf_poll = -1;
2546 	options->tcp_rcv_buf = -1;
2547 	options->send_version_first = -1;
2548 }
2549 
2550 /*
2551  * A petite version of fill_default_options() that just fills the options
2552  * needed for hostname canonicalization to proceed.
2553  */
2554 void
fill_default_options_for_canonicalization(Options * options)2555 fill_default_options_for_canonicalization(Options *options)
2556 {
2557 	if (options->canonicalize_max_dots == -1)
2558 		options->canonicalize_max_dots = 1;
2559 	if (options->canonicalize_fallback_local == -1)
2560 		options->canonicalize_fallback_local = 1;
2561 	if (options->canonicalize_hostname == -1)
2562 		options->canonicalize_hostname = SSH_CANONICALISE_NO;
2563 }
2564 
2565 /*
2566  * Called after processing other sources of option data, this fills those
2567  * options for which no value has been specified with their default values.
2568  */
2569 int
fill_default_options(Options * options)2570 fill_default_options(Options * options)
2571 {
2572 	char *all_cipher, *all_mac, *all_kex, *all_key, *all_sig;
2573 	char *def_cipher, *def_mac, *def_kex, *def_key, *def_sig;
2574 	int ret = 0, r;
2575 
2576 	if (options->forward_agent == -1)
2577 		options->forward_agent = 0;
2578 	if (options->forward_x11 == -1)
2579 		options->forward_x11 = 0;
2580 	if (options->forward_x11_trusted == -1)
2581 		options->forward_x11_trusted = 0;
2582 	if (options->forward_x11_timeout == -1)
2583 		options->forward_x11_timeout = 1200;
2584 	/*
2585 	 * stdio forwarding (-W) changes the default for these but we defer
2586 	 * setting the values so they can be overridden.
2587 	 */
2588 	if (options->exit_on_forward_failure == -1)
2589 		options->exit_on_forward_failure =
2590 		    options->stdio_forward_host != NULL ? 1 : 0;
2591 	if (options->clear_forwardings == -1)
2592 		options->clear_forwardings =
2593 		    options->stdio_forward_host != NULL ? 1 : 0;
2594 	if (options->clear_forwardings == 1)
2595 		clear_forwardings(options);
2596 
2597 	if (options->xauth_location == NULL)
2598 		options->xauth_location = xstrdup(_PATH_XAUTH);
2599 	if (options->fwd_opts.gateway_ports == -1)
2600 		options->fwd_opts.gateway_ports = 0;
2601 	if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1)
2602 		options->fwd_opts.streamlocal_bind_mask = 0177;
2603 	if (options->fwd_opts.streamlocal_bind_unlink == -1)
2604 		options->fwd_opts.streamlocal_bind_unlink = 0;
2605 	if (options->pubkey_authentication == -1)
2606 		options->pubkey_authentication = SSH_PUBKEY_AUTH_ALL;
2607 #if defined(KRB4) || defined(KRB5)
2608 	if (options->kerberos_authentication == -1)
2609 		options->kerberos_authentication = 1;
2610 #endif
2611 #if defined(AFS) || defined(KRB5)
2612 	if (options->kerberos_tgt_passing == -1)
2613 		options->kerberos_tgt_passing = 1;
2614 #endif
2615 #ifdef AFS
2616 	if (options->afs_token_passing == -1)
2617 		options->afs_token_passing = 1;
2618 #endif
2619 	if (options->gss_authentication == -1)
2620 		options->gss_authentication = 0;
2621 	if (options->gss_deleg_creds == -1)
2622 		options->gss_deleg_creds = 0;
2623 	if (options->password_authentication == -1)
2624 		options->password_authentication = 1;
2625 	if (options->kbd_interactive_authentication == -1)
2626 		options->kbd_interactive_authentication = 1;
2627 	if (options->hostbased_authentication == -1)
2628 		options->hostbased_authentication = 0;
2629 	if (options->batch_mode == -1)
2630 		options->batch_mode = 0;
2631 	if (options->check_host_ip == -1)
2632 		options->check_host_ip = 0;
2633 	if (options->strict_host_key_checking == -1)
2634 		options->strict_host_key_checking = SSH_STRICT_HOSTKEY_ASK;
2635 	if (options->compression == -1)
2636 		options->compression = 0;
2637 	if (options->tcp_keep_alive == -1)
2638 		options->tcp_keep_alive = 1;
2639 	if (options->port == -1)
2640 		options->port = 0;	/* Filled in ssh_connect. */
2641 	if (options->address_family == -1)
2642 		options->address_family = AF_UNSPEC;
2643 	if (options->connection_attempts == -1)
2644 		options->connection_attempts = 1;
2645 	if (options->number_of_password_prompts == -1)
2646 		options->number_of_password_prompts = 3;
2647 	/* options->hostkeyalgorithms, default set in myproposals.h */
2648 	if (options->add_keys_to_agent == -1) {
2649 		options->add_keys_to_agent = 0;
2650 		options->add_keys_to_agent_lifespan = 0;
2651 	}
2652 	if (options->num_identity_files == 0) {
2653 		add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_RSA, 0);
2654 		add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_ECDSA, 0);
2655 		add_identity_file(options, "~/",
2656 		    _PATH_SSH_CLIENT_ID_ECDSA_SK, 0);
2657 		add_identity_file(options, "~/",
2658 		    _PATH_SSH_CLIENT_ID_ED25519, 0);
2659 		add_identity_file(options, "~/",
2660 		    _PATH_SSH_CLIENT_ID_ED25519_SK, 0);
2661 		add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_XMSS, 0);
2662 		add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_DSA, 0);
2663 	}
2664 	if (options->escape_char == -1)
2665 		options->escape_char = '~';
2666 	if (options->num_system_hostfiles == 0) {
2667 		options->system_hostfiles[options->num_system_hostfiles++] =
2668 		    xstrdup(_PATH_SSH_SYSTEM_HOSTFILE);
2669 		options->system_hostfiles[options->num_system_hostfiles++] =
2670 		    xstrdup(_PATH_SSH_SYSTEM_HOSTFILE2);
2671 	}
2672 	if (options->update_hostkeys == -1) {
2673 		if (options->verify_host_key_dns <= 0 &&
2674 		    (options->num_user_hostfiles == 0 ||
2675 		    (options->num_user_hostfiles == 1 && strcmp(options->
2676 		    user_hostfiles[0], _PATH_SSH_USER_HOSTFILE) == 0)))
2677 			options->update_hostkeys = SSH_UPDATE_HOSTKEYS_YES;
2678 		else
2679 			options->update_hostkeys = SSH_UPDATE_HOSTKEYS_NO;
2680 	}
2681 	if (options->num_user_hostfiles == 0) {
2682 		options->user_hostfiles[options->num_user_hostfiles++] =
2683 		    xstrdup(_PATH_SSH_USER_HOSTFILE);
2684 		options->user_hostfiles[options->num_user_hostfiles++] =
2685 		    xstrdup(_PATH_SSH_USER_HOSTFILE2);
2686 	}
2687 	if (options->log_level == SYSLOG_LEVEL_NOT_SET)
2688 		options->log_level = SYSLOG_LEVEL_INFO;
2689 	if (options->log_facility == SYSLOG_FACILITY_NOT_SET)
2690 		options->log_facility = SYSLOG_FACILITY_USER;
2691 	if (options->no_host_authentication_for_localhost == - 1)
2692 		options->no_host_authentication_for_localhost = 0;
2693 	if (options->identities_only == -1)
2694 		options->identities_only = 0;
2695 	if (options->enable_ssh_keysign == -1)
2696 		options->enable_ssh_keysign = 0;
2697 	if (options->rekey_limit == -1)
2698 		options->rekey_limit = 0;
2699 	if (options->rekey_interval == -1)
2700 		options->rekey_interval = 0;
2701 	if (options->verify_host_key_dns == -1)
2702 		options->verify_host_key_dns = 0;
2703 	if (options->server_alive_interval == -1)
2704 		options->server_alive_interval = 0;
2705 	if (options->server_alive_count_max == -1)
2706 		options->server_alive_count_max = 3;
2707 	if (options->none_switch == -1)
2708 	        options->none_switch = 0;
2709 	if (options->hpn_disabled == -1)
2710 	        options->hpn_disabled = 0;
2711 	if (options->hpn_buffer_size > -1)
2712 	{
2713 	  /* if a user tries to set the size to 0 set it to 1KB */
2714 		if (options->hpn_buffer_size == 0)
2715 			options->hpn_buffer_size = 1;
2716 		/*limit the buffer to 64MB*/
2717 		if (options->hpn_buffer_size > (SSHBUF_SIZE_MAX / 1024))
2718 		{
2719 			options->hpn_buffer_size = SSHBUF_SIZE_MAX;
2720 			debug("User requested buffer larger than 256MB. Request reverted to 256MB");
2721 		} else
2722 			options->hpn_buffer_size *= 1024;
2723 		debug("hpn_buffer_size set to %d", options->hpn_buffer_size);
2724 	}
2725 	if (options->tcp_rcv_buf == 0)
2726 		options->tcp_rcv_buf = 1;
2727 	if (options->tcp_rcv_buf > -1)
2728 		options->tcp_rcv_buf *=1024;
2729 	if (options->tcp_rcv_buf_poll == -1)
2730 		options->tcp_rcv_buf_poll = 1;
2731 	if (options->control_master == -1)
2732 		options->control_master = 0;
2733 	if (options->control_persist == -1) {
2734 		options->control_persist = 0;
2735 		options->control_persist_timeout = 0;
2736 	}
2737 	if (options->hash_known_hosts == -1)
2738 		options->hash_known_hosts = 0;
2739 	if (options->tun_open == -1)
2740 		options->tun_open = SSH_TUNMODE_NO;
2741 	if (options->tun_local == -1)
2742 		options->tun_local = SSH_TUNID_ANY;
2743 	if (options->tun_remote == -1)
2744 		options->tun_remote = SSH_TUNID_ANY;
2745 	if (options->permit_local_command == -1)
2746 		options->permit_local_command = 0;
2747 	if (options->visual_host_key == -1)
2748 		options->visual_host_key = 0;
2749 	if (options->ip_qos_interactive == -1)
2750 		options->ip_qos_interactive = IPTOS_DSCP_AF21;
2751 	if (options->ip_qos_bulk == -1)
2752 		options->ip_qos_bulk = IPTOS_DSCP_CS1;
2753 	if (options->request_tty == -1)
2754 		options->request_tty = REQUEST_TTY_AUTO;
2755 	if (options->session_type == -1)
2756 		options->session_type = SESSION_TYPE_DEFAULT;
2757 	if (options->stdin_null == -1)
2758 		options->stdin_null = 0;
2759 	if (options->fork_after_authentication == -1)
2760 		options->fork_after_authentication = 0;
2761 	if (options->proxy_use_fdpass == -1)
2762 		options->proxy_use_fdpass = 0;
2763 	if (options->canonicalize_max_dots == -1)
2764 		options->canonicalize_max_dots = 1;
2765 	if (options->canonicalize_fallback_local == -1)
2766 		options->canonicalize_fallback_local = 1;
2767 	if (options->canonicalize_hostname == -1)
2768 		options->canonicalize_hostname = SSH_CANONICALISE_NO;
2769 	if (options->fingerprint_hash == -1)
2770 		options->fingerprint_hash = SSH_FP_HASH_DEFAULT;
2771 	if (options->sk_provider == NULL)
2772 		options->sk_provider = xstrdup("internal");
2773 	if (options->required_rsa_size == -1)
2774 		options->required_rsa_size = SSH_RSA_MINIMUM_MODULUS_SIZE;
2775 	if (options->enable_escape_commandline == -1)
2776 		options->enable_escape_commandline = 0;
2777 
2778 	/* Expand KEX name lists */
2779 	all_cipher = cipher_alg_list(',', 0);
2780 	all_mac = mac_alg_list(',');
2781 	all_kex = kex_alg_list(',');
2782 	all_key = sshkey_alg_list(0, 0, 1, ',');
2783 	all_sig = sshkey_alg_list(0, 1, 1, ',');
2784 	/* remove unsupported algos from default lists */
2785 	def_cipher = match_filter_allowlist(KEX_CLIENT_ENCRYPT, all_cipher);
2786 	def_mac = match_filter_allowlist(KEX_CLIENT_MAC, all_mac);
2787 	def_kex = match_filter_allowlist(KEX_CLIENT_KEX, all_kex);
2788 	def_key = match_filter_allowlist(KEX_DEFAULT_PK_ALG, all_key);
2789 	def_sig = match_filter_allowlist(SSH_ALLOWED_CA_SIGALGS, all_sig);
2790 #define ASSEMBLE(what, defaults, all) \
2791 	do { \
2792 		if ((r = kex_assemble_names(&options->what, \
2793 		    defaults, all)) != 0) { \
2794 			error_fr(r, "%s", #what); \
2795 			goto fail; \
2796 		} \
2797 	} while (0)
2798 	ASSEMBLE(ciphers, def_cipher, all_cipher);
2799 	ASSEMBLE(macs, def_mac, all_mac);
2800 	ASSEMBLE(kex_algorithms, def_kex, all_kex);
2801 	ASSEMBLE(hostbased_accepted_algos, def_key, all_key);
2802 	ASSEMBLE(pubkey_accepted_algos, def_key, all_key);
2803 	ASSEMBLE(ca_sign_algorithms, def_sig, all_sig);
2804 #undef ASSEMBLE
2805 
2806 	if (options->send_version_first == -1)
2807 		options->send_version_first = 1;
2808 #define CLEAR_ON_NONE(v) \
2809 	do { \
2810 		if (option_clear_or_none(v)) { \
2811 			free(v); \
2812 			v = NULL; \
2813 		} \
2814 	} while(0)
2815 	CLEAR_ON_NONE(options->local_command);
2816 	CLEAR_ON_NONE(options->remote_command);
2817 	CLEAR_ON_NONE(options->proxy_command);
2818 	CLEAR_ON_NONE(options->control_path);
2819 	CLEAR_ON_NONE(options->revoked_host_keys);
2820 	CLEAR_ON_NONE(options->pkcs11_provider);
2821 	CLEAR_ON_NONE(options->sk_provider);
2822 	CLEAR_ON_NONE(options->known_hosts_command);
2823 	if (options->jump_host != NULL &&
2824 	    strcmp(options->jump_host, "none") == 0 &&
2825 	    options->jump_port == 0 && options->jump_user == NULL) {
2826 		free(options->jump_host);
2827 		options->jump_host = NULL;
2828 	}
2829 	if (options->num_permitted_cnames == 1 &&
2830 	    !config_has_permitted_cnames(options)) {
2831 		/* clean up CanonicalizePermittedCNAMEs=none */
2832 		free(options->permitted_cnames[0].source_list);
2833 		free(options->permitted_cnames[0].target_list);
2834 		memset(options->permitted_cnames, '\0',
2835 		    sizeof(*options->permitted_cnames));
2836 		options->num_permitted_cnames = 0;
2837 	}
2838 	/* options->identity_agent distinguishes NULL from 'none' */
2839 	/* options->user will be set in the main program if appropriate */
2840 	/* options->hostname will be set in the main program if appropriate */
2841 	/* options->host_key_alias should not be set by default */
2842 	/* options->preferred_authentications will be set in ssh */
2843 
2844 	/* success */
2845 	ret = 0;
2846  fail:
2847 	free(all_cipher);
2848 	free(all_mac);
2849 	free(all_kex);
2850 	free(all_key);
2851 	free(all_sig);
2852 	free(def_cipher);
2853 	free(def_mac);
2854 	free(def_kex);
2855 	free(def_key);
2856 	free(def_sig);
2857 	return ret;
2858 }
2859 
2860 void
free_options(Options * o)2861 free_options(Options *o)
2862 {
2863 	int i;
2864 
2865 	if (o == NULL)
2866 		return;
2867 
2868 #define FREE_ARRAY(type, n, a) \
2869 	do { \
2870 		type _i; \
2871 		for (_i = 0; _i < (n); _i++) \
2872 			free((a)[_i]); \
2873 	} while (0)
2874 
2875 	free(o->forward_agent_sock_path);
2876 	free(o->xauth_location);
2877 	FREE_ARRAY(u_int, o->num_log_verbose, o->log_verbose);
2878 	free(o->log_verbose);
2879 	free(o->ciphers);
2880 	free(o->macs);
2881 	free(o->hostkeyalgorithms);
2882 	free(o->kex_algorithms);
2883 	free(o->ca_sign_algorithms);
2884 	free(o->hostname);
2885 	free(o->host_key_alias);
2886 	free(o->proxy_command);
2887 	free(o->user);
2888 	FREE_ARRAY(u_int, o->num_system_hostfiles, o->system_hostfiles);
2889 	FREE_ARRAY(u_int, o->num_user_hostfiles, o->user_hostfiles);
2890 	free(o->preferred_authentications);
2891 	free(o->bind_address);
2892 	free(o->bind_interface);
2893 	free(o->pkcs11_provider);
2894 	free(o->sk_provider);
2895 	for (i = 0; i < o->num_identity_files; i++) {
2896 		free(o->identity_files[i]);
2897 		sshkey_free(o->identity_keys[i]);
2898 	}
2899 	for (i = 0; i < o->num_certificate_files; i++) {
2900 		free(o->certificate_files[i]);
2901 		sshkey_free(o->certificates[i]);
2902 	}
2903 	free(o->identity_agent);
2904 	for (i = 0; i < o->num_local_forwards; i++) {
2905 		free(o->local_forwards[i].listen_host);
2906 		free(o->local_forwards[i].listen_path);
2907 		free(o->local_forwards[i].connect_host);
2908 		free(o->local_forwards[i].connect_path);
2909 	}
2910 	free(o->local_forwards);
2911 	for (i = 0; i < o->num_remote_forwards; i++) {
2912 		free(o->remote_forwards[i].listen_host);
2913 		free(o->remote_forwards[i].listen_path);
2914 		free(o->remote_forwards[i].connect_host);
2915 		free(o->remote_forwards[i].connect_path);
2916 	}
2917 	free(o->remote_forwards);
2918 	free(o->stdio_forward_host);
2919 	FREE_ARRAY(u_int, o->num_send_env, o->send_env);
2920 	free(o->send_env);
2921 	FREE_ARRAY(u_int, o->num_setenv, o->setenv);
2922 	free(o->setenv);
2923 	free(o->control_path);
2924 	free(o->local_command);
2925 	free(o->remote_command);
2926 	FREE_ARRAY(int, o->num_canonical_domains, o->canonical_domains);
2927 	for (i = 0; i < o->num_permitted_cnames; i++) {
2928 		free(o->permitted_cnames[i].source_list);
2929 		free(o->permitted_cnames[i].target_list);
2930 	}
2931 	free(o->revoked_host_keys);
2932 	free(o->hostbased_accepted_algos);
2933 	free(o->pubkey_accepted_algos);
2934 	free(o->jump_user);
2935 	free(o->jump_host);
2936 	free(o->jump_extra);
2937 	free(o->ignored_unknown);
2938 	explicit_bzero(o, sizeof(*o));
2939 #undef FREE_ARRAY
2940 }
2941 
2942 struct fwdarg {
2943 	char *arg;
2944 	int ispath;
2945 };
2946 
2947 /*
2948  * parse_fwd_field
2949  * parses the next field in a port forwarding specification.
2950  * sets fwd to the parsed field and advances p past the colon
2951  * or sets it to NULL at end of string.
2952  * returns 0 on success, else non-zero.
2953  */
2954 static int
parse_fwd_field(char ** p,struct fwdarg * fwd)2955 parse_fwd_field(char **p, struct fwdarg *fwd)
2956 {
2957 	char *ep, *cp = *p;
2958 	int ispath = 0;
2959 
2960 	if (*cp == '\0') {
2961 		*p = NULL;
2962 		return -1;	/* end of string */
2963 	}
2964 
2965 	/*
2966 	 * A field escaped with square brackets is used literally.
2967 	 * XXX - allow ']' to be escaped via backslash?
2968 	 */
2969 	if (*cp == '[') {
2970 		/* find matching ']' */
2971 		for (ep = cp + 1; *ep != ']' && *ep != '\0'; ep++) {
2972 			if (*ep == '/')
2973 				ispath = 1;
2974 		}
2975 		/* no matching ']' or not at end of field. */
2976 		if (ep[0] != ']' || (ep[1] != ':' && ep[1] != '\0'))
2977 			return -1;
2978 		/* NUL terminate the field and advance p past the colon */
2979 		*ep++ = '\0';
2980 		if (*ep != '\0')
2981 			*ep++ = '\0';
2982 		fwd->arg = cp + 1;
2983 		fwd->ispath = ispath;
2984 		*p = ep;
2985 		return 0;
2986 	}
2987 
2988 	for (cp = *p; *cp != '\0'; cp++) {
2989 		switch (*cp) {
2990 		case '\\':
2991 			memmove(cp, cp + 1, strlen(cp + 1) + 1);
2992 			if (*cp == '\0')
2993 				return -1;
2994 			break;
2995 		case '/':
2996 			ispath = 1;
2997 			break;
2998 		case ':':
2999 			*cp++ = '\0';
3000 			goto done;
3001 		}
3002 	}
3003 done:
3004 	fwd->arg = *p;
3005 	fwd->ispath = ispath;
3006 	*p = cp;
3007 	return 0;
3008 }
3009 
3010 /*
3011  * parse_forward
3012  * parses a string containing a port forwarding specification of the form:
3013  *   dynamicfwd == 0
3014  *	[listenhost:]listenport|listenpath:connecthost:connectport|connectpath
3015  *	listenpath:connectpath
3016  *   dynamicfwd == 1
3017  *	[listenhost:]listenport
3018  * returns number of arguments parsed or zero on error
3019  */
3020 int
parse_forward(struct Forward * fwd,const char * fwdspec,int dynamicfwd,int remotefwd)3021 parse_forward(struct Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
3022 {
3023 	struct fwdarg fwdargs[4];
3024 	char *p, *cp;
3025 	int i, err;
3026 
3027 	memset(fwd, 0, sizeof(*fwd));
3028 	memset(fwdargs, 0, sizeof(fwdargs));
3029 
3030 	/*
3031 	 * We expand environment variables before checking if we think they're
3032 	 * paths so that if ${VAR} expands to a fully qualified path it is
3033 	 * treated as a path.
3034 	 */
3035 	cp = p = dollar_expand(&err, fwdspec);
3036 	if (p == NULL || err)
3037 		return 0;
3038 
3039 	/* skip leading spaces */
3040 	while (isspace((u_char)*cp))
3041 		cp++;
3042 
3043 	for (i = 0; i < 4; ++i) {
3044 		if (parse_fwd_field(&cp, &fwdargs[i]) != 0)
3045 			break;
3046 	}
3047 
3048 	/* Check for trailing garbage */
3049 	if (cp != NULL && *cp != '\0') {
3050 		i = 0;	/* failure */
3051 	}
3052 
3053 	switch (i) {
3054 	case 1:
3055 		if (fwdargs[0].ispath) {
3056 			fwd->listen_path = xstrdup(fwdargs[0].arg);
3057 			fwd->listen_port = PORT_STREAMLOCAL;
3058 		} else {
3059 			fwd->listen_host = NULL;
3060 			fwd->listen_port = a2port(fwdargs[0].arg);
3061 		}
3062 		fwd->connect_host = xstrdup("socks");
3063 		break;
3064 
3065 	case 2:
3066 		if (fwdargs[0].ispath && fwdargs[1].ispath) {
3067 			fwd->listen_path = xstrdup(fwdargs[0].arg);
3068 			fwd->listen_port = PORT_STREAMLOCAL;
3069 			fwd->connect_path = xstrdup(fwdargs[1].arg);
3070 			fwd->connect_port = PORT_STREAMLOCAL;
3071 		} else if (fwdargs[1].ispath) {
3072 			fwd->listen_host = NULL;
3073 			fwd->listen_port = a2port(fwdargs[0].arg);
3074 			fwd->connect_path = xstrdup(fwdargs[1].arg);
3075 			fwd->connect_port = PORT_STREAMLOCAL;
3076 		} else {
3077 			fwd->listen_host = xstrdup(fwdargs[0].arg);
3078 			fwd->listen_port = a2port(fwdargs[1].arg);
3079 			fwd->connect_host = xstrdup("socks");
3080 		}
3081 		break;
3082 
3083 	case 3:
3084 		if (fwdargs[0].ispath) {
3085 			fwd->listen_path = xstrdup(fwdargs[0].arg);
3086 			fwd->listen_port = PORT_STREAMLOCAL;
3087 			fwd->connect_host = xstrdup(fwdargs[1].arg);
3088 			fwd->connect_port = a2port(fwdargs[2].arg);
3089 		} else if (fwdargs[2].ispath) {
3090 			fwd->listen_host = xstrdup(fwdargs[0].arg);
3091 			fwd->listen_port = a2port(fwdargs[1].arg);
3092 			fwd->connect_path = xstrdup(fwdargs[2].arg);
3093 			fwd->connect_port = PORT_STREAMLOCAL;
3094 		} else {
3095 			fwd->listen_host = NULL;
3096 			fwd->listen_port = a2port(fwdargs[0].arg);
3097 			fwd->connect_host = xstrdup(fwdargs[1].arg);
3098 			fwd->connect_port = a2port(fwdargs[2].arg);
3099 		}
3100 		break;
3101 
3102 	case 4:
3103 		fwd->listen_host = xstrdup(fwdargs[0].arg);
3104 		fwd->listen_port = a2port(fwdargs[1].arg);
3105 		fwd->connect_host = xstrdup(fwdargs[2].arg);
3106 		fwd->connect_port = a2port(fwdargs[3].arg);
3107 		break;
3108 	default:
3109 		i = 0; /* failure */
3110 	}
3111 
3112 	free(p);
3113 
3114 	if (dynamicfwd) {
3115 		if (!(i == 1 || i == 2))
3116 			goto fail_free;
3117 	} else {
3118 		if (!(i == 3 || i == 4)) {
3119 			if (fwd->connect_path == NULL &&
3120 			    fwd->listen_path == NULL)
3121 				goto fail_free;
3122 		}
3123 		if (fwd->connect_port <= 0 && fwd->connect_path == NULL)
3124 			goto fail_free;
3125 	}
3126 
3127 	if ((fwd->listen_port < 0 && fwd->listen_path == NULL) ||
3128 	    (!remotefwd && fwd->listen_port == 0))
3129 		goto fail_free;
3130 	if (fwd->connect_host != NULL &&
3131 	    strlen(fwd->connect_host) >= NI_MAXHOST)
3132 		goto fail_free;
3133 	/*
3134 	 * XXX - if connecting to a remote socket, max sun len may not
3135 	 * match this host
3136 	 */
3137 	if (fwd->connect_path != NULL &&
3138 	    strlen(fwd->connect_path) >= PATH_MAX_SUN)
3139 		goto fail_free;
3140 	if (fwd->listen_host != NULL &&
3141 	    strlen(fwd->listen_host) >= NI_MAXHOST)
3142 		goto fail_free;
3143 	if (fwd->listen_path != NULL &&
3144 	    strlen(fwd->listen_path) >= PATH_MAX_SUN)
3145 		goto fail_free;
3146 
3147 	return (i);
3148 
3149  fail_free:
3150 	free(fwd->connect_host);
3151 	fwd->connect_host = NULL;
3152 	free(fwd->connect_path);
3153 	fwd->connect_path = NULL;
3154 	free(fwd->listen_host);
3155 	fwd->listen_host = NULL;
3156 	free(fwd->listen_path);
3157 	fwd->listen_path = NULL;
3158 	return (0);
3159 }
3160 
3161 int
parse_jump(const char * s,Options * o,int active)3162 parse_jump(const char *s, Options *o, int active)
3163 {
3164 	char *orig, *sdup, *cp;
3165 	char *host = NULL, *user = NULL;
3166 	int r, ret = -1, port = -1, first;
3167 
3168 	active &= o->proxy_command == NULL && o->jump_host == NULL;
3169 
3170 	orig = sdup = xstrdup(s);
3171 
3172 	/* Remove comment and trailing whitespace */
3173 	if ((cp = strchr(orig, '#')) != NULL)
3174 		*cp = '\0';
3175 	rtrim(orig);
3176 
3177 	first = active;
3178 	do {
3179 		if (strcasecmp(s, "none") == 0)
3180 			break;
3181 		if ((cp = strrchr(sdup, ',')) == NULL)
3182 			cp = sdup; /* last */
3183 		else
3184 			*cp++ = '\0';
3185 
3186 		if (first) {
3187 			/* First argument and configuration is active */
3188 			r = parse_ssh_uri(cp, &user, &host, &port);
3189 			if (r == -1 || (r == 1 &&
3190 			    parse_user_host_port(cp, &user, &host, &port) != 0))
3191 				goto out;
3192 		} else {
3193 			/* Subsequent argument or inactive configuration */
3194 			r = parse_ssh_uri(cp, NULL, NULL, NULL);
3195 			if (r == -1 || (r == 1 &&
3196 			    parse_user_host_port(cp, NULL, NULL, NULL) != 0))
3197 				goto out;
3198 		}
3199 		first = 0; /* only check syntax for subsequent hosts */
3200 	} while (cp != sdup);
3201 	/* success */
3202 	if (active) {
3203 		if (strcasecmp(s, "none") == 0) {
3204 			o->jump_host = xstrdup("none");
3205 			o->jump_port = 0;
3206 		} else {
3207 			o->jump_user = user;
3208 			o->jump_host = host;
3209 			o->jump_port = port;
3210 			o->proxy_command = xstrdup("none");
3211 			user = host = NULL;
3212 			if ((cp = strrchr(s, ',')) != NULL && cp != s) {
3213 				o->jump_extra = xstrdup(s);
3214 				o->jump_extra[cp - s] = '\0';
3215 			}
3216 		}
3217 	}
3218 	ret = 0;
3219  out:
3220 	free(orig);
3221 	free(user);
3222 	free(host);
3223 	return ret;
3224 }
3225 
3226 int
parse_ssh_uri(const char * uri,char ** userp,char ** hostp,int * portp)3227 parse_ssh_uri(const char *uri, char **userp, char **hostp, int *portp)
3228 {
3229 	char *user = NULL, *host = NULL, *path = NULL;
3230 	int r, port;
3231 
3232 	r = parse_uri("ssh", uri, &user, &host, &port, &path);
3233 	if (r == 0 && path != NULL)
3234 		r = -1;		/* path not allowed */
3235 	if (r == 0) {
3236 		if (userp != NULL) {
3237 			*userp = user;
3238 			user = NULL;
3239 		}
3240 		if (hostp != NULL) {
3241 			*hostp = host;
3242 			host = NULL;
3243 		}
3244 		if (portp != NULL)
3245 			*portp = port;
3246 	}
3247 	free(user);
3248 	free(host);
3249 	free(path);
3250 	return r;
3251 }
3252 
3253 /* XXX the following is a near-vebatim copy from servconf.c; refactor */
3254 static const char *
fmt_multistate_int(int val,const struct multistate * m)3255 fmt_multistate_int(int val, const struct multistate *m)
3256 {
3257 	u_int i;
3258 
3259 	for (i = 0; m[i].key != NULL; i++) {
3260 		if (m[i].value == val)
3261 			return m[i].key;
3262 	}
3263 	return "UNKNOWN";
3264 }
3265 
3266 static const char *
fmt_intarg(OpCodes code,int val)3267 fmt_intarg(OpCodes code, int val)
3268 {
3269 	if (val == -1)
3270 		return "unset";
3271 	switch (code) {
3272 	case oAddressFamily:
3273 		return fmt_multistate_int(val, multistate_addressfamily);
3274 	case oVerifyHostKeyDNS:
3275 	case oUpdateHostkeys:
3276 		return fmt_multistate_int(val, multistate_yesnoask);
3277 	case oStrictHostKeyChecking:
3278 		return fmt_multistate_int(val, multistate_strict_hostkey);
3279 	case oControlMaster:
3280 		return fmt_multistate_int(val, multistate_controlmaster);
3281 	case oTunnel:
3282 		return fmt_multistate_int(val, multistate_tunnel);
3283 	case oRequestTTY:
3284 		return fmt_multistate_int(val, multistate_requesttty);
3285 	case oSessionType:
3286 		return fmt_multistate_int(val, multistate_sessiontype);
3287 	case oCanonicalizeHostname:
3288 		return fmt_multistate_int(val, multistate_canonicalizehostname);
3289 	case oAddKeysToAgent:
3290 		return fmt_multistate_int(val, multistate_yesnoaskconfirm);
3291 	case oPubkeyAuthentication:
3292 		return fmt_multistate_int(val, multistate_pubkey_auth);
3293 	case oFingerprintHash:
3294 		return ssh_digest_alg_name(val);
3295 	default:
3296 		switch (val) {
3297 		case 0:
3298 			return "no";
3299 		case 1:
3300 			return "yes";
3301 		default:
3302 			return "UNKNOWN";
3303 		}
3304 	}
3305 }
3306 
3307 static const char *
lookup_opcode_name(OpCodes code)3308 lookup_opcode_name(OpCodes code)
3309 {
3310 	u_int i;
3311 
3312 	for (i = 0; keywords[i].name != NULL; i++)
3313 		if (keywords[i].opcode == code)
3314 			return(keywords[i].name);
3315 	return "UNKNOWN";
3316 }
3317 
3318 static void
dump_cfg_int(OpCodes code,int val)3319 dump_cfg_int(OpCodes code, int val)
3320 {
3321 	printf("%s %d\n", lookup_opcode_name(code), val);
3322 }
3323 
3324 static void
dump_cfg_fmtint(OpCodes code,int val)3325 dump_cfg_fmtint(OpCodes code, int val)
3326 {
3327 	printf("%s %s\n", lookup_opcode_name(code), fmt_intarg(code, val));
3328 }
3329 
3330 static void
dump_cfg_string(OpCodes code,const char * val)3331 dump_cfg_string(OpCodes code, const char *val)
3332 {
3333 	if (val == NULL)
3334 		return;
3335 	printf("%s %s\n", lookup_opcode_name(code), val);
3336 }
3337 
3338 static void
dump_cfg_strarray(OpCodes code,u_int count,char ** vals)3339 dump_cfg_strarray(OpCodes code, u_int count, char **vals)
3340 {
3341 	u_int i;
3342 
3343 	for (i = 0; i < count; i++)
3344 		printf("%s %s\n", lookup_opcode_name(code), vals[i]);
3345 }
3346 
3347 static void
dump_cfg_strarray_oneline(OpCodes code,u_int count,char ** vals)3348 dump_cfg_strarray_oneline(OpCodes code, u_int count, char **vals)
3349 {
3350 	u_int i;
3351 
3352 	printf("%s", lookup_opcode_name(code));
3353 	if (count == 0)
3354 		printf(" none");
3355 	for (i = 0; i < count; i++)
3356 		printf(" %s",  vals[i]);
3357 	printf("\n");
3358 }
3359 
3360 static void
dump_cfg_forwards(OpCodes code,u_int count,const struct Forward * fwds)3361 dump_cfg_forwards(OpCodes code, u_int count, const struct Forward *fwds)
3362 {
3363 	const struct Forward *fwd;
3364 	u_int i;
3365 
3366 	/* oDynamicForward */
3367 	for (i = 0; i < count; i++) {
3368 		fwd = &fwds[i];
3369 		if (code == oDynamicForward && fwd->connect_host != NULL &&
3370 		    strcmp(fwd->connect_host, "socks") != 0)
3371 			continue;
3372 		if (code == oLocalForward && fwd->connect_host != NULL &&
3373 		    strcmp(fwd->connect_host, "socks") == 0)
3374 			continue;
3375 		printf("%s", lookup_opcode_name(code));
3376 		if (fwd->listen_port == PORT_STREAMLOCAL)
3377 			printf(" %s", fwd->listen_path);
3378 		else if (fwd->listen_host == NULL)
3379 			printf(" %d", fwd->listen_port);
3380 		else {
3381 			printf(" [%s]:%d",
3382 			    fwd->listen_host, fwd->listen_port);
3383 		}
3384 		if (code != oDynamicForward) {
3385 			if (fwd->connect_port == PORT_STREAMLOCAL)
3386 				printf(" %s", fwd->connect_path);
3387 			else if (fwd->connect_host == NULL)
3388 				printf(" %d", fwd->connect_port);
3389 			else {
3390 				printf(" [%s]:%d",
3391 				    fwd->connect_host, fwd->connect_port);
3392 			}
3393 		}
3394 		printf("\n");
3395 	}
3396 }
3397 
3398 void
dump_client_config(Options * o,const char * host)3399 dump_client_config(Options *o, const char *host)
3400 {
3401 	int i, r;
3402 	char buf[8], *all_key;
3403 
3404 	/*
3405 	 * Expand HostKeyAlgorithms name lists. This isn't handled in
3406 	 * fill_default_options() like the other algorithm lists because
3407 	 * the host key algorithms are by default dynamically chosen based
3408 	 * on the host's keys found in known_hosts.
3409 	 */
3410 	all_key = sshkey_alg_list(0, 0, 1, ',');
3411 	if ((r = kex_assemble_names(&o->hostkeyalgorithms, kex_default_pk_alg(),
3412 	    all_key)) != 0)
3413 		fatal_fr(r, "expand HostKeyAlgorithms");
3414 	free(all_key);
3415 
3416 	/* Most interesting options first: user, host, port */
3417 	dump_cfg_string(oHost, o->host_arg);
3418 	dump_cfg_string(oUser, o->user);
3419 	dump_cfg_string(oHostname, host);
3420 	dump_cfg_int(oPort, o->port);
3421 
3422 	/* Flag options */
3423 	dump_cfg_fmtint(oAddressFamily, o->address_family);
3424 	dump_cfg_fmtint(oBatchMode, o->batch_mode);
3425 	dump_cfg_fmtint(oCanonicalizeFallbackLocal, o->canonicalize_fallback_local);
3426 	dump_cfg_fmtint(oCanonicalizeHostname, o->canonicalize_hostname);
3427 	dump_cfg_fmtint(oCheckHostIP, o->check_host_ip);
3428 	dump_cfg_fmtint(oCompression, o->compression);
3429 	dump_cfg_fmtint(oControlMaster, o->control_master);
3430 	dump_cfg_fmtint(oEnableSSHKeysign, o->enable_ssh_keysign);
3431 	dump_cfg_fmtint(oClearAllForwardings, o->clear_forwardings);
3432 	dump_cfg_fmtint(oExitOnForwardFailure, o->exit_on_forward_failure);
3433 	dump_cfg_fmtint(oFingerprintHash, o->fingerprint_hash);
3434 	dump_cfg_fmtint(oForwardX11, o->forward_x11);
3435 	dump_cfg_fmtint(oForwardX11Trusted, o->forward_x11_trusted);
3436 	dump_cfg_fmtint(oGatewayPorts, o->fwd_opts.gateway_ports);
3437 #ifdef GSSAPI
3438 	dump_cfg_fmtint(oGssAuthentication, o->gss_authentication);
3439 	dump_cfg_fmtint(oGssDelegateCreds, o->gss_deleg_creds);
3440 #endif /* GSSAPI */
3441 	dump_cfg_fmtint(oHashKnownHosts, o->hash_known_hosts);
3442 	dump_cfg_fmtint(oHostbasedAuthentication, o->hostbased_authentication);
3443 	dump_cfg_fmtint(oIdentitiesOnly, o->identities_only);
3444 	dump_cfg_fmtint(oKbdInteractiveAuthentication, o->kbd_interactive_authentication);
3445 	dump_cfg_fmtint(oNoHostAuthenticationForLocalhost, o->no_host_authentication_for_localhost);
3446 	dump_cfg_fmtint(oPasswordAuthentication, o->password_authentication);
3447 	dump_cfg_fmtint(oPermitLocalCommand, o->permit_local_command);
3448 	dump_cfg_fmtint(oProxyUseFdpass, o->proxy_use_fdpass);
3449 	dump_cfg_fmtint(oPubkeyAuthentication, o->pubkey_authentication);
3450 	dump_cfg_fmtint(oRequestTTY, o->request_tty);
3451 	dump_cfg_fmtint(oSessionType, o->session_type);
3452 	dump_cfg_fmtint(oStdinNull, o->stdin_null);
3453 	dump_cfg_fmtint(oForkAfterAuthentication, o->fork_after_authentication);
3454 	dump_cfg_fmtint(oStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink);
3455 	dump_cfg_fmtint(oStrictHostKeyChecking, o->strict_host_key_checking);
3456 	dump_cfg_fmtint(oTCPKeepAlive, o->tcp_keep_alive);
3457 	dump_cfg_fmtint(oTunnel, o->tun_open);
3458 	dump_cfg_fmtint(oVerifyHostKeyDNS, o->verify_host_key_dns);
3459 	dump_cfg_fmtint(oVisualHostKey, o->visual_host_key);
3460 	dump_cfg_fmtint(oUpdateHostkeys, o->update_hostkeys);
3461 	dump_cfg_fmtint(oEnableEscapeCommandline, o->enable_escape_commandline);
3462 
3463 	/* Integer options */
3464 	dump_cfg_int(oCanonicalizeMaxDots, o->canonicalize_max_dots);
3465 	dump_cfg_int(oConnectionAttempts, o->connection_attempts);
3466 	dump_cfg_int(oForwardX11Timeout, o->forward_x11_timeout);
3467 	dump_cfg_int(oNumberOfPasswordPrompts, o->number_of_password_prompts);
3468 	dump_cfg_int(oServerAliveCountMax, o->server_alive_count_max);
3469 	dump_cfg_int(oServerAliveInterval, o->server_alive_interval);
3470 	dump_cfg_int(oRequiredRSASize, o->required_rsa_size);
3471 
3472 	/* String options */
3473 	dump_cfg_string(oBindAddress, o->bind_address);
3474 	dump_cfg_string(oBindInterface, o->bind_interface);
3475 	dump_cfg_string(oCiphers, o->ciphers);
3476 	dump_cfg_string(oControlPath, o->control_path);
3477 	dump_cfg_string(oHostKeyAlgorithms, o->hostkeyalgorithms);
3478 	dump_cfg_string(oHostKeyAlias, o->host_key_alias);
3479 	dump_cfg_string(oHostbasedAcceptedAlgorithms, o->hostbased_accepted_algos);
3480 	dump_cfg_string(oIdentityAgent, o->identity_agent);
3481 	dump_cfg_string(oIgnoreUnknown, o->ignored_unknown);
3482 	dump_cfg_string(oKbdInteractiveDevices, o->kbd_interactive_devices);
3483 	dump_cfg_string(oKexAlgorithms, o->kex_algorithms);
3484 	dump_cfg_string(oCASignatureAlgorithms, o->ca_sign_algorithms);
3485 	dump_cfg_string(oLocalCommand, o->local_command);
3486 	dump_cfg_string(oRemoteCommand, o->remote_command);
3487 	dump_cfg_string(oLogLevel, log_level_name(o->log_level));
3488 	dump_cfg_string(oMacs, o->macs);
3489 #ifdef ENABLE_PKCS11
3490 	dump_cfg_string(oPKCS11Provider, o->pkcs11_provider);
3491 #endif
3492 	dump_cfg_string(oSecurityKeyProvider, o->sk_provider);
3493 	dump_cfg_string(oPreferredAuthentications, o->preferred_authentications);
3494 	dump_cfg_string(oPubkeyAcceptedAlgorithms, o->pubkey_accepted_algos);
3495 	dump_cfg_string(oRevokedHostKeys, o->revoked_host_keys);
3496 	dump_cfg_string(oXAuthLocation, o->xauth_location);
3497 	dump_cfg_string(oKnownHostsCommand, o->known_hosts_command);
3498 
3499 	/* Forwards */
3500 	dump_cfg_forwards(oDynamicForward, o->num_local_forwards, o->local_forwards);
3501 	dump_cfg_forwards(oLocalForward, o->num_local_forwards, o->local_forwards);
3502 	dump_cfg_forwards(oRemoteForward, o->num_remote_forwards, o->remote_forwards);
3503 
3504 	/* String array options */
3505 	dump_cfg_strarray(oIdentityFile, o->num_identity_files, o->identity_files);
3506 	dump_cfg_strarray_oneline(oCanonicalDomains, o->num_canonical_domains, o->canonical_domains);
3507 	dump_cfg_strarray(oCertificateFile, o->num_certificate_files, o->certificate_files);
3508 	dump_cfg_strarray_oneline(oGlobalKnownHostsFile, o->num_system_hostfiles, o->system_hostfiles);
3509 	dump_cfg_strarray_oneline(oUserKnownHostsFile, o->num_user_hostfiles, o->user_hostfiles);
3510 	dump_cfg_strarray(oSendEnv, o->num_send_env, o->send_env);
3511 	dump_cfg_strarray(oSetEnv, o->num_setenv, o->setenv);
3512 	dump_cfg_strarray_oneline(oLogVerbose,
3513 	    o->num_log_verbose, o->log_verbose);
3514 
3515 	/* Special cases */
3516 
3517 	/* PermitRemoteOpen */
3518 	if (o->num_permitted_remote_opens == 0)
3519 		printf("%s any\n", lookup_opcode_name(oPermitRemoteOpen));
3520 	else
3521 		dump_cfg_strarray_oneline(oPermitRemoteOpen,
3522 		    o->num_permitted_remote_opens, o->permitted_remote_opens);
3523 
3524 	/* AddKeysToAgent */
3525 	if (o->add_keys_to_agent_lifespan <= 0)
3526 		dump_cfg_fmtint(oAddKeysToAgent, o->add_keys_to_agent);
3527 	else {
3528 		printf("addkeystoagent%s %d\n",
3529 		    o->add_keys_to_agent == 3 ? " confirm" : "",
3530 		    o->add_keys_to_agent_lifespan);
3531 	}
3532 
3533 	/* oForwardAgent */
3534 	if (o->forward_agent_sock_path == NULL)
3535 		dump_cfg_fmtint(oForwardAgent, o->forward_agent);
3536 	else
3537 		dump_cfg_string(oForwardAgent, o->forward_agent_sock_path);
3538 
3539 	/* oConnectTimeout */
3540 	if (o->connection_timeout == -1)
3541 		printf("connecttimeout none\n");
3542 	else
3543 		dump_cfg_int(oConnectTimeout, o->connection_timeout);
3544 
3545 	/* oTunnelDevice */
3546 	printf("tunneldevice");
3547 	if (o->tun_local == SSH_TUNID_ANY)
3548 		printf(" any");
3549 	else
3550 		printf(" %d", o->tun_local);
3551 	if (o->tun_remote == SSH_TUNID_ANY)
3552 		printf(":any");
3553 	else
3554 		printf(":%d", o->tun_remote);
3555 	printf("\n");
3556 
3557 	/* oCanonicalizePermittedCNAMEs */
3558 	printf("canonicalizePermittedcnames");
3559 	if (o->num_permitted_cnames == 0)
3560 		printf(" none");
3561 	for (i = 0; i < o->num_permitted_cnames; i++) {
3562 		printf(" %s:%s", o->permitted_cnames[i].source_list,
3563 		    o->permitted_cnames[i].target_list);
3564 	}
3565 	printf("\n");
3566 
3567 	/* oControlPersist */
3568 	if (o->control_persist == 0 || o->control_persist_timeout == 0)
3569 		dump_cfg_fmtint(oControlPersist, o->control_persist);
3570 	else
3571 		dump_cfg_int(oControlPersist, o->control_persist_timeout);
3572 
3573 	/* oEscapeChar */
3574 	if (o->escape_char == SSH_ESCAPECHAR_NONE)
3575 		printf("escapechar none\n");
3576 	else {
3577 		vis(buf, o->escape_char, VIS_WHITE, 0);
3578 		printf("escapechar %s\n", buf);
3579 	}
3580 
3581 	/* oIPQoS */
3582 	printf("ipqos %s ", iptos2str(o->ip_qos_interactive));
3583 	printf("%s\n", iptos2str(o->ip_qos_bulk));
3584 
3585 	/* oRekeyLimit */
3586 	printf("rekeylimit %llu %d\n",
3587 	    (unsigned long long)o->rekey_limit, o->rekey_interval);
3588 
3589 	/* oStreamLocalBindMask */
3590 	printf("streamlocalbindmask 0%o\n",
3591 	    o->fwd_opts.streamlocal_bind_mask);
3592 
3593 	/* oLogFacility */
3594 	printf("syslogfacility %s\n", log_facility_name(o->log_facility));
3595 
3596 	/* oProxyCommand / oProxyJump */
3597 	if (o->jump_host == NULL)
3598 		dump_cfg_string(oProxyCommand, o->proxy_command);
3599 	else {
3600 		/* Check for numeric addresses */
3601 		i = strchr(o->jump_host, ':') != NULL ||
3602 		    strspn(o->jump_host, "1234567890.") == strlen(o->jump_host);
3603 		snprintf(buf, sizeof(buf), "%d", o->jump_port);
3604 		printf("proxyjump %s%s%s%s%s%s%s%s%s\n",
3605 		    /* optional additional jump spec */
3606 		    o->jump_extra == NULL ? "" : o->jump_extra,
3607 		    o->jump_extra == NULL ? "" : ",",
3608 		    /* optional user */
3609 		    o->jump_user == NULL ? "" : o->jump_user,
3610 		    o->jump_user == NULL ? "" : "@",
3611 		    /* opening [ if hostname is numeric */
3612 		    i ? "[" : "",
3613 		    /* mandatory hostname */
3614 		    o->jump_host,
3615 		    /* closing ] if hostname is numeric */
3616 		    i ? "]" : "",
3617 		    /* optional port number */
3618 		    o->jump_port <= 0 ? "" : ":",
3619 		    o->jump_port <= 0 ? "" : buf);
3620 	}
3621 }
3622