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