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