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