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