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