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