xref: /openbsd-src/usr.bin/ssh/readconf.c (revision 7c0ec4b8992567abb1e1536622dc789a9a39d9f1)
1 /* $OpenBSD: readconf.c,v 1.389 2024/09/03 05:29:55 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, char **condition, struct passwd *pw,
687     const char *host_arg, const char *original_host, int final_pass,
688     int *want_final_pass, const char *filename, int linenum)
689 {
690 	char *arg, *oattrib, *attrib, *cmd, *cp = *condition, *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 	    cp, host, original_host);
711 	while ((oattrib = attrib = strdelim(&cp)) && *attrib != '\0') {
712 		/* Terminate on comment */
713 		if (*attrib == '#') {
714 			cp = NULL; /* mark all arguments consumed */
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 || ((arg = strdelim(&cp)) != NULL &&
724 			    *arg != '\0' && *arg != '#')) {
725 				error("%.200s line %d: '%s' cannot be combined "
726 				    "with other Match attributes",
727 				    filename, linenum, oattrib);
728 				result = -1;
729 				goto out;
730 			}
731 			if (arg != NULL && *arg == '#')
732 				cp = NULL; /* mark all arguments consumed */
733 			if (result)
734 				result = negate ? 0 : 1;
735 			goto out;
736 		}
737 		attributes++;
738 		/* criteria "final" and "canonical" have no argument */
739 		if (strcasecmp(attrib, "canonical") == 0 ||
740 		    strcasecmp(attrib, "final") == 0) {
741 			/*
742 			 * If the config requests "Match final" then remember
743 			 * this so we can perform a second pass later.
744 			 */
745 			if (strcasecmp(attrib, "final") == 0 &&
746 			    want_final_pass != NULL)
747 				*want_final_pass = 1;
748 			r = !!final_pass;  /* force bitmask member to boolean */
749 			if (r == (negate ? 1 : 0))
750 				this_result = result = 0;
751 			debug3("%.200s line %d: %smatched '%s'",
752 			    filename, linenum,
753 			    this_result ? "" : "not ", oattrib);
754 			continue;
755 		}
756 		/* All other criteria require an argument */
757 		if ((arg = strdelim(&cp)) == NULL ||
758 		    *arg == '\0' || *arg == '#') {
759 			error("Missing Match criteria for %s", attrib);
760 			result = -1;
761 			goto out;
762 		}
763 		if (strcasecmp(attrib, "host") == 0) {
764 			criteria = xstrdup(host);
765 			r = match_hostname(host, arg) == 1;
766 			if (r == (negate ? 1 : 0))
767 				this_result = result = 0;
768 		} else if (strcasecmp(attrib, "originalhost") == 0) {
769 			criteria = xstrdup(original_host);
770 			r = match_hostname(original_host, arg) == 1;
771 			if (r == (negate ? 1 : 0))
772 				this_result = result = 0;
773 		} else if (strcasecmp(attrib, "user") == 0) {
774 			criteria = xstrdup(ruser);
775 			r = match_pattern_list(ruser, arg, 0) == 1;
776 			if (r == (negate ? 1 : 0))
777 				this_result = result = 0;
778 		} else if (strcasecmp(attrib, "localuser") == 0) {
779 			criteria = xstrdup(pw->pw_name);
780 			r = match_pattern_list(pw->pw_name, arg, 0) == 1;
781 			if (r == (negate ? 1 : 0))
782 				this_result = result = 0;
783 		} else if (strcasecmp(attrib, "localnetwork") == 0) {
784 			if (addr_match_cidr_list(NULL, arg) == -1) {
785 				/* Error already printed */
786 				result = -1;
787 				goto out;
788 			}
789 			r = check_match_ifaddrs(arg) == 1;
790 			if (r == (negate ? 1 : 0))
791 				this_result = result = 0;
792 		} else if (strcasecmp(attrib, "tagged") == 0) {
793 			criteria = xstrdup(options->tag == NULL ? "" :
794 			    options->tag);
795 			r = match_pattern_list(criteria, arg, 0) == 1;
796 			if (r == (negate ? 1 : 0))
797 				this_result = result = 0;
798 		} else if (strcasecmp(attrib, "exec") == 0) {
799 			if ((cmd = expand_match_exec_or_include_path(arg,
800 			    options, pw, host_arg, original_host,
801 			    final_pass, 0)) == NULL) {
802 				fatal("%.200s line %d: failed to expand match "
803 				    "exec '%.100s'", filename, linenum, arg);
804 			}
805 			if (result != 1) {
806 				/* skip execution if prior predicate failed */
807 				debug3("%.200s line %d: skipped exec "
808 				    "\"%.100s\"", filename, linenum, cmd);
809 				free(cmd);
810 				continue;
811 			}
812 			r = execute_in_shell(cmd);
813 			if (r == -1) {
814 				fatal("%.200s line %d: match exec "
815 				    "'%.100s' error", filename,
816 				    linenum, cmd);
817 			}
818 			criteria = xstrdup(cmd);
819 			free(cmd);
820 			/* Force exit status to boolean */
821 			r = r == 0;
822 			if (r == (negate ? 1 : 0))
823 				this_result = result = 0;
824 		} else {
825 			error("Unsupported Match attribute %s", attrib);
826 			result = -1;
827 			goto out;
828 		}
829 		debug3("%.200s line %d: %smatched '%s%s%.100s%s' ",
830 		    filename, linenum, this_result ? "": "not ", oattrib,
831 		    criteria == NULL ? "" : " \"",
832 		    criteria == NULL ? "" : criteria,
833 		    criteria == NULL ? "" : "\"");
834 		free(criteria);
835 	}
836 	if (attributes == 0) {
837 		error("One or more attributes required for Match");
838 		result = -1;
839 		goto out;
840 	}
841  out:
842 	if (result != -1)
843 		debug2("match %sfound", result ? "" : "not ");
844 	*condition = cp;
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, pw, host, original_host,
1788 		    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 		/*
1797 		 * If match_cfg_line() didn't consume all its arguments then
1798 		 * arrange for the extra arguments check below to fail.
1799 		 */
1800 
1801 		if (str == NULL || *str == '\0')
1802 			argv_consume(&ac);
1803 		break;
1804 
1805 	case oEscapeChar:
1806 		intptr = &options->escape_char;
1807 		arg = argv_next(&ac, &av);
1808 		if (!arg || *arg == '\0') {
1809 			error("%.200s line %d: Missing argument.",
1810 			    filename, linenum);
1811 			goto out;
1812 		}
1813 		if (strcmp(arg, "none") == 0)
1814 			value = SSH_ESCAPECHAR_NONE;
1815 		else if (arg[1] == '\0')
1816 			value = (u_char) arg[0];
1817 		else if (arg[0] == '^' && arg[2] == 0 &&
1818 		    (u_char) arg[1] >= 64 && (u_char) arg[1] < 128)
1819 			value = (u_char) arg[1] & 31;
1820 		else {
1821 			error("%.200s line %d: Bad escape character.",
1822 			    filename, linenum);
1823 			goto out;
1824 		}
1825 		if (*activep && *intptr == -1)
1826 			*intptr = value;
1827 		break;
1828 
1829 	case oAddressFamily:
1830 		intptr = &options->address_family;
1831 		multistate_ptr = multistate_addressfamily;
1832 		goto parse_multistate;
1833 
1834 	case oEnableSSHKeysign:
1835 		intptr = &options->enable_ssh_keysign;
1836 		goto parse_flag;
1837 
1838 	case oIdentitiesOnly:
1839 		intptr = &options->identities_only;
1840 		goto parse_flag;
1841 
1842 	case oServerAliveInterval:
1843 		intptr = &options->server_alive_interval;
1844 		goto parse_time;
1845 
1846 	case oServerAliveCountMax:
1847 		intptr = &options->server_alive_count_max;
1848 		goto parse_int;
1849 
1850 	case oSendEnv:
1851 		/* XXX appends to list; doesn't respect first-match-wins */
1852 		while ((arg = argv_next(&ac, &av)) != NULL) {
1853 			if (*arg == '\0' || strchr(arg, '=') != NULL) {
1854 				error("%s line %d: Invalid environment name.",
1855 				    filename, linenum);
1856 				goto out;
1857 			}
1858 			found = 1;
1859 			if (!*activep)
1860 				continue;
1861 			if (*arg == '-') {
1862 				/* Removing an env var */
1863 				rm_env(options, arg, filename, linenum);
1864 				continue;
1865 			}
1866 			opt_array_append(filename, linenum,
1867 			    lookup_opcode_name(opcode),
1868 			    &options->send_env, &options->num_send_env, arg);
1869 		}
1870 		if (!found) {
1871 			fatal("%s line %d: no %s specified",
1872 			    filename, linenum, keyword);
1873 		}
1874 		break;
1875 
1876 	case oSetEnv:
1877 		found = options->num_setenv == 0;
1878 		while ((arg = argv_next(&ac, &av)) != NULL) {
1879 			if (strchr(arg, '=') == NULL) {
1880 				error("%s line %d: Invalid SetEnv.",
1881 				    filename, linenum);
1882 				goto out;
1883 			}
1884 			if (lookup_setenv_in_list(arg, strs, nstrs) != NULL) {
1885 				debug2("%s line %d: ignoring duplicate env "
1886 				    "name \"%.64s\"", filename, linenum, arg);
1887 				continue;
1888 			}
1889 			opt_array_append(filename, linenum,
1890 			    lookup_opcode_name(opcode),
1891 			    &strs, &nstrs, arg);
1892 		}
1893 		if (nstrs == 0) {
1894 			fatal("%s line %d: no %s specified",
1895 			    filename, linenum, keyword);
1896 		}
1897 		if (found && *activep) {
1898 			options->setenv = strs;
1899 			options->num_setenv = nstrs;
1900 			strs = NULL; /* transferred */
1901 			nstrs = 0;
1902 		}
1903 		break;
1904 
1905 	case oControlPath:
1906 		charptr = &options->control_path;
1907 		goto parse_string;
1908 
1909 	case oControlMaster:
1910 		intptr = &options->control_master;
1911 		multistate_ptr = multistate_controlmaster;
1912 		goto parse_multistate;
1913 
1914 	case oControlPersist:
1915 		/* no/false/yes/true, or a time spec */
1916 		intptr = &options->control_persist;
1917 		arg = argv_next(&ac, &av);
1918 		if (!arg || *arg == '\0') {
1919 			error("%.200s line %d: Missing ControlPersist"
1920 			    " argument.", filename, linenum);
1921 			goto out;
1922 		}
1923 		value = 0;
1924 		value2 = 0;	/* timeout */
1925 		if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
1926 			value = 0;
1927 		else if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
1928 			value = 1;
1929 		else if ((value2 = convtime(arg)) >= 0)
1930 			value = 1;
1931 		else {
1932 			error("%.200s line %d: Bad ControlPersist argument.",
1933 			    filename, linenum);
1934 			goto out;
1935 		}
1936 		if (*activep && *intptr == -1) {
1937 			*intptr = value;
1938 			options->control_persist_timeout = value2;
1939 		}
1940 		break;
1941 
1942 	case oHashKnownHosts:
1943 		intptr = &options->hash_known_hosts;
1944 		goto parse_flag;
1945 
1946 	case oTunnel:
1947 		intptr = &options->tun_open;
1948 		multistate_ptr = multistate_tunnel;
1949 		goto parse_multistate;
1950 
1951 	case oTunnelDevice:
1952 		arg = argv_next(&ac, &av);
1953 		if (!arg || *arg == '\0') {
1954 			error("%.200s line %d: Missing argument.",
1955 			    filename, linenum);
1956 			goto out;
1957 		}
1958 		value = a2tun(arg, &value2);
1959 		if (value == SSH_TUNID_ERR) {
1960 			error("%.200s line %d: Bad tun device.",
1961 			    filename, linenum);
1962 			goto out;
1963 		}
1964 		if (*activep && options->tun_local == -1) {
1965 			options->tun_local = value;
1966 			options->tun_remote = value2;
1967 		}
1968 		break;
1969 
1970 	case oLocalCommand:
1971 		charptr = &options->local_command;
1972 		goto parse_command;
1973 
1974 	case oPermitLocalCommand:
1975 		intptr = &options->permit_local_command;
1976 		goto parse_flag;
1977 
1978 	case oRemoteCommand:
1979 		charptr = &options->remote_command;
1980 		goto parse_command;
1981 
1982 	case oVisualHostKey:
1983 		intptr = &options->visual_host_key;
1984 		goto parse_flag;
1985 
1986 	case oInclude:
1987 		if (cmdline) {
1988 			error("Include directive not supported as a "
1989 			    "command-line option");
1990 			goto out;
1991 		}
1992 		value = 0;
1993 		while ((arg = argv_next(&ac, &av)) != NULL) {
1994 			if (*arg == '\0') {
1995 				error("%s line %d: keyword %s empty argument",
1996 				    filename, linenum, keyword);
1997 				goto out;
1998 			}
1999 			/* Expand %tokens and environment variables */
2000 			if ((p = expand_match_exec_or_include_path(arg,
2001 			    options, pw, host, original_host,
2002 			    flags & SSHCONF_FINAL, 1)) == NULL) {
2003 				error("%.200s line %d: Unable to expand user "
2004 				    "config file '%.100s'",
2005 				    filename, linenum, arg);
2006 				continue;
2007 			}
2008 			/*
2009 			 * Ensure all paths are anchored. User configuration
2010 			 * files may begin with '~/' but system configurations
2011 			 * must not. If the path is relative, then treat it
2012 			 * as living in ~/.ssh for user configurations or
2013 			 * /etc/ssh for system ones.
2014 			 */
2015 			if (*p == '~' && (flags & SSHCONF_USERCONF) == 0) {
2016 				error("%.200s line %d: bad include path %s.",
2017 				    filename, linenum, p);
2018 				goto out;
2019 			}
2020 			if (!path_absolute(p) && *p != '~') {
2021 				xasprintf(&arg2, "%s/%s",
2022 				    (flags & SSHCONF_USERCONF) ?
2023 				    "~/" _PATH_SSH_USER_DIR : SSHDIR, p);
2024 			} else {
2025 				arg2 = xstrdup(p);
2026 			}
2027 			free(p);
2028 			memset(&gl, 0, sizeof(gl));
2029 			r = glob(arg2, GLOB_TILDE, NULL, &gl);
2030 			if (r == GLOB_NOMATCH) {
2031 				debug("%.200s line %d: include %s matched no "
2032 				    "files",filename, linenum, arg2);
2033 				free(arg2);
2034 				continue;
2035 			} else if (r != 0) {
2036 				error("%.200s line %d: glob failed for %s.",
2037 				    filename, linenum, arg2);
2038 				goto out;
2039 			}
2040 			free(arg2);
2041 			oactive = *activep;
2042 			for (i = 0; i < gl.gl_pathc; i++) {
2043 				debug3("%.200s line %d: Including file %s "
2044 				    "depth %d%s", filename, linenum,
2045 				    gl.gl_pathv[i], depth,
2046 				    oactive ? "" : " (parse only)");
2047 				r = read_config_file_depth(gl.gl_pathv[i],
2048 				    pw, host, original_host, options,
2049 				    flags | SSHCONF_CHECKPERM |
2050 				    (oactive ? 0 : SSHCONF_NEVERMATCH),
2051 				    activep, want_final_pass, depth + 1);
2052 				if (r != 1 && errno != ENOENT) {
2053 					error("%.200s line %d: Can't open user "
2054 					    "config file %.100s: %.100s",
2055 					    filename, linenum, gl.gl_pathv[i],
2056 					    strerror(errno));
2057 					globfree(&gl);
2058 					goto out;
2059 				}
2060 				/*
2061 				 * don't let Match in includes clobber the
2062 				 * containing file's Match state.
2063 				 */
2064 				*activep = oactive;
2065 				if (r != 1)
2066 					value = -1;
2067 			}
2068 			globfree(&gl);
2069 		}
2070 		if (value != 0)
2071 			ret = value;
2072 		break;
2073 
2074 	case oIPQoS:
2075 		arg = argv_next(&ac, &av);
2076 		if ((value = parse_ipqos(arg)) == -1) {
2077 			error("%s line %d: Bad IPQoS value: %s",
2078 			    filename, linenum, arg);
2079 			goto out;
2080 		}
2081 		arg = argv_next(&ac, &av);
2082 		if (arg == NULL)
2083 			value2 = value;
2084 		else if ((value2 = parse_ipqos(arg)) == -1) {
2085 			error("%s line %d: Bad IPQoS value: %s",
2086 			    filename, linenum, arg);
2087 			goto out;
2088 		}
2089 		if (*activep && options->ip_qos_interactive == -1) {
2090 			options->ip_qos_interactive = value;
2091 			options->ip_qos_bulk = value2;
2092 		}
2093 		break;
2094 
2095 	case oRequestTTY:
2096 		intptr = &options->request_tty;
2097 		multistate_ptr = multistate_requesttty;
2098 		goto parse_multistate;
2099 
2100 	case oSessionType:
2101 		intptr = &options->session_type;
2102 		multistate_ptr = multistate_sessiontype;
2103 		goto parse_multistate;
2104 
2105 	case oStdinNull:
2106 		intptr = &options->stdin_null;
2107 		goto parse_flag;
2108 
2109 	case oForkAfterAuthentication:
2110 		intptr = &options->fork_after_authentication;
2111 		goto parse_flag;
2112 
2113 	case oIgnoreUnknown:
2114 		charptr = &options->ignored_unknown;
2115 		goto parse_string;
2116 
2117 	case oProxyUseFdpass:
2118 		intptr = &options->proxy_use_fdpass;
2119 		goto parse_flag;
2120 
2121 	case oCanonicalDomains:
2122 		found = options->num_canonical_domains == 0;
2123 		while ((arg = argv_next(&ac, &av)) != NULL) {
2124 			/* Allow "none" only in first position */
2125 			if (strcasecmp(arg, "none") == 0) {
2126 				if (nstrs > 0 || ac > 0) {
2127 					error("%s line %d: keyword %s \"none\" "
2128 					    "argument must appear alone.",
2129 					    filename, linenum, keyword);
2130 					goto out;
2131 				}
2132 			}
2133 			if (!valid_domain(arg, 1, &errstr)) {
2134 				error("%s line %d: %s", filename, linenum,
2135 				    errstr);
2136 				goto out;
2137 			}
2138 			opt_array_append(filename, linenum, keyword,
2139 			    &strs, &nstrs, arg);
2140 		}
2141 		if (nstrs == 0) {
2142 			fatal("%s line %d: no %s specified",
2143 			    filename, linenum, keyword);
2144 		}
2145 		if (found && *activep) {
2146 			options->canonical_domains = strs;
2147 			options->num_canonical_domains = nstrs;
2148 			strs = NULL; /* transferred */
2149 			nstrs = 0;
2150 		}
2151 		break;
2152 
2153 	case oCanonicalizePermittedCNAMEs:
2154 		found = options->num_permitted_cnames == 0;
2155 		while ((arg = argv_next(&ac, &av)) != NULL) {
2156 			/*
2157 			 * Either 'none' (only in first position), '*' for
2158 			 * everything or 'list:list'
2159 			 */
2160 			if (strcasecmp(arg, "none") == 0) {
2161 				if (ncnames > 0 || ac > 0) {
2162 					error("%s line %d: keyword %s \"none\" "
2163 					    "argument must appear alone.",
2164 					    filename, linenum, keyword);
2165 					goto out;
2166 				}
2167 				arg2 = "";
2168 			} else if (strcmp(arg, "*") == 0) {
2169 				arg2 = arg;
2170 			} else {
2171 				lowercase(arg);
2172 				if ((arg2 = strchr(arg, ':')) == NULL ||
2173 				    arg2[1] == '\0') {
2174 					error("%s line %d: "
2175 					    "Invalid permitted CNAME \"%s\"",
2176 					    filename, linenum, arg);
2177 					goto out;
2178 				}
2179 				*arg2 = '\0';
2180 				arg2++;
2181 			}
2182 			cnames = xrecallocarray(cnames, ncnames, ncnames + 1,
2183 			    sizeof(*cnames));
2184 			cnames[ncnames].source_list = xstrdup(arg);
2185 			cnames[ncnames].target_list = xstrdup(arg2);
2186 			ncnames++;
2187 		}
2188 		if (ncnames == 0) {
2189 			fatal("%s line %d: no %s specified",
2190 			    filename, linenum, keyword);
2191 		}
2192 		if (found && *activep) {
2193 			options->permitted_cnames = cnames;
2194 			options->num_permitted_cnames = ncnames;
2195 			cnames = NULL; /* transferred */
2196 			ncnames = 0;
2197 		}
2198 		/* un-transferred cnames is cleaned up before exit */
2199 		break;
2200 
2201 	case oCanonicalizeHostname:
2202 		intptr = &options->canonicalize_hostname;
2203 		multistate_ptr = multistate_canonicalizehostname;
2204 		goto parse_multistate;
2205 
2206 	case oCanonicalizeMaxDots:
2207 		intptr = &options->canonicalize_max_dots;
2208 		goto parse_int;
2209 
2210 	case oCanonicalizeFallbackLocal:
2211 		intptr = &options->canonicalize_fallback_local;
2212 		goto parse_flag;
2213 
2214 	case oStreamLocalBindMask:
2215 		arg = argv_next(&ac, &av);
2216 		if (!arg || *arg == '\0') {
2217 			error("%.200s line %d: Missing StreamLocalBindMask "
2218 			    "argument.", filename, linenum);
2219 			goto out;
2220 		}
2221 		/* Parse mode in octal format */
2222 		value = strtol(arg, &endofnumber, 8);
2223 		if (arg == endofnumber || value < 0 || value > 0777) {
2224 			error("%.200s line %d: Bad mask.", filename, linenum);
2225 			goto out;
2226 		}
2227 		options->fwd_opts.streamlocal_bind_mask = (mode_t)value;
2228 		break;
2229 
2230 	case oStreamLocalBindUnlink:
2231 		intptr = &options->fwd_opts.streamlocal_bind_unlink;
2232 		goto parse_flag;
2233 
2234 	case oRevokedHostKeys:
2235 		charptr = &options->revoked_host_keys;
2236 		goto parse_string;
2237 
2238 	case oFingerprintHash:
2239 		intptr = &options->fingerprint_hash;
2240 		arg = argv_next(&ac, &av);
2241 		if (!arg || *arg == '\0') {
2242 			error("%.200s line %d: Missing argument.",
2243 			    filename, linenum);
2244 			goto out;
2245 		}
2246 		if ((value = ssh_digest_alg_by_name(arg)) == -1) {
2247 			error("%.200s line %d: Invalid hash algorithm \"%s\".",
2248 			    filename, linenum, arg);
2249 			goto out;
2250 		}
2251 		if (*activep && *intptr == -1)
2252 			*intptr = value;
2253 		break;
2254 
2255 	case oUpdateHostkeys:
2256 		intptr = &options->update_hostkeys;
2257 		multistate_ptr = multistate_yesnoask;
2258 		goto parse_multistate;
2259 
2260 	case oHostbasedAcceptedAlgorithms:
2261 		charptr = &options->hostbased_accepted_algos;
2262 		ca_only = 0;
2263 		goto parse_pubkey_algos;
2264 
2265 	case oPubkeyAcceptedAlgorithms:
2266 		charptr = &options->pubkey_accepted_algos;
2267 		ca_only = 0;
2268 		goto parse_pubkey_algos;
2269 
2270 	case oAddKeysToAgent:
2271 		arg = argv_next(&ac, &av);
2272 		arg2 = argv_next(&ac, &av);
2273 		value = parse_multistate_value(arg, filename, linenum,
2274 		    multistate_yesnoaskconfirm);
2275 		value2 = 0; /* unlimited lifespan by default */
2276 		if (value == 3 && arg2 != NULL) {
2277 			/* allow "AddKeysToAgent confirm 5m" */
2278 			if ((value2 = convtime(arg2)) == -1) {
2279 				error("%s line %d: invalid time value.",
2280 				    filename, linenum);
2281 				goto out;
2282 			}
2283 		} else if (value == -1 && arg2 == NULL) {
2284 			if ((value2 = convtime(arg)) == -1) {
2285 				error("%s line %d: unsupported option",
2286 				    filename, linenum);
2287 				goto out;
2288 			}
2289 			value = 1; /* yes */
2290 		} else if (value == -1 || arg2 != NULL) {
2291 			error("%s line %d: unsupported option",
2292 			    filename, linenum);
2293 			goto out;
2294 		}
2295 		if (*activep && options->add_keys_to_agent == -1) {
2296 			options->add_keys_to_agent = value;
2297 			options->add_keys_to_agent_lifespan = value2;
2298 		}
2299 		break;
2300 
2301 	case oIdentityAgent:
2302 		charptr = &options->identity_agent;
2303 		arg = argv_next(&ac, &av);
2304 		if (!arg || *arg == '\0') {
2305 			error("%.200s line %d: Missing argument.",
2306 			    filename, linenum);
2307 			goto out;
2308 		}
2309   parse_agent_path:
2310 		/* Extra validation if the string represents an env var. */
2311 		if ((arg2 = dollar_expand(&r, arg)) == NULL || r) {
2312 			error("%.200s line %d: Invalid environment expansion "
2313 			    "%s.", filename, linenum, arg);
2314 			goto out;
2315 		}
2316 		free(arg2);
2317 		/* check for legacy environment format */
2318 		if (arg[0] == '$' && arg[1] != '{' &&
2319 		    !valid_env_name(arg + 1)) {
2320 			error("%.200s line %d: Invalid environment name %s.",
2321 			    filename, linenum, arg);
2322 			goto out;
2323 		}
2324 		if (*activep && *charptr == NULL)
2325 			*charptr = xstrdup(arg);
2326 		break;
2327 
2328 	case oEnableEscapeCommandline:
2329 		intptr = &options->enable_escape_commandline;
2330 		goto parse_flag;
2331 
2332 	case oRequiredRSASize:
2333 		intptr = &options->required_rsa_size;
2334 		goto parse_int;
2335 
2336 	case oObscureKeystrokeTiming:
2337 		value = -1;
2338 		while ((arg = argv_next(&ac, &av)) != NULL) {
2339 			if (value != -1) {
2340 				error("%s line %d: invalid arguments",
2341 				    filename, linenum);
2342 				goto out;
2343 			}
2344 			if (strcmp(arg, "yes") == 0 ||
2345 			    strcmp(arg, "true") == 0)
2346 				value = SSH_KEYSTROKE_DEFAULT_INTERVAL_MS;
2347 			else if (strcmp(arg, "no") == 0 ||
2348 			    strcmp(arg, "false") == 0)
2349 				value = 0;
2350 			else if (strncmp(arg, "interval:", 9) == 0) {
2351 				if ((errstr = atoi_err(arg + 9,
2352 				    &value)) != NULL) {
2353 					error("%s line %d: integer value %s.",
2354 					    filename, linenum, errstr);
2355 					goto out;
2356 				}
2357 				if (value <= 0 || value > 1000) {
2358 					error("%s line %d: value out of range.",
2359 					    filename, linenum);
2360 					goto out;
2361 				}
2362 			} else {
2363 				error("%s line %d: unsupported argument \"%s\"",
2364 				    filename, linenum, arg);
2365 				goto out;
2366 			}
2367 		}
2368 		if (value == -1) {
2369 			error("%s line %d: missing argument",
2370 			    filename, linenum);
2371 			goto out;
2372 		}
2373 		intptr = &options->obscure_keystroke_timing_interval;
2374 		if (*activep && *intptr == -1)
2375 			*intptr = value;
2376 		break;
2377 
2378 	case oChannelTimeout:
2379 		found = options->num_channel_timeouts == 0;
2380 		while ((arg = argv_next(&ac, &av)) != NULL) {
2381 			/* Allow "none" only in first position */
2382 			if (strcasecmp(arg, "none") == 0) {
2383 				if (nstrs > 0 || ac > 0) {
2384 					error("%s line %d: keyword %s \"none\" "
2385 					    "argument must appear alone.",
2386 					    filename, linenum, keyword);
2387 					goto out;
2388 				}
2389 			} else if (parse_pattern_interval(arg,
2390 			    NULL, NULL) != 0) {
2391 				fatal("%s line %d: invalid channel timeout %s",
2392 				    filename, linenum, arg);
2393 			}
2394 			opt_array_append(filename, linenum, keyword,
2395 			    &strs, &nstrs, arg);
2396 		}
2397 		if (nstrs == 0) {
2398 			fatal("%s line %d: no %s specified",
2399 			    filename, linenum, keyword);
2400 		}
2401 		if (found && *activep) {
2402 			options->channel_timeouts = strs;
2403 			options->num_channel_timeouts = nstrs;
2404 			strs = NULL; /* transferred */
2405 			nstrs = 0;
2406 		}
2407 		break;
2408 
2409 	case oDeprecated:
2410 		debug("%s line %d: Deprecated option \"%s\"",
2411 		    filename, linenum, keyword);
2412 		argv_consume(&ac);
2413 		break;
2414 
2415 	case oUnsupported:
2416 		error("%s line %d: Unsupported option \"%s\"",
2417 		    filename, linenum, keyword);
2418 		argv_consume(&ac);
2419 		break;
2420 
2421 	default:
2422 		error("%s line %d: Unimplemented opcode %d",
2423 		    filename, linenum, opcode);
2424 		goto out;
2425 	}
2426 
2427 	/* Check that there is no garbage at end of line. */
2428 	if (ac > 0) {
2429 		error("%.200s line %d: keyword %s extra arguments "
2430 		    "at end of line", filename, linenum, keyword);
2431 		goto out;
2432 	}
2433 
2434 	/* success */
2435 	ret = 0;
2436  out:
2437 	free_canon_cnames(cnames, ncnames);
2438 	opt_array_free2(strs, NULL, nstrs);
2439 	argv_free(oav, oac);
2440 	return ret;
2441 }
2442 
2443 /*
2444  * Reads the config file and modifies the options accordingly.  Options
2445  * should already be initialized before this call.  This never returns if
2446  * there is an error.  If the file does not exist, this returns 0.
2447  */
2448 int
2449 read_config_file(const char *filename, struct passwd *pw, const char *host,
2450     const char *original_host, Options *options, int flags,
2451     int *want_final_pass)
2452 {
2453 	int active = 1;
2454 
2455 	return read_config_file_depth(filename, pw, host, original_host,
2456 	    options, flags, &active, want_final_pass, 0);
2457 }
2458 
2459 #define READCONF_MAX_DEPTH	16
2460 static int
2461 read_config_file_depth(const char *filename, struct passwd *pw,
2462     const char *host, const char *original_host, Options *options,
2463     int flags, int *activep, int *want_final_pass, int depth)
2464 {
2465 	FILE *f;
2466 	char *line = NULL;
2467 	size_t linesize = 0;
2468 	int linenum;
2469 	int bad_options = 0;
2470 
2471 	if (depth < 0 || depth > READCONF_MAX_DEPTH)
2472 		fatal("Too many recursive configuration includes");
2473 
2474 	if ((f = fopen(filename, "r")) == NULL)
2475 		return 0;
2476 
2477 	if (flags & SSHCONF_CHECKPERM) {
2478 		struct stat sb;
2479 
2480 		if (fstat(fileno(f), &sb) == -1)
2481 			fatal("fstat %s: %s", filename, strerror(errno));
2482 		if (((sb.st_uid != 0 && sb.st_uid != getuid()) ||
2483 		    (sb.st_mode & 022) != 0))
2484 			fatal("Bad owner or permissions on %s", filename);
2485 	}
2486 
2487 	debug("Reading configuration data %.200s", filename);
2488 
2489 	/*
2490 	 * Mark that we are now processing the options.  This flag is turned
2491 	 * on/off by Host specifications.
2492 	 */
2493 	linenum = 0;
2494 	while (getline(&line, &linesize, f) != -1) {
2495 		/* Update line number counter. */
2496 		linenum++;
2497 		/*
2498 		 * Trim out comments and strip whitespace.
2499 		 * NB - preserve newlines, they are needed to reproduce
2500 		 * line numbers later for error messages.
2501 		 */
2502 		if (process_config_line_depth(options, pw, host, original_host,
2503 		    line, filename, linenum, activep, flags, want_final_pass,
2504 		    depth) != 0)
2505 			bad_options++;
2506 	}
2507 	free(line);
2508 	fclose(f);
2509 	if (bad_options > 0)
2510 		fatal("%s: terminating, %d bad configuration options",
2511 		    filename, bad_options);
2512 	return 1;
2513 }
2514 
2515 /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */
2516 int
2517 option_clear_or_none(const char *o)
2518 {
2519 	return o == NULL || strcasecmp(o, "none") == 0;
2520 }
2521 
2522 /*
2523  * Returns 1 if CanonicalizePermittedCNAMEs have been specified, 0 otherwise.
2524  * Allowed to be called on non-final configuration.
2525  */
2526 int
2527 config_has_permitted_cnames(Options *options)
2528 {
2529 	if (options->num_permitted_cnames == 1 &&
2530 	    strcasecmp(options->permitted_cnames[0].source_list, "none") == 0 &&
2531 	    strcmp(options->permitted_cnames[0].target_list, "") == 0)
2532 		return 0;
2533 	return options->num_permitted_cnames > 0;
2534 }
2535 
2536 /*
2537  * Initializes options to special values that indicate that they have not yet
2538  * been set.  Read_config_file will only set options with this value. Options
2539  * are processed in the following order: command line, user config file,
2540  * system config file.  Last, fill_default_options is called.
2541  */
2542 
2543 void
2544 initialize_options(Options * options)
2545 {
2546 	memset(options, 'X', sizeof(*options));
2547 	options->host_arg = NULL;
2548 	options->forward_agent = -1;
2549 	options->forward_agent_sock_path = NULL;
2550 	options->forward_x11 = -1;
2551 	options->forward_x11_trusted = -1;
2552 	options->forward_x11_timeout = -1;
2553 	options->stdio_forward_host = NULL;
2554 	options->stdio_forward_port = 0;
2555 	options->clear_forwardings = -1;
2556 	options->exit_on_forward_failure = -1;
2557 	options->xauth_location = NULL;
2558 	options->fwd_opts.gateway_ports = -1;
2559 	options->fwd_opts.streamlocal_bind_mask = (mode_t)-1;
2560 	options->fwd_opts.streamlocal_bind_unlink = -1;
2561 	options->pubkey_authentication = -1;
2562 	options->gss_authentication = -1;
2563 	options->gss_deleg_creds = -1;
2564 	options->password_authentication = -1;
2565 	options->kbd_interactive_authentication = -1;
2566 	options->kbd_interactive_devices = NULL;
2567 	options->hostbased_authentication = -1;
2568 	options->batch_mode = -1;
2569 	options->check_host_ip = -1;
2570 	options->strict_host_key_checking = -1;
2571 	options->compression = -1;
2572 	options->tcp_keep_alive = -1;
2573 	options->port = -1;
2574 	options->address_family = -1;
2575 	options->connection_attempts = -1;
2576 	options->connection_timeout = -1;
2577 	options->number_of_password_prompts = -1;
2578 	options->ciphers = NULL;
2579 	options->macs = NULL;
2580 	options->kex_algorithms = NULL;
2581 	options->hostkeyalgorithms = NULL;
2582 	options->ca_sign_algorithms = NULL;
2583 	options->num_identity_files = 0;
2584 	memset(options->identity_keys, 0, sizeof(options->identity_keys));
2585 	options->num_certificate_files = 0;
2586 	memset(options->certificates, 0, sizeof(options->certificates));
2587 	options->hostname = NULL;
2588 	options->host_key_alias = NULL;
2589 	options->proxy_command = NULL;
2590 	options->jump_user = NULL;
2591 	options->jump_host = NULL;
2592 	options->jump_port = -1;
2593 	options->jump_extra = NULL;
2594 	options->user = NULL;
2595 	options->escape_char = -1;
2596 	options->num_system_hostfiles = 0;
2597 	options->num_user_hostfiles = 0;
2598 	options->local_forwards = NULL;
2599 	options->num_local_forwards = 0;
2600 	options->remote_forwards = NULL;
2601 	options->num_remote_forwards = 0;
2602 	options->permitted_remote_opens = NULL;
2603 	options->num_permitted_remote_opens = 0;
2604 	options->log_facility = SYSLOG_FACILITY_NOT_SET;
2605 	options->log_level = SYSLOG_LEVEL_NOT_SET;
2606 	options->num_log_verbose = 0;
2607 	options->log_verbose = NULL;
2608 	options->preferred_authentications = NULL;
2609 	options->bind_address = NULL;
2610 	options->bind_interface = NULL;
2611 	options->pkcs11_provider = NULL;
2612 	options->sk_provider = NULL;
2613 	options->enable_ssh_keysign = - 1;
2614 	options->no_host_authentication_for_localhost = - 1;
2615 	options->identities_only = - 1;
2616 	options->rekey_limit = - 1;
2617 	options->rekey_interval = -1;
2618 	options->verify_host_key_dns = -1;
2619 	options->server_alive_interval = -1;
2620 	options->server_alive_count_max = -1;
2621 	options->send_env = NULL;
2622 	options->num_send_env = 0;
2623 	options->setenv = NULL;
2624 	options->num_setenv = 0;
2625 	options->control_path = NULL;
2626 	options->control_master = -1;
2627 	options->control_persist = -1;
2628 	options->control_persist_timeout = 0;
2629 	options->hash_known_hosts = -1;
2630 	options->tun_open = -1;
2631 	options->tun_local = -1;
2632 	options->tun_remote = -1;
2633 	options->local_command = NULL;
2634 	options->permit_local_command = -1;
2635 	options->remote_command = NULL;
2636 	options->add_keys_to_agent = -1;
2637 	options->add_keys_to_agent_lifespan = -1;
2638 	options->identity_agent = NULL;
2639 	options->visual_host_key = -1;
2640 	options->ip_qos_interactive = -1;
2641 	options->ip_qos_bulk = -1;
2642 	options->request_tty = -1;
2643 	options->session_type = -1;
2644 	options->stdin_null = -1;
2645 	options->fork_after_authentication = -1;
2646 	options->proxy_use_fdpass = -1;
2647 	options->ignored_unknown = NULL;
2648 	options->num_canonical_domains = 0;
2649 	options->num_permitted_cnames = 0;
2650 	options->canonicalize_max_dots = -1;
2651 	options->canonicalize_fallback_local = -1;
2652 	options->canonicalize_hostname = -1;
2653 	options->revoked_host_keys = NULL;
2654 	options->fingerprint_hash = -1;
2655 	options->update_hostkeys = -1;
2656 	options->hostbased_accepted_algos = NULL;
2657 	options->pubkey_accepted_algos = NULL;
2658 	options->known_hosts_command = NULL;
2659 	options->required_rsa_size = -1;
2660 	options->enable_escape_commandline = -1;
2661 	options->obscure_keystroke_timing_interval = -1;
2662 	options->tag = NULL;
2663 	options->channel_timeouts = NULL;
2664 	options->num_channel_timeouts = 0;
2665 }
2666 
2667 /*
2668  * A petite version of fill_default_options() that just fills the options
2669  * needed for hostname canonicalization to proceed.
2670  */
2671 void
2672 fill_default_options_for_canonicalization(Options *options)
2673 {
2674 	if (options->canonicalize_max_dots == -1)
2675 		options->canonicalize_max_dots = 1;
2676 	if (options->canonicalize_fallback_local == -1)
2677 		options->canonicalize_fallback_local = 1;
2678 	if (options->canonicalize_hostname == -1)
2679 		options->canonicalize_hostname = SSH_CANONICALISE_NO;
2680 }
2681 
2682 /*
2683  * Called after processing other sources of option data, this fills those
2684  * options for which no value has been specified with their default values.
2685  */
2686 int
2687 fill_default_options(Options * options)
2688 {
2689 	char *all_cipher, *all_mac, *all_kex, *all_key, *all_sig;
2690 	char *def_cipher, *def_mac, *def_kex, *def_key, *def_sig;
2691 	int ret = 0, r;
2692 
2693 	if (options->forward_agent == -1)
2694 		options->forward_agent = 0;
2695 	if (options->forward_x11 == -1)
2696 		options->forward_x11 = 0;
2697 	if (options->forward_x11_trusted == -1)
2698 		options->forward_x11_trusted = 0;
2699 	if (options->forward_x11_timeout == -1)
2700 		options->forward_x11_timeout = 1200;
2701 	/*
2702 	 * stdio forwarding (-W) changes the default for these but we defer
2703 	 * setting the values so they can be overridden.
2704 	 */
2705 	if (options->exit_on_forward_failure == -1)
2706 		options->exit_on_forward_failure =
2707 		    options->stdio_forward_host != NULL ? 1 : 0;
2708 	if (options->clear_forwardings == -1)
2709 		options->clear_forwardings =
2710 		    options->stdio_forward_host != NULL ? 1 : 0;
2711 	if (options->clear_forwardings == 1)
2712 		clear_forwardings(options);
2713 
2714 	if (options->xauth_location == NULL)
2715 		options->xauth_location = xstrdup(_PATH_XAUTH);
2716 	if (options->fwd_opts.gateway_ports == -1)
2717 		options->fwd_opts.gateway_ports = 0;
2718 	if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1)
2719 		options->fwd_opts.streamlocal_bind_mask = 0177;
2720 	if (options->fwd_opts.streamlocal_bind_unlink == -1)
2721 		options->fwd_opts.streamlocal_bind_unlink = 0;
2722 	if (options->pubkey_authentication == -1)
2723 		options->pubkey_authentication = SSH_PUBKEY_AUTH_ALL;
2724 	if (options->gss_authentication == -1)
2725 		options->gss_authentication = 0;
2726 	if (options->gss_deleg_creds == -1)
2727 		options->gss_deleg_creds = 0;
2728 	if (options->password_authentication == -1)
2729 		options->password_authentication = 1;
2730 	if (options->kbd_interactive_authentication == -1)
2731 		options->kbd_interactive_authentication = 1;
2732 	if (options->hostbased_authentication == -1)
2733 		options->hostbased_authentication = 0;
2734 	if (options->batch_mode == -1)
2735 		options->batch_mode = 0;
2736 	if (options->check_host_ip == -1)
2737 		options->check_host_ip = 0;
2738 	if (options->strict_host_key_checking == -1)
2739 		options->strict_host_key_checking = SSH_STRICT_HOSTKEY_ASK;
2740 	if (options->compression == -1)
2741 		options->compression = 0;
2742 	if (options->tcp_keep_alive == -1)
2743 		options->tcp_keep_alive = 1;
2744 	if (options->port == -1)
2745 		options->port = 0;	/* Filled in ssh_connect. */
2746 	if (options->address_family == -1)
2747 		options->address_family = AF_UNSPEC;
2748 	if (options->connection_attempts == -1)
2749 		options->connection_attempts = 1;
2750 	if (options->number_of_password_prompts == -1)
2751 		options->number_of_password_prompts = 3;
2752 	/* options->hostkeyalgorithms, default set in myproposals.h */
2753 	if (options->add_keys_to_agent == -1) {
2754 		options->add_keys_to_agent = 0;
2755 		options->add_keys_to_agent_lifespan = 0;
2756 	}
2757 	if (options->num_identity_files == 0) {
2758 		add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_RSA, 0);
2759 		add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_ECDSA, 0);
2760 		add_identity_file(options, "~/",
2761 		    _PATH_SSH_CLIENT_ID_ECDSA_SK, 0);
2762 		add_identity_file(options, "~/",
2763 		    _PATH_SSH_CLIENT_ID_ED25519, 0);
2764 		add_identity_file(options, "~/",
2765 		    _PATH_SSH_CLIENT_ID_ED25519_SK, 0);
2766 		add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_XMSS, 0);
2767 #ifdef WITH_DSA
2768 		add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_DSA, 0);
2769 #endif
2770 	}
2771 	if (options->escape_char == -1)
2772 		options->escape_char = '~';
2773 	if (options->num_system_hostfiles == 0) {
2774 		options->system_hostfiles[options->num_system_hostfiles++] =
2775 		    xstrdup(_PATH_SSH_SYSTEM_HOSTFILE);
2776 		options->system_hostfiles[options->num_system_hostfiles++] =
2777 		    xstrdup(_PATH_SSH_SYSTEM_HOSTFILE2);
2778 	}
2779 	if (options->update_hostkeys == -1) {
2780 		if (options->verify_host_key_dns <= 0 &&
2781 		    (options->num_user_hostfiles == 0 ||
2782 		    (options->num_user_hostfiles == 1 && strcmp(options->
2783 		    user_hostfiles[0], _PATH_SSH_USER_HOSTFILE) == 0)))
2784 			options->update_hostkeys = SSH_UPDATE_HOSTKEYS_YES;
2785 		else
2786 			options->update_hostkeys = SSH_UPDATE_HOSTKEYS_NO;
2787 	}
2788 	if (options->num_user_hostfiles == 0) {
2789 		options->user_hostfiles[options->num_user_hostfiles++] =
2790 		    xstrdup(_PATH_SSH_USER_HOSTFILE);
2791 		options->user_hostfiles[options->num_user_hostfiles++] =
2792 		    xstrdup(_PATH_SSH_USER_HOSTFILE2);
2793 	}
2794 	if (options->log_level == SYSLOG_LEVEL_NOT_SET)
2795 		options->log_level = SYSLOG_LEVEL_INFO;
2796 	if (options->log_facility == SYSLOG_FACILITY_NOT_SET)
2797 		options->log_facility = SYSLOG_FACILITY_USER;
2798 	if (options->no_host_authentication_for_localhost == - 1)
2799 		options->no_host_authentication_for_localhost = 0;
2800 	if (options->identities_only == -1)
2801 		options->identities_only = 0;
2802 	if (options->enable_ssh_keysign == -1)
2803 		options->enable_ssh_keysign = 0;
2804 	if (options->rekey_limit == -1)
2805 		options->rekey_limit = 0;
2806 	if (options->rekey_interval == -1)
2807 		options->rekey_interval = 0;
2808 	if (options->verify_host_key_dns == -1)
2809 		options->verify_host_key_dns = 0;
2810 	if (options->server_alive_interval == -1)
2811 		options->server_alive_interval = 0;
2812 	if (options->server_alive_count_max == -1)
2813 		options->server_alive_count_max = 3;
2814 	if (options->control_master == -1)
2815 		options->control_master = 0;
2816 	if (options->control_persist == -1) {
2817 		options->control_persist = 0;
2818 		options->control_persist_timeout = 0;
2819 	}
2820 	if (options->hash_known_hosts == -1)
2821 		options->hash_known_hosts = 0;
2822 	if (options->tun_open == -1)
2823 		options->tun_open = SSH_TUNMODE_NO;
2824 	if (options->tun_local == -1)
2825 		options->tun_local = SSH_TUNID_ANY;
2826 	if (options->tun_remote == -1)
2827 		options->tun_remote = SSH_TUNID_ANY;
2828 	if (options->permit_local_command == -1)
2829 		options->permit_local_command = 0;
2830 	if (options->visual_host_key == -1)
2831 		options->visual_host_key = 0;
2832 	if (options->ip_qos_interactive == -1)
2833 		options->ip_qos_interactive = IPTOS_DSCP_AF21;
2834 	if (options->ip_qos_bulk == -1)
2835 		options->ip_qos_bulk = IPTOS_DSCP_CS1;
2836 	if (options->request_tty == -1)
2837 		options->request_tty = REQUEST_TTY_AUTO;
2838 	if (options->session_type == -1)
2839 		options->session_type = SESSION_TYPE_DEFAULT;
2840 	if (options->stdin_null == -1)
2841 		options->stdin_null = 0;
2842 	if (options->fork_after_authentication == -1)
2843 		options->fork_after_authentication = 0;
2844 	if (options->proxy_use_fdpass == -1)
2845 		options->proxy_use_fdpass = 0;
2846 	if (options->canonicalize_max_dots == -1)
2847 		options->canonicalize_max_dots = 1;
2848 	if (options->canonicalize_fallback_local == -1)
2849 		options->canonicalize_fallback_local = 1;
2850 	if (options->canonicalize_hostname == -1)
2851 		options->canonicalize_hostname = SSH_CANONICALISE_NO;
2852 	if (options->fingerprint_hash == -1)
2853 		options->fingerprint_hash = SSH_FP_HASH_DEFAULT;
2854 	if (options->sk_provider == NULL)
2855 		options->sk_provider = xstrdup("internal");
2856 	if (options->required_rsa_size == -1)
2857 		options->required_rsa_size = SSH_RSA_MINIMUM_MODULUS_SIZE;
2858 	if (options->enable_escape_commandline == -1)
2859 		options->enable_escape_commandline = 0;
2860 	if (options->obscure_keystroke_timing_interval == -1) {
2861 		options->obscure_keystroke_timing_interval =
2862 		    SSH_KEYSTROKE_DEFAULT_INTERVAL_MS;
2863 	}
2864 
2865 	/* Expand KEX name lists */
2866 	all_cipher = cipher_alg_list(',', 0);
2867 	all_mac = mac_alg_list(',');
2868 	all_kex = kex_alg_list(',');
2869 	all_key = sshkey_alg_list(0, 0, 1, ',');
2870 	all_sig = sshkey_alg_list(0, 1, 1, ',');
2871 	/* remove unsupported algos from default lists */
2872 	def_cipher = match_filter_allowlist(KEX_CLIENT_ENCRYPT, all_cipher);
2873 	def_mac = match_filter_allowlist(KEX_CLIENT_MAC, all_mac);
2874 	def_kex = match_filter_allowlist(KEX_CLIENT_KEX, all_kex);
2875 	def_key = match_filter_allowlist(KEX_DEFAULT_PK_ALG, all_key);
2876 	def_sig = match_filter_allowlist(SSH_ALLOWED_CA_SIGALGS, all_sig);
2877 #define ASSEMBLE(what, defaults, all) \
2878 	do { \
2879 		if ((r = kex_assemble_names(&options->what, \
2880 		    defaults, all)) != 0) { \
2881 			error_fr(r, "%s", #what); \
2882 			goto fail; \
2883 		} \
2884 	} while (0)
2885 	ASSEMBLE(ciphers, def_cipher, all_cipher);
2886 	ASSEMBLE(macs, def_mac, all_mac);
2887 	ASSEMBLE(kex_algorithms, def_kex, all_kex);
2888 	ASSEMBLE(hostbased_accepted_algos, def_key, all_key);
2889 	ASSEMBLE(pubkey_accepted_algos, def_key, all_key);
2890 	ASSEMBLE(ca_sign_algorithms, def_sig, all_sig);
2891 #undef ASSEMBLE
2892 
2893 #define CLEAR_ON_NONE(v) \
2894 	do { \
2895 		if (option_clear_or_none(v)) { \
2896 			free(v); \
2897 			v = NULL; \
2898 		} \
2899 	} while(0)
2900 #define CLEAR_ON_NONE_ARRAY(v, nv, none) \
2901 	do { \
2902 		if (options->nv == 1 && \
2903 		    strcasecmp(options->v[0], none) == 0) { \
2904 			free(options->v[0]); \
2905 			free(options->v); \
2906 			options->v = NULL; \
2907 			options->nv = 0; \
2908 		} \
2909 	} while (0)
2910 	CLEAR_ON_NONE(options->local_command);
2911 	CLEAR_ON_NONE(options->remote_command);
2912 	CLEAR_ON_NONE(options->proxy_command);
2913 	CLEAR_ON_NONE(options->control_path);
2914 	CLEAR_ON_NONE(options->revoked_host_keys);
2915 	CLEAR_ON_NONE(options->pkcs11_provider);
2916 	CLEAR_ON_NONE(options->sk_provider);
2917 	CLEAR_ON_NONE(options->known_hosts_command);
2918 	CLEAR_ON_NONE_ARRAY(channel_timeouts, num_channel_timeouts, "none");
2919 #undef CLEAR_ON_NONE
2920 #undef CLEAR_ON_NONE_ARRAY
2921 	if (options->jump_host != NULL &&
2922 	    strcmp(options->jump_host, "none") == 0 &&
2923 	    options->jump_port == 0 && options->jump_user == NULL) {
2924 		free(options->jump_host);
2925 		options->jump_host = NULL;
2926 	}
2927 	if (options->num_permitted_cnames == 1 &&
2928 	    !config_has_permitted_cnames(options)) {
2929 		/* clean up CanonicalizePermittedCNAMEs=none */
2930 		free(options->permitted_cnames[0].source_list);
2931 		free(options->permitted_cnames[0].target_list);
2932 		memset(options->permitted_cnames, '\0',
2933 		    sizeof(*options->permitted_cnames));
2934 		options->num_permitted_cnames = 0;
2935 	}
2936 	/* options->identity_agent distinguishes NULL from 'none' */
2937 	/* options->user will be set in the main program if appropriate */
2938 	/* options->hostname will be set in the main program if appropriate */
2939 	/* options->host_key_alias should not be set by default */
2940 	/* options->preferred_authentications will be set in ssh */
2941 
2942 	/* success */
2943 	ret = 0;
2944  fail:
2945 	free(all_cipher);
2946 	free(all_mac);
2947 	free(all_kex);
2948 	free(all_key);
2949 	free(all_sig);
2950 	free(def_cipher);
2951 	free(def_mac);
2952 	free(def_kex);
2953 	free(def_key);
2954 	free(def_sig);
2955 	return ret;
2956 }
2957 
2958 void
2959 free_options(Options *o)
2960 {
2961 	int i;
2962 
2963 	if (o == NULL)
2964 		return;
2965 
2966 #define FREE_ARRAY(type, n, a) \
2967 	do { \
2968 		type _i; \
2969 		for (_i = 0; _i < (n); _i++) \
2970 			free((a)[_i]); \
2971 	} while (0)
2972 
2973 	free(o->forward_agent_sock_path);
2974 	free(o->xauth_location);
2975 	FREE_ARRAY(u_int, o->num_log_verbose, o->log_verbose);
2976 	free(o->log_verbose);
2977 	free(o->ciphers);
2978 	free(o->macs);
2979 	free(o->hostkeyalgorithms);
2980 	free(o->kex_algorithms);
2981 	free(o->ca_sign_algorithms);
2982 	free(o->hostname);
2983 	free(o->host_key_alias);
2984 	free(o->proxy_command);
2985 	free(o->user);
2986 	FREE_ARRAY(u_int, o->num_system_hostfiles, o->system_hostfiles);
2987 	FREE_ARRAY(u_int, o->num_user_hostfiles, o->user_hostfiles);
2988 	free(o->preferred_authentications);
2989 	free(o->bind_address);
2990 	free(o->bind_interface);
2991 	free(o->pkcs11_provider);
2992 	free(o->sk_provider);
2993 	for (i = 0; i < o->num_identity_files; i++) {
2994 		free(o->identity_files[i]);
2995 		sshkey_free(o->identity_keys[i]);
2996 	}
2997 	for (i = 0; i < o->num_certificate_files; i++) {
2998 		free(o->certificate_files[i]);
2999 		sshkey_free(o->certificates[i]);
3000 	}
3001 	free(o->identity_agent);
3002 	for (i = 0; i < o->num_local_forwards; i++) {
3003 		free(o->local_forwards[i].listen_host);
3004 		free(o->local_forwards[i].listen_path);
3005 		free(o->local_forwards[i].connect_host);
3006 		free(o->local_forwards[i].connect_path);
3007 	}
3008 	free(o->local_forwards);
3009 	for (i = 0; i < o->num_remote_forwards; i++) {
3010 		free(o->remote_forwards[i].listen_host);
3011 		free(o->remote_forwards[i].listen_path);
3012 		free(o->remote_forwards[i].connect_host);
3013 		free(o->remote_forwards[i].connect_path);
3014 	}
3015 	free(o->remote_forwards);
3016 	free(o->stdio_forward_host);
3017 	FREE_ARRAY(u_int, o->num_send_env, o->send_env);
3018 	free(o->send_env);
3019 	FREE_ARRAY(u_int, o->num_setenv, o->setenv);
3020 	free(o->setenv);
3021 	free(o->control_path);
3022 	free(o->local_command);
3023 	free(o->remote_command);
3024 	FREE_ARRAY(int, o->num_canonical_domains, o->canonical_domains);
3025 	for (i = 0; i < o->num_permitted_cnames; i++) {
3026 		free(o->permitted_cnames[i].source_list);
3027 		free(o->permitted_cnames[i].target_list);
3028 	}
3029 	free(o->revoked_host_keys);
3030 	free(o->hostbased_accepted_algos);
3031 	free(o->pubkey_accepted_algos);
3032 	free(o->jump_user);
3033 	free(o->jump_host);
3034 	free(o->jump_extra);
3035 	free(o->ignored_unknown);
3036 	explicit_bzero(o, sizeof(*o));
3037 #undef FREE_ARRAY
3038 }
3039 
3040 struct fwdarg {
3041 	char *arg;
3042 	int ispath;
3043 };
3044 
3045 /*
3046  * parse_fwd_field
3047  * parses the next field in a port forwarding specification.
3048  * sets fwd to the parsed field and advances p past the colon
3049  * or sets it to NULL at end of string.
3050  * returns 0 on success, else non-zero.
3051  */
3052 static int
3053 parse_fwd_field(char **p, struct fwdarg *fwd)
3054 {
3055 	char *ep, *cp = *p;
3056 	int ispath = 0;
3057 
3058 	if (*cp == '\0') {
3059 		*p = NULL;
3060 		return -1;	/* end of string */
3061 	}
3062 
3063 	/*
3064 	 * A field escaped with square brackets is used literally.
3065 	 * XXX - allow ']' to be escaped via backslash?
3066 	 */
3067 	if (*cp == '[') {
3068 		/* find matching ']' */
3069 		for (ep = cp + 1; *ep != ']' && *ep != '\0'; ep++) {
3070 			if (*ep == '/')
3071 				ispath = 1;
3072 		}
3073 		/* no matching ']' or not at end of field. */
3074 		if (ep[0] != ']' || (ep[1] != ':' && ep[1] != '\0'))
3075 			return -1;
3076 		/* NUL terminate the field and advance p past the colon */
3077 		*ep++ = '\0';
3078 		if (*ep != '\0')
3079 			*ep++ = '\0';
3080 		fwd->arg = cp + 1;
3081 		fwd->ispath = ispath;
3082 		*p = ep;
3083 		return 0;
3084 	}
3085 
3086 	for (cp = *p; *cp != '\0'; cp++) {
3087 		switch (*cp) {
3088 		case '\\':
3089 			memmove(cp, cp + 1, strlen(cp + 1) + 1);
3090 			if (*cp == '\0')
3091 				return -1;
3092 			break;
3093 		case '/':
3094 			ispath = 1;
3095 			break;
3096 		case ':':
3097 			*cp++ = '\0';
3098 			goto done;
3099 		}
3100 	}
3101 done:
3102 	fwd->arg = *p;
3103 	fwd->ispath = ispath;
3104 	*p = cp;
3105 	return 0;
3106 }
3107 
3108 /*
3109  * parse_forward
3110  * parses a string containing a port forwarding specification of the form:
3111  *   dynamicfwd == 0
3112  *	[listenhost:]listenport|listenpath:connecthost:connectport|connectpath
3113  *	listenpath:connectpath
3114  *   dynamicfwd == 1
3115  *	[listenhost:]listenport
3116  * returns number of arguments parsed or zero on error
3117  */
3118 int
3119 parse_forward(struct Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
3120 {
3121 	struct fwdarg fwdargs[4];
3122 	char *p, *cp;
3123 	int i, err;
3124 
3125 	memset(fwd, 0, sizeof(*fwd));
3126 	memset(fwdargs, 0, sizeof(fwdargs));
3127 
3128 	/*
3129 	 * We expand environment variables before checking if we think they're
3130 	 * paths so that if ${VAR} expands to a fully qualified path it is
3131 	 * treated as a path.
3132 	 */
3133 	cp = p = dollar_expand(&err, fwdspec);
3134 	if (p == NULL || err)
3135 		return 0;
3136 
3137 	/* skip leading spaces */
3138 	while (isspace((u_char)*cp))
3139 		cp++;
3140 
3141 	for (i = 0; i < 4; ++i) {
3142 		if (parse_fwd_field(&cp, &fwdargs[i]) != 0)
3143 			break;
3144 	}
3145 
3146 	/* Check for trailing garbage */
3147 	if (cp != NULL && *cp != '\0') {
3148 		i = 0;	/* failure */
3149 	}
3150 
3151 	switch (i) {
3152 	case 1:
3153 		if (fwdargs[0].ispath) {
3154 			fwd->listen_path = xstrdup(fwdargs[0].arg);
3155 			fwd->listen_port = PORT_STREAMLOCAL;
3156 		} else {
3157 			fwd->listen_host = NULL;
3158 			fwd->listen_port = a2port(fwdargs[0].arg);
3159 		}
3160 		fwd->connect_host = xstrdup("socks");
3161 		break;
3162 
3163 	case 2:
3164 		if (fwdargs[0].ispath && fwdargs[1].ispath) {
3165 			fwd->listen_path = xstrdup(fwdargs[0].arg);
3166 			fwd->listen_port = PORT_STREAMLOCAL;
3167 			fwd->connect_path = xstrdup(fwdargs[1].arg);
3168 			fwd->connect_port = PORT_STREAMLOCAL;
3169 		} else if (fwdargs[1].ispath) {
3170 			fwd->listen_host = NULL;
3171 			fwd->listen_port = a2port(fwdargs[0].arg);
3172 			fwd->connect_path = xstrdup(fwdargs[1].arg);
3173 			fwd->connect_port = PORT_STREAMLOCAL;
3174 		} else {
3175 			fwd->listen_host = xstrdup(fwdargs[0].arg);
3176 			fwd->listen_port = a2port(fwdargs[1].arg);
3177 			fwd->connect_host = xstrdup("socks");
3178 		}
3179 		break;
3180 
3181 	case 3:
3182 		if (fwdargs[0].ispath) {
3183 			fwd->listen_path = xstrdup(fwdargs[0].arg);
3184 			fwd->listen_port = PORT_STREAMLOCAL;
3185 			fwd->connect_host = xstrdup(fwdargs[1].arg);
3186 			fwd->connect_port = a2port(fwdargs[2].arg);
3187 		} else if (fwdargs[2].ispath) {
3188 			fwd->listen_host = xstrdup(fwdargs[0].arg);
3189 			fwd->listen_port = a2port(fwdargs[1].arg);
3190 			fwd->connect_path = xstrdup(fwdargs[2].arg);
3191 			fwd->connect_port = PORT_STREAMLOCAL;
3192 		} else {
3193 			fwd->listen_host = NULL;
3194 			fwd->listen_port = a2port(fwdargs[0].arg);
3195 			fwd->connect_host = xstrdup(fwdargs[1].arg);
3196 			fwd->connect_port = a2port(fwdargs[2].arg);
3197 		}
3198 		break;
3199 
3200 	case 4:
3201 		fwd->listen_host = xstrdup(fwdargs[0].arg);
3202 		fwd->listen_port = a2port(fwdargs[1].arg);
3203 		fwd->connect_host = xstrdup(fwdargs[2].arg);
3204 		fwd->connect_port = a2port(fwdargs[3].arg);
3205 		break;
3206 	default:
3207 		i = 0; /* failure */
3208 	}
3209 
3210 	free(p);
3211 
3212 	if (dynamicfwd) {
3213 		if (!(i == 1 || i == 2))
3214 			goto fail_free;
3215 	} else {
3216 		if (!(i == 3 || i == 4)) {
3217 			if (fwd->connect_path == NULL &&
3218 			    fwd->listen_path == NULL)
3219 				goto fail_free;
3220 		}
3221 		if (fwd->connect_port <= 0 && fwd->connect_path == NULL)
3222 			goto fail_free;
3223 	}
3224 
3225 	if ((fwd->listen_port < 0 && fwd->listen_path == NULL) ||
3226 	    (!remotefwd && fwd->listen_port == 0))
3227 		goto fail_free;
3228 	if (fwd->connect_host != NULL &&
3229 	    strlen(fwd->connect_host) >= NI_MAXHOST)
3230 		goto fail_free;
3231 	/*
3232 	 * XXX - if connecting to a remote socket, max sun len may not
3233 	 * match this host
3234 	 */
3235 	if (fwd->connect_path != NULL &&
3236 	    strlen(fwd->connect_path) >= PATH_MAX_SUN)
3237 		goto fail_free;
3238 	if (fwd->listen_host != NULL &&
3239 	    strlen(fwd->listen_host) >= NI_MAXHOST)
3240 		goto fail_free;
3241 	if (fwd->listen_path != NULL &&
3242 	    strlen(fwd->listen_path) >= PATH_MAX_SUN)
3243 		goto fail_free;
3244 
3245 	return (i);
3246 
3247  fail_free:
3248 	free(fwd->connect_host);
3249 	fwd->connect_host = NULL;
3250 	free(fwd->connect_path);
3251 	fwd->connect_path = NULL;
3252 	free(fwd->listen_host);
3253 	fwd->listen_host = NULL;
3254 	free(fwd->listen_path);
3255 	fwd->listen_path = NULL;
3256 	return (0);
3257 }
3258 
3259 int
3260 parse_jump(const char *s, Options *o, int active)
3261 {
3262 	char *orig, *sdup, *cp;
3263 	char *host = NULL, *user = NULL;
3264 	int r, ret = -1, port = -1, first;
3265 
3266 	active &= o->proxy_command == NULL && o->jump_host == NULL;
3267 
3268 	orig = sdup = xstrdup(s);
3269 
3270 	/* Remove comment and trailing whitespace */
3271 	if ((cp = strchr(orig, '#')) != NULL)
3272 		*cp = '\0';
3273 	rtrim(orig);
3274 
3275 	first = active;
3276 	do {
3277 		if (strcasecmp(s, "none") == 0)
3278 			break;
3279 		if ((cp = strrchr(sdup, ',')) == NULL)
3280 			cp = sdup; /* last */
3281 		else
3282 			*cp++ = '\0';
3283 
3284 		if (first) {
3285 			/* First argument and configuration is active */
3286 			r = parse_ssh_uri(cp, &user, &host, &port);
3287 			if (r == -1 || (r == 1 &&
3288 			    parse_user_host_port(cp, &user, &host, &port) != 0))
3289 				goto out;
3290 		} else {
3291 			/* Subsequent argument or inactive configuration */
3292 			r = parse_ssh_uri(cp, NULL, NULL, NULL);
3293 			if (r == -1 || (r == 1 &&
3294 			    parse_user_host_port(cp, NULL, NULL, NULL) != 0))
3295 				goto out;
3296 		}
3297 		first = 0; /* only check syntax for subsequent hosts */
3298 	} while (cp != sdup);
3299 	/* success */
3300 	if (active) {
3301 		if (strcasecmp(s, "none") == 0) {
3302 			o->jump_host = xstrdup("none");
3303 			o->jump_port = 0;
3304 		} else {
3305 			o->jump_user = user;
3306 			o->jump_host = host;
3307 			o->jump_port = port;
3308 			o->proxy_command = xstrdup("none");
3309 			user = host = NULL;
3310 			if ((cp = strrchr(s, ',')) != NULL && cp != s) {
3311 				o->jump_extra = xstrdup(s);
3312 				o->jump_extra[cp - s] = '\0';
3313 			}
3314 		}
3315 	}
3316 	ret = 0;
3317  out:
3318 	free(orig);
3319 	free(user);
3320 	free(host);
3321 	return ret;
3322 }
3323 
3324 int
3325 parse_ssh_uri(const char *uri, char **userp, char **hostp, int *portp)
3326 {
3327 	char *user = NULL, *host = NULL, *path = NULL;
3328 	int r, port;
3329 
3330 	r = parse_uri("ssh", uri, &user, &host, &port, &path);
3331 	if (r == 0 && path != NULL)
3332 		r = -1;		/* path not allowed */
3333 	if (r == 0) {
3334 		if (userp != NULL) {
3335 			*userp = user;
3336 			user = NULL;
3337 		}
3338 		if (hostp != NULL) {
3339 			*hostp = host;
3340 			host = NULL;
3341 		}
3342 		if (portp != NULL)
3343 			*portp = port;
3344 	}
3345 	free(user);
3346 	free(host);
3347 	free(path);
3348 	return r;
3349 }
3350 
3351 /* XXX the following is a near-verbatim copy from servconf.c; refactor */
3352 static const char *
3353 fmt_multistate_int(int val, const struct multistate *m)
3354 {
3355 	u_int i;
3356 
3357 	for (i = 0; m[i].key != NULL; i++) {
3358 		if (m[i].value == val)
3359 			return m[i].key;
3360 	}
3361 	return "UNKNOWN";
3362 }
3363 
3364 static const char *
3365 fmt_intarg(OpCodes code, int val)
3366 {
3367 	if (val == -1)
3368 		return "unset";
3369 	switch (code) {
3370 	case oAddressFamily:
3371 		return fmt_multistate_int(val, multistate_addressfamily);
3372 	case oVerifyHostKeyDNS:
3373 	case oUpdateHostkeys:
3374 		return fmt_multistate_int(val, multistate_yesnoask);
3375 	case oStrictHostKeyChecking:
3376 		return fmt_multistate_int(val, multistate_strict_hostkey);
3377 	case oControlMaster:
3378 		return fmt_multistate_int(val, multistate_controlmaster);
3379 	case oTunnel:
3380 		return fmt_multistate_int(val, multistate_tunnel);
3381 	case oRequestTTY:
3382 		return fmt_multistate_int(val, multistate_requesttty);
3383 	case oSessionType:
3384 		return fmt_multistate_int(val, multistate_sessiontype);
3385 	case oCanonicalizeHostname:
3386 		return fmt_multistate_int(val, multistate_canonicalizehostname);
3387 	case oAddKeysToAgent:
3388 		return fmt_multistate_int(val, multistate_yesnoaskconfirm);
3389 	case oPubkeyAuthentication:
3390 		return fmt_multistate_int(val, multistate_pubkey_auth);
3391 	case oFingerprintHash:
3392 		return ssh_digest_alg_name(val);
3393 	default:
3394 		switch (val) {
3395 		case 0:
3396 			return "no";
3397 		case 1:
3398 			return "yes";
3399 		default:
3400 			return "UNKNOWN";
3401 		}
3402 	}
3403 }
3404 
3405 static const char *
3406 lookup_opcode_name(OpCodes code)
3407 {
3408 	u_int i;
3409 
3410 	for (i = 0; keywords[i].name != NULL; i++)
3411 		if (keywords[i].opcode == code)
3412 			return(keywords[i].name);
3413 	return "UNKNOWN";
3414 }
3415 
3416 static void
3417 dump_cfg_int(OpCodes code, int val)
3418 {
3419 	if (code == oObscureKeystrokeTiming) {
3420 		if (val == 0) {
3421 			printf("%s no\n", lookup_opcode_name(code));
3422 			return;
3423 		} else if (val == SSH_KEYSTROKE_DEFAULT_INTERVAL_MS) {
3424 			printf("%s yes\n", lookup_opcode_name(code));
3425 			return;
3426 		}
3427 		/* FALLTHROUGH */
3428 	}
3429 	printf("%s %d\n", lookup_opcode_name(code), val);
3430 }
3431 
3432 static void
3433 dump_cfg_fmtint(OpCodes code, int val)
3434 {
3435 	printf("%s %s\n", lookup_opcode_name(code), fmt_intarg(code, val));
3436 }
3437 
3438 static void
3439 dump_cfg_string(OpCodes code, const char *val)
3440 {
3441 	if (val == NULL)
3442 		return;
3443 	printf("%s %s\n", lookup_opcode_name(code), val);
3444 }
3445 
3446 static void
3447 dump_cfg_strarray(OpCodes code, u_int count, char **vals)
3448 {
3449 	u_int i;
3450 
3451 	for (i = 0; i < count; i++)
3452 		printf("%s %s\n", lookup_opcode_name(code), vals[i]);
3453 }
3454 
3455 static void
3456 dump_cfg_strarray_oneline(OpCodes code, u_int count, char **vals)
3457 {
3458 	u_int i;
3459 
3460 	printf("%s", lookup_opcode_name(code));
3461 	if (count == 0)
3462 		printf(" none");
3463 	for (i = 0; i < count; i++)
3464 		printf(" %s",  vals[i]);
3465 	printf("\n");
3466 }
3467 
3468 static void
3469 dump_cfg_forwards(OpCodes code, u_int count, const struct Forward *fwds)
3470 {
3471 	const struct Forward *fwd;
3472 	u_int i;
3473 
3474 	/* oDynamicForward */
3475 	for (i = 0; i < count; i++) {
3476 		fwd = &fwds[i];
3477 		if (code == oDynamicForward && fwd->connect_host != NULL &&
3478 		    strcmp(fwd->connect_host, "socks") != 0)
3479 			continue;
3480 		if (code == oLocalForward && fwd->connect_host != NULL &&
3481 		    strcmp(fwd->connect_host, "socks") == 0)
3482 			continue;
3483 		printf("%s", lookup_opcode_name(code));
3484 		if (fwd->listen_port == PORT_STREAMLOCAL)
3485 			printf(" %s", fwd->listen_path);
3486 		else if (fwd->listen_host == NULL)
3487 			printf(" %d", fwd->listen_port);
3488 		else {
3489 			printf(" [%s]:%d",
3490 			    fwd->listen_host, fwd->listen_port);
3491 		}
3492 		if (code != oDynamicForward) {
3493 			if (fwd->connect_port == PORT_STREAMLOCAL)
3494 				printf(" %s", fwd->connect_path);
3495 			else if (fwd->connect_host == NULL)
3496 				printf(" %d", fwd->connect_port);
3497 			else {
3498 				printf(" [%s]:%d",
3499 				    fwd->connect_host, fwd->connect_port);
3500 			}
3501 		}
3502 		printf("\n");
3503 	}
3504 }
3505 
3506 void
3507 dump_client_config(Options *o, const char *host)
3508 {
3509 	int i, r;
3510 	char buf[8], *all_key;
3511 
3512 	/*
3513 	 * Expand HostKeyAlgorithms name lists. This isn't handled in
3514 	 * fill_default_options() like the other algorithm lists because
3515 	 * the host key algorithms are by default dynamically chosen based
3516 	 * on the host's keys found in known_hosts.
3517 	 */
3518 	all_key = sshkey_alg_list(0, 0, 1, ',');
3519 	if ((r = kex_assemble_names(&o->hostkeyalgorithms, kex_default_pk_alg(),
3520 	    all_key)) != 0)
3521 		fatal_fr(r, "expand HostKeyAlgorithms");
3522 	free(all_key);
3523 
3524 	/* Most interesting options first: user, host, port */
3525 	dump_cfg_string(oHost, o->host_arg);
3526 	dump_cfg_string(oUser, o->user);
3527 	dump_cfg_string(oHostname, host);
3528 	dump_cfg_int(oPort, o->port);
3529 
3530 	/* Flag options */
3531 	dump_cfg_fmtint(oAddressFamily, o->address_family);
3532 	dump_cfg_fmtint(oBatchMode, o->batch_mode);
3533 	dump_cfg_fmtint(oCanonicalizeFallbackLocal, o->canonicalize_fallback_local);
3534 	dump_cfg_fmtint(oCanonicalizeHostname, o->canonicalize_hostname);
3535 	dump_cfg_fmtint(oCheckHostIP, o->check_host_ip);
3536 	dump_cfg_fmtint(oCompression, o->compression);
3537 	dump_cfg_fmtint(oControlMaster, o->control_master);
3538 	dump_cfg_fmtint(oEnableSSHKeysign, o->enable_ssh_keysign);
3539 	dump_cfg_fmtint(oClearAllForwardings, o->clear_forwardings);
3540 	dump_cfg_fmtint(oExitOnForwardFailure, o->exit_on_forward_failure);
3541 	dump_cfg_fmtint(oFingerprintHash, o->fingerprint_hash);
3542 	dump_cfg_fmtint(oForwardX11, o->forward_x11);
3543 	dump_cfg_fmtint(oForwardX11Trusted, o->forward_x11_trusted);
3544 	dump_cfg_fmtint(oGatewayPorts, o->fwd_opts.gateway_ports);
3545 #ifdef GSSAPI
3546 	dump_cfg_fmtint(oGssAuthentication, o->gss_authentication);
3547 	dump_cfg_fmtint(oGssDelegateCreds, o->gss_deleg_creds);
3548 #endif /* GSSAPI */
3549 	dump_cfg_fmtint(oHashKnownHosts, o->hash_known_hosts);
3550 	dump_cfg_fmtint(oHostbasedAuthentication, o->hostbased_authentication);
3551 	dump_cfg_fmtint(oIdentitiesOnly, o->identities_only);
3552 	dump_cfg_fmtint(oKbdInteractiveAuthentication, o->kbd_interactive_authentication);
3553 	dump_cfg_fmtint(oNoHostAuthenticationForLocalhost, o->no_host_authentication_for_localhost);
3554 	dump_cfg_fmtint(oPasswordAuthentication, o->password_authentication);
3555 	dump_cfg_fmtint(oPermitLocalCommand, o->permit_local_command);
3556 	dump_cfg_fmtint(oProxyUseFdpass, o->proxy_use_fdpass);
3557 	dump_cfg_fmtint(oPubkeyAuthentication, o->pubkey_authentication);
3558 	dump_cfg_fmtint(oRequestTTY, o->request_tty);
3559 	dump_cfg_fmtint(oSessionType, o->session_type);
3560 	dump_cfg_fmtint(oStdinNull, o->stdin_null);
3561 	dump_cfg_fmtint(oForkAfterAuthentication, o->fork_after_authentication);
3562 	dump_cfg_fmtint(oStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink);
3563 	dump_cfg_fmtint(oStrictHostKeyChecking, o->strict_host_key_checking);
3564 	dump_cfg_fmtint(oTCPKeepAlive, o->tcp_keep_alive);
3565 	dump_cfg_fmtint(oTunnel, o->tun_open);
3566 	dump_cfg_fmtint(oVerifyHostKeyDNS, o->verify_host_key_dns);
3567 	dump_cfg_fmtint(oVisualHostKey, o->visual_host_key);
3568 	dump_cfg_fmtint(oUpdateHostkeys, o->update_hostkeys);
3569 	dump_cfg_fmtint(oEnableEscapeCommandline, o->enable_escape_commandline);
3570 
3571 	/* Integer options */
3572 	dump_cfg_int(oCanonicalizeMaxDots, o->canonicalize_max_dots);
3573 	dump_cfg_int(oConnectionAttempts, o->connection_attempts);
3574 	dump_cfg_int(oForwardX11Timeout, o->forward_x11_timeout);
3575 	dump_cfg_int(oNumberOfPasswordPrompts, o->number_of_password_prompts);
3576 	dump_cfg_int(oServerAliveCountMax, o->server_alive_count_max);
3577 	dump_cfg_int(oServerAliveInterval, o->server_alive_interval);
3578 	dump_cfg_int(oRequiredRSASize, o->required_rsa_size);
3579 	dump_cfg_int(oObscureKeystrokeTiming,
3580 	    o->obscure_keystroke_timing_interval);
3581 
3582 	/* String options */
3583 	dump_cfg_string(oBindAddress, o->bind_address);
3584 	dump_cfg_string(oBindInterface, o->bind_interface);
3585 	dump_cfg_string(oCiphers, o->ciphers);
3586 	dump_cfg_string(oControlPath, o->control_path);
3587 	dump_cfg_string(oHostKeyAlgorithms, o->hostkeyalgorithms);
3588 	dump_cfg_string(oHostKeyAlias, o->host_key_alias);
3589 	dump_cfg_string(oHostbasedAcceptedAlgorithms, o->hostbased_accepted_algos);
3590 	dump_cfg_string(oIdentityAgent, o->identity_agent);
3591 	dump_cfg_string(oIgnoreUnknown, o->ignored_unknown);
3592 	dump_cfg_string(oKbdInteractiveDevices, o->kbd_interactive_devices);
3593 	dump_cfg_string(oKexAlgorithms, o->kex_algorithms);
3594 	dump_cfg_string(oCASignatureAlgorithms, o->ca_sign_algorithms);
3595 	dump_cfg_string(oLocalCommand, o->local_command);
3596 	dump_cfg_string(oRemoteCommand, o->remote_command);
3597 	dump_cfg_string(oLogLevel, log_level_name(o->log_level));
3598 	dump_cfg_string(oMacs, o->macs);
3599 #ifdef ENABLE_PKCS11
3600 	dump_cfg_string(oPKCS11Provider, o->pkcs11_provider);
3601 #endif
3602 	dump_cfg_string(oSecurityKeyProvider, o->sk_provider);
3603 	dump_cfg_string(oPreferredAuthentications, o->preferred_authentications);
3604 	dump_cfg_string(oPubkeyAcceptedAlgorithms, o->pubkey_accepted_algos);
3605 	dump_cfg_string(oRevokedHostKeys, o->revoked_host_keys);
3606 	dump_cfg_string(oXAuthLocation, o->xauth_location);
3607 	dump_cfg_string(oKnownHostsCommand, o->known_hosts_command);
3608 	dump_cfg_string(oTag, o->tag);
3609 
3610 	/* Forwards */
3611 	dump_cfg_forwards(oDynamicForward, o->num_local_forwards, o->local_forwards);
3612 	dump_cfg_forwards(oLocalForward, o->num_local_forwards, o->local_forwards);
3613 	dump_cfg_forwards(oRemoteForward, o->num_remote_forwards, o->remote_forwards);
3614 
3615 	/* String array options */
3616 	dump_cfg_strarray(oIdentityFile, o->num_identity_files, o->identity_files);
3617 	dump_cfg_strarray_oneline(oCanonicalDomains, o->num_canonical_domains, o->canonical_domains);
3618 	dump_cfg_strarray(oCertificateFile, o->num_certificate_files, o->certificate_files);
3619 	dump_cfg_strarray_oneline(oGlobalKnownHostsFile, o->num_system_hostfiles, o->system_hostfiles);
3620 	dump_cfg_strarray_oneline(oUserKnownHostsFile, o->num_user_hostfiles, o->user_hostfiles);
3621 	dump_cfg_strarray(oSendEnv, o->num_send_env, o->send_env);
3622 	dump_cfg_strarray(oSetEnv, o->num_setenv, o->setenv);
3623 	dump_cfg_strarray_oneline(oLogVerbose,
3624 	    o->num_log_verbose, o->log_verbose);
3625 	dump_cfg_strarray_oneline(oChannelTimeout,
3626 	    o->num_channel_timeouts, o->channel_timeouts);
3627 
3628 	/* Special cases */
3629 
3630 	/* PermitRemoteOpen */
3631 	if (o->num_permitted_remote_opens == 0)
3632 		printf("%s any\n", lookup_opcode_name(oPermitRemoteOpen));
3633 	else
3634 		dump_cfg_strarray_oneline(oPermitRemoteOpen,
3635 		    o->num_permitted_remote_opens, o->permitted_remote_opens);
3636 
3637 	/* AddKeysToAgent */
3638 	if (o->add_keys_to_agent_lifespan <= 0)
3639 		dump_cfg_fmtint(oAddKeysToAgent, o->add_keys_to_agent);
3640 	else {
3641 		printf("addkeystoagent%s %d\n",
3642 		    o->add_keys_to_agent == 3 ? " confirm" : "",
3643 		    o->add_keys_to_agent_lifespan);
3644 	}
3645 
3646 	/* oForwardAgent */
3647 	if (o->forward_agent_sock_path == NULL)
3648 		dump_cfg_fmtint(oForwardAgent, o->forward_agent);
3649 	else
3650 		dump_cfg_string(oForwardAgent, o->forward_agent_sock_path);
3651 
3652 	/* oConnectTimeout */
3653 	if (o->connection_timeout == -1)
3654 		printf("connecttimeout none\n");
3655 	else
3656 		dump_cfg_int(oConnectTimeout, o->connection_timeout);
3657 
3658 	/* oTunnelDevice */
3659 	printf("tunneldevice");
3660 	if (o->tun_local == SSH_TUNID_ANY)
3661 		printf(" any");
3662 	else
3663 		printf(" %d", o->tun_local);
3664 	if (o->tun_remote == SSH_TUNID_ANY)
3665 		printf(":any");
3666 	else
3667 		printf(":%d", o->tun_remote);
3668 	printf("\n");
3669 
3670 	/* oCanonicalizePermittedCNAMEs */
3671 	printf("canonicalizePermittedcnames");
3672 	if (o->num_permitted_cnames == 0)
3673 		printf(" none");
3674 	for (i = 0; i < o->num_permitted_cnames; i++) {
3675 		printf(" %s:%s", o->permitted_cnames[i].source_list,
3676 		    o->permitted_cnames[i].target_list);
3677 	}
3678 	printf("\n");
3679 
3680 	/* oControlPersist */
3681 	if (o->control_persist == 0 || o->control_persist_timeout == 0)
3682 		dump_cfg_fmtint(oControlPersist, o->control_persist);
3683 	else
3684 		dump_cfg_int(oControlPersist, o->control_persist_timeout);
3685 
3686 	/* oEscapeChar */
3687 	if (o->escape_char == SSH_ESCAPECHAR_NONE)
3688 		printf("escapechar none\n");
3689 	else {
3690 		vis(buf, o->escape_char, VIS_WHITE, 0);
3691 		printf("escapechar %s\n", buf);
3692 	}
3693 
3694 	/* oIPQoS */
3695 	printf("ipqos %s ", iptos2str(o->ip_qos_interactive));
3696 	printf("%s\n", iptos2str(o->ip_qos_bulk));
3697 
3698 	/* oRekeyLimit */
3699 	printf("rekeylimit %llu %d\n",
3700 	    (unsigned long long)o->rekey_limit, o->rekey_interval);
3701 
3702 	/* oStreamLocalBindMask */
3703 	printf("streamlocalbindmask 0%o\n",
3704 	    o->fwd_opts.streamlocal_bind_mask);
3705 
3706 	/* oLogFacility */
3707 	printf("syslogfacility %s\n", log_facility_name(o->log_facility));
3708 
3709 	/* oProxyCommand / oProxyJump */
3710 	if (o->jump_host == NULL)
3711 		dump_cfg_string(oProxyCommand, o->proxy_command);
3712 	else {
3713 		/* Check for numeric addresses */
3714 		i = strchr(o->jump_host, ':') != NULL ||
3715 		    strspn(o->jump_host, "1234567890.") == strlen(o->jump_host);
3716 		snprintf(buf, sizeof(buf), "%d", o->jump_port);
3717 		printf("proxyjump %s%s%s%s%s%s%s%s%s\n",
3718 		    /* optional additional jump spec */
3719 		    o->jump_extra == NULL ? "" : o->jump_extra,
3720 		    o->jump_extra == NULL ? "" : ",",
3721 		    /* optional user */
3722 		    o->jump_user == NULL ? "" : o->jump_user,
3723 		    o->jump_user == NULL ? "" : "@",
3724 		    /* opening [ if hostname is numeric */
3725 		    i ? "[" : "",
3726 		    /* mandatory hostname */
3727 		    o->jump_host,
3728 		    /* closing ] if hostname is numeric */
3729 		    i ? "]" : "",
3730 		    /* optional port number */
3731 		    o->jump_port <= 0 ? "" : ":",
3732 		    o->jump_port <= 0 ? "" : buf);
3733 	}
3734 }
3735