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