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