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