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