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