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