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