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