xref: /openssh-portable/readconf.c (revision 4d28fa78)
1 /* $OpenBSD: readconf.c,v 1.307 2019/06/28 13:35:04 deraadt Exp $ */
2 /*
3  * Author: Tatu Ylonen <ylo@cs.hut.fi>
4  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
5  *                    All rights reserved
6  * Functions for reading the configuration files.
7  *
8  * As far as I am concerned, the code I have written for this software
9  * can be used freely for any purpose.  Any derived versions of this
10  * software must be clearly marked as such, and if the derived work is
11  * incompatible with the protocol description in the RFC file, it must be
12  * called by a name other than "ssh" or "Secure Shell".
13  */
14 
15 #include "includes.h"
16 
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <sys/socket.h>
20 #include <sys/wait.h>
21 #include <sys/un.h>
22 
23 #include <netinet/in.h>
24 #include <netinet/in_systm.h>
25 #include <netinet/ip.h>
26 #include <arpa/inet.h>
27 
28 #include <ctype.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <limits.h>
32 #include <netdb.h>
33 #ifdef HAVE_PATHS_H
34 # include <paths.h>
35 #endif
36 #include <pwd.h>
37 #include <signal.h>
38 #include <stdarg.h>
39 #include <stdio.h>
40 #include <string.h>
41 #include <unistd.h>
42 #ifdef USE_SYSTEM_GLOB
43 # include <glob.h>
44 #else
45 # include "openbsd-compat/glob.h"
46 #endif
47 #ifdef HAVE_UTIL_H
48 #include <util.h>
49 #endif
50 #if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS)
51 # include <vis.h>
52 #endif
53 
54 #include "xmalloc.h"
55 #include "ssh.h"
56 #include "ssherr.h"
57 #include "compat.h"
58 #include "cipher.h"
59 #include "pathnames.h"
60 #include "log.h"
61 #include "sshkey.h"
62 #include "misc.h"
63 #include "readconf.h"
64 #include "match.h"
65 #include "kex.h"
66 #include "mac.h"
67 #include "uidswap.h"
68 #include "myproposal.h"
69 #include "digest.h"
70 
71 /* Format of the configuration file:
72 
73    # Configuration data is parsed as follows:
74    #  1. command line options
75    #  2. user-specific file
76    #  3. system-wide file
77    # Any configuration value is only changed the first time it is set.
78    # Thus, host-specific definitions should be at the beginning of the
79    # configuration file, and defaults at the end.
80 
81    # Host-specific declarations.  These may override anything above.  A single
82    # host may match multiple declarations; these are processed in the order
83    # that they are given in.
84 
85    Host *.ngs.fi ngs.fi
86      User foo
87 
88    Host fake.com
89      Hostname another.host.name.real.org
90      User blaah
91      Port 34289
92      ForwardX11 no
93      ForwardAgent no
94 
95    Host books.com
96      RemoteForward 9999 shadows.cs.hut.fi:9999
97      Ciphers 3des-cbc
98 
99    Host fascist.blob.com
100      Port 23123
101      User tylonen
102      PasswordAuthentication no
103 
104    Host puukko.hut.fi
105      User t35124p
106      ProxyCommand ssh-proxy %h %p
107 
108    Host *.fr
109      PublicKeyAuthentication no
110 
111    Host *.su
112      Ciphers aes128-ctr
113      PasswordAuthentication no
114 
115    Host vpn.fake.com
116      Tunnel yes
117      TunnelDevice 3
118 
119    # Defaults for various options
120    Host *
121      ForwardAgent no
122      ForwardX11 no
123      PasswordAuthentication yes
124      RSAAuthentication yes
125      RhostsRSAAuthentication 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 	oHost, oMatch, oInclude,
147 	oForwardAgent, oForwardX11, oForwardX11Trusted, oForwardX11Timeout,
148 	oGatewayPorts, oExitOnForwardFailure,
149 	oPasswordAuthentication, oRSAAuthentication,
150 	oChallengeResponseAuthentication, oXAuthLocation,
151 	oIdentityFile, oHostname, oPort, oCipher, oRemoteForward, oLocalForward,
152 	oCertificateFile, oAddKeysToAgent, oIdentityAgent,
153 	oUser, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
154 	oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
155 	oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
156 	oCompressionLevel, oTCPKeepAlive, oNumberOfPasswordPrompts,
157 	oUsePrivilegedPort, oLogFacility, oLogLevel, oCiphers, oMacs,
158 	oPubkeyAuthentication,
159 	oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
160 	oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
161 	oHostKeyAlgorithms, oBindAddress, oBindInterface, oPKCS11Provider,
162 	oClearAllForwardings, oNoHostAuthenticationForLocalhost,
163 	oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
164 	oAddressFamily, oGssAuthentication, oGssDelegateCreds,
165 	oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
166 	oSendEnv, oSetEnv, oControlPath, oControlMaster, oControlPersist,
167 	oHashKnownHosts,
168 	oTunnel, oTunnelDevice,
169 	oLocalCommand, oPermitLocalCommand, oRemoteCommand,
170 	oVisualHostKey,
171 	oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass,
172 	oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots,
173 	oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs,
174 	oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys,
175 	oFingerprintHash, oUpdateHostkeys, oHostbasedKeyTypes,
176 	oPubkeyAcceptedKeyTypes, oCASignatureAlgorithms, oProxyJump,
177 	oIgnore, oIgnoredUnknownOption, oDeprecated, oUnsupported
178 } OpCodes;
179 
180 /* Textual representations of the tokens. */
181 
182 static struct {
183 	const char *name;
184 	OpCodes opcode;
185 } keywords[] = {
186 	/* Deprecated options */
187 	{ "protocol", oIgnore }, /* NB. silently ignored */
188 	{ "cipher", oDeprecated },
189 	{ "fallbacktorsh", oDeprecated },
190 	{ "globalknownhostsfile2", oDeprecated },
191 	{ "rhostsauthentication", oDeprecated },
192 	{ "userknownhostsfile2", oDeprecated },
193 	{ "useroaming", oDeprecated },
194 	{ "usersh", oDeprecated },
195 	{ "useprivilegedport", oDeprecated },
196 
197 	/* Unsupported options */
198 	{ "afstokenpassing", oUnsupported },
199 	{ "kerberosauthentication", oUnsupported },
200 	{ "kerberostgtpassing", oUnsupported },
201 
202 	/* Sometimes-unsupported options */
203 #if defined(GSSAPI)
204 	{ "gssapiauthentication", oGssAuthentication },
205 	{ "gssapidelegatecredentials", oGssDelegateCreds },
206 # else
207 	{ "gssapiauthentication", oUnsupported },
208 	{ "gssapidelegatecredentials", oUnsupported },
209 #endif
210 #ifdef ENABLE_PKCS11
211 	{ "pkcs11provider", oPKCS11Provider },
212 	{ "smartcarddevice", oPKCS11Provider },
213 # else
214 	{ "smartcarddevice", oUnsupported },
215 	{ "pkcs11provider", oUnsupported },
216 #endif
217 	{ "rsaauthentication", oUnsupported },
218 	{ "rhostsrsaauthentication", oUnsupported },
219 	{ "compressionlevel", oUnsupported },
220 
221 	{ "forwardagent", oForwardAgent },
222 	{ "forwardx11", oForwardX11 },
223 	{ "forwardx11trusted", oForwardX11Trusted },
224 	{ "forwardx11timeout", oForwardX11Timeout },
225 	{ "exitonforwardfailure", oExitOnForwardFailure },
226 	{ "xauthlocation", oXAuthLocation },
227 	{ "gatewayports", oGatewayPorts },
228 	{ "passwordauthentication", oPasswordAuthentication },
229 	{ "kbdinteractiveauthentication", oKbdInteractiveAuthentication },
230 	{ "kbdinteractivedevices", oKbdInteractiveDevices },
231 	{ "pubkeyauthentication", oPubkeyAuthentication },
232 	{ "dsaauthentication", oPubkeyAuthentication },		    /* alias */
233 	{ "hostbasedauthentication", oHostbasedAuthentication },
234 	{ "challengeresponseauthentication", oChallengeResponseAuthentication },
235 	{ "skeyauthentication", oUnsupported },
236 	{ "tisauthentication", oChallengeResponseAuthentication },  /* alias */
237 	{ "identityfile", oIdentityFile },
238 	{ "identityfile2", oIdentityFile },			/* obsolete */
239 	{ "identitiesonly", oIdentitiesOnly },
240 	{ "certificatefile", oCertificateFile },
241 	{ "addkeystoagent", oAddKeysToAgent },
242 	{ "identityagent", oIdentityAgent },
243 	{ "hostname", oHostname },
244 	{ "hostkeyalias", oHostKeyAlias },
245 	{ "proxycommand", oProxyCommand },
246 	{ "port", oPort },
247 	{ "ciphers", oCiphers },
248 	{ "macs", oMacs },
249 	{ "remoteforward", oRemoteForward },
250 	{ "localforward", oLocalForward },
251 	{ "user", oUser },
252 	{ "host", oHost },
253 	{ "match", oMatch },
254 	{ "escapechar", oEscapeChar },
255 	{ "globalknownhostsfile", oGlobalKnownHostsFile },
256 	{ "userknownhostsfile", oUserKnownHostsFile },
257 	{ "connectionattempts", oConnectionAttempts },
258 	{ "batchmode", oBatchMode },
259 	{ "checkhostip", oCheckHostIP },
260 	{ "stricthostkeychecking", oStrictHostKeyChecking },
261 	{ "compression", oCompression },
262 	{ "tcpkeepalive", oTCPKeepAlive },
263 	{ "keepalive", oTCPKeepAlive },				/* obsolete */
264 	{ "numberofpasswordprompts", oNumberOfPasswordPrompts },
265 	{ "syslogfacility", oLogFacility },
266 	{ "loglevel", oLogLevel },
267 	{ "dynamicforward", oDynamicForward },
268 	{ "preferredauthentications", oPreferredAuthentications },
269 	{ "hostkeyalgorithms", oHostKeyAlgorithms },
270 	{ "casignaturealgorithms", oCASignatureAlgorithms },
271 	{ "bindaddress", oBindAddress },
272 	{ "bindinterface", oBindInterface },
273 	{ "clearallforwardings", oClearAllForwardings },
274 	{ "enablesshkeysign", oEnableSSHKeysign },
275 	{ "verifyhostkeydns", oVerifyHostKeyDNS },
276 	{ "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
277 	{ "rekeylimit", oRekeyLimit },
278 	{ "connecttimeout", oConnectTimeout },
279 	{ "addressfamily", oAddressFamily },
280 	{ "serveraliveinterval", oServerAliveInterval },
281 	{ "serveralivecountmax", oServerAliveCountMax },
282 	{ "sendenv", oSendEnv },
283 	{ "setenv", oSetEnv },
284 	{ "controlpath", oControlPath },
285 	{ "controlmaster", oControlMaster },
286 	{ "controlpersist", oControlPersist },
287 	{ "hashknownhosts", oHashKnownHosts },
288 	{ "include", oInclude },
289 	{ "tunnel", oTunnel },
290 	{ "tunneldevice", oTunnelDevice },
291 	{ "localcommand", oLocalCommand },
292 	{ "permitlocalcommand", oPermitLocalCommand },
293 	{ "remotecommand", oRemoteCommand },
294 	{ "visualhostkey", oVisualHostKey },
295 	{ "kexalgorithms", oKexAlgorithms },
296 	{ "ipqos", oIPQoS },
297 	{ "requesttty", oRequestTTY },
298 	{ "proxyusefdpass", oProxyUseFdpass },
299 	{ "canonicaldomains", oCanonicalDomains },
300 	{ "canonicalizefallbacklocal", oCanonicalizeFallbackLocal },
301 	{ "canonicalizehostname", oCanonicalizeHostname },
302 	{ "canonicalizemaxdots", oCanonicalizeMaxDots },
303 	{ "canonicalizepermittedcnames", oCanonicalizePermittedCNAMEs },
304 	{ "streamlocalbindmask", oStreamLocalBindMask },
305 	{ "streamlocalbindunlink", oStreamLocalBindUnlink },
306 	{ "revokedhostkeys", oRevokedHostKeys },
307 	{ "fingerprinthash", oFingerprintHash },
308 	{ "updatehostkeys", oUpdateHostkeys },
309 	{ "hostbasedkeytypes", oHostbasedKeyTypes },
310 	{ "pubkeyacceptedkeytypes", oPubkeyAcceptedKeyTypes },
311 	{ "ignoreunknown", oIgnoreUnknown },
312 	{ "proxyjump", oProxyJump },
313 
314 	{ NULL, oBadOption }
315 };
316 
317 /*
318  * Adds a local TCP/IP port forward to options.  Never returns if there is an
319  * error.
320  */
321 
322 void
add_local_forward(Options * options,const struct Forward * newfwd)323 add_local_forward(Options *options, const struct Forward *newfwd)
324 {
325 	struct Forward *fwd;
326 	int i;
327 
328 	/* Don't add duplicates */
329 	for (i = 0; i < options->num_local_forwards; i++) {
330 		if (forward_equals(newfwd, options->local_forwards + i))
331 			return;
332 	}
333 	options->local_forwards = xreallocarray(options->local_forwards,
334 	    options->num_local_forwards + 1,
335 	    sizeof(*options->local_forwards));
336 	fwd = &options->local_forwards[options->num_local_forwards++];
337 
338 	fwd->listen_host = newfwd->listen_host;
339 	fwd->listen_port = newfwd->listen_port;
340 	fwd->listen_path = newfwd->listen_path;
341 	fwd->connect_host = newfwd->connect_host;
342 	fwd->connect_port = newfwd->connect_port;
343 	fwd->connect_path = newfwd->connect_path;
344 }
345 
346 /*
347  * Adds a remote TCP/IP port forward to options.  Never returns if there is
348  * an error.
349  */
350 
351 void
add_remote_forward(Options * options,const struct Forward * newfwd)352 add_remote_forward(Options *options, const struct Forward *newfwd)
353 {
354 	struct Forward *fwd;
355 	int i;
356 
357 	/* Don't add duplicates */
358 	for (i = 0; i < options->num_remote_forwards; i++) {
359 		if (forward_equals(newfwd, options->remote_forwards + i))
360 			return;
361 	}
362 	options->remote_forwards = xreallocarray(options->remote_forwards,
363 	    options->num_remote_forwards + 1,
364 	    sizeof(*options->remote_forwards));
365 	fwd = &options->remote_forwards[options->num_remote_forwards++];
366 
367 	fwd->listen_host = newfwd->listen_host;
368 	fwd->listen_port = newfwd->listen_port;
369 	fwd->listen_path = newfwd->listen_path;
370 	fwd->connect_host = newfwd->connect_host;
371 	fwd->connect_port = newfwd->connect_port;
372 	fwd->connect_path = newfwd->connect_path;
373 	fwd->handle = newfwd->handle;
374 	fwd->allocated_port = 0;
375 }
376 
377 static void
clear_forwardings(Options * options)378 clear_forwardings(Options *options)
379 {
380 	int i;
381 
382 	for (i = 0; i < options->num_local_forwards; i++) {
383 		free(options->local_forwards[i].listen_host);
384 		free(options->local_forwards[i].listen_path);
385 		free(options->local_forwards[i].connect_host);
386 		free(options->local_forwards[i].connect_path);
387 	}
388 	if (options->num_local_forwards > 0) {
389 		free(options->local_forwards);
390 		options->local_forwards = NULL;
391 	}
392 	options->num_local_forwards = 0;
393 	for (i = 0; i < options->num_remote_forwards; i++) {
394 		free(options->remote_forwards[i].listen_host);
395 		free(options->remote_forwards[i].listen_path);
396 		free(options->remote_forwards[i].connect_host);
397 		free(options->remote_forwards[i].connect_path);
398 	}
399 	if (options->num_remote_forwards > 0) {
400 		free(options->remote_forwards);
401 		options->remote_forwards = NULL;
402 	}
403 	options->num_remote_forwards = 0;
404 	options->tun_open = SSH_TUNMODE_NO;
405 }
406 
407 void
add_certificate_file(Options * options,const char * path,int userprovided)408 add_certificate_file(Options *options, const char *path, int userprovided)
409 {
410 	int i;
411 
412 	if (options->num_certificate_files >= SSH_MAX_CERTIFICATE_FILES)
413 		fatal("Too many certificate files specified (max %d)",
414 		    SSH_MAX_CERTIFICATE_FILES);
415 
416 	/* Avoid registering duplicates */
417 	for (i = 0; i < options->num_certificate_files; i++) {
418 		if (options->certificate_file_userprovided[i] == userprovided &&
419 		    strcmp(options->certificate_files[i], path) == 0) {
420 			debug2("%s: ignoring duplicate key %s", __func__, path);
421 			return;
422 		}
423 	}
424 
425 	options->certificate_file_userprovided[options->num_certificate_files] =
426 	    userprovided;
427 	options->certificate_files[options->num_certificate_files++] =
428 	    xstrdup(path);
429 }
430 
431 void
add_identity_file(Options * options,const char * dir,const char * filename,int userprovided)432 add_identity_file(Options *options, const char *dir, const char *filename,
433     int userprovided)
434 {
435 	char *path;
436 	int i;
437 
438 	if (options->num_identity_files >= SSH_MAX_IDENTITY_FILES)
439 		fatal("Too many identity files specified (max %d)",
440 		    SSH_MAX_IDENTITY_FILES);
441 
442 	if (dir == NULL) /* no dir, filename is absolute */
443 		path = xstrdup(filename);
444 	else if (xasprintf(&path, "%s%s", dir, filename) >= PATH_MAX)
445 		fatal("Identity file path %s too long", path);
446 
447 	/* Avoid registering duplicates */
448 	for (i = 0; i < options->num_identity_files; i++) {
449 		if (options->identity_file_userprovided[i] == userprovided &&
450 		    strcmp(options->identity_files[i], path) == 0) {
451 			debug2("%s: ignoring duplicate key %s", __func__, path);
452 			free(path);
453 			return;
454 		}
455 	}
456 
457 	options->identity_file_userprovided[options->num_identity_files] =
458 	    userprovided;
459 	options->identity_files[options->num_identity_files++] = path;
460 }
461 
462 int
default_ssh_port(void)463 default_ssh_port(void)
464 {
465 	static int port;
466 	struct servent *sp;
467 
468 	if (port == 0) {
469 		sp = getservbyname(SSH_SERVICE_NAME, "tcp");
470 		port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT;
471 	}
472 	return port;
473 }
474 
475 /*
476  * Execute a command in a shell.
477  * Return its exit status or -1 on abnormal exit.
478  */
479 static int
execute_in_shell(const char * cmd)480 execute_in_shell(const char *cmd)
481 {
482 	char *shell;
483 	pid_t pid;
484 	int devnull, status;
485 
486 	if ((shell = getenv("SHELL")) == NULL)
487 		shell = _PATH_BSHELL;
488 
489 	/* Need this to redirect subprocess stdin/out */
490 	if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1)
491 		fatal("open(/dev/null): %s", strerror(errno));
492 
493 	debug("Executing command: '%.500s'", cmd);
494 
495 	/* Fork and execute the command. */
496 	if ((pid = fork()) == 0) {
497 		char *argv[4];
498 
499 		/* Redirect child stdin and stdout. Leave stderr */
500 		if (dup2(devnull, STDIN_FILENO) == -1)
501 			fatal("dup2: %s", strerror(errno));
502 		if (dup2(devnull, STDOUT_FILENO) == -1)
503 			fatal("dup2: %s", strerror(errno));
504 		if (devnull > STDERR_FILENO)
505 			close(devnull);
506 		closefrom(STDERR_FILENO + 1);
507 
508 		argv[0] = shell;
509 		argv[1] = "-c";
510 		argv[2] = xstrdup(cmd);
511 		argv[3] = NULL;
512 
513 		execv(argv[0], argv);
514 		error("Unable to execute '%.100s': %s", cmd, strerror(errno));
515 		/* Die with signal to make this error apparent to parent. */
516 		signal(SIGTERM, SIG_DFL);
517 		kill(getpid(), SIGTERM);
518 		_exit(1);
519 	}
520 	/* Parent. */
521 	if (pid == -1)
522 		fatal("%s: fork: %.100s", __func__, strerror(errno));
523 
524 	close(devnull);
525 
526 	while (waitpid(pid, &status, 0) == -1) {
527 		if (errno != EINTR && errno != EAGAIN)
528 			fatal("%s: waitpid: %s", __func__, strerror(errno));
529 	}
530 	if (!WIFEXITED(status)) {
531 		error("command '%.100s' exited abnormally", cmd);
532 		return -1;
533 	}
534 	debug3("command returned status %d", WEXITSTATUS(status));
535 	return WEXITSTATUS(status);
536 }
537 
538 /*
539  * Parse and execute a Match directive.
540  */
541 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)542 match_cfg_line(Options *options, char **condition, struct passwd *pw,
543     const char *host_arg, const char *original_host, int final_pass,
544     int *want_final_pass, const char *filename, int linenum)
545 {
546 	char *arg, *oattrib, *attrib, *cmd, *cp = *condition, *host, *criteria;
547 	const char *ruser;
548 	int r, port, this_result, result = 1, attributes = 0, negate;
549 	char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV];
550 	char uidstr[32];
551 
552 	/*
553 	 * Configuration is likely to be incomplete at this point so we
554 	 * must be prepared to use default values.
555 	 */
556 	port = options->port <= 0 ? default_ssh_port() : options->port;
557 	ruser = options->user == NULL ? pw->pw_name : options->user;
558 	if (final_pass) {
559 		host = xstrdup(options->hostname);
560 	} else if (options->hostname != NULL) {
561 		/* NB. Please keep in sync with ssh.c:main() */
562 		host = percent_expand(options->hostname,
563 		    "h", host_arg, (char *)NULL);
564 	} else {
565 		host = xstrdup(host_arg);
566 	}
567 
568 	debug2("checking match for '%s' host %s originally %s",
569 	    cp, host, original_host);
570 	while ((oattrib = attrib = strdelim(&cp)) && *attrib != '\0') {
571 		criteria = NULL;
572 		this_result = 1;
573 		if ((negate = attrib[0] == '!'))
574 			attrib++;
575 		/* criteria "all" and "canonical" have no argument */
576 		if (strcasecmp(attrib, "all") == 0) {
577 			if (attributes > 1 ||
578 			    ((arg = strdelim(&cp)) != NULL && *arg != '\0')) {
579 				error("%.200s line %d: '%s' cannot be combined "
580 				    "with other Match attributes",
581 				    filename, linenum, oattrib);
582 				result = -1;
583 				goto out;
584 			}
585 			if (result)
586 				result = negate ? 0 : 1;
587 			goto out;
588 		}
589 		attributes++;
590 		if (strcasecmp(attrib, "canonical") == 0 ||
591 		    strcasecmp(attrib, "final") == 0) {
592 			/*
593 			 * If the config requests "Match final" then remember
594 			 * this so we can perform a second pass later.
595 			 */
596 			if (strcasecmp(attrib, "final") == 0 &&
597 			    want_final_pass != NULL)
598 				*want_final_pass = 1;
599 			r = !!final_pass;  /* force bitmask member to boolean */
600 			if (r == (negate ? 1 : 0))
601 				this_result = result = 0;
602 			debug3("%.200s line %d: %smatched '%s'",
603 			    filename, linenum,
604 			    this_result ? "" : "not ", oattrib);
605 			continue;
606 		}
607 		/* All other criteria require an argument */
608 		if ((arg = strdelim(&cp)) == NULL || *arg == '\0') {
609 			error("Missing Match criteria for %s", attrib);
610 			result = -1;
611 			goto out;
612 		}
613 		if (strcasecmp(attrib, "host") == 0) {
614 			criteria = xstrdup(host);
615 			r = match_hostname(host, arg) == 1;
616 			if (r == (negate ? 1 : 0))
617 				this_result = result = 0;
618 		} else if (strcasecmp(attrib, "originalhost") == 0) {
619 			criteria = xstrdup(original_host);
620 			r = match_hostname(original_host, arg) == 1;
621 			if (r == (negate ? 1 : 0))
622 				this_result = result = 0;
623 		} else if (strcasecmp(attrib, "user") == 0) {
624 			criteria = xstrdup(ruser);
625 			r = match_pattern_list(ruser, arg, 0) == 1;
626 			if (r == (negate ? 1 : 0))
627 				this_result = result = 0;
628 		} else if (strcasecmp(attrib, "localuser") == 0) {
629 			criteria = xstrdup(pw->pw_name);
630 			r = match_pattern_list(pw->pw_name, arg, 0) == 1;
631 			if (r == (negate ? 1 : 0))
632 				this_result = result = 0;
633 		} else if (strcasecmp(attrib, "exec") == 0) {
634 			if (gethostname(thishost, sizeof(thishost)) == -1)
635 				fatal("gethostname: %s", strerror(errno));
636 			strlcpy(shorthost, thishost, sizeof(shorthost));
637 			shorthost[strcspn(thishost, ".")] = '\0';
638 			snprintf(portstr, sizeof(portstr), "%d", port);
639 			snprintf(uidstr, sizeof(uidstr), "%llu",
640 			    (unsigned long long)pw->pw_uid);
641 
642 			cmd = percent_expand(arg,
643 			    "L", shorthost,
644 			    "d", pw->pw_dir,
645 			    "h", host,
646 			    "l", thishost,
647 			    "n", original_host,
648 			    "p", portstr,
649 			    "r", ruser,
650 			    "u", pw->pw_name,
651 			    "i", uidstr,
652 			    (char *)NULL);
653 			if (result != 1) {
654 				/* skip execution if prior predicate failed */
655 				debug3("%.200s line %d: skipped exec "
656 				    "\"%.100s\"", filename, linenum, cmd);
657 				free(cmd);
658 				continue;
659 			}
660 			r = execute_in_shell(cmd);
661 			if (r == -1) {
662 				fatal("%.200s line %d: match exec "
663 				    "'%.100s' error", filename,
664 				    linenum, cmd);
665 			}
666 			criteria = xstrdup(cmd);
667 			free(cmd);
668 			/* Force exit status to boolean */
669 			r = r == 0;
670 			if (r == (negate ? 1 : 0))
671 				this_result = result = 0;
672 		} else {
673 			error("Unsupported Match attribute %s", attrib);
674 			result = -1;
675 			goto out;
676 		}
677 		debug3("%.200s line %d: %smatched '%s \"%.100s\"' ",
678 		    filename, linenum, this_result ? "": "not ",
679 		    oattrib, criteria);
680 		free(criteria);
681 	}
682 	if (attributes == 0) {
683 		error("One or more attributes required for Match");
684 		result = -1;
685 		goto out;
686 	}
687  out:
688 	if (result != -1)
689 		debug2("match %sfound", result ? "" : "not ");
690 	*condition = cp;
691 	free(host);
692 	return result;
693 }
694 
695 /* Remove environment variable by pattern */
696 static void
rm_env(Options * options,const char * arg,const char * filename,int linenum)697 rm_env(Options *options, const char *arg, const char *filename, int linenum)
698 {
699 	int i, j;
700 	char *cp;
701 
702 	/* Remove an environment variable */
703 	for (i = 0; i < options->num_send_env; ) {
704 		cp = xstrdup(options->send_env[i]);
705 		if (!match_pattern(cp, arg + 1)) {
706 			free(cp);
707 			i++;
708 			continue;
709 		}
710 		debug3("%s line %d: removing environment %s",
711 		    filename, linenum, cp);
712 		free(cp);
713 		free(options->send_env[i]);
714 		options->send_env[i] = NULL;
715 		for (j = i; j < options->num_send_env - 1; j++) {
716 			options->send_env[j] = options->send_env[j + 1];
717 			options->send_env[j + 1] = NULL;
718 		}
719 		options->num_send_env--;
720 		/* NB. don't increment i */
721 	}
722 }
723 
724 /*
725  * Returns the number of the token pointed to by cp or oBadOption.
726  */
727 static OpCodes
parse_token(const char * cp,const char * filename,int linenum,const char * ignored_unknown)728 parse_token(const char *cp, const char *filename, int linenum,
729     const char *ignored_unknown)
730 {
731 	int i;
732 
733 	for (i = 0; keywords[i].name; i++)
734 		if (strcmp(cp, keywords[i].name) == 0)
735 			return keywords[i].opcode;
736 	if (ignored_unknown != NULL &&
737 	    match_pattern_list(cp, ignored_unknown, 1) == 1)
738 		return oIgnoredUnknownOption;
739 	error("%s: line %d: Bad configuration option: %s",
740 	    filename, linenum, cp);
741 	return oBadOption;
742 }
743 
744 /* Multistate option parsing */
745 struct multistate {
746 	char *key;
747 	int value;
748 };
749 static const struct multistate multistate_flag[] = {
750 	{ "true",			1 },
751 	{ "false",			0 },
752 	{ "yes",			1 },
753 	{ "no",				0 },
754 	{ NULL, -1 }
755 };
756 static const struct multistate multistate_yesnoask[] = {
757 	{ "true",			1 },
758 	{ "false",			0 },
759 	{ "yes",			1 },
760 	{ "no",				0 },
761 	{ "ask",			2 },
762 	{ NULL, -1 }
763 };
764 static const struct multistate multistate_strict_hostkey[] = {
765 	{ "true",			SSH_STRICT_HOSTKEY_YES },
766 	{ "false",			SSH_STRICT_HOSTKEY_OFF },
767 	{ "yes",			SSH_STRICT_HOSTKEY_YES },
768 	{ "no",				SSH_STRICT_HOSTKEY_OFF },
769 	{ "ask",			SSH_STRICT_HOSTKEY_ASK },
770 	{ "off",			SSH_STRICT_HOSTKEY_OFF },
771 	{ "accept-new",			SSH_STRICT_HOSTKEY_NEW },
772 	{ NULL, -1 }
773 };
774 static const struct multistate multistate_yesnoaskconfirm[] = {
775 	{ "true",			1 },
776 	{ "false",			0 },
777 	{ "yes",			1 },
778 	{ "no",				0 },
779 	{ "ask",			2 },
780 	{ "confirm",			3 },
781 	{ NULL, -1 }
782 };
783 static const struct multistate multistate_addressfamily[] = {
784 	{ "inet",			AF_INET },
785 	{ "inet6",			AF_INET6 },
786 	{ "any",			AF_UNSPEC },
787 	{ NULL, -1 }
788 };
789 static const struct multistate multistate_controlmaster[] = {
790 	{ "true",			SSHCTL_MASTER_YES },
791 	{ "yes",			SSHCTL_MASTER_YES },
792 	{ "false",			SSHCTL_MASTER_NO },
793 	{ "no",				SSHCTL_MASTER_NO },
794 	{ "auto",			SSHCTL_MASTER_AUTO },
795 	{ "ask",			SSHCTL_MASTER_ASK },
796 	{ "autoask",			SSHCTL_MASTER_AUTO_ASK },
797 	{ NULL, -1 }
798 };
799 static const struct multistate multistate_tunnel[] = {
800 	{ "ethernet",			SSH_TUNMODE_ETHERNET },
801 	{ "point-to-point",		SSH_TUNMODE_POINTOPOINT },
802 	{ "true",			SSH_TUNMODE_DEFAULT },
803 	{ "yes",			SSH_TUNMODE_DEFAULT },
804 	{ "false",			SSH_TUNMODE_NO },
805 	{ "no",				SSH_TUNMODE_NO },
806 	{ NULL, -1 }
807 };
808 static const struct multistate multistate_requesttty[] = {
809 	{ "true",			REQUEST_TTY_YES },
810 	{ "yes",			REQUEST_TTY_YES },
811 	{ "false",			REQUEST_TTY_NO },
812 	{ "no",				REQUEST_TTY_NO },
813 	{ "force",			REQUEST_TTY_FORCE },
814 	{ "auto",			REQUEST_TTY_AUTO },
815 	{ NULL, -1 }
816 };
817 static const struct multistate multistate_canonicalizehostname[] = {
818 	{ "true",			SSH_CANONICALISE_YES },
819 	{ "false",			SSH_CANONICALISE_NO },
820 	{ "yes",			SSH_CANONICALISE_YES },
821 	{ "no",				SSH_CANONICALISE_NO },
822 	{ "always",			SSH_CANONICALISE_ALWAYS },
823 	{ NULL, -1 }
824 };
825 
826 /*
827  * Processes a single option line as used in the configuration files. This
828  * only sets those values that have not already been set.
829  */
830 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)831 process_config_line(Options *options, struct passwd *pw, const char *host,
832     const char *original_host, char *line, const char *filename,
833     int linenum, int *activep, int flags)
834 {
835 	return process_config_line_depth(options, pw, host, original_host,
836 	    line, filename, linenum, activep, flags, NULL, 0);
837 }
838 
839 #define WHITESPACE " \t\r\n"
840 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)841 process_config_line_depth(Options *options, struct passwd *pw, const char *host,
842     const char *original_host, char *line, const char *filename,
843     int linenum, int *activep, int flags, int *want_final_pass, int depth)
844 {
845 	char *s, **charptr, *endofnumber, *keyword, *arg, *arg2;
846 	char **cpptr, fwdarg[256];
847 	u_int i, *uintptr, max_entries = 0;
848 	int r, oactive, negated, opcode, *intptr, value, value2, cmdline = 0;
849 	int remotefwd, dynamicfwd;
850 	LogLevel *log_level_ptr;
851 	SyslogFacility *log_facility_ptr;
852 	long long val64;
853 	size_t len;
854 	struct Forward fwd;
855 	const struct multistate *multistate_ptr;
856 	struct allowed_cname *cname;
857 	glob_t gl;
858 	const char *errstr;
859 
860 	if (activep == NULL) { /* We are processing a command line directive */
861 		cmdline = 1;
862 		activep = &cmdline;
863 	}
864 
865 	/* Strip trailing whitespace. Allow \f (form feed) at EOL only */
866 	if ((len = strlen(line)) == 0)
867 		return 0;
868 	for (len--; len > 0; len--) {
869 		if (strchr(WHITESPACE "\f", line[len]) == NULL)
870 			break;
871 		line[len] = '\0';
872 	}
873 
874 	s = line;
875 	/* Get the keyword. (Each line is supposed to begin with a keyword). */
876 	if ((keyword = strdelim(&s)) == NULL)
877 		return 0;
878 	/* Ignore leading whitespace. */
879 	if (*keyword == '\0')
880 		keyword = strdelim(&s);
881 	if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#')
882 		return 0;
883 	/* Match lowercase keyword */
884 	lowercase(keyword);
885 
886 	opcode = parse_token(keyword, filename, linenum,
887 	    options->ignored_unknown);
888 
889 	switch (opcode) {
890 	case oBadOption:
891 		/* don't panic, but count bad options */
892 		return -1;
893 	case oIgnore:
894 		return 0;
895 	case oIgnoredUnknownOption:
896 		debug("%s line %d: Ignored unknown option \"%s\"",
897 		    filename, linenum, keyword);
898 		return 0;
899 	case oConnectTimeout:
900 		intptr = &options->connection_timeout;
901 parse_time:
902 		arg = strdelim(&s);
903 		if (!arg || *arg == '\0')
904 			fatal("%s line %d: missing time value.",
905 			    filename, linenum);
906 		if (strcmp(arg, "none") == 0)
907 			value = -1;
908 		else if ((value = convtime(arg)) == -1)
909 			fatal("%s line %d: invalid time value.",
910 			    filename, linenum);
911 		if (*activep && *intptr == -1)
912 			*intptr = value;
913 		break;
914 
915 	case oForwardAgent:
916 		intptr = &options->forward_agent;
917  parse_flag:
918 		multistate_ptr = multistate_flag;
919  parse_multistate:
920 		arg = strdelim(&s);
921 		if (!arg || *arg == '\0')
922 			fatal("%s line %d: missing argument.",
923 			    filename, linenum);
924 		value = -1;
925 		for (i = 0; multistate_ptr[i].key != NULL; i++) {
926 			if (strcasecmp(arg, multistate_ptr[i].key) == 0) {
927 				value = multistate_ptr[i].value;
928 				break;
929 			}
930 		}
931 		if (value == -1)
932 			fatal("%s line %d: unsupported option \"%s\".",
933 			    filename, linenum, arg);
934 		if (*activep && *intptr == -1)
935 			*intptr = value;
936 		break;
937 
938 	case oForwardX11:
939 		intptr = &options->forward_x11;
940 		goto parse_flag;
941 
942 	case oForwardX11Trusted:
943 		intptr = &options->forward_x11_trusted;
944 		goto parse_flag;
945 
946 	case oForwardX11Timeout:
947 		intptr = &options->forward_x11_timeout;
948 		goto parse_time;
949 
950 	case oGatewayPorts:
951 		intptr = &options->fwd_opts.gateway_ports;
952 		goto parse_flag;
953 
954 	case oExitOnForwardFailure:
955 		intptr = &options->exit_on_forward_failure;
956 		goto parse_flag;
957 
958 	case oPasswordAuthentication:
959 		intptr = &options->password_authentication;
960 		goto parse_flag;
961 
962 	case oKbdInteractiveAuthentication:
963 		intptr = &options->kbd_interactive_authentication;
964 		goto parse_flag;
965 
966 	case oKbdInteractiveDevices:
967 		charptr = &options->kbd_interactive_devices;
968 		goto parse_string;
969 
970 	case oPubkeyAuthentication:
971 		intptr = &options->pubkey_authentication;
972 		goto parse_flag;
973 
974 	case oHostbasedAuthentication:
975 		intptr = &options->hostbased_authentication;
976 		goto parse_flag;
977 
978 	case oChallengeResponseAuthentication:
979 		intptr = &options->challenge_response_authentication;
980 		goto parse_flag;
981 
982 	case oGssAuthentication:
983 		intptr = &options->gss_authentication;
984 		goto parse_flag;
985 
986 	case oGssDelegateCreds:
987 		intptr = &options->gss_deleg_creds;
988 		goto parse_flag;
989 
990 	case oBatchMode:
991 		intptr = &options->batch_mode;
992 		goto parse_flag;
993 
994 	case oCheckHostIP:
995 		intptr = &options->check_host_ip;
996 		goto parse_flag;
997 
998 	case oVerifyHostKeyDNS:
999 		intptr = &options->verify_host_key_dns;
1000 		multistate_ptr = multistate_yesnoask;
1001 		goto parse_multistate;
1002 
1003 	case oStrictHostKeyChecking:
1004 		intptr = &options->strict_host_key_checking;
1005 		multistate_ptr = multistate_strict_hostkey;
1006 		goto parse_multistate;
1007 
1008 	case oCompression:
1009 		intptr = &options->compression;
1010 		goto parse_flag;
1011 
1012 	case oTCPKeepAlive:
1013 		intptr = &options->tcp_keep_alive;
1014 		goto parse_flag;
1015 
1016 	case oNoHostAuthenticationForLocalhost:
1017 		intptr = &options->no_host_authentication_for_localhost;
1018 		goto parse_flag;
1019 
1020 	case oNumberOfPasswordPrompts:
1021 		intptr = &options->number_of_password_prompts;
1022 		goto parse_int;
1023 
1024 	case oRekeyLimit:
1025 		arg = strdelim(&s);
1026 		if (!arg || *arg == '\0')
1027 			fatal("%.200s line %d: Missing argument.", filename,
1028 			    linenum);
1029 		if (strcmp(arg, "default") == 0) {
1030 			val64 = 0;
1031 		} else {
1032 			if (scan_scaled(arg, &val64) == -1)
1033 				fatal("%.200s line %d: Bad number '%s': %s",
1034 				    filename, linenum, arg, strerror(errno));
1035 			if (val64 != 0 && val64 < 16)
1036 				fatal("%.200s line %d: RekeyLimit too small",
1037 				    filename, linenum);
1038 		}
1039 		if (*activep && options->rekey_limit == -1)
1040 			options->rekey_limit = val64;
1041 		if (s != NULL) { /* optional rekey interval present */
1042 			if (strcmp(s, "none") == 0) {
1043 				(void)strdelim(&s);	/* discard */
1044 				break;
1045 			}
1046 			intptr = &options->rekey_interval;
1047 			goto parse_time;
1048 		}
1049 		break;
1050 
1051 	case oIdentityFile:
1052 		arg = strdelim(&s);
1053 		if (!arg || *arg == '\0')
1054 			fatal("%.200s line %d: Missing argument.", filename, linenum);
1055 		if (*activep) {
1056 			intptr = &options->num_identity_files;
1057 			if (*intptr >= SSH_MAX_IDENTITY_FILES)
1058 				fatal("%.200s line %d: Too many identity files specified (max %d).",
1059 				    filename, linenum, SSH_MAX_IDENTITY_FILES);
1060 			add_identity_file(options, NULL,
1061 			    arg, flags & SSHCONF_USERCONF);
1062 		}
1063 		break;
1064 
1065 	case oCertificateFile:
1066 		arg = strdelim(&s);
1067 		if (!arg || *arg == '\0')
1068 			fatal("%.200s line %d: Missing argument.",
1069 			    filename, linenum);
1070 		if (*activep) {
1071 			intptr = &options->num_certificate_files;
1072 			if (*intptr >= SSH_MAX_CERTIFICATE_FILES) {
1073 				fatal("%.200s line %d: Too many certificate "
1074 				    "files specified (max %d).",
1075 				    filename, linenum,
1076 				    SSH_MAX_CERTIFICATE_FILES);
1077 			}
1078 			add_certificate_file(options, arg,
1079 			    flags & SSHCONF_USERCONF);
1080 		}
1081 		break;
1082 
1083 	case oXAuthLocation:
1084 		charptr=&options->xauth_location;
1085 		goto parse_string;
1086 
1087 	case oUser:
1088 		charptr = &options->user;
1089 parse_string:
1090 		arg = strdelim(&s);
1091 		if (!arg || *arg == '\0')
1092 			fatal("%.200s line %d: Missing argument.",
1093 			    filename, linenum);
1094 		if (*activep && *charptr == NULL)
1095 			*charptr = xstrdup(arg);
1096 		break;
1097 
1098 	case oGlobalKnownHostsFile:
1099 		cpptr = (char **)&options->system_hostfiles;
1100 		uintptr = &options->num_system_hostfiles;
1101 		max_entries = SSH_MAX_HOSTS_FILES;
1102 parse_char_array:
1103 		if (*activep && *uintptr == 0) {
1104 			while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1105 				if ((*uintptr) >= max_entries)
1106 					fatal("%s line %d: "
1107 					    "too many authorized keys files.",
1108 					    filename, linenum);
1109 				cpptr[(*uintptr)++] = xstrdup(arg);
1110 			}
1111 		}
1112 		return 0;
1113 
1114 	case oUserKnownHostsFile:
1115 		cpptr = (char **)&options->user_hostfiles;
1116 		uintptr = &options->num_user_hostfiles;
1117 		max_entries = SSH_MAX_HOSTS_FILES;
1118 		goto parse_char_array;
1119 
1120 	case oHostname:
1121 		charptr = &options->hostname;
1122 		goto parse_string;
1123 
1124 	case oHostKeyAlias:
1125 		charptr = &options->host_key_alias;
1126 		goto parse_string;
1127 
1128 	case oPreferredAuthentications:
1129 		charptr = &options->preferred_authentications;
1130 		goto parse_string;
1131 
1132 	case oBindAddress:
1133 		charptr = &options->bind_address;
1134 		goto parse_string;
1135 
1136 	case oBindInterface:
1137 		charptr = &options->bind_interface;
1138 		goto parse_string;
1139 
1140 	case oPKCS11Provider:
1141 		charptr = &options->pkcs11_provider;
1142 		goto parse_string;
1143 
1144 	case oProxyCommand:
1145 		charptr = &options->proxy_command;
1146 		/* Ignore ProxyCommand if ProxyJump already specified */
1147 		if (options->jump_host != NULL)
1148 			charptr = &options->jump_host; /* Skip below */
1149 parse_command:
1150 		if (s == NULL)
1151 			fatal("%.200s line %d: Missing argument.", filename, linenum);
1152 		len = strspn(s, WHITESPACE "=");
1153 		if (*activep && *charptr == NULL)
1154 			*charptr = xstrdup(s + len);
1155 		return 0;
1156 
1157 	case oProxyJump:
1158 		if (s == NULL) {
1159 			fatal("%.200s line %d: Missing argument.",
1160 			    filename, linenum);
1161 		}
1162 		len = strspn(s, WHITESPACE "=");
1163 		if (parse_jump(s + len, options, *activep) == -1) {
1164 			fatal("%.200s line %d: Invalid ProxyJump \"%s\"",
1165 			    filename, linenum, s + len);
1166 		}
1167 		return 0;
1168 
1169 	case oPort:
1170 		arg = strdelim(&s);
1171 		if (!arg || *arg == '\0')
1172 			fatal("%.200s line %d: Missing argument.",
1173 			    filename, linenum);
1174 		value = a2port(arg);
1175 		if (value <= 0)
1176 			fatal("%.200s line %d: Bad port '%s'.",
1177 			    filename, linenum, arg);
1178 		if (*activep && options->port == -1)
1179 			options->port = value;
1180 		break;
1181 
1182 	case oConnectionAttempts:
1183 		intptr = &options->connection_attempts;
1184 parse_int:
1185 		arg = strdelim(&s);
1186 		if ((errstr = atoi_err(arg, &value)) != NULL)
1187 			fatal("%s line %d: integer value %s.",
1188 			    filename, linenum, errstr);
1189 		if (*activep && *intptr == -1)
1190 			*intptr = value;
1191 		break;
1192 
1193 	case oCiphers:
1194 		arg = strdelim(&s);
1195 		if (!arg || *arg == '\0')
1196 			fatal("%.200s line %d: Missing argument.", filename, linenum);
1197 		if (*arg != '-' && !ciphers_valid(*arg == '+' ? arg + 1 : arg))
1198 			fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.",
1199 			    filename, linenum, arg ? arg : "<NONE>");
1200 		if (*activep && options->ciphers == NULL)
1201 			options->ciphers = xstrdup(arg);
1202 		break;
1203 
1204 	case oMacs:
1205 		arg = strdelim(&s);
1206 		if (!arg || *arg == '\0')
1207 			fatal("%.200s line %d: Missing argument.", filename, linenum);
1208 		if (*arg != '-' && !mac_valid(*arg == '+' ? arg + 1 : arg))
1209 			fatal("%.200s line %d: Bad SSH2 MAC spec '%s'.",
1210 			    filename, linenum, arg ? arg : "<NONE>");
1211 		if (*activep && options->macs == NULL)
1212 			options->macs = xstrdup(arg);
1213 		break;
1214 
1215 	case oKexAlgorithms:
1216 		arg = strdelim(&s);
1217 		if (!arg || *arg == '\0')
1218 			fatal("%.200s line %d: Missing argument.",
1219 			    filename, linenum);
1220 		if (*arg != '-' &&
1221 		    !kex_names_valid(*arg == '+' ? arg + 1 : arg))
1222 			fatal("%.200s line %d: Bad SSH2 KexAlgorithms '%s'.",
1223 			    filename, linenum, arg ? arg : "<NONE>");
1224 		if (*activep && options->kex_algorithms == NULL)
1225 			options->kex_algorithms = xstrdup(arg);
1226 		break;
1227 
1228 	case oHostKeyAlgorithms:
1229 		charptr = &options->hostkeyalgorithms;
1230 parse_keytypes:
1231 		arg = strdelim(&s);
1232 		if (!arg || *arg == '\0')
1233 			fatal("%.200s line %d: Missing argument.",
1234 			    filename, linenum);
1235 		if (*arg != '-' &&
1236 		    !sshkey_names_valid2(*arg == '+' ? arg + 1 : arg, 1))
1237 			fatal("%s line %d: Bad key types '%s'.",
1238 				filename, linenum, arg ? arg : "<NONE>");
1239 		if (*activep && *charptr == NULL)
1240 			*charptr = xstrdup(arg);
1241 		break;
1242 
1243 	case oCASignatureAlgorithms:
1244 		charptr = &options->ca_sign_algorithms;
1245 		goto parse_keytypes;
1246 
1247 	case oLogLevel:
1248 		log_level_ptr = &options->log_level;
1249 		arg = strdelim(&s);
1250 		value = log_level_number(arg);
1251 		if (value == SYSLOG_LEVEL_NOT_SET)
1252 			fatal("%.200s line %d: unsupported log level '%s'",
1253 			    filename, linenum, arg ? arg : "<NONE>");
1254 		if (*activep && *log_level_ptr == SYSLOG_LEVEL_NOT_SET)
1255 			*log_level_ptr = (LogLevel) value;
1256 		break;
1257 
1258 	case oLogFacility:
1259 		log_facility_ptr = &options->log_facility;
1260 		arg = strdelim(&s);
1261 		value = log_facility_number(arg);
1262 		if (value == SYSLOG_FACILITY_NOT_SET)
1263 			fatal("%.200s line %d: unsupported log facility '%s'",
1264 			    filename, linenum, arg ? arg : "<NONE>");
1265 		if (*log_facility_ptr == -1)
1266 			*log_facility_ptr = (SyslogFacility) value;
1267 		break;
1268 
1269 	case oLocalForward:
1270 	case oRemoteForward:
1271 	case oDynamicForward:
1272 		arg = strdelim(&s);
1273 		if (arg == NULL || *arg == '\0')
1274 			fatal("%.200s line %d: Missing port argument.",
1275 			    filename, linenum);
1276 
1277 		remotefwd = (opcode == oRemoteForward);
1278 		dynamicfwd = (opcode == oDynamicForward);
1279 
1280 		if (!dynamicfwd) {
1281 			arg2 = strdelim(&s);
1282 			if (arg2 == NULL || *arg2 == '\0') {
1283 				if (remotefwd)
1284 					dynamicfwd = 1;
1285 				else
1286 					fatal("%.200s line %d: Missing target "
1287 					    "argument.", filename, linenum);
1288 			} else {
1289 				/* construct a string for parse_forward */
1290 				snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg,
1291 				    arg2);
1292 			}
1293 		}
1294 		if (dynamicfwd)
1295 			strlcpy(fwdarg, arg, sizeof(fwdarg));
1296 
1297 		if (parse_forward(&fwd, fwdarg, dynamicfwd, remotefwd) == 0)
1298 			fatal("%.200s line %d: Bad forwarding specification.",
1299 			    filename, linenum);
1300 
1301 		if (*activep) {
1302 			if (remotefwd) {
1303 				add_remote_forward(options, &fwd);
1304 			} else {
1305 				add_local_forward(options, &fwd);
1306 			}
1307 		}
1308 		break;
1309 
1310 	case oClearAllForwardings:
1311 		intptr = &options->clear_forwardings;
1312 		goto parse_flag;
1313 
1314 	case oHost:
1315 		if (cmdline)
1316 			fatal("Host directive not supported as a command-line "
1317 			    "option");
1318 		*activep = 0;
1319 		arg2 = NULL;
1320 		while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1321 			if ((flags & SSHCONF_NEVERMATCH) != 0)
1322 				break;
1323 			negated = *arg == '!';
1324 			if (negated)
1325 				arg++;
1326 			if (match_pattern(host, arg)) {
1327 				if (negated) {
1328 					debug("%.200s line %d: Skipping Host "
1329 					    "block because of negated match "
1330 					    "for %.100s", filename, linenum,
1331 					    arg);
1332 					*activep = 0;
1333 					break;
1334 				}
1335 				if (!*activep)
1336 					arg2 = arg; /* logged below */
1337 				*activep = 1;
1338 			}
1339 		}
1340 		if (*activep)
1341 			debug("%.200s line %d: Applying options for %.100s",
1342 			    filename, linenum, arg2);
1343 		/* Avoid garbage check below, as strdelim is done. */
1344 		return 0;
1345 
1346 	case oMatch:
1347 		if (cmdline)
1348 			fatal("Host directive not supported as a command-line "
1349 			    "option");
1350 		value = match_cfg_line(options, &s, pw, host, original_host,
1351 		    flags & SSHCONF_FINAL, want_final_pass,
1352 		    filename, linenum);
1353 		if (value < 0)
1354 			fatal("%.200s line %d: Bad Match condition", filename,
1355 			    linenum);
1356 		*activep = (flags & SSHCONF_NEVERMATCH) ? 0 : value;
1357 		break;
1358 
1359 	case oEscapeChar:
1360 		intptr = &options->escape_char;
1361 		arg = strdelim(&s);
1362 		if (!arg || *arg == '\0')
1363 			fatal("%.200s line %d: Missing argument.", filename, linenum);
1364 		if (strcmp(arg, "none") == 0)
1365 			value = SSH_ESCAPECHAR_NONE;
1366 		else if (arg[1] == '\0')
1367 			value = (u_char) arg[0];
1368 		else if (arg[0] == '^' && arg[2] == 0 &&
1369 		    (u_char) arg[1] >= 64 && (u_char) arg[1] < 128)
1370 			value = (u_char) arg[1] & 31;
1371 		else {
1372 			fatal("%.200s line %d: Bad escape character.",
1373 			    filename, linenum);
1374 			/* NOTREACHED */
1375 			value = 0;	/* Avoid compiler warning. */
1376 		}
1377 		if (*activep && *intptr == -1)
1378 			*intptr = value;
1379 		break;
1380 
1381 	case oAddressFamily:
1382 		intptr = &options->address_family;
1383 		multistate_ptr = multistate_addressfamily;
1384 		goto parse_multistate;
1385 
1386 	case oEnableSSHKeysign:
1387 		intptr = &options->enable_ssh_keysign;
1388 		goto parse_flag;
1389 
1390 	case oIdentitiesOnly:
1391 		intptr = &options->identities_only;
1392 		goto parse_flag;
1393 
1394 	case oServerAliveInterval:
1395 		intptr = &options->server_alive_interval;
1396 		goto parse_time;
1397 
1398 	case oServerAliveCountMax:
1399 		intptr = &options->server_alive_count_max;
1400 		goto parse_int;
1401 
1402 	case oSendEnv:
1403 		while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1404 			if (strchr(arg, '=') != NULL)
1405 				fatal("%s line %d: Invalid environment name.",
1406 				    filename, linenum);
1407 			if (!*activep)
1408 				continue;
1409 			if (*arg == '-') {
1410 				/* Removing an env var */
1411 				rm_env(options, arg, filename, linenum);
1412 				continue;
1413 			} else {
1414 				/* Adding an env var */
1415 				if (options->num_send_env >= INT_MAX)
1416 					fatal("%s line %d: too many send env.",
1417 					    filename, linenum);
1418 				options->send_env = xrecallocarray(
1419 				    options->send_env, options->num_send_env,
1420 				    options->num_send_env + 1,
1421 				    sizeof(*options->send_env));
1422 				options->send_env[options->num_send_env++] =
1423 				    xstrdup(arg);
1424 			}
1425 		}
1426 		break;
1427 
1428 	case oSetEnv:
1429 		value = options->num_setenv;
1430 		while ((arg = strdelimw(&s)) != NULL && *arg != '\0') {
1431 			if (strchr(arg, '=') == NULL)
1432 				fatal("%s line %d: Invalid SetEnv.",
1433 				    filename, linenum);
1434 			if (!*activep || value != 0)
1435 				continue;
1436 			/* Adding a setenv var */
1437 			if (options->num_setenv >= INT_MAX)
1438 				fatal("%s line %d: too many SetEnv.",
1439 				    filename, linenum);
1440 			options->setenv = xrecallocarray(
1441 			    options->setenv, options->num_setenv,
1442 			    options->num_setenv + 1, sizeof(*options->setenv));
1443 			options->setenv[options->num_setenv++] = xstrdup(arg);
1444 		}
1445 		break;
1446 
1447 	case oControlPath:
1448 		charptr = &options->control_path;
1449 		goto parse_string;
1450 
1451 	case oControlMaster:
1452 		intptr = &options->control_master;
1453 		multistate_ptr = multistate_controlmaster;
1454 		goto parse_multistate;
1455 
1456 	case oControlPersist:
1457 		/* no/false/yes/true, or a time spec */
1458 		intptr = &options->control_persist;
1459 		arg = strdelim(&s);
1460 		if (!arg || *arg == '\0')
1461 			fatal("%.200s line %d: Missing ControlPersist"
1462 			    " argument.", filename, linenum);
1463 		value = 0;
1464 		value2 = 0;	/* timeout */
1465 		if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
1466 			value = 0;
1467 		else if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
1468 			value = 1;
1469 		else if ((value2 = convtime(arg)) >= 0)
1470 			value = 1;
1471 		else
1472 			fatal("%.200s line %d: Bad ControlPersist argument.",
1473 			    filename, linenum);
1474 		if (*activep && *intptr == -1) {
1475 			*intptr = value;
1476 			options->control_persist_timeout = value2;
1477 		}
1478 		break;
1479 
1480 	case oHashKnownHosts:
1481 		intptr = &options->hash_known_hosts;
1482 		goto parse_flag;
1483 
1484 	case oTunnel:
1485 		intptr = &options->tun_open;
1486 		multistate_ptr = multistate_tunnel;
1487 		goto parse_multistate;
1488 
1489 	case oTunnelDevice:
1490 		arg = strdelim(&s);
1491 		if (!arg || *arg == '\0')
1492 			fatal("%.200s line %d: Missing argument.", filename, linenum);
1493 		value = a2tun(arg, &value2);
1494 		if (value == SSH_TUNID_ERR)
1495 			fatal("%.200s line %d: Bad tun device.", filename, linenum);
1496 		if (*activep) {
1497 			options->tun_local = value;
1498 			options->tun_remote = value2;
1499 		}
1500 		break;
1501 
1502 	case oLocalCommand:
1503 		charptr = &options->local_command;
1504 		goto parse_command;
1505 
1506 	case oPermitLocalCommand:
1507 		intptr = &options->permit_local_command;
1508 		goto parse_flag;
1509 
1510 	case oRemoteCommand:
1511 		charptr = &options->remote_command;
1512 		goto parse_command;
1513 
1514 	case oVisualHostKey:
1515 		intptr = &options->visual_host_key;
1516 		goto parse_flag;
1517 
1518 	case oInclude:
1519 		if (cmdline)
1520 			fatal("Include directive not supported as a "
1521 			    "command-line option");
1522 		value = 0;
1523 		while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1524 			/*
1525 			 * Ensure all paths are anchored. User configuration
1526 			 * files may begin with '~/' but system configurations
1527 			 * must not. If the path is relative, then treat it
1528 			 * as living in ~/.ssh for user configurations or
1529 			 * /etc/ssh for system ones.
1530 			 */
1531 			if (*arg == '~' && (flags & SSHCONF_USERCONF) == 0)
1532 				fatal("%.200s line %d: bad include path %s.",
1533 				    filename, linenum, arg);
1534 			if (!path_absolute(arg) && *arg != '~') {
1535 				xasprintf(&arg2, "%s/%s",
1536 				    (flags & SSHCONF_USERCONF) ?
1537 				    "~/" _PATH_SSH_USER_DIR : SSHDIR, arg);
1538 			} else
1539 				arg2 = xstrdup(arg);
1540 			memset(&gl, 0, sizeof(gl));
1541 			r = glob(arg2, GLOB_TILDE, NULL, &gl);
1542 			if (r == GLOB_NOMATCH) {
1543 				debug("%.200s line %d: include %s matched no "
1544 				    "files",filename, linenum, arg2);
1545 				free(arg2);
1546 				continue;
1547 			} else if (r != 0 || gl.gl_pathc < 0)
1548 				fatal("%.200s line %d: glob failed for %s.",
1549 				    filename, linenum, arg2);
1550 			free(arg2);
1551 			oactive = *activep;
1552 			for (i = 0; i < (u_int)gl.gl_pathc; i++) {
1553 				debug3("%.200s line %d: Including file %s "
1554 				    "depth %d%s", filename, linenum,
1555 				    gl.gl_pathv[i], depth,
1556 				    oactive ? "" : " (parse only)");
1557 				r = read_config_file_depth(gl.gl_pathv[i],
1558 				    pw, host, original_host, options,
1559 				    flags | SSHCONF_CHECKPERM |
1560 				    (oactive ? 0 : SSHCONF_NEVERMATCH),
1561 				    activep, want_final_pass, depth + 1);
1562 				if (r != 1 && errno != ENOENT) {
1563 					fatal("Can't open user config file "
1564 					    "%.100s: %.100s", gl.gl_pathv[i],
1565 					    strerror(errno));
1566 				}
1567 				/*
1568 				 * don't let Match in includes clobber the
1569 				 * containing file's Match state.
1570 				 */
1571 				*activep = oactive;
1572 				if (r != 1)
1573 					value = -1;
1574 			}
1575 			globfree(&gl);
1576 		}
1577 		if (value != 0)
1578 			return value;
1579 		break;
1580 
1581 	case oIPQoS:
1582 		arg = strdelim(&s);
1583 		if ((value = parse_ipqos(arg)) == -1)
1584 			fatal("%s line %d: Bad IPQoS value: %s",
1585 			    filename, linenum, arg);
1586 		arg = strdelim(&s);
1587 		if (arg == NULL)
1588 			value2 = value;
1589 		else if ((value2 = parse_ipqos(arg)) == -1)
1590 			fatal("%s line %d: Bad IPQoS value: %s",
1591 			    filename, linenum, arg);
1592 		if (*activep) {
1593 			options->ip_qos_interactive = value;
1594 			options->ip_qos_bulk = value2;
1595 		}
1596 		break;
1597 
1598 	case oRequestTTY:
1599 		intptr = &options->request_tty;
1600 		multistate_ptr = multistate_requesttty;
1601 		goto parse_multistate;
1602 
1603 	case oIgnoreUnknown:
1604 		charptr = &options->ignored_unknown;
1605 		goto parse_string;
1606 
1607 	case oProxyUseFdpass:
1608 		intptr = &options->proxy_use_fdpass;
1609 		goto parse_flag;
1610 
1611 	case oCanonicalDomains:
1612 		value = options->num_canonical_domains != 0;
1613 		while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1614 			if (!valid_domain(arg, 1, &errstr)) {
1615 				fatal("%s line %d: %s", filename, linenum,
1616 				    errstr);
1617 			}
1618 			if (!*activep || value)
1619 				continue;
1620 			if (options->num_canonical_domains >= MAX_CANON_DOMAINS)
1621 				fatal("%s line %d: too many hostname suffixes.",
1622 				    filename, linenum);
1623 			options->canonical_domains[
1624 			    options->num_canonical_domains++] = xstrdup(arg);
1625 		}
1626 		break;
1627 
1628 	case oCanonicalizePermittedCNAMEs:
1629 		value = options->num_permitted_cnames != 0;
1630 		while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1631 			/* Either '*' for everything or 'list:list' */
1632 			if (strcmp(arg, "*") == 0)
1633 				arg2 = arg;
1634 			else {
1635 				lowercase(arg);
1636 				if ((arg2 = strchr(arg, ':')) == NULL ||
1637 				    arg2[1] == '\0') {
1638 					fatal("%s line %d: "
1639 					    "Invalid permitted CNAME \"%s\"",
1640 					    filename, linenum, arg);
1641 				}
1642 				*arg2 = '\0';
1643 				arg2++;
1644 			}
1645 			if (!*activep || value)
1646 				continue;
1647 			if (options->num_permitted_cnames >= MAX_CANON_DOMAINS)
1648 				fatal("%s line %d: too many permitted CNAMEs.",
1649 				    filename, linenum);
1650 			cname = options->permitted_cnames +
1651 			    options->num_permitted_cnames++;
1652 			cname->source_list = xstrdup(arg);
1653 			cname->target_list = xstrdup(arg2);
1654 		}
1655 		break;
1656 
1657 	case oCanonicalizeHostname:
1658 		intptr = &options->canonicalize_hostname;
1659 		multistate_ptr = multistate_canonicalizehostname;
1660 		goto parse_multistate;
1661 
1662 	case oCanonicalizeMaxDots:
1663 		intptr = &options->canonicalize_max_dots;
1664 		goto parse_int;
1665 
1666 	case oCanonicalizeFallbackLocal:
1667 		intptr = &options->canonicalize_fallback_local;
1668 		goto parse_flag;
1669 
1670 	case oStreamLocalBindMask:
1671 		arg = strdelim(&s);
1672 		if (!arg || *arg == '\0')
1673 			fatal("%.200s line %d: Missing StreamLocalBindMask argument.", filename, linenum);
1674 		/* Parse mode in octal format */
1675 		value = strtol(arg, &endofnumber, 8);
1676 		if (arg == endofnumber || value < 0 || value > 0777)
1677 			fatal("%.200s line %d: Bad mask.", filename, linenum);
1678 		options->fwd_opts.streamlocal_bind_mask = (mode_t)value;
1679 		break;
1680 
1681 	case oStreamLocalBindUnlink:
1682 		intptr = &options->fwd_opts.streamlocal_bind_unlink;
1683 		goto parse_flag;
1684 
1685 	case oRevokedHostKeys:
1686 		charptr = &options->revoked_host_keys;
1687 		goto parse_string;
1688 
1689 	case oFingerprintHash:
1690 		intptr = &options->fingerprint_hash;
1691 		arg = strdelim(&s);
1692 		if (!arg || *arg == '\0')
1693 			fatal("%.200s line %d: Missing argument.",
1694 			    filename, linenum);
1695 		if ((value = ssh_digest_alg_by_name(arg)) == -1)
1696 			fatal("%.200s line %d: Invalid hash algorithm \"%s\".",
1697 			    filename, linenum, arg);
1698 		if (*activep && *intptr == -1)
1699 			*intptr = value;
1700 		break;
1701 
1702 	case oUpdateHostkeys:
1703 		intptr = &options->update_hostkeys;
1704 		multistate_ptr = multistate_yesnoask;
1705 		goto parse_multistate;
1706 
1707 	case oHostbasedKeyTypes:
1708 		charptr = &options->hostbased_key_types;
1709 		goto parse_keytypes;
1710 
1711 	case oPubkeyAcceptedKeyTypes:
1712 		charptr = &options->pubkey_key_types;
1713 		goto parse_keytypes;
1714 
1715 	case oAddKeysToAgent:
1716 		intptr = &options->add_keys_to_agent;
1717 		multistate_ptr = multistate_yesnoaskconfirm;
1718 		goto parse_multistate;
1719 
1720 	case oIdentityAgent:
1721 		charptr = &options->identity_agent;
1722 		arg = strdelim(&s);
1723 		if (!arg || *arg == '\0')
1724 			fatal("%.200s line %d: Missing argument.",
1725 			    filename, linenum);
1726 		/* Extra validation if the string represents an env var. */
1727 		if (arg[0] == '$' && !valid_env_name(arg + 1)) {
1728 			fatal("%.200s line %d: Invalid environment name %s.",
1729 			    filename, linenum, arg);
1730 		}
1731 		if (*activep && *charptr == NULL)
1732 			*charptr = xstrdup(arg);
1733 		break;
1734 
1735 	case oDeprecated:
1736 		debug("%s line %d: Deprecated option \"%s\"",
1737 		    filename, linenum, keyword);
1738 		return 0;
1739 
1740 	case oUnsupported:
1741 		error("%s line %d: Unsupported option \"%s\"",
1742 		    filename, linenum, keyword);
1743 		return 0;
1744 
1745 	default:
1746 		fatal("%s: Unimplemented opcode %d", __func__, opcode);
1747 	}
1748 
1749 	/* Check that there is no garbage at end of line. */
1750 	if ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1751 		fatal("%.200s line %d: garbage at end of line; \"%.200s\".",
1752 		    filename, linenum, arg);
1753 	}
1754 	return 0;
1755 }
1756 
1757 /*
1758  * Reads the config file and modifies the options accordingly.  Options
1759  * should already be initialized before this call.  This never returns if
1760  * there is an error.  If the file does not exist, this returns 0.
1761  */
1762 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)1763 read_config_file(const char *filename, struct passwd *pw, const char *host,
1764     const char *original_host, Options *options, int flags,
1765     int *want_final_pass)
1766 {
1767 	int active = 1;
1768 
1769 	return read_config_file_depth(filename, pw, host, original_host,
1770 	    options, flags, &active, want_final_pass, 0);
1771 }
1772 
1773 #define READCONF_MAX_DEPTH	16
1774 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)1775 read_config_file_depth(const char *filename, struct passwd *pw,
1776     const char *host, const char *original_host, Options *options,
1777     int flags, int *activep, int *want_final_pass, int depth)
1778 {
1779 	FILE *f;
1780 	char *line = NULL;
1781 	size_t linesize = 0;
1782 	int linenum;
1783 	int bad_options = 0;
1784 
1785 	if (depth < 0 || depth > READCONF_MAX_DEPTH)
1786 		fatal("Too many recursive configuration includes");
1787 
1788 	if ((f = fopen(filename, "r")) == NULL)
1789 		return 0;
1790 
1791 	if (flags & SSHCONF_CHECKPERM) {
1792 		struct stat sb;
1793 
1794 		if (fstat(fileno(f), &sb) == -1)
1795 			fatal("fstat %s: %s", filename, strerror(errno));
1796 		if (((sb.st_uid != 0 && sb.st_uid != getuid()) ||
1797 		    (sb.st_mode & 022) != 0))
1798 			fatal("Bad owner or permissions on %s", filename);
1799 	}
1800 
1801 	debug("Reading configuration data %.200s", filename);
1802 
1803 	/*
1804 	 * Mark that we are now processing the options.  This flag is turned
1805 	 * on/off by Host specifications.
1806 	 */
1807 	linenum = 0;
1808 	while (getline(&line, &linesize, f) != -1) {
1809 		/* Update line number counter. */
1810 		linenum++;
1811 		if (process_config_line_depth(options, pw, host, original_host,
1812 		    line, filename, linenum, activep, flags, want_final_pass,
1813 		    depth) != 0)
1814 			bad_options++;
1815 	}
1816 	free(line);
1817 	fclose(f);
1818 	if (bad_options > 0)
1819 		fatal("%s: terminating, %d bad configuration options",
1820 		    filename, bad_options);
1821 	return 1;
1822 }
1823 
1824 /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */
1825 int
option_clear_or_none(const char * o)1826 option_clear_or_none(const char *o)
1827 {
1828 	return o == NULL || strcasecmp(o, "none") == 0;
1829 }
1830 
1831 /*
1832  * Initializes options to special values that indicate that they have not yet
1833  * been set.  Read_config_file will only set options with this value. Options
1834  * are processed in the following order: command line, user config file,
1835  * system config file.  Last, fill_default_options is called.
1836  */
1837 
1838 void
initialize_options(Options * options)1839 initialize_options(Options * options)
1840 {
1841 	memset(options, 'X', sizeof(*options));
1842 	options->forward_agent = -1;
1843 	options->forward_x11 = -1;
1844 	options->forward_x11_trusted = -1;
1845 	options->forward_x11_timeout = -1;
1846 	options->stdio_forward_host = NULL;
1847 	options->stdio_forward_port = 0;
1848 	options->clear_forwardings = -1;
1849 	options->exit_on_forward_failure = -1;
1850 	options->xauth_location = NULL;
1851 	options->fwd_opts.gateway_ports = -1;
1852 	options->fwd_opts.streamlocal_bind_mask = (mode_t)-1;
1853 	options->fwd_opts.streamlocal_bind_unlink = -1;
1854 	options->pubkey_authentication = -1;
1855 	options->challenge_response_authentication = -1;
1856 	options->gss_authentication = -1;
1857 	options->gss_deleg_creds = -1;
1858 	options->password_authentication = -1;
1859 	options->kbd_interactive_authentication = -1;
1860 	options->kbd_interactive_devices = NULL;
1861 	options->hostbased_authentication = -1;
1862 	options->batch_mode = -1;
1863 	options->check_host_ip = -1;
1864 	options->strict_host_key_checking = -1;
1865 	options->compression = -1;
1866 	options->tcp_keep_alive = -1;
1867 	options->port = -1;
1868 	options->address_family = -1;
1869 	options->connection_attempts = -1;
1870 	options->connection_timeout = -1;
1871 	options->number_of_password_prompts = -1;
1872 	options->ciphers = NULL;
1873 	options->macs = NULL;
1874 	options->kex_algorithms = NULL;
1875 	options->hostkeyalgorithms = NULL;
1876 	options->ca_sign_algorithms = NULL;
1877 	options->num_identity_files = 0;
1878 	options->num_certificate_files = 0;
1879 	options->hostname = NULL;
1880 	options->host_key_alias = NULL;
1881 	options->proxy_command = NULL;
1882 	options->jump_user = NULL;
1883 	options->jump_host = NULL;
1884 	options->jump_port = -1;
1885 	options->jump_extra = NULL;
1886 	options->user = NULL;
1887 	options->escape_char = -1;
1888 	options->num_system_hostfiles = 0;
1889 	options->num_user_hostfiles = 0;
1890 	options->local_forwards = NULL;
1891 	options->num_local_forwards = 0;
1892 	options->remote_forwards = NULL;
1893 	options->num_remote_forwards = 0;
1894 	options->log_facility = SYSLOG_FACILITY_NOT_SET;
1895 	options->log_level = SYSLOG_LEVEL_NOT_SET;
1896 	options->preferred_authentications = NULL;
1897 	options->bind_address = NULL;
1898 	options->bind_interface = NULL;
1899 	options->pkcs11_provider = NULL;
1900 	options->enable_ssh_keysign = - 1;
1901 	options->no_host_authentication_for_localhost = - 1;
1902 	options->identities_only = - 1;
1903 	options->rekey_limit = - 1;
1904 	options->rekey_interval = -1;
1905 	options->verify_host_key_dns = -1;
1906 	options->server_alive_interval = -1;
1907 	options->server_alive_count_max = -1;
1908 	options->send_env = NULL;
1909 	options->num_send_env = 0;
1910 	options->setenv = NULL;
1911 	options->num_setenv = 0;
1912 	options->control_path = NULL;
1913 	options->control_master = -1;
1914 	options->control_persist = -1;
1915 	options->control_persist_timeout = 0;
1916 	options->hash_known_hosts = -1;
1917 	options->tun_open = -1;
1918 	options->tun_local = -1;
1919 	options->tun_remote = -1;
1920 	options->local_command = NULL;
1921 	options->permit_local_command = -1;
1922 	options->remote_command = NULL;
1923 	options->add_keys_to_agent = -1;
1924 	options->identity_agent = NULL;
1925 	options->visual_host_key = -1;
1926 	options->ip_qos_interactive = -1;
1927 	options->ip_qos_bulk = -1;
1928 	options->request_tty = -1;
1929 	options->proxy_use_fdpass = -1;
1930 	options->ignored_unknown = NULL;
1931 	options->num_canonical_domains = 0;
1932 	options->num_permitted_cnames = 0;
1933 	options->canonicalize_max_dots = -1;
1934 	options->canonicalize_fallback_local = -1;
1935 	options->canonicalize_hostname = -1;
1936 	options->revoked_host_keys = NULL;
1937 	options->fingerprint_hash = -1;
1938 	options->update_hostkeys = -1;
1939 	options->hostbased_key_types = NULL;
1940 	options->pubkey_key_types = NULL;
1941 }
1942 
1943 /*
1944  * A petite version of fill_default_options() that just fills the options
1945  * needed for hostname canonicalization to proceed.
1946  */
1947 void
fill_default_options_for_canonicalization(Options * options)1948 fill_default_options_for_canonicalization(Options *options)
1949 {
1950 	if (options->canonicalize_max_dots == -1)
1951 		options->canonicalize_max_dots = 1;
1952 	if (options->canonicalize_fallback_local == -1)
1953 		options->canonicalize_fallback_local = 1;
1954 	if (options->canonicalize_hostname == -1)
1955 		options->canonicalize_hostname = SSH_CANONICALISE_NO;
1956 }
1957 
1958 /*
1959  * Called after processing other sources of option data, this fills those
1960  * options for which no value has been specified with their default values.
1961  */
1962 void
fill_default_options(Options * options)1963 fill_default_options(Options * options)
1964 {
1965 	char *all_cipher, *all_mac, *all_kex, *all_key, *all_sig;
1966 	int r;
1967 
1968 	if (options->forward_agent == -1)
1969 		options->forward_agent = 0;
1970 	if (options->forward_x11 == -1)
1971 		options->forward_x11 = 0;
1972 	if (options->forward_x11_trusted == -1)
1973 		options->forward_x11_trusted = 0;
1974 	if (options->forward_x11_timeout == -1)
1975 		options->forward_x11_timeout = 1200;
1976 	/*
1977 	 * stdio forwarding (-W) changes the default for these but we defer
1978 	 * setting the values so they can be overridden.
1979 	 */
1980 	if (options->exit_on_forward_failure == -1)
1981 		options->exit_on_forward_failure =
1982 		    options->stdio_forward_host != NULL ? 1 : 0;
1983 	if (options->clear_forwardings == -1)
1984 		options->clear_forwardings =
1985 		    options->stdio_forward_host != NULL ? 1 : 0;
1986 	if (options->clear_forwardings == 1)
1987 		clear_forwardings(options);
1988 
1989 	if (options->xauth_location == NULL)
1990 		options->xauth_location = _PATH_XAUTH;
1991 	if (options->fwd_opts.gateway_ports == -1)
1992 		options->fwd_opts.gateway_ports = 0;
1993 	if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1)
1994 		options->fwd_opts.streamlocal_bind_mask = 0177;
1995 	if (options->fwd_opts.streamlocal_bind_unlink == -1)
1996 		options->fwd_opts.streamlocal_bind_unlink = 0;
1997 	if (options->pubkey_authentication == -1)
1998 		options->pubkey_authentication = 1;
1999 	if (options->challenge_response_authentication == -1)
2000 		options->challenge_response_authentication = 1;
2001 	if (options->gss_authentication == -1)
2002 		options->gss_authentication = 0;
2003 	if (options->gss_deleg_creds == -1)
2004 		options->gss_deleg_creds = 0;
2005 	if (options->password_authentication == -1)
2006 		options->password_authentication = 1;
2007 	if (options->kbd_interactive_authentication == -1)
2008 		options->kbd_interactive_authentication = 1;
2009 	if (options->hostbased_authentication == -1)
2010 		options->hostbased_authentication = 0;
2011 	if (options->batch_mode == -1)
2012 		options->batch_mode = 0;
2013 	if (options->check_host_ip == -1)
2014 		options->check_host_ip = 1;
2015 	if (options->strict_host_key_checking == -1)
2016 		options->strict_host_key_checking = SSH_STRICT_HOSTKEY_ASK;
2017 	if (options->compression == -1)
2018 		options->compression = 0;
2019 	if (options->tcp_keep_alive == -1)
2020 		options->tcp_keep_alive = 1;
2021 	if (options->port == -1)
2022 		options->port = 0;	/* Filled in ssh_connect. */
2023 	if (options->address_family == -1)
2024 		options->address_family = AF_UNSPEC;
2025 	if (options->connection_attempts == -1)
2026 		options->connection_attempts = 1;
2027 	if (options->number_of_password_prompts == -1)
2028 		options->number_of_password_prompts = 3;
2029 	/* options->hostkeyalgorithms, default set in myproposals.h */
2030 	if (options->add_keys_to_agent == -1)
2031 		options->add_keys_to_agent = 0;
2032 	if (options->num_identity_files == 0) {
2033 		add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_RSA, 0);
2034 		add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_DSA, 0);
2035 #ifdef OPENSSL_HAS_ECC
2036 		add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_ECDSA, 0);
2037 #endif
2038 		add_identity_file(options, "~/",
2039 		    _PATH_SSH_CLIENT_ID_ED25519, 0);
2040 		add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_XMSS, 0);
2041 	}
2042 	if (options->escape_char == -1)
2043 		options->escape_char = '~';
2044 	if (options->num_system_hostfiles == 0) {
2045 		options->system_hostfiles[options->num_system_hostfiles++] =
2046 		    xstrdup(_PATH_SSH_SYSTEM_HOSTFILE);
2047 		options->system_hostfiles[options->num_system_hostfiles++] =
2048 		    xstrdup(_PATH_SSH_SYSTEM_HOSTFILE2);
2049 	}
2050 	if (options->num_user_hostfiles == 0) {
2051 		options->user_hostfiles[options->num_user_hostfiles++] =
2052 		    xstrdup(_PATH_SSH_USER_HOSTFILE);
2053 		options->user_hostfiles[options->num_user_hostfiles++] =
2054 		    xstrdup(_PATH_SSH_USER_HOSTFILE2);
2055 	}
2056 	if (options->log_level == SYSLOG_LEVEL_NOT_SET)
2057 		options->log_level = SYSLOG_LEVEL_INFO;
2058 	if (options->log_facility == SYSLOG_FACILITY_NOT_SET)
2059 		options->log_facility = SYSLOG_FACILITY_USER;
2060 	if (options->no_host_authentication_for_localhost == - 1)
2061 		options->no_host_authentication_for_localhost = 0;
2062 	if (options->identities_only == -1)
2063 		options->identities_only = 0;
2064 	if (options->enable_ssh_keysign == -1)
2065 		options->enable_ssh_keysign = 0;
2066 	if (options->rekey_limit == -1)
2067 		options->rekey_limit = 0;
2068 	if (options->rekey_interval == -1)
2069 		options->rekey_interval = 0;
2070 	if (options->verify_host_key_dns == -1)
2071 		options->verify_host_key_dns = 0;
2072 	if (options->server_alive_interval == -1)
2073 		options->server_alive_interval = 0;
2074 	if (options->server_alive_count_max == -1)
2075 		options->server_alive_count_max = 3;
2076 	if (options->control_master == -1)
2077 		options->control_master = 0;
2078 	if (options->control_persist == -1) {
2079 		options->control_persist = 0;
2080 		options->control_persist_timeout = 0;
2081 	}
2082 	if (options->hash_known_hosts == -1)
2083 		options->hash_known_hosts = 0;
2084 	if (options->tun_open == -1)
2085 		options->tun_open = SSH_TUNMODE_NO;
2086 	if (options->tun_local == -1)
2087 		options->tun_local = SSH_TUNID_ANY;
2088 	if (options->tun_remote == -1)
2089 		options->tun_remote = SSH_TUNID_ANY;
2090 	if (options->permit_local_command == -1)
2091 		options->permit_local_command = 0;
2092 	if (options->visual_host_key == -1)
2093 		options->visual_host_key = 0;
2094 	if (options->ip_qos_interactive == -1)
2095 		options->ip_qos_interactive = IPTOS_DSCP_AF21;
2096 	if (options->ip_qos_bulk == -1)
2097 		options->ip_qos_bulk = IPTOS_DSCP_CS1;
2098 	if (options->request_tty == -1)
2099 		options->request_tty = REQUEST_TTY_AUTO;
2100 	if (options->proxy_use_fdpass == -1)
2101 		options->proxy_use_fdpass = 0;
2102 	if (options->canonicalize_max_dots == -1)
2103 		options->canonicalize_max_dots = 1;
2104 	if (options->canonicalize_fallback_local == -1)
2105 		options->canonicalize_fallback_local = 1;
2106 	if (options->canonicalize_hostname == -1)
2107 		options->canonicalize_hostname = SSH_CANONICALISE_NO;
2108 	if (options->fingerprint_hash == -1)
2109 		options->fingerprint_hash = SSH_FP_HASH_DEFAULT;
2110 	if (options->update_hostkeys == -1)
2111 		options->update_hostkeys = 0;
2112 
2113 	/* Expand KEX name lists */
2114 	all_cipher = cipher_alg_list(',', 0);
2115 	all_mac = mac_alg_list(',');
2116 	all_kex = kex_alg_list(',');
2117 	all_key = sshkey_alg_list(0, 0, 1, ',');
2118 	all_sig = sshkey_alg_list(0, 1, 1, ',');
2119 #define ASSEMBLE(what, defaults, all) \
2120 	do { \
2121 		if ((r = kex_assemble_names(&options->what, \
2122 		    defaults, all)) != 0) \
2123 			fatal("%s: %s: %s", __func__, #what, ssh_err(r)); \
2124 	} while (0)
2125 	ASSEMBLE(ciphers, KEX_CLIENT_ENCRYPT, all_cipher);
2126 	ASSEMBLE(macs, KEX_CLIENT_MAC, all_mac);
2127 	ASSEMBLE(kex_algorithms, KEX_CLIENT_KEX, all_kex);
2128 	ASSEMBLE(hostbased_key_types, KEX_DEFAULT_PK_ALG, all_key);
2129 	ASSEMBLE(pubkey_key_types, KEX_DEFAULT_PK_ALG, all_key);
2130 	ASSEMBLE(ca_sign_algorithms, SSH_ALLOWED_CA_SIGALGS, all_sig);
2131 #undef ASSEMBLE
2132 	free(all_cipher);
2133 	free(all_mac);
2134 	free(all_kex);
2135 	free(all_key);
2136 	free(all_sig);
2137 
2138 #define CLEAR_ON_NONE(v) \
2139 	do { \
2140 		if (option_clear_or_none(v)) { \
2141 			free(v); \
2142 			v = NULL; \
2143 		} \
2144 	} while(0)
2145 	CLEAR_ON_NONE(options->local_command);
2146 	CLEAR_ON_NONE(options->remote_command);
2147 	CLEAR_ON_NONE(options->proxy_command);
2148 	CLEAR_ON_NONE(options->control_path);
2149 	CLEAR_ON_NONE(options->revoked_host_keys);
2150 	CLEAR_ON_NONE(options->pkcs11_provider);
2151 	if (options->jump_host != NULL &&
2152 	    strcmp(options->jump_host, "none") == 0 &&
2153 	    options->jump_port == 0 && options->jump_user == NULL) {
2154 		free(options->jump_host);
2155 		options->jump_host = NULL;
2156 	}
2157 	/* options->identity_agent distinguishes NULL from 'none' */
2158 	/* options->user will be set in the main program if appropriate */
2159 	/* options->hostname will be set in the main program if appropriate */
2160 	/* options->host_key_alias should not be set by default */
2161 	/* options->preferred_authentications will be set in ssh */
2162 }
2163 
2164 struct fwdarg {
2165 	char *arg;
2166 	int ispath;
2167 };
2168 
2169 /*
2170  * parse_fwd_field
2171  * parses the next field in a port forwarding specification.
2172  * sets fwd to the parsed field and advances p past the colon
2173  * or sets it to NULL at end of string.
2174  * returns 0 on success, else non-zero.
2175  */
2176 static int
parse_fwd_field(char ** p,struct fwdarg * fwd)2177 parse_fwd_field(char **p, struct fwdarg *fwd)
2178 {
2179 	char *ep, *cp = *p;
2180 	int ispath = 0;
2181 
2182 	if (*cp == '\0') {
2183 		*p = NULL;
2184 		return -1;	/* end of string */
2185 	}
2186 
2187 	/*
2188 	 * A field escaped with square brackets is used literally.
2189 	 * XXX - allow ']' to be escaped via backslash?
2190 	 */
2191 	if (*cp == '[') {
2192 		/* find matching ']' */
2193 		for (ep = cp + 1; *ep != ']' && *ep != '\0'; ep++) {
2194 			if (*ep == '/')
2195 				ispath = 1;
2196 		}
2197 		/* no matching ']' or not at end of field. */
2198 		if (ep[0] != ']' || (ep[1] != ':' && ep[1] != '\0'))
2199 			return -1;
2200 		/* NUL terminate the field and advance p past the colon */
2201 		*ep++ = '\0';
2202 		if (*ep != '\0')
2203 			*ep++ = '\0';
2204 		fwd->arg = cp + 1;
2205 		fwd->ispath = ispath;
2206 		*p = ep;
2207 		return 0;
2208 	}
2209 
2210 	for (cp = *p; *cp != '\0'; cp++) {
2211 		switch (*cp) {
2212 		case '\\':
2213 			memmove(cp, cp + 1, strlen(cp + 1) + 1);
2214 			if (*cp == '\0')
2215 				return -1;
2216 			break;
2217 		case '/':
2218 			ispath = 1;
2219 			break;
2220 		case ':':
2221 			*cp++ = '\0';
2222 			goto done;
2223 		}
2224 	}
2225 done:
2226 	fwd->arg = *p;
2227 	fwd->ispath = ispath;
2228 	*p = cp;
2229 	return 0;
2230 }
2231 
2232 /*
2233  * parse_forward
2234  * parses a string containing a port forwarding specification of the form:
2235  *   dynamicfwd == 0
2236  *	[listenhost:]listenport|listenpath:connecthost:connectport|connectpath
2237  *	listenpath:connectpath
2238  *   dynamicfwd == 1
2239  *	[listenhost:]listenport
2240  * returns number of arguments parsed or zero on error
2241  */
2242 int
parse_forward(struct Forward * fwd,const char * fwdspec,int dynamicfwd,int remotefwd)2243 parse_forward(struct Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
2244 {
2245 	struct fwdarg fwdargs[4];
2246 	char *p, *cp;
2247 	int i;
2248 
2249 	memset(fwd, 0, sizeof(*fwd));
2250 	memset(fwdargs, 0, sizeof(fwdargs));
2251 
2252 	cp = p = xstrdup(fwdspec);
2253 
2254 	/* skip leading spaces */
2255 	while (isspace((u_char)*cp))
2256 		cp++;
2257 
2258 	for (i = 0; i < 4; ++i) {
2259 		if (parse_fwd_field(&cp, &fwdargs[i]) != 0)
2260 			break;
2261 	}
2262 
2263 	/* Check for trailing garbage */
2264 	if (cp != NULL && *cp != '\0') {
2265 		i = 0;	/* failure */
2266 	}
2267 
2268 	switch (i) {
2269 	case 1:
2270 		if (fwdargs[0].ispath) {
2271 			fwd->listen_path = xstrdup(fwdargs[0].arg);
2272 			fwd->listen_port = PORT_STREAMLOCAL;
2273 		} else {
2274 			fwd->listen_host = NULL;
2275 			fwd->listen_port = a2port(fwdargs[0].arg);
2276 		}
2277 		fwd->connect_host = xstrdup("socks");
2278 		break;
2279 
2280 	case 2:
2281 		if (fwdargs[0].ispath && fwdargs[1].ispath) {
2282 			fwd->listen_path = xstrdup(fwdargs[0].arg);
2283 			fwd->listen_port = PORT_STREAMLOCAL;
2284 			fwd->connect_path = xstrdup(fwdargs[1].arg);
2285 			fwd->connect_port = PORT_STREAMLOCAL;
2286 		} else if (fwdargs[1].ispath) {
2287 			fwd->listen_host = NULL;
2288 			fwd->listen_port = a2port(fwdargs[0].arg);
2289 			fwd->connect_path = xstrdup(fwdargs[1].arg);
2290 			fwd->connect_port = PORT_STREAMLOCAL;
2291 		} else {
2292 			fwd->listen_host = xstrdup(fwdargs[0].arg);
2293 			fwd->listen_port = a2port(fwdargs[1].arg);
2294 			fwd->connect_host = xstrdup("socks");
2295 		}
2296 		break;
2297 
2298 	case 3:
2299 		if (fwdargs[0].ispath) {
2300 			fwd->listen_path = xstrdup(fwdargs[0].arg);
2301 			fwd->listen_port = PORT_STREAMLOCAL;
2302 			fwd->connect_host = xstrdup(fwdargs[1].arg);
2303 			fwd->connect_port = a2port(fwdargs[2].arg);
2304 		} else if (fwdargs[2].ispath) {
2305 			fwd->listen_host = xstrdup(fwdargs[0].arg);
2306 			fwd->listen_port = a2port(fwdargs[1].arg);
2307 			fwd->connect_path = xstrdup(fwdargs[2].arg);
2308 			fwd->connect_port = PORT_STREAMLOCAL;
2309 		} else {
2310 			fwd->listen_host = NULL;
2311 			fwd->listen_port = a2port(fwdargs[0].arg);
2312 			fwd->connect_host = xstrdup(fwdargs[1].arg);
2313 			fwd->connect_port = a2port(fwdargs[2].arg);
2314 		}
2315 		break;
2316 
2317 	case 4:
2318 		fwd->listen_host = xstrdup(fwdargs[0].arg);
2319 		fwd->listen_port = a2port(fwdargs[1].arg);
2320 		fwd->connect_host = xstrdup(fwdargs[2].arg);
2321 		fwd->connect_port = a2port(fwdargs[3].arg);
2322 		break;
2323 	default:
2324 		i = 0; /* failure */
2325 	}
2326 
2327 	free(p);
2328 
2329 	if (dynamicfwd) {
2330 		if (!(i == 1 || i == 2))
2331 			goto fail_free;
2332 	} else {
2333 		if (!(i == 3 || i == 4)) {
2334 			if (fwd->connect_path == NULL &&
2335 			    fwd->listen_path == NULL)
2336 				goto fail_free;
2337 		}
2338 		if (fwd->connect_port <= 0 && fwd->connect_path == NULL)
2339 			goto fail_free;
2340 	}
2341 
2342 	if ((fwd->listen_port < 0 && fwd->listen_path == NULL) ||
2343 	    (!remotefwd && fwd->listen_port == 0))
2344 		goto fail_free;
2345 	if (fwd->connect_host != NULL &&
2346 	    strlen(fwd->connect_host) >= NI_MAXHOST)
2347 		goto fail_free;
2348 	/* XXX - if connecting to a remote socket, max sun len may not match this host */
2349 	if (fwd->connect_path != NULL &&
2350 	    strlen(fwd->connect_path) >= PATH_MAX_SUN)
2351 		goto fail_free;
2352 	if (fwd->listen_host != NULL &&
2353 	    strlen(fwd->listen_host) >= NI_MAXHOST)
2354 		goto fail_free;
2355 	if (fwd->listen_path != NULL &&
2356 	    strlen(fwd->listen_path) >= PATH_MAX_SUN)
2357 		goto fail_free;
2358 
2359 	return (i);
2360 
2361  fail_free:
2362 	free(fwd->connect_host);
2363 	fwd->connect_host = NULL;
2364 	free(fwd->connect_path);
2365 	fwd->connect_path = NULL;
2366 	free(fwd->listen_host);
2367 	fwd->listen_host = NULL;
2368 	free(fwd->listen_path);
2369 	fwd->listen_path = NULL;
2370 	return (0);
2371 }
2372 
2373 int
parse_jump(const char * s,Options * o,int active)2374 parse_jump(const char *s, Options *o, int active)
2375 {
2376 	char *orig, *sdup, *cp;
2377 	char *host = NULL, *user = NULL;
2378 	int ret = -1, port = -1, first;
2379 
2380 	active &= o->proxy_command == NULL && o->jump_host == NULL;
2381 
2382 	orig = sdup = xstrdup(s);
2383 	first = active;
2384 	do {
2385 		if (strcasecmp(s, "none") == 0)
2386 			break;
2387 		if ((cp = strrchr(sdup, ',')) == NULL)
2388 			cp = sdup; /* last */
2389 		else
2390 			*cp++ = '\0';
2391 
2392 		if (first) {
2393 			/* First argument and configuration is active */
2394 			if (parse_ssh_uri(cp, &user, &host, &port) == -1 ||
2395 			    parse_user_host_port(cp, &user, &host, &port) != 0)
2396 				goto out;
2397 		} else {
2398 			/* Subsequent argument or inactive configuration */
2399 			if (parse_ssh_uri(cp, NULL, NULL, NULL) == -1 ||
2400 			    parse_user_host_port(cp, NULL, NULL, NULL) != 0)
2401 				goto out;
2402 		}
2403 		first = 0; /* only check syntax for subsequent hosts */
2404 	} while (cp != sdup);
2405 	/* success */
2406 	if (active) {
2407 		if (strcasecmp(s, "none") == 0) {
2408 			o->jump_host = xstrdup("none");
2409 			o->jump_port = 0;
2410 		} else {
2411 			o->jump_user = user;
2412 			o->jump_host = host;
2413 			o->jump_port = port;
2414 			o->proxy_command = xstrdup("none");
2415 			user = host = NULL;
2416 			if ((cp = strrchr(s, ',')) != NULL && cp != s) {
2417 				o->jump_extra = xstrdup(s);
2418 				o->jump_extra[cp - s] = '\0';
2419 			}
2420 		}
2421 	}
2422 	ret = 0;
2423  out:
2424 	free(orig);
2425 	free(user);
2426 	free(host);
2427 	return ret;
2428 }
2429 
2430 int
parse_ssh_uri(const char * uri,char ** userp,char ** hostp,int * portp)2431 parse_ssh_uri(const char *uri, char **userp, char **hostp, int *portp)
2432 {
2433 	char *path;
2434 	int r;
2435 
2436 	r = parse_uri("ssh", uri, userp, hostp, portp, &path);
2437 	if (r == 0 && path != NULL)
2438 		r = -1;		/* path not allowed */
2439 	return r;
2440 }
2441 
2442 /* XXX the following is a near-vebatim copy from servconf.c; refactor */
2443 static const char *
fmt_multistate_int(int val,const struct multistate * m)2444 fmt_multistate_int(int val, const struct multistate *m)
2445 {
2446 	u_int i;
2447 
2448 	for (i = 0; m[i].key != NULL; i++) {
2449 		if (m[i].value == val)
2450 			return m[i].key;
2451 	}
2452 	return "UNKNOWN";
2453 }
2454 
2455 static const char *
fmt_intarg(OpCodes code,int val)2456 fmt_intarg(OpCodes code, int val)
2457 {
2458 	if (val == -1)
2459 		return "unset";
2460 	switch (code) {
2461 	case oAddressFamily:
2462 		return fmt_multistate_int(val, multistate_addressfamily);
2463 	case oVerifyHostKeyDNS:
2464 	case oUpdateHostkeys:
2465 		return fmt_multistate_int(val, multistate_yesnoask);
2466 	case oStrictHostKeyChecking:
2467 		return fmt_multistate_int(val, multistate_strict_hostkey);
2468 	case oControlMaster:
2469 		return fmt_multistate_int(val, multistate_controlmaster);
2470 	case oTunnel:
2471 		return fmt_multistate_int(val, multistate_tunnel);
2472 	case oRequestTTY:
2473 		return fmt_multistate_int(val, multistate_requesttty);
2474 	case oCanonicalizeHostname:
2475 		return fmt_multistate_int(val, multistate_canonicalizehostname);
2476 	case oAddKeysToAgent:
2477 		return fmt_multistate_int(val, multistate_yesnoaskconfirm);
2478 	case oFingerprintHash:
2479 		return ssh_digest_alg_name(val);
2480 	default:
2481 		switch (val) {
2482 		case 0:
2483 			return "no";
2484 		case 1:
2485 			return "yes";
2486 		default:
2487 			return "UNKNOWN";
2488 		}
2489 	}
2490 }
2491 
2492 static const char *
lookup_opcode_name(OpCodes code)2493 lookup_opcode_name(OpCodes code)
2494 {
2495 	u_int i;
2496 
2497 	for (i = 0; keywords[i].name != NULL; i++)
2498 		if (keywords[i].opcode == code)
2499 			return(keywords[i].name);
2500 	return "UNKNOWN";
2501 }
2502 
2503 static void
dump_cfg_int(OpCodes code,int val)2504 dump_cfg_int(OpCodes code, int val)
2505 {
2506 	printf("%s %d\n", lookup_opcode_name(code), val);
2507 }
2508 
2509 static void
dump_cfg_fmtint(OpCodes code,int val)2510 dump_cfg_fmtint(OpCodes code, int val)
2511 {
2512 	printf("%s %s\n", lookup_opcode_name(code), fmt_intarg(code, val));
2513 }
2514 
2515 static void
dump_cfg_string(OpCodes code,const char * val)2516 dump_cfg_string(OpCodes code, const char *val)
2517 {
2518 	if (val == NULL)
2519 		return;
2520 	printf("%s %s\n", lookup_opcode_name(code), val);
2521 }
2522 
2523 static void
dump_cfg_strarray(OpCodes code,u_int count,char ** vals)2524 dump_cfg_strarray(OpCodes code, u_int count, char **vals)
2525 {
2526 	u_int i;
2527 
2528 	for (i = 0; i < count; i++)
2529 		printf("%s %s\n", lookup_opcode_name(code), vals[i]);
2530 }
2531 
2532 static void
dump_cfg_strarray_oneline(OpCodes code,u_int count,char ** vals)2533 dump_cfg_strarray_oneline(OpCodes code, u_int count, char **vals)
2534 {
2535 	u_int i;
2536 
2537 	printf("%s", lookup_opcode_name(code));
2538 	for (i = 0; i < count; i++)
2539 		printf(" %s",  vals[i]);
2540 	printf("\n");
2541 }
2542 
2543 static void
dump_cfg_forwards(OpCodes code,u_int count,const struct Forward * fwds)2544 dump_cfg_forwards(OpCodes code, u_int count, const struct Forward *fwds)
2545 {
2546 	const struct Forward *fwd;
2547 	u_int i;
2548 
2549 	/* oDynamicForward */
2550 	for (i = 0; i < count; i++) {
2551 		fwd = &fwds[i];
2552 		if (code == oDynamicForward && fwd->connect_host != NULL &&
2553 		    strcmp(fwd->connect_host, "socks") != 0)
2554 			continue;
2555 		if (code == oLocalForward && fwd->connect_host != NULL &&
2556 		    strcmp(fwd->connect_host, "socks") == 0)
2557 			continue;
2558 		printf("%s", lookup_opcode_name(code));
2559 		if (fwd->listen_port == PORT_STREAMLOCAL)
2560 			printf(" %s", fwd->listen_path);
2561 		else if (fwd->listen_host == NULL)
2562 			printf(" %d", fwd->listen_port);
2563 		else {
2564 			printf(" [%s]:%d",
2565 			    fwd->listen_host, fwd->listen_port);
2566 		}
2567 		if (code != oDynamicForward) {
2568 			if (fwd->connect_port == PORT_STREAMLOCAL)
2569 				printf(" %s", fwd->connect_path);
2570 			else if (fwd->connect_host == NULL)
2571 				printf(" %d", fwd->connect_port);
2572 			else {
2573 				printf(" [%s]:%d",
2574 				    fwd->connect_host, fwd->connect_port);
2575 			}
2576 		}
2577 		printf("\n");
2578 	}
2579 }
2580 
2581 void
dump_client_config(Options * o,const char * host)2582 dump_client_config(Options *o, const char *host)
2583 {
2584 	int i;
2585 	char buf[8], *all_key;
2586 
2587 	/* This is normally prepared in ssh_kex2 */
2588 	all_key = sshkey_alg_list(0, 0, 1, ',');
2589 	if (kex_assemble_names( &o->hostkeyalgorithms,
2590 	    KEX_DEFAULT_PK_ALG, all_key) != 0)
2591 		fatal("%s: kex_assemble_names failed", __func__);
2592 	free(all_key);
2593 
2594 	/* Most interesting options first: user, host, port */
2595 	dump_cfg_string(oUser, o->user);
2596 	dump_cfg_string(oHostname, host);
2597 	dump_cfg_int(oPort, o->port);
2598 
2599 	/* Flag options */
2600 	dump_cfg_fmtint(oAddKeysToAgent, o->add_keys_to_agent);
2601 	dump_cfg_fmtint(oAddressFamily, o->address_family);
2602 	dump_cfg_fmtint(oBatchMode, o->batch_mode);
2603 	dump_cfg_fmtint(oCanonicalizeFallbackLocal, o->canonicalize_fallback_local);
2604 	dump_cfg_fmtint(oCanonicalizeHostname, o->canonicalize_hostname);
2605 	dump_cfg_fmtint(oChallengeResponseAuthentication, o->challenge_response_authentication);
2606 	dump_cfg_fmtint(oCheckHostIP, o->check_host_ip);
2607 	dump_cfg_fmtint(oCompression, o->compression);
2608 	dump_cfg_fmtint(oControlMaster, o->control_master);
2609 	dump_cfg_fmtint(oEnableSSHKeysign, o->enable_ssh_keysign);
2610 	dump_cfg_fmtint(oClearAllForwardings, o->clear_forwardings);
2611 	dump_cfg_fmtint(oExitOnForwardFailure, o->exit_on_forward_failure);
2612 	dump_cfg_fmtint(oFingerprintHash, o->fingerprint_hash);
2613 	dump_cfg_fmtint(oForwardAgent, o->forward_agent);
2614 	dump_cfg_fmtint(oForwardX11, o->forward_x11);
2615 	dump_cfg_fmtint(oForwardX11Trusted, o->forward_x11_trusted);
2616 	dump_cfg_fmtint(oGatewayPorts, o->fwd_opts.gateway_ports);
2617 #ifdef GSSAPI
2618 	dump_cfg_fmtint(oGssAuthentication, o->gss_authentication);
2619 	dump_cfg_fmtint(oGssDelegateCreds, o->gss_deleg_creds);
2620 #endif /* GSSAPI */
2621 	dump_cfg_fmtint(oHashKnownHosts, o->hash_known_hosts);
2622 	dump_cfg_fmtint(oHostbasedAuthentication, o->hostbased_authentication);
2623 	dump_cfg_fmtint(oIdentitiesOnly, o->identities_only);
2624 	dump_cfg_fmtint(oKbdInteractiveAuthentication, o->kbd_interactive_authentication);
2625 	dump_cfg_fmtint(oNoHostAuthenticationForLocalhost, o->no_host_authentication_for_localhost);
2626 	dump_cfg_fmtint(oPasswordAuthentication, o->password_authentication);
2627 	dump_cfg_fmtint(oPermitLocalCommand, o->permit_local_command);
2628 	dump_cfg_fmtint(oProxyUseFdpass, o->proxy_use_fdpass);
2629 	dump_cfg_fmtint(oPubkeyAuthentication, o->pubkey_authentication);
2630 	dump_cfg_fmtint(oRequestTTY, o->request_tty);
2631 	dump_cfg_fmtint(oStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink);
2632 	dump_cfg_fmtint(oStrictHostKeyChecking, o->strict_host_key_checking);
2633 	dump_cfg_fmtint(oTCPKeepAlive, o->tcp_keep_alive);
2634 	dump_cfg_fmtint(oTunnel, o->tun_open);
2635 	dump_cfg_fmtint(oVerifyHostKeyDNS, o->verify_host_key_dns);
2636 	dump_cfg_fmtint(oVisualHostKey, o->visual_host_key);
2637 	dump_cfg_fmtint(oUpdateHostkeys, o->update_hostkeys);
2638 
2639 	/* Integer options */
2640 	dump_cfg_int(oCanonicalizeMaxDots, o->canonicalize_max_dots);
2641 	dump_cfg_int(oConnectionAttempts, o->connection_attempts);
2642 	dump_cfg_int(oForwardX11Timeout, o->forward_x11_timeout);
2643 	dump_cfg_int(oNumberOfPasswordPrompts, o->number_of_password_prompts);
2644 	dump_cfg_int(oServerAliveCountMax, o->server_alive_count_max);
2645 	dump_cfg_int(oServerAliveInterval, o->server_alive_interval);
2646 
2647 	/* String options */
2648 	dump_cfg_string(oBindAddress, o->bind_address);
2649 	dump_cfg_string(oBindInterface, o->bind_interface);
2650 	dump_cfg_string(oCiphers, o->ciphers ? o->ciphers : KEX_CLIENT_ENCRYPT);
2651 	dump_cfg_string(oControlPath, o->control_path);
2652 	dump_cfg_string(oHostKeyAlgorithms, o->hostkeyalgorithms);
2653 	dump_cfg_string(oHostKeyAlias, o->host_key_alias);
2654 	dump_cfg_string(oHostbasedKeyTypes, o->hostbased_key_types);
2655 	dump_cfg_string(oIdentityAgent, o->identity_agent);
2656 	dump_cfg_string(oIgnoreUnknown, o->ignored_unknown);
2657 	dump_cfg_string(oKbdInteractiveDevices, o->kbd_interactive_devices);
2658 	dump_cfg_string(oKexAlgorithms, o->kex_algorithms ? o->kex_algorithms : KEX_CLIENT_KEX);
2659 	dump_cfg_string(oCASignatureAlgorithms, o->ca_sign_algorithms ? o->ca_sign_algorithms : SSH_ALLOWED_CA_SIGALGS);
2660 	dump_cfg_string(oLocalCommand, o->local_command);
2661 	dump_cfg_string(oRemoteCommand, o->remote_command);
2662 	dump_cfg_string(oLogLevel, log_level_name(o->log_level));
2663 	dump_cfg_string(oMacs, o->macs ? o->macs : KEX_CLIENT_MAC);
2664 #ifdef ENABLE_PKCS11
2665 	dump_cfg_string(oPKCS11Provider, o->pkcs11_provider);
2666 #endif
2667 	dump_cfg_string(oPreferredAuthentications, o->preferred_authentications);
2668 	dump_cfg_string(oPubkeyAcceptedKeyTypes, o->pubkey_key_types);
2669 	dump_cfg_string(oRevokedHostKeys, o->revoked_host_keys);
2670 	dump_cfg_string(oXAuthLocation, o->xauth_location);
2671 
2672 	/* Forwards */
2673 	dump_cfg_forwards(oDynamicForward, o->num_local_forwards, o->local_forwards);
2674 	dump_cfg_forwards(oLocalForward, o->num_local_forwards, o->local_forwards);
2675 	dump_cfg_forwards(oRemoteForward, o->num_remote_forwards, o->remote_forwards);
2676 
2677 	/* String array options */
2678 	dump_cfg_strarray(oIdentityFile, o->num_identity_files, o->identity_files);
2679 	dump_cfg_strarray_oneline(oCanonicalDomains, o->num_canonical_domains, o->canonical_domains);
2680 	dump_cfg_strarray(oCertificateFile, o->num_certificate_files, o->certificate_files);
2681 	dump_cfg_strarray_oneline(oGlobalKnownHostsFile, o->num_system_hostfiles, o->system_hostfiles);
2682 	dump_cfg_strarray_oneline(oUserKnownHostsFile, o->num_user_hostfiles, o->user_hostfiles);
2683 	dump_cfg_strarray(oSendEnv, o->num_send_env, o->send_env);
2684 	dump_cfg_strarray(oSetEnv, o->num_setenv, o->setenv);
2685 
2686 	/* Special cases */
2687 
2688 	/* oConnectTimeout */
2689 	if (o->connection_timeout == -1)
2690 		printf("connecttimeout none\n");
2691 	else
2692 		dump_cfg_int(oConnectTimeout, o->connection_timeout);
2693 
2694 	/* oTunnelDevice */
2695 	printf("tunneldevice");
2696 	if (o->tun_local == SSH_TUNID_ANY)
2697 		printf(" any");
2698 	else
2699 		printf(" %d", o->tun_local);
2700 	if (o->tun_remote == SSH_TUNID_ANY)
2701 		printf(":any");
2702 	else
2703 		printf(":%d", o->tun_remote);
2704 	printf("\n");
2705 
2706 	/* oCanonicalizePermittedCNAMEs */
2707 	if ( o->num_permitted_cnames > 0) {
2708 		printf("canonicalizePermittedcnames");
2709 		for (i = 0; i < o->num_permitted_cnames; i++) {
2710 			printf(" %s:%s", o->permitted_cnames[i].source_list,
2711 			    o->permitted_cnames[i].target_list);
2712 		}
2713 		printf("\n");
2714 	}
2715 
2716 	/* oControlPersist */
2717 	if (o->control_persist == 0 || o->control_persist_timeout == 0)
2718 		dump_cfg_fmtint(oControlPersist, o->control_persist);
2719 	else
2720 		dump_cfg_int(oControlPersist, o->control_persist_timeout);
2721 
2722 	/* oEscapeChar */
2723 	if (o->escape_char == SSH_ESCAPECHAR_NONE)
2724 		printf("escapechar none\n");
2725 	else {
2726 		vis(buf, o->escape_char, VIS_WHITE, 0);
2727 		printf("escapechar %s\n", buf);
2728 	}
2729 
2730 	/* oIPQoS */
2731 	printf("ipqos %s ", iptos2str(o->ip_qos_interactive));
2732 	printf("%s\n", iptos2str(o->ip_qos_bulk));
2733 
2734 	/* oRekeyLimit */
2735 	printf("rekeylimit %llu %d\n",
2736 	    (unsigned long long)o->rekey_limit, o->rekey_interval);
2737 
2738 	/* oStreamLocalBindMask */
2739 	printf("streamlocalbindmask 0%o\n",
2740 	    o->fwd_opts.streamlocal_bind_mask);
2741 
2742 	/* oLogFacility */
2743 	printf("syslogfacility %s\n", log_facility_name(o->log_facility));
2744 
2745 	/* oProxyCommand / oProxyJump */
2746 	if (o->jump_host == NULL)
2747 		dump_cfg_string(oProxyCommand, o->proxy_command);
2748 	else {
2749 		/* Check for numeric addresses */
2750 		i = strchr(o->jump_host, ':') != NULL ||
2751 		    strspn(o->jump_host, "1234567890.") == strlen(o->jump_host);
2752 		snprintf(buf, sizeof(buf), "%d", o->jump_port);
2753 		printf("proxyjump %s%s%s%s%s%s%s%s%s\n",
2754 		    /* optional additional jump spec */
2755 		    o->jump_extra == NULL ? "" : o->jump_extra,
2756 		    o->jump_extra == NULL ? "" : ",",
2757 		    /* optional user */
2758 		    o->jump_user == NULL ? "" : o->jump_user,
2759 		    o->jump_user == NULL ? "" : "@",
2760 		    /* opening [ if hostname is numeric */
2761 		    i ? "[" : "",
2762 		    /* mandatory hostname */
2763 		    o->jump_host,
2764 		    /* closing ] if hostname is numeric */
2765 		    i ? "]" : "",
2766 		    /* optional port number */
2767 		    o->jump_port <= 0 ? "" : ":",
2768 		    o->jump_port <= 0 ? "" : buf);
2769 	}
2770 }
2771