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