1296853Sdes/* $OpenBSD: readconf.c,v 1.250 2016/02/08 23:40:12 djm Exp $ */
257429Smarkm/*
357429Smarkm * Author: Tatu Ylonen <ylo@cs.hut.fi>
457429Smarkm * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
557429Smarkm *                    All rights reserved
657429Smarkm * Functions for reading the configuration files.
760576Skris *
865674Skris * As far as I am concerned, the code I have written for this software
965674Skris * can be used freely for any purpose.  Any derived versions of this
1065674Skris * software must be clearly marked as such, and if the derived work is
1165674Skris * incompatible with the protocol description in the RFC file, it must be
1265674Skris * called by a name other than "ssh" or "Secure Shell".
1357429Smarkm */
1457429Smarkm
1557429Smarkm#include "includes.h"
16162856Sdes__RCSID("$FreeBSD: releng/10.3/crypto/openssh/readconf.c 296853 2016-03-14 13:05:13Z des $");
1757429Smarkm
18162856Sdes#include <sys/types.h>
19162856Sdes#include <sys/stat.h>
20162856Sdes#include <sys/socket.h>
21181918Sdes#include <sys/sysctl.h>
22262566Sdes#include <sys/wait.h>
23295367Sdes#include <sys/un.h>
24162856Sdes
25162856Sdes#include <netinet/in.h>
26221420Sdes#include <netinet/in_systm.h>
27221420Sdes#include <netinet/ip.h>
28264377Sdes#include <arpa/inet.h>
29162856Sdes
30162856Sdes#include <ctype.h>
31162856Sdes#include <errno.h>
32262566Sdes#include <fcntl.h>
33295367Sdes#include <limits.h>
34162856Sdes#include <netdb.h>
35262566Sdes#ifdef HAVE_PATHS_H
36262566Sdes# include <paths.h>
37262566Sdes#endif
38262566Sdes#include <pwd.h>
39162856Sdes#include <signal.h>
40162856Sdes#include <stdarg.h>
41162856Sdes#include <stdio.h>
42162856Sdes#include <string.h>
43162856Sdes#include <unistd.h>
44255767Sdes#ifdef HAVE_UTIL_H
45255767Sdes#include <util.h>
46255767Sdes#endif
47295367Sdes#if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS)
48295367Sdes# include <vis.h>
49295367Sdes#endif
50162856Sdes
51162856Sdes#include "xmalloc.h"
5257429Smarkm#include "ssh.h"
5376262Sgreen#include "compat.h"
5476262Sgreen#include "cipher.h"
5576262Sgreen#include "pathnames.h"
5676262Sgreen#include "log.h"
57295367Sdes#include "sshkey.h"
58295367Sdes#include "misc.h"
5957429Smarkm#include "readconf.h"
6060576Skris#include "match.h"
6176262Sgreen#include "kex.h"
6276262Sgreen#include "mac.h"
63262566Sdes#include "uidswap.h"
64295367Sdes#include "myproposal.h"
65295367Sdes#include "digest.h"
66192595Sdes#include "version.h"
6757429Smarkm
6857429Smarkm/* Format of the configuration file:
6957429Smarkm
7057429Smarkm   # Configuration data is parsed as follows:
7157429Smarkm   #  1. command line options
7257429Smarkm   #  2. user-specific file
7357429Smarkm   #  3. system-wide file
7457429Smarkm   # Any configuration value is only changed the first time it is set.
7557429Smarkm   # Thus, host-specific definitions should be at the beginning of the
7657429Smarkm   # configuration file, and defaults at the end.
7757429Smarkm
7857429Smarkm   # Host-specific declarations.  These may override anything above.  A single
7957429Smarkm   # host may match multiple declarations; these are processed in the order
8057429Smarkm   # that they are given in.
8157429Smarkm
8257429Smarkm   Host *.ngs.fi ngs.fi
8398684Sdes     User foo
8457429Smarkm
8557429Smarkm   Host fake.com
8657429Smarkm     HostName another.host.name.real.org
8757429Smarkm     User blaah
8857429Smarkm     Port 34289
8957429Smarkm     ForwardX11 no
9057429Smarkm     ForwardAgent no
9157429Smarkm
9257429Smarkm   Host books.com
9357429Smarkm     RemoteForward 9999 shadows.cs.hut.fi:9999
9457429Smarkm     Cipher 3des
9557429Smarkm
9657429Smarkm   Host fascist.blob.com
9757429Smarkm     Port 23123
9857429Smarkm     User tylonen
9957429Smarkm     PasswordAuthentication no
10057429Smarkm
10157429Smarkm   Host puukko.hut.fi
10257429Smarkm     User t35124p
10357429Smarkm     ProxyCommand ssh-proxy %h %p
10457429Smarkm
10557429Smarkm   Host *.fr
10698684Sdes     PublicKeyAuthentication no
10757429Smarkm
10857429Smarkm   Host *.su
10957429Smarkm     Cipher none
11057429Smarkm     PasswordAuthentication no
11157429Smarkm
112157019Sdes   Host vpn.fake.com
113157019Sdes     Tunnel yes
114157019Sdes     TunnelDevice 3
115157019Sdes
11657429Smarkm   # Defaults for various options
11757429Smarkm   Host *
11857429Smarkm     ForwardAgent no
11976262Sgreen     ForwardX11 no
12057429Smarkm     PasswordAuthentication yes
12157429Smarkm     RSAAuthentication yes
12257429Smarkm     RhostsRSAAuthentication yes
12357429Smarkm     StrictHostKeyChecking yes
124126277Sdes     TcpKeepAlive no
12557429Smarkm     IdentityFile ~/.ssh/identity
12657429Smarkm     Port 22
12757429Smarkm     EscapeChar ~
12857429Smarkm
12957429Smarkm*/
13057429Smarkm
13157429Smarkm/* Keyword tokens. */
13257429Smarkm
13357429Smarkmtypedef enum {
13457429Smarkm	oBadOption,
135295367Sdes	oVersionAddendum,
136262566Sdes	oHost, oMatch,
137215116Sdes	oForwardAgent, oForwardX11, oForwardX11Trusted, oForwardX11Timeout,
138215116Sdes	oGatewayPorts, oExitOnForwardFailure,
13998684Sdes	oPasswordAuthentication, oRSAAuthentication,
14076262Sgreen	oChallengeResponseAuthentication, oXAuthLocation,
14157429Smarkm	oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward,
142296853Sdes	oCertificateFile, oAddKeysToAgent,
143262566Sdes	oUser, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
14457429Smarkm	oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
14557429Smarkm	oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
146126277Sdes	oCompressionLevel, oTCPKeepAlive, oNumberOfPasswordPrompts,
14776262Sgreen	oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oMacs,
148295367Sdes	oPubkeyAuthentication,
14976262Sgreen	oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
15076262Sgreen	oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
151204917Sdes	oHostKeyAlgorithms, oBindAddress, oPKCS11Provider,
15293698Sdes	oClearAllForwardings, oNoHostAuthenticationForLocalhost,
153124211Sdes	oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
154124211Sdes	oAddressFamily, oGssAuthentication, oGssDelegateCreds,
155128461Sdes	oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
156215116Sdes	oSendEnv, oControlPath, oControlMaster, oControlPersist,
157215116Sdes	oHashKnownHosts,
158157019Sdes	oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand,
159296853Sdes	oVisualHostKey,
160262566Sdes	oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass,
161262566Sdes	oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots,
162262566Sdes	oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs,
163295367Sdes	oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys,
164295367Sdes	oFingerprintHash, oUpdateHostkeys, oHostbasedKeyTypes,
165295367Sdes	oPubkeyAcceptedKeyTypes,
166294693Sdes	oIgnoredUnknownOption, oDeprecated, oUnsupported
16757429Smarkm} OpCodes;
16857429Smarkm
16957429Smarkm/* Textual representations of the tokens. */
17057429Smarkm
17157429Smarkmstatic struct {
17257429Smarkm	const char *name;
17357429Smarkm	OpCodes opcode;
17457429Smarkm} keywords[] = {
17557429Smarkm	{ "forwardagent", oForwardAgent },
17657429Smarkm	{ "forwardx11", oForwardX11 },
177126277Sdes	{ "forwardx11trusted", oForwardX11Trusted },
178215116Sdes	{ "forwardx11timeout", oForwardX11Timeout },
179162856Sdes	{ "exitonforwardfailure", oExitOnForwardFailure },
18065674Skris	{ "xauthlocation", oXAuthLocation },
18157429Smarkm	{ "gatewayports", oGatewayPorts },
18257429Smarkm	{ "useprivilegedport", oUsePrivilegedPort },
183124211Sdes	{ "rhostsauthentication", oDeprecated },
18457429Smarkm	{ "passwordauthentication", oPasswordAuthentication },
18569591Sgreen	{ "kbdinteractiveauthentication", oKbdInteractiveAuthentication },
18669591Sgreen	{ "kbdinteractivedevices", oKbdInteractiveDevices },
18757429Smarkm	{ "rsaauthentication", oRSAAuthentication },
18876262Sgreen	{ "pubkeyauthentication", oPubkeyAuthentication },
18976262Sgreen	{ "dsaauthentication", oPubkeyAuthentication },		    /* alias */
19076262Sgreen	{ "rhostsrsaauthentication", oRhostsRSAAuthentication },
19176262Sgreen	{ "hostbasedauthentication", oHostbasedAuthentication },
19276262Sgreen	{ "challengeresponseauthentication", oChallengeResponseAuthentication },
19376262Sgreen	{ "skeyauthentication", oChallengeResponseAuthentication }, /* alias */
19476262Sgreen	{ "tisauthentication", oChallengeResponseAuthentication },  /* alias */
195124211Sdes	{ "kerberosauthentication", oUnsupported },
196124211Sdes	{ "kerberostgtpassing", oUnsupported },
197124211Sdes	{ "afstokenpassing", oUnsupported },
198124211Sdes#if defined(GSSAPI)
199124211Sdes	{ "gssapiauthentication", oGssAuthentication },
200124211Sdes	{ "gssapidelegatecredentials", oGssDelegateCreds },
201124211Sdes#else
202124211Sdes	{ "gssapiauthentication", oUnsupported },
203124211Sdes	{ "gssapidelegatecredentials", oUnsupported },
20492559Sdes#endif
20598684Sdes	{ "fallbacktorsh", oDeprecated },
20698684Sdes	{ "usersh", oDeprecated },
20757429Smarkm	{ "identityfile", oIdentityFile },
208192595Sdes	{ "identityfile2", oIdentityFile },			/* obsolete */
209128460Sdes	{ "identitiesonly", oIdentitiesOnly },
210296853Sdes	{ "certificatefile", oCertificateFile },
211296853Sdes	{ "addkeystoagent", oAddKeysToAgent },
21257429Smarkm	{ "hostname", oHostName },
21376262Sgreen	{ "hostkeyalias", oHostKeyAlias },
21457429Smarkm	{ "proxycommand", oProxyCommand },
21557429Smarkm	{ "port", oPort },
21657429Smarkm	{ "cipher", oCipher },
21760576Skris	{ "ciphers", oCiphers },
21876262Sgreen	{ "macs", oMacs },
21960576Skris	{ "protocol", oProtocol },
22057429Smarkm	{ "remoteforward", oRemoteForward },
22157429Smarkm	{ "localforward", oLocalForward },
22257429Smarkm	{ "user", oUser },
22357429Smarkm	{ "host", oHost },
224262566Sdes	{ "match", oMatch },
22557429Smarkm	{ "escapechar", oEscapeChar },
22657429Smarkm	{ "globalknownhostsfile", oGlobalKnownHostsFile },
227226046Sdes	{ "globalknownhostsfile2", oDeprecated },
228192595Sdes	{ "userknownhostsfile", oUserKnownHostsFile },
229295367Sdes	{ "userknownhostsfile2", oDeprecated },
23057429Smarkm	{ "connectionattempts", oConnectionAttempts },
23157429Smarkm	{ "batchmode", oBatchMode },
23257429Smarkm	{ "checkhostip", oCheckHostIP },
23357429Smarkm	{ "stricthostkeychecking", oStrictHostKeyChecking },
23457429Smarkm	{ "compression", oCompression },
23557429Smarkm	{ "compressionlevel", oCompressionLevel },
236126277Sdes	{ "tcpkeepalive", oTCPKeepAlive },
237126277Sdes	{ "keepalive", oTCPKeepAlive },				/* obsolete */
23857429Smarkm	{ "numberofpasswordprompts", oNumberOfPasswordPrompts },
23957429Smarkm	{ "loglevel", oLogLevel },
24076262Sgreen	{ "dynamicforward", oDynamicForward },
24176262Sgreen	{ "preferredauthentications", oPreferredAuthentications },
24276262Sgreen	{ "hostkeyalgorithms", oHostKeyAlgorithms },
24392559Sdes	{ "bindaddress", oBindAddress },
244204917Sdes#ifdef ENABLE_PKCS11
245204917Sdes	{ "smartcarddevice", oPKCS11Provider },
246204917Sdes	{ "pkcs11provider", oPKCS11Provider },
247124211Sdes#else
248124211Sdes	{ "smartcarddevice", oUnsupported },
249204917Sdes	{ "pkcs11provider", oUnsupported },
250124211Sdes#endif
25192559Sdes	{ "clearallforwardings", oClearAllForwardings },
252113911Sdes	{ "enablesshkeysign", oEnableSSHKeysign },
253124211Sdes	{ "verifyhostkeydns", oVerifyHostKeyDNS },
25492559Sdes	{ "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
255124211Sdes	{ "rekeylimit", oRekeyLimit },
256124211Sdes	{ "connecttimeout", oConnectTimeout },
257124211Sdes	{ "addressfamily", oAddressFamily },
258126277Sdes	{ "serveraliveinterval", oServerAliveInterval },
259126277Sdes	{ "serveralivecountmax", oServerAliveCountMax },
260137019Sdes	{ "sendenv", oSendEnv },
261137019Sdes	{ "controlpath", oControlPath },
262137019Sdes	{ "controlmaster", oControlMaster },
263215116Sdes	{ "controlpersist", oControlPersist },
264147005Sdes	{ "hashknownhosts", oHashKnownHosts },
265157019Sdes	{ "tunnel", oTunnel },
266157019Sdes	{ "tunneldevice", oTunnelDevice },
267157019Sdes	{ "localcommand", oLocalCommand },
268157019Sdes	{ "permitlocalcommand", oPermitLocalCommand },
269181111Sdes	{ "visualhostkey", oVisualHostKey },
270296853Sdes	{ "useroaming", oDeprecated },
271221420Sdes	{ "kexalgorithms", oKexAlgorithms },
272221420Sdes	{ "ipqos", oIPQoS },
273226046Sdes	{ "requesttty", oRequestTTY },
274262566Sdes	{ "proxyusefdpass", oProxyUseFdpass },
275262566Sdes	{ "canonicaldomains", oCanonicalDomains },
276262566Sdes	{ "canonicalizefallbacklocal", oCanonicalizeFallbackLocal },
277262566Sdes	{ "canonicalizehostname", oCanonicalizeHostname },
278262566Sdes	{ "canonicalizemaxdots", oCanonicalizeMaxDots },
279262566Sdes	{ "canonicalizepermittedcnames", oCanonicalizePermittedCNAMEs },
280295367Sdes	{ "streamlocalbindmask", oStreamLocalBindMask },
281295367Sdes	{ "streamlocalbindunlink", oStreamLocalBindUnlink },
282295367Sdes	{ "revokedhostkeys", oRevokedHostKeys },
283295367Sdes	{ "fingerprinthash", oFingerprintHash },
284295367Sdes	{ "updatehostkeys", oUpdateHostkeys },
285295367Sdes	{ "hostbasedkeytypes", oHostbasedKeyTypes },
286295367Sdes	{ "pubkeyacceptedkeytypes", oPubkeyAcceptedKeyTypes },
287255767Sdes	{ "ignoreunknown", oIgnoreUnknown },
288294693Sdes	{ "hpndisabled", oDeprecated },
289294693Sdes	{ "hpnbuffersize", oDeprecated },
290294693Sdes	{ "tcprcvbufpoll", oDeprecated },
291294693Sdes	{ "tcprcvbuf", oDeprecated },
292295367Sdes	{ "noneenabled", oUnsupported },
293295367Sdes	{ "noneswitch", oUnsupported },
29499048Sdes	{ "versionaddendum", oVersionAddendum },
295231584Sed
29692559Sdes	{ NULL, oBadOption }
29757429Smarkm};
29857429Smarkm
29957429Smarkm/*
30057429Smarkm * Adds a local TCP/IP port forward to options.  Never returns if there is an
30157429Smarkm * error.
30257429Smarkm */
30357429Smarkm
30460576Skrisvoid
305295367Sdesadd_local_forward(Options *options, const struct Forward *newfwd)
30657429Smarkm{
307295367Sdes	struct Forward *fwd;
308106130Sdes#ifndef NO_IPPORT_RESERVED_CONCEPT
30957429Smarkm	extern uid_t original_real_uid;
310181918Sdes	int ipport_reserved;
311181918Sdes#ifdef __FreeBSD__
312181918Sdes	size_t len_ipport_reserved = sizeof(ipport_reserved);
313181918Sdes
314181918Sdes	if (sysctlbyname("net.inet.ip.portrange.reservedhigh",
315181918Sdes	    &ipport_reserved, &len_ipport_reserved, NULL, 0) != 0)
316181918Sdes		ipport_reserved = IPPORT_RESERVED;
317181918Sdes	else
318181918Sdes		ipport_reserved++;
319181918Sdes#else
320181918Sdes	ipport_reserved = IPPORT_RESERVED;
321181918Sdes#endif
322181918Sdes	if (newfwd->listen_port < ipport_reserved && original_real_uid != 0)
323295367Sdes	if (newfwd->listen_port < ipport_reserved && original_real_uid != 0 &&
324295367Sdes	    newfwd->listen_path == NULL)
32576262Sgreen		fatal("Privileged ports can only be forwarded by root.");
32698941Sdes#endif
327295367Sdes	options->local_forwards = xreallocarray(options->local_forwards,
328215116Sdes	    options->num_local_forwards + 1,
329215116Sdes	    sizeof(*options->local_forwards));
33057429Smarkm	fwd = &options->local_forwards[options->num_local_forwards++];
331147005Sdes
332192595Sdes	fwd->listen_host = newfwd->listen_host;
333147005Sdes	fwd->listen_port = newfwd->listen_port;
334295367Sdes	fwd->listen_path = newfwd->listen_path;
335192595Sdes	fwd->connect_host = newfwd->connect_host;
336147005Sdes	fwd->connect_port = newfwd->connect_port;
337295367Sdes	fwd->connect_path = newfwd->connect_path;
33857429Smarkm}
33957429Smarkm
34057429Smarkm/*
34157429Smarkm * Adds a remote TCP/IP port forward to options.  Never returns if there is
34257429Smarkm * an error.
34357429Smarkm */
34457429Smarkm
34560576Skrisvoid
346295367Sdesadd_remote_forward(Options *options, const struct Forward *newfwd)
34757429Smarkm{
348295367Sdes	struct Forward *fwd;
349215116Sdes
350295367Sdes	options->remote_forwards = xreallocarray(options->remote_forwards,
351215116Sdes	    options->num_remote_forwards + 1,
352215116Sdes	    sizeof(*options->remote_forwards));
35357429Smarkm	fwd = &options->remote_forwards[options->num_remote_forwards++];
354147005Sdes
355192595Sdes	fwd->listen_host = newfwd->listen_host;
356147005Sdes	fwd->listen_port = newfwd->listen_port;
357295367Sdes	fwd->listen_path = newfwd->listen_path;
358192595Sdes	fwd->connect_host = newfwd->connect_host;
359147005Sdes	fwd->connect_port = newfwd->connect_port;
360295367Sdes	fwd->connect_path = newfwd->connect_path;
361240075Sdes	fwd->handle = newfwd->handle;
362215116Sdes	fwd->allocated_port = 0;
36357429Smarkm}
36457429Smarkm
36592559Sdesstatic void
36692559Sdesclear_forwardings(Options *options)
36792559Sdes{
36892559Sdes	int i;
36992559Sdes
370147005Sdes	for (i = 0; i < options->num_local_forwards; i++) {
371255767Sdes		free(options->local_forwards[i].listen_host);
372295367Sdes		free(options->local_forwards[i].listen_path);
373255767Sdes		free(options->local_forwards[i].connect_host);
374295367Sdes		free(options->local_forwards[i].connect_path);
375147005Sdes	}
376215116Sdes	if (options->num_local_forwards > 0) {
377255767Sdes		free(options->local_forwards);
378215116Sdes		options->local_forwards = NULL;
379215116Sdes	}
38092559Sdes	options->num_local_forwards = 0;
381147005Sdes	for (i = 0; i < options->num_remote_forwards; i++) {
382255767Sdes		free(options->remote_forwards[i].listen_host);
383295367Sdes		free(options->remote_forwards[i].listen_path);
384255767Sdes		free(options->remote_forwards[i].connect_host);
385295367Sdes		free(options->remote_forwards[i].connect_path);
386147005Sdes	}
387215116Sdes	if (options->num_remote_forwards > 0) {
388255767Sdes		free(options->remote_forwards);
389215116Sdes		options->remote_forwards = NULL;
390215116Sdes	}
39192559Sdes	options->num_remote_forwards = 0;
392157019Sdes	options->tun_open = SSH_TUNMODE_NO;
39392559Sdes}
39492559Sdes
395249016Sdesvoid
396296853Sdesadd_certificate_file(Options *options, const char *path, int userprovided)
397296853Sdes{
398296853Sdes	int i;
399296853Sdes
400296853Sdes	if (options->num_certificate_files >= SSH_MAX_CERTIFICATE_FILES)
401296853Sdes		fatal("Too many certificate files specified (max %d)",
402296853Sdes		    SSH_MAX_CERTIFICATE_FILES);
403296853Sdes
404296853Sdes	/* Avoid registering duplicates */
405296853Sdes	for (i = 0; i < options->num_certificate_files; i++) {
406296853Sdes		if (options->certificate_file_userprovided[i] == userprovided &&
407296853Sdes		    strcmp(options->certificate_files[i], path) == 0) {
408296853Sdes			debug2("%s: ignoring duplicate key %s", __func__, path);
409296853Sdes			return;
410296853Sdes		}
411296853Sdes	}
412296853Sdes
413296853Sdes	options->certificate_file_userprovided[options->num_certificate_files] =
414296853Sdes	    userprovided;
415296853Sdes	options->certificate_files[options->num_certificate_files++] =
416296853Sdes	    xstrdup(path);
417296853Sdes}
418296853Sdes
419296853Sdesvoid
420249016Sdesadd_identity_file(Options *options, const char *dir, const char *filename,
421249016Sdes    int userprovided)
422249016Sdes{
423249016Sdes	char *path;
424295367Sdes	int i;
425249016Sdes
426249016Sdes	if (options->num_identity_files >= SSH_MAX_IDENTITY_FILES)
427249016Sdes		fatal("Too many identity files specified (max %d)",
428249016Sdes		    SSH_MAX_IDENTITY_FILES);
429249016Sdes
430249016Sdes	if (dir == NULL) /* no dir, filename is absolute */
431249016Sdes		path = xstrdup(filename);
432249016Sdes	else
433249016Sdes		(void)xasprintf(&path, "%.100s%.100s", dir, filename);
434249016Sdes
435295367Sdes	/* Avoid registering duplicates */
436295367Sdes	for (i = 0; i < options->num_identity_files; i++) {
437295367Sdes		if (options->identity_file_userprovided[i] == userprovided &&
438295367Sdes		    strcmp(options->identity_files[i], path) == 0) {
439295367Sdes			debug2("%s: ignoring duplicate key %s", __func__, path);
440295367Sdes			free(path);
441295367Sdes			return;
442295367Sdes		}
443295367Sdes	}
444295367Sdes
445249016Sdes	options->identity_file_userprovided[options->num_identity_files] =
446249016Sdes	    userprovided;
447249016Sdes	options->identity_files[options->num_identity_files++] = path;
448249016Sdes}
449249016Sdes
450262566Sdesint
451262566Sdesdefault_ssh_port(void)
452262566Sdes{
453262566Sdes	static int port;
454262566Sdes	struct servent *sp;
455262566Sdes
456262566Sdes	if (port == 0) {
457262566Sdes		sp = getservbyname(SSH_SERVICE_NAME, "tcp");
458262566Sdes		port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT;
459262566Sdes	}
460262566Sdes	return port;
461262566Sdes}
462262566Sdes
46357429Smarkm/*
464262566Sdes * Execute a command in a shell.
465262566Sdes * Return its exit status or -1 on abnormal exit.
466262566Sdes */
467262566Sdesstatic int
468262566Sdesexecute_in_shell(const char *cmd)
469262566Sdes{
470296853Sdes	char *shell;
471262566Sdes	pid_t pid;
472262566Sdes	int devnull, status;
473262566Sdes	extern uid_t original_real_uid;
474262566Sdes
475262566Sdes	if ((shell = getenv("SHELL")) == NULL)
476262566Sdes		shell = _PATH_BSHELL;
477262566Sdes
478262566Sdes	/* Need this to redirect subprocess stdin/out */
479262566Sdes	if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1)
480262566Sdes		fatal("open(/dev/null): %s", strerror(errno));
481262566Sdes
482262566Sdes	debug("Executing command: '%.500s'", cmd);
483262566Sdes
484262566Sdes	/* Fork and execute the command. */
485262566Sdes	if ((pid = fork()) == 0) {
486262566Sdes		char *argv[4];
487262566Sdes
488262566Sdes		/* Child.  Permanently give up superuser privileges. */
489262566Sdes		permanently_drop_suid(original_real_uid);
490262566Sdes
491262566Sdes		/* Redirect child stdin and stdout. Leave stderr */
492262566Sdes		if (dup2(devnull, STDIN_FILENO) == -1)
493262566Sdes			fatal("dup2: %s", strerror(errno));
494262566Sdes		if (dup2(devnull, STDOUT_FILENO) == -1)
495262566Sdes			fatal("dup2: %s", strerror(errno));
496262566Sdes		if (devnull > STDERR_FILENO)
497262566Sdes			close(devnull);
498262566Sdes		closefrom(STDERR_FILENO + 1);
499262566Sdes
500262566Sdes		argv[0] = shell;
501262566Sdes		argv[1] = "-c";
502296853Sdes		argv[2] = xstrdup(cmd);
503262566Sdes		argv[3] = NULL;
504262566Sdes
505262566Sdes		execv(argv[0], argv);
506262566Sdes		error("Unable to execute '%.100s': %s", cmd, strerror(errno));
507262566Sdes		/* Die with signal to make this error apparent to parent. */
508262566Sdes		signal(SIGTERM, SIG_DFL);
509262566Sdes		kill(getpid(), SIGTERM);
510262566Sdes		_exit(1);
511262566Sdes	}
512262566Sdes	/* Parent. */
513262566Sdes	if (pid < 0)
514262566Sdes		fatal("%s: fork: %.100s", __func__, strerror(errno));
515262566Sdes
516262566Sdes	close(devnull);
517262566Sdes
518262566Sdes	while (waitpid(pid, &status, 0) == -1) {
519262566Sdes		if (errno != EINTR && errno != EAGAIN)
520262566Sdes			fatal("%s: waitpid: %s", __func__, strerror(errno));
521262566Sdes	}
522262566Sdes	if (!WIFEXITED(status)) {
523262566Sdes		error("command '%.100s' exited abnormally", cmd);
524262566Sdes		return -1;
525295367Sdes	}
526262566Sdes	debug3("command returned status %d", WEXITSTATUS(status));
527262566Sdes	return WEXITSTATUS(status);
528262566Sdes}
529262566Sdes
530262566Sdes/*
531262566Sdes * Parse and execute a Match directive.
532262566Sdes */
533262566Sdesstatic int
534262566Sdesmatch_cfg_line(Options *options, char **condition, struct passwd *pw,
535295367Sdes    const char *host_arg, const char *original_host, int post_canon,
536295367Sdes    const char *filename, int linenum)
537262566Sdes{
538295367Sdes	char *arg, *oattrib, *attrib, *cmd, *cp = *condition, *host, *criteria;
539262566Sdes	const char *ruser;
540295367Sdes	int r, port, this_result, result = 1, attributes = 0, negate;
541262566Sdes	char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV];
542262566Sdes
543262566Sdes	/*
544262566Sdes	 * Configuration is likely to be incomplete at this point so we
545262566Sdes	 * must be prepared to use default values.
546262566Sdes	 */
547262566Sdes	port = options->port <= 0 ? default_ssh_port() : options->port;
548262566Sdes	ruser = options->user == NULL ? pw->pw_name : options->user;
549296853Sdes	if (post_canon) {
550296853Sdes		host = xstrdup(options->hostname);
551296853Sdes	} else if (options->hostname != NULL) {
552262566Sdes		/* NB. Please keep in sync with ssh.c:main() */
553262566Sdes		host = percent_expand(options->hostname,
554262566Sdes		    "h", host_arg, (char *)NULL);
555296853Sdes	} else {
556262566Sdes		host = xstrdup(host_arg);
557296853Sdes	}
558262566Sdes
559295367Sdes	debug2("checking match for '%s' host %s originally %s",
560295367Sdes	    cp, host, original_host);
561295367Sdes	while ((oattrib = attrib = strdelim(&cp)) && *attrib != '\0') {
562295367Sdes		criteria = NULL;
563295367Sdes		this_result = 1;
564295367Sdes		if ((negate = attrib[0] == '!'))
565295367Sdes			attrib++;
566295367Sdes		/* criteria "all" and "canonical" have no argument */
567262566Sdes		if (strcasecmp(attrib, "all") == 0) {
568295367Sdes			if (attributes > 1 ||
569262566Sdes			    ((arg = strdelim(&cp)) != NULL && *arg != '\0')) {
570295367Sdes				error("%.200s line %d: '%s' cannot be combined "
571295367Sdes				    "with other Match attributes",
572295367Sdes				    filename, linenum, oattrib);
573262566Sdes				result = -1;
574262566Sdes				goto out;
575262566Sdes			}
576295367Sdes			if (result)
577295367Sdes				result = negate ? 0 : 1;
578262566Sdes			goto out;
579262566Sdes		}
580295367Sdes		attributes++;
581295367Sdes		if (strcasecmp(attrib, "canonical") == 0) {
582295367Sdes			r = !!post_canon;  /* force bitmask member to boolean */
583295367Sdes			if (r == (negate ? 1 : 0))
584295367Sdes				this_result = result = 0;
585295367Sdes			debug3("%.200s line %d: %smatched '%s'",
586295367Sdes			    filename, linenum,
587295367Sdes			    this_result ? "" : "not ", oattrib);
588295367Sdes			continue;
589295367Sdes		}
590295367Sdes		/* All other criteria require an argument */
591262566Sdes		if ((arg = strdelim(&cp)) == NULL || *arg == '\0') {
592262566Sdes			error("Missing Match criteria for %s", attrib);
593262566Sdes			result = -1;
594262566Sdes			goto out;
595262566Sdes		}
596262566Sdes		if (strcasecmp(attrib, "host") == 0) {
597295367Sdes			criteria = xstrdup(host);
598295367Sdes			r = match_hostname(host, arg) == 1;
599295367Sdes			if (r == (negate ? 1 : 0))
600295367Sdes				this_result = result = 0;
601262566Sdes		} else if (strcasecmp(attrib, "originalhost") == 0) {
602295367Sdes			criteria = xstrdup(original_host);
603295367Sdes			r = match_hostname(original_host, arg) == 1;
604295367Sdes			if (r == (negate ? 1 : 0))
605295367Sdes				this_result = result = 0;
606262566Sdes		} else if (strcasecmp(attrib, "user") == 0) {
607295367Sdes			criteria = xstrdup(ruser);
608295367Sdes			r = match_pattern_list(ruser, arg, 0) == 1;
609295367Sdes			if (r == (negate ? 1 : 0))
610295367Sdes				this_result = result = 0;
611262566Sdes		} else if (strcasecmp(attrib, "localuser") == 0) {
612295367Sdes			criteria = xstrdup(pw->pw_name);
613295367Sdes			r = match_pattern_list(pw->pw_name, arg, 0) == 1;
614295367Sdes			if (r == (negate ? 1 : 0))
615295367Sdes				this_result = result = 0;
616262566Sdes		} else if (strcasecmp(attrib, "exec") == 0) {
617262566Sdes			if (gethostname(thishost, sizeof(thishost)) == -1)
618262566Sdes				fatal("gethostname: %s", strerror(errno));
619262566Sdes			strlcpy(shorthost, thishost, sizeof(shorthost));
620262566Sdes			shorthost[strcspn(thishost, ".")] = '\0';
621262566Sdes			snprintf(portstr, sizeof(portstr), "%d", port);
622262566Sdes
623262566Sdes			cmd = percent_expand(arg,
624262566Sdes			    "L", shorthost,
625262566Sdes			    "d", pw->pw_dir,
626262566Sdes			    "h", host,
627262566Sdes			    "l", thishost,
628295367Sdes			    "n", original_host,
629262566Sdes			    "p", portstr,
630262566Sdes			    "r", ruser,
631262566Sdes			    "u", pw->pw_name,
632262566Sdes			    (char *)NULL);
633264377Sdes			if (result != 1) {
634264377Sdes				/* skip execution if prior predicate failed */
635295367Sdes				debug3("%.200s line %d: skipped exec "
636295367Sdes				    "\"%.100s\"", filename, linenum, cmd);
637295367Sdes				free(cmd);
638295367Sdes				continue;
639264377Sdes			}
640295367Sdes			r = execute_in_shell(cmd);
641295367Sdes			if (r == -1) {
642295367Sdes				fatal("%.200s line %d: match exec "
643295367Sdes				    "'%.100s' error", filename,
644295367Sdes				    linenum, cmd);
645295367Sdes			}
646295367Sdes			criteria = xstrdup(cmd);
647262566Sdes			free(cmd);
648295367Sdes			/* Force exit status to boolean */
649295367Sdes			r = r == 0;
650295367Sdes			if (r == (negate ? 1 : 0))
651295367Sdes				this_result = result = 0;
652262566Sdes		} else {
653262566Sdes			error("Unsupported Match attribute %s", attrib);
654262566Sdes			result = -1;
655262566Sdes			goto out;
656262566Sdes		}
657295367Sdes		debug3("%.200s line %d: %smatched '%s \"%.100s\"' ",
658295367Sdes		    filename, linenum, this_result ? "": "not ",
659295367Sdes		    oattrib, criteria);
660295367Sdes		free(criteria);
661262566Sdes	}
662262566Sdes	if (attributes == 0) {
663262566Sdes		error("One or more attributes required for Match");
664262566Sdes		result = -1;
665262566Sdes		goto out;
666262566Sdes	}
667295367Sdes out:
668295367Sdes	if (result != -1)
669295367Sdes		debug2("match %sfound", result ? "" : "not ");
670262566Sdes	*condition = cp;
671262566Sdes	free(host);
672262566Sdes	return result;
673262566Sdes}
674262566Sdes
675262566Sdes/* Check and prepare a domain name: removes trailing '.' and lowercases */
676262566Sdesstatic void
677262566Sdesvalid_domain(char *name, const char *filename, int linenum)
678262566Sdes{
679262566Sdes	size_t i, l = strlen(name);
680262566Sdes	u_char c, last = '\0';
681262566Sdes
682262566Sdes	if (l == 0)
683262566Sdes		fatal("%s line %d: empty hostname suffix", filename, linenum);
684262566Sdes	if (!isalpha((u_char)name[0]) && !isdigit((u_char)name[0]))
685262566Sdes		fatal("%s line %d: hostname suffix \"%.100s\" "
686262566Sdes		    "starts with invalid character", filename, linenum, name);
687262566Sdes	for (i = 0; i < l; i++) {
688262566Sdes		c = tolower((u_char)name[i]);
689262566Sdes		name[i] = (char)c;
690262566Sdes		if (last == '.' && c == '.')
691262566Sdes			fatal("%s line %d: hostname suffix \"%.100s\" contains "
692262566Sdes			    "consecutive separators", filename, linenum, name);
693262566Sdes		if (c != '.' && c != '-' && !isalnum(c) &&
694262566Sdes		    c != '_') /* technically invalid, but common */
695262566Sdes			fatal("%s line %d: hostname suffix \"%.100s\" contains "
696262566Sdes			    "invalid characters", filename, linenum, name);
697262566Sdes		last = c;
698262566Sdes	}
699262566Sdes	if (name[l - 1] == '.')
700262566Sdes		name[l - 1] = '\0';
701262566Sdes}
702262566Sdes
703262566Sdes/*
70476262Sgreen * Returns the number of the token pointed to by cp or oBadOption.
70557429Smarkm */
70660576Skrisstatic OpCodes
707255767Sdesparse_token(const char *cp, const char *filename, int linenum,
708255767Sdes    const char *ignored_unknown)
70957429Smarkm{
710255767Sdes	int i;
71157429Smarkm
71257429Smarkm	for (i = 0; keywords[i].name; i++)
713255767Sdes		if (strcmp(cp, keywords[i].name) == 0)
71457429Smarkm			return keywords[i].opcode;
715295367Sdes	if (ignored_unknown != NULL &&
716295367Sdes	    match_pattern_list(cp, ignored_unknown, 1) == 1)
717255767Sdes		return oIgnoredUnknownOption;
71876262Sgreen	error("%s: line %d: Bad configuration option: %s",
71976262Sgreen	    filename, linenum, cp);
72057429Smarkm	return oBadOption;
72157429Smarkm}
72257429Smarkm
723262566Sdes/* Multistate option parsing */
724262566Sdesstruct multistate {
725262566Sdes	char *key;
726262566Sdes	int value;
727262566Sdes};
728262566Sdesstatic const struct multistate multistate_flag[] = {
729262566Sdes	{ "true",			1 },
730262566Sdes	{ "false",			0 },
731262566Sdes	{ "yes",			1 },
732262566Sdes	{ "no",				0 },
733262566Sdes	{ NULL, -1 }
734262566Sdes};
735262566Sdesstatic const struct multistate multistate_yesnoask[] = {
736262566Sdes	{ "true",			1 },
737262566Sdes	{ "false",			0 },
738262566Sdes	{ "yes",			1 },
739262566Sdes	{ "no",				0 },
740262566Sdes	{ "ask",			2 },
741262566Sdes	{ NULL, -1 }
742262566Sdes};
743296853Sdesstatic const struct multistate multistate_yesnoaskconfirm[] = {
744296853Sdes	{ "true",			1 },
745296853Sdes	{ "false",			0 },
746296853Sdes	{ "yes",			1 },
747296853Sdes	{ "no",				0 },
748296853Sdes	{ "ask",			2 },
749296853Sdes	{ "confirm",			3 },
750296853Sdes	{ NULL, -1 }
751296853Sdes};
752262566Sdesstatic const struct multistate multistate_addressfamily[] = {
753262566Sdes	{ "inet",			AF_INET },
754262566Sdes	{ "inet6",			AF_INET6 },
755262566Sdes	{ "any",			AF_UNSPEC },
756262566Sdes	{ NULL, -1 }
757262566Sdes};
758262566Sdesstatic const struct multistate multistate_controlmaster[] = {
759262566Sdes	{ "true",			SSHCTL_MASTER_YES },
760262566Sdes	{ "yes",			SSHCTL_MASTER_YES },
761262566Sdes	{ "false",			SSHCTL_MASTER_NO },
762262566Sdes	{ "no",				SSHCTL_MASTER_NO },
763262566Sdes	{ "auto",			SSHCTL_MASTER_AUTO },
764262566Sdes	{ "ask",			SSHCTL_MASTER_ASK },
765262566Sdes	{ "autoask",			SSHCTL_MASTER_AUTO_ASK },
766262566Sdes	{ NULL, -1 }
767262566Sdes};
768262566Sdesstatic const struct multistate multistate_tunnel[] = {
769262566Sdes	{ "ethernet",			SSH_TUNMODE_ETHERNET },
770262566Sdes	{ "point-to-point",		SSH_TUNMODE_POINTOPOINT },
771262566Sdes	{ "true",			SSH_TUNMODE_DEFAULT },
772262566Sdes	{ "yes",			SSH_TUNMODE_DEFAULT },
773262566Sdes	{ "false",			SSH_TUNMODE_NO },
774262566Sdes	{ "no",				SSH_TUNMODE_NO },
775262566Sdes	{ NULL, -1 }
776262566Sdes};
777262566Sdesstatic const struct multistate multistate_requesttty[] = {
778262566Sdes	{ "true",			REQUEST_TTY_YES },
779262566Sdes	{ "yes",			REQUEST_TTY_YES },
780262566Sdes	{ "false",			REQUEST_TTY_NO },
781262566Sdes	{ "no",				REQUEST_TTY_NO },
782262566Sdes	{ "force",			REQUEST_TTY_FORCE },
783262566Sdes	{ "auto",			REQUEST_TTY_AUTO },
784262566Sdes	{ NULL, -1 }
785262566Sdes};
786262566Sdesstatic const struct multistate multistate_canonicalizehostname[] = {
787262566Sdes	{ "true",			SSH_CANONICALISE_YES },
788262566Sdes	{ "false",			SSH_CANONICALISE_NO },
789262566Sdes	{ "yes",			SSH_CANONICALISE_YES },
790262566Sdes	{ "no",				SSH_CANONICALISE_NO },
791262566Sdes	{ "always",			SSH_CANONICALISE_ALWAYS },
792262566Sdes	{ NULL, -1 }
793262566Sdes};
794262566Sdes
79557429Smarkm/*
79657429Smarkm * Processes a single option line as used in the configuration files. This
79757429Smarkm * only sets those values that have not already been set.
79857429Smarkm */
799113911Sdes#define WHITESPACE " \t\r\n"
80057429Smarkmint
801262566Sdesprocess_config_line(Options *options, struct passwd *pw, const char *host,
802295367Sdes    const char *original_host, char *line, const char *filename,
803295367Sdes    int linenum, int *activep, int flags)
80457429Smarkm{
805226046Sdes	char *s, **charptr, *endofnumber, *keyword, *arg, *arg2;
806226046Sdes	char **cpptr, fwdarg[256];
807255767Sdes	u_int i, *uintptr, max_entries = 0;
808262566Sdes	int negated, opcode, *intptr, value, value2, cmdline = 0;
809181111Sdes	LogLevel *log_level_ptr;
810255767Sdes	long long val64;
811113911Sdes	size_t len;
812295367Sdes	struct Forward fwd;
813262566Sdes	const struct multistate *multistate_ptr;
814262566Sdes	struct allowed_cname *cname;
81557429Smarkm
816262566Sdes	if (activep == NULL) { /* We are processing a command line directive */
817262566Sdes		cmdline = 1;
818262566Sdes		activep = &cmdline;
819262566Sdes	}
820262566Sdes
821124211Sdes	/* Strip trailing whitespace */
822295367Sdes	if ((len = strlen(line)) == 0)
823295367Sdes		return 0;
824295367Sdes	for (len--; len > 0; len--) {
825124211Sdes		if (strchr(WHITESPACE, line[len]) == NULL)
826124211Sdes			break;
827124211Sdes		line[len] = '\0';
828124211Sdes	}
829124211Sdes
83065674Skris	s = line;
83165674Skris	/* Get the keyword. (Each line is supposed to begin with a keyword). */
832162856Sdes	if ((keyword = strdelim(&s)) == NULL)
833162856Sdes		return 0;
83465674Skris	/* Ignore leading whitespace. */
83565674Skris	if (*keyword == '\0')
83665674Skris		keyword = strdelim(&s);
83776262Sgreen	if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#')
83857429Smarkm		return 0;
839255767Sdes	/* Match lowercase keyword */
840262566Sdes	lowercase(keyword);
84157429Smarkm
842255767Sdes	opcode = parse_token(keyword, filename, linenum,
843255767Sdes	    options->ignored_unknown);
84457429Smarkm
84557429Smarkm	switch (opcode) {
84657429Smarkm	case oBadOption:
84757429Smarkm		/* don't panic, but count bad options */
84857429Smarkm		return -1;
84957429Smarkm		/* NOTREACHED */
850255767Sdes	case oIgnoredUnknownOption:
851255767Sdes		debug("%s line %d: Ignored unknown option \"%s\"",
852255767Sdes		    filename, linenum, keyword);
853255767Sdes		return 0;
854124211Sdes	case oConnectTimeout:
855124211Sdes		intptr = &options->connection_timeout;
856126277Sdesparse_time:
857124211Sdes		arg = strdelim(&s);
858124211Sdes		if (!arg || *arg == '\0')
859124211Sdes			fatal("%s line %d: missing time value.",
860124211Sdes			    filename, linenum);
861295367Sdes		if (strcmp(arg, "none") == 0)
862295367Sdes			value = -1;
863295367Sdes		else if ((value = convtime(arg)) == -1)
864124211Sdes			fatal("%s line %d: invalid time value.",
865124211Sdes			    filename, linenum);
866181111Sdes		if (*activep && *intptr == -1)
867124211Sdes			*intptr = value;
868124211Sdes		break;
869124211Sdes
87057429Smarkm	case oForwardAgent:
87157429Smarkm		intptr = &options->forward_agent;
872262566Sdes parse_flag:
873262566Sdes		multistate_ptr = multistate_flag;
874262566Sdes parse_multistate:
87565674Skris		arg = strdelim(&s);
87665674Skris		if (!arg || *arg == '\0')
877262566Sdes			fatal("%s line %d: missing argument.",
878262566Sdes			    filename, linenum);
879262566Sdes		value = -1;
880262566Sdes		for (i = 0; multistate_ptr[i].key != NULL; i++) {
881262566Sdes			if (strcasecmp(arg, multistate_ptr[i].key) == 0) {
882262566Sdes				value = multistate_ptr[i].value;
883262566Sdes				break;
884262566Sdes			}
885262566Sdes		}
886262566Sdes		if (value == -1)
887262566Sdes			fatal("%s line %d: unsupported option \"%s\".",
888262566Sdes			    filename, linenum, arg);
88957429Smarkm		if (*activep && *intptr == -1)
89057429Smarkm			*intptr = value;
89157429Smarkm		break;
89257429Smarkm
89357429Smarkm	case oForwardX11:
89457429Smarkm		intptr = &options->forward_x11;
89557429Smarkm		goto parse_flag;
89657429Smarkm
897126277Sdes	case oForwardX11Trusted:
898126277Sdes		intptr = &options->forward_x11_trusted;
899126277Sdes		goto parse_flag;
900295367Sdes
901215116Sdes	case oForwardX11Timeout:
902215116Sdes		intptr = &options->forward_x11_timeout;
903215116Sdes		goto parse_time;
904126277Sdes
90557429Smarkm	case oGatewayPorts:
906295367Sdes		intptr = &options->fwd_opts.gateway_ports;
90757429Smarkm		goto parse_flag;
90857429Smarkm
909162856Sdes	case oExitOnForwardFailure:
910162856Sdes		intptr = &options->exit_on_forward_failure;
911162856Sdes		goto parse_flag;
912162856Sdes
91357429Smarkm	case oUsePrivilegedPort:
91457429Smarkm		intptr = &options->use_privileged_port;
91557429Smarkm		goto parse_flag;
91657429Smarkm
91757429Smarkm	case oPasswordAuthentication:
91857429Smarkm		intptr = &options->password_authentication;
91957429Smarkm		goto parse_flag;
92057429Smarkm
92169591Sgreen	case oKbdInteractiveAuthentication:
92269591Sgreen		intptr = &options->kbd_interactive_authentication;
92369591Sgreen		goto parse_flag;
92469591Sgreen
92569591Sgreen	case oKbdInteractiveDevices:
92669591Sgreen		charptr = &options->kbd_interactive_devices;
92769591Sgreen		goto parse_string;
92869591Sgreen
92976262Sgreen	case oPubkeyAuthentication:
93076262Sgreen		intptr = &options->pubkey_authentication;
93160576Skris		goto parse_flag;
93260576Skris
93357429Smarkm	case oRSAAuthentication:
93457429Smarkm		intptr = &options->rsa_authentication;
93557429Smarkm		goto parse_flag;
93657429Smarkm
93757429Smarkm	case oRhostsRSAAuthentication:
93857429Smarkm		intptr = &options->rhosts_rsa_authentication;
93957429Smarkm		goto parse_flag;
94057429Smarkm
94176262Sgreen	case oHostbasedAuthentication:
94276262Sgreen		intptr = &options->hostbased_authentication;
94357429Smarkm		goto parse_flag;
94457429Smarkm
94592559Sdes	case oChallengeResponseAuthentication:
94692559Sdes		intptr = &options->challenge_response_authentication;
94792559Sdes		goto parse_flag;
948124211Sdes
949124211Sdes	case oGssAuthentication:
950124211Sdes		intptr = &options->gss_authentication;
95157429Smarkm		goto parse_flag;
952124211Sdes
953124211Sdes	case oGssDelegateCreds:
954124211Sdes		intptr = &options->gss_deleg_creds;
95576262Sgreen		goto parse_flag;
956124211Sdes
95757429Smarkm	case oBatchMode:
95857429Smarkm		intptr = &options->batch_mode;
95957429Smarkm		goto parse_flag;
96057429Smarkm
96157429Smarkm	case oCheckHostIP:
96257429Smarkm		intptr = &options->check_host_ip;
96357429Smarkm		goto parse_flag;
96457429Smarkm
965124211Sdes	case oVerifyHostKeyDNS:
966124211Sdes		intptr = &options->verify_host_key_dns;
967262566Sdes		multistate_ptr = multistate_yesnoask;
968262566Sdes		goto parse_multistate;
969124211Sdes
97057429Smarkm	case oStrictHostKeyChecking:
97157429Smarkm		intptr = &options->strict_host_key_checking;
972262566Sdes		multistate_ptr = multistate_yesnoask;
973262566Sdes		goto parse_multistate;
97457429Smarkm
97557429Smarkm	case oCompression:
97657429Smarkm		intptr = &options->compression;
97757429Smarkm		goto parse_flag;
97857429Smarkm
979126277Sdes	case oTCPKeepAlive:
980126277Sdes		intptr = &options->tcp_keep_alive;
98157429Smarkm		goto parse_flag;
98257429Smarkm
98392559Sdes	case oNoHostAuthenticationForLocalhost:
98492559Sdes		intptr = &options->no_host_authentication_for_localhost;
98592559Sdes		goto parse_flag;
98692559Sdes
98757429Smarkm	case oNumberOfPasswordPrompts:
98857429Smarkm		intptr = &options->number_of_password_prompts;
98957429Smarkm		goto parse_int;
99057429Smarkm
99157429Smarkm	case oCompressionLevel:
99257429Smarkm		intptr = &options->compression_level;
99357429Smarkm		goto parse_int;
99457429Smarkm
995124211Sdes	case oRekeyLimit:
996124211Sdes		arg = strdelim(&s);
997124211Sdes		if (!arg || *arg == '\0')
998255767Sdes			fatal("%.200s line %d: Missing argument.", filename,
999255767Sdes			    linenum);
1000255767Sdes		if (strcmp(arg, "default") == 0) {
1001255767Sdes			val64 = 0;
1002255767Sdes		} else {
1003255767Sdes			if (scan_scaled(arg, &val64) == -1)
1004255767Sdes				fatal("%.200s line %d: Bad number '%s': %s",
1005255767Sdes				    filename, linenum, arg, strerror(errno));
1006255767Sdes			if (val64 != 0 && val64 < 16)
1007255767Sdes				fatal("%.200s line %d: RekeyLimit too small",
1008255767Sdes				    filename, linenum);
1009124211Sdes		}
1010181111Sdes		if (*activep && options->rekey_limit == -1)
1011296853Sdes			options->rekey_limit = val64;
1012255767Sdes		if (s != NULL) { /* optional rekey interval present */
1013255767Sdes			if (strcmp(s, "none") == 0) {
1014255767Sdes				(void)strdelim(&s);	/* discard */
1015255767Sdes				break;
1016255767Sdes			}
1017255767Sdes			intptr = &options->rekey_interval;
1018255767Sdes			goto parse_time;
1019255767Sdes		}
1020124211Sdes		break;
1021124211Sdes
102257429Smarkm	case oIdentityFile:
102365674Skris		arg = strdelim(&s);
102465674Skris		if (!arg || *arg == '\0')
102557429Smarkm			fatal("%.200s line %d: Missing argument.", filename, linenum);
102657429Smarkm		if (*activep) {
102776262Sgreen			intptr = &options->num_identity_files;
102860576Skris			if (*intptr >= SSH_MAX_IDENTITY_FILES)
102957429Smarkm				fatal("%.200s line %d: Too many identity files specified (max %d).",
103092559Sdes				    filename, linenum, SSH_MAX_IDENTITY_FILES);
1031295367Sdes			add_identity_file(options, NULL,
1032295367Sdes			    arg, flags & SSHCONF_USERCONF);
103357429Smarkm		}
103457429Smarkm		break;
103557429Smarkm
1036296853Sdes	case oCertificateFile:
1037296853Sdes		arg = strdelim(&s);
1038296853Sdes		if (!arg || *arg == '\0')
1039296853Sdes			fatal("%.200s line %d: Missing argument.",
1040296853Sdes			    filename, linenum);
1041296853Sdes		if (*activep) {
1042296853Sdes			intptr = &options->num_certificate_files;
1043296853Sdes			if (*intptr >= SSH_MAX_CERTIFICATE_FILES) {
1044296853Sdes				fatal("%.200s line %d: Too many certificate "
1045296853Sdes				    "files specified (max %d).",
1046296853Sdes				    filename, linenum,
1047296853Sdes				    SSH_MAX_CERTIFICATE_FILES);
1048296853Sdes			}
1049296853Sdes			add_certificate_file(options, arg,
1050296853Sdes			    flags & SSHCONF_USERCONF);
1051296853Sdes		}
1052296853Sdes		break;
1053296853Sdes
105465674Skris	case oXAuthLocation:
105565674Skris		charptr=&options->xauth_location;
105665674Skris		goto parse_string;
105765674Skris
105857429Smarkm	case oUser:
105957429Smarkm		charptr = &options->user;
106057429Smarkmparse_string:
106165674Skris		arg = strdelim(&s);
106265674Skris		if (!arg || *arg == '\0')
1063226046Sdes			fatal("%.200s line %d: Missing argument.",
1064226046Sdes			    filename, linenum);
106557429Smarkm		if (*activep && *charptr == NULL)
106665674Skris			*charptr = xstrdup(arg);
106757429Smarkm		break;
106857429Smarkm
106957429Smarkm	case oGlobalKnownHostsFile:
1070226046Sdes		cpptr = (char **)&options->system_hostfiles;
1071226046Sdes		uintptr = &options->num_system_hostfiles;
1072226046Sdes		max_entries = SSH_MAX_HOSTS_FILES;
1073226046Sdesparse_char_array:
1074226046Sdes		if (*activep && *uintptr == 0) {
1075226046Sdes			while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1076226046Sdes				if ((*uintptr) >= max_entries)
1077226046Sdes					fatal("%s line %d: "
1078226046Sdes					    "too many authorized keys files.",
1079226046Sdes					    filename, linenum);
1080226046Sdes				cpptr[(*uintptr)++] = xstrdup(arg);
1081226046Sdes			}
1082226046Sdes		}
1083226046Sdes		return 0;
108457429Smarkm
108557429Smarkm	case oUserKnownHostsFile:
1086226046Sdes		cpptr = (char **)&options->user_hostfiles;
1087226046Sdes		uintptr = &options->num_user_hostfiles;
1088226046Sdes		max_entries = SSH_MAX_HOSTS_FILES;
1089226046Sdes		goto parse_char_array;
109057429Smarkm
109157429Smarkm	case oHostName:
109257429Smarkm		charptr = &options->hostname;
109357429Smarkm		goto parse_string;
109457429Smarkm
109576262Sgreen	case oHostKeyAlias:
109676262Sgreen		charptr = &options->host_key_alias;
109776262Sgreen		goto parse_string;
109876262Sgreen
109976262Sgreen	case oPreferredAuthentications:
110076262Sgreen		charptr = &options->preferred_authentications;
110176262Sgreen		goto parse_string;
110276262Sgreen
110392559Sdes	case oBindAddress:
110492559Sdes		charptr = &options->bind_address;
110592559Sdes		goto parse_string;
110692559Sdes
1107204917Sdes	case oPKCS11Provider:
1108204917Sdes		charptr = &options->pkcs11_provider;
110992559Sdes		goto parse_string;
111092559Sdes
111157429Smarkm	case oProxyCommand:
1112157019Sdes		charptr = &options->proxy_command;
1113157019Sdesparse_command:
1114124211Sdes		if (s == NULL)
1115124211Sdes			fatal("%.200s line %d: Missing argument.", filename, linenum);
1116113911Sdes		len = strspn(s, WHITESPACE "=");
111757429Smarkm		if (*activep && *charptr == NULL)
1118113911Sdes			*charptr = xstrdup(s + len);
111957429Smarkm		return 0;
112057429Smarkm
112157429Smarkm	case oPort:
112257429Smarkm		intptr = &options->port;
112357429Smarkmparse_int:
112465674Skris		arg = strdelim(&s);
112565674Skris		if (!arg || *arg == '\0')
112657429Smarkm			fatal("%.200s line %d: Missing argument.", filename, linenum);
112765674Skris		if (arg[0] < '0' || arg[0] > '9')
112857429Smarkm			fatal("%.200s line %d: Bad number.", filename, linenum);
112957429Smarkm
113057429Smarkm		/* Octal, decimal, or hex format? */
113165674Skris		value = strtol(arg, &endofnumber, 0);
113265674Skris		if (arg == endofnumber)
113357429Smarkm			fatal("%.200s line %d: Bad number.", filename, linenum);
113457429Smarkm		if (*activep && *intptr == -1)
113557429Smarkm			*intptr = value;
113657429Smarkm		break;
113757429Smarkm
113857429Smarkm	case oConnectionAttempts:
113957429Smarkm		intptr = &options->connection_attempts;
114057429Smarkm		goto parse_int;
114157429Smarkm
114257429Smarkm	case oCipher:
114357429Smarkm		intptr = &options->cipher;
114465674Skris		arg = strdelim(&s);
114565674Skris		if (!arg || *arg == '\0')
114661203Skris			fatal("%.200s line %d: Missing argument.", filename, linenum);
114765674Skris		value = cipher_number(arg);
114857429Smarkm		if (value == -1)
114957429Smarkm			fatal("%.200s line %d: Bad cipher '%s'.",
115092559Sdes			    filename, linenum, arg ? arg : "<NONE>");
115157429Smarkm		if (*activep && *intptr == -1)
115257429Smarkm			*intptr = value;
115357429Smarkm		break;
115457429Smarkm
115560576Skris	case oCiphers:
115665674Skris		arg = strdelim(&s);
115765674Skris		if (!arg || *arg == '\0')
115861203Skris			fatal("%.200s line %d: Missing argument.", filename, linenum);
1159295367Sdes		if (!ciphers_valid(*arg == '+' ? arg + 1 : arg))
116060576Skris			fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.",
116192559Sdes			    filename, linenum, arg ? arg : "<NONE>");
116260576Skris		if (*activep && options->ciphers == NULL)
116365674Skris			options->ciphers = xstrdup(arg);
116460576Skris		break;
116560576Skris
116676262Sgreen	case oMacs:
116776262Sgreen		arg = strdelim(&s);
116876262Sgreen		if (!arg || *arg == '\0')
116976262Sgreen			fatal("%.200s line %d: Missing argument.", filename, linenum);
1170295367Sdes		if (!mac_valid(*arg == '+' ? arg + 1 : arg))
117176262Sgreen			fatal("%.200s line %d: Bad SSH2 Mac spec '%s'.",
117292559Sdes			    filename, linenum, arg ? arg : "<NONE>");
117376262Sgreen		if (*activep && options->macs == NULL)
117476262Sgreen			options->macs = xstrdup(arg);
117576262Sgreen		break;
117676262Sgreen
1177221420Sdes	case oKexAlgorithms:
1178221420Sdes		arg = strdelim(&s);
1179221420Sdes		if (!arg || *arg == '\0')
1180221420Sdes			fatal("%.200s line %d: Missing argument.",
1181221420Sdes			    filename, linenum);
1182295367Sdes		if (!kex_names_valid(*arg == '+' ? arg + 1 : arg))
1183221420Sdes			fatal("%.200s line %d: Bad SSH2 KexAlgorithms '%s'.",
1184221420Sdes			    filename, linenum, arg ? arg : "<NONE>");
1185221420Sdes		if (*activep && options->kex_algorithms == NULL)
1186221420Sdes			options->kex_algorithms = xstrdup(arg);
1187221420Sdes		break;
1188221420Sdes
118976262Sgreen	case oHostKeyAlgorithms:
1190295367Sdes		charptr = &options->hostkeyalgorithms;
1191295367Sdesparse_keytypes:
119276262Sgreen		arg = strdelim(&s);
119376262Sgreen		if (!arg || *arg == '\0')
1194295367Sdes			fatal("%.200s line %d: Missing argument.",
1195295367Sdes			    filename, linenum);
1196295367Sdes		if (!sshkey_names_valid2(*arg == '+' ? arg + 1 : arg, 1))
1197295367Sdes			fatal("%s line %d: Bad key types '%s'.",
1198295367Sdes				filename, linenum, arg ? arg : "<NONE>");
1199295367Sdes		if (*activep && *charptr == NULL)
1200295367Sdes			*charptr = xstrdup(arg);
120176262Sgreen		break;
120276262Sgreen
120360576Skris	case oProtocol:
120460576Skris		intptr = &options->protocol;
120565674Skris		arg = strdelim(&s);
120665674Skris		if (!arg || *arg == '\0')
120761203Skris			fatal("%.200s line %d: Missing argument.", filename, linenum);
120865674Skris		value = proto_spec(arg);
120960576Skris		if (value == SSH_PROTO_UNKNOWN)
121060576Skris			fatal("%.200s line %d: Bad protocol spec '%s'.",
121192559Sdes			    filename, linenum, arg ? arg : "<NONE>");
121260576Skris		if (*activep && *intptr == SSH_PROTO_UNKNOWN)
121360576Skris			*intptr = value;
121460576Skris		break;
121560576Skris
121657429Smarkm	case oLogLevel:
1217181111Sdes		log_level_ptr = &options->log_level;
121865674Skris		arg = strdelim(&s);
121965674Skris		value = log_level_number(arg);
122092559Sdes		if (value == SYSLOG_LEVEL_NOT_SET)
122176262Sgreen			fatal("%.200s line %d: unsupported log level '%s'",
122292559Sdes			    filename, linenum, arg ? arg : "<NONE>");
1223181111Sdes		if (*activep && *log_level_ptr == SYSLOG_LEVEL_NOT_SET)
1224181111Sdes			*log_level_ptr = (LogLevel) value;
122557429Smarkm		break;
122657429Smarkm
122792559Sdes	case oLocalForward:
122857429Smarkm	case oRemoteForward:
1229192595Sdes	case oDynamicForward:
123065674Skris		arg = strdelim(&s);
1231147005Sdes		if (arg == NULL || *arg == '\0')
123292559Sdes			fatal("%.200s line %d: Missing port argument.",
123392559Sdes			    filename, linenum);
1234147005Sdes
1235192595Sdes		if (opcode == oLocalForward ||
1236192595Sdes		    opcode == oRemoteForward) {
1237192595Sdes			arg2 = strdelim(&s);
1238192595Sdes			if (arg2 == NULL || *arg2 == '\0')
1239192595Sdes				fatal("%.200s line %d: Missing target argument.",
1240192595Sdes				    filename, linenum);
1241147005Sdes
1242192595Sdes			/* construct a string for parse_forward */
1243192595Sdes			snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg, arg2);
1244192595Sdes		} else if (opcode == oDynamicForward) {
1245192595Sdes			strlcpy(fwdarg, arg, sizeof(fwdarg));
1246192595Sdes		}
1247192595Sdes
1248192595Sdes		if (parse_forward(&fwd, fwdarg,
1249192595Sdes		    opcode == oDynamicForward ? 1 : 0,
1250192595Sdes		    opcode == oRemoteForward ? 1 : 0) == 0)
125192559Sdes			fatal("%.200s line %d: Bad forwarding specification.",
125292559Sdes			    filename, linenum);
1253147005Sdes
125492559Sdes		if (*activep) {
1255192595Sdes			if (opcode == oLocalForward ||
1256192595Sdes			    opcode == oDynamicForward)
1257147005Sdes				add_local_forward(options, &fwd);
125892559Sdes			else if (opcode == oRemoteForward)
1259147005Sdes				add_remote_forward(options, &fwd);
126092559Sdes		}
126157429Smarkm		break;
126257429Smarkm
126392559Sdes	case oClearAllForwardings:
126492559Sdes		intptr = &options->clear_forwardings;
126592559Sdes		goto parse_flag;
126692559Sdes
126757429Smarkm	case oHost:
1268262566Sdes		if (cmdline)
1269262566Sdes			fatal("Host directive not supported as a command-line "
1270262566Sdes			    "option");
127157429Smarkm		*activep = 0;
1272226046Sdes		arg2 = NULL;
1273226046Sdes		while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1274226046Sdes			negated = *arg == '!';
1275226046Sdes			if (negated)
1276226046Sdes				arg++;
127765674Skris			if (match_pattern(host, arg)) {
1278226046Sdes				if (negated) {
1279226046Sdes					debug("%.200s line %d: Skipping Host "
1280226046Sdes					    "block because of negated match "
1281226046Sdes					    "for %.100s", filename, linenum,
1282226046Sdes					    arg);
1283226046Sdes					*activep = 0;
1284226046Sdes					break;
1285226046Sdes				}
1286226046Sdes				if (!*activep)
1287226046Sdes					arg2 = arg; /* logged below */
128857429Smarkm				*activep = 1;
128957429Smarkm			}
1290226046Sdes		}
1291226046Sdes		if (*activep)
1292226046Sdes			debug("%.200s line %d: Applying options for %.100s",
1293226046Sdes			    filename, linenum, arg2);
129465674Skris		/* Avoid garbage check below, as strdelim is done. */
129557429Smarkm		return 0;
129657429Smarkm
1297262566Sdes	case oMatch:
1298262566Sdes		if (cmdline)
1299262566Sdes			fatal("Host directive not supported as a command-line "
1300262566Sdes			    "option");
1301295367Sdes		value = match_cfg_line(options, &s, pw, host, original_host,
1302295367Sdes		    flags & SSHCONF_POSTCANON, filename, linenum);
1303262566Sdes		if (value < 0)
1304262566Sdes			fatal("%.200s line %d: Bad Match condition", filename,
1305262566Sdes			    linenum);
1306262566Sdes		*activep = value;
1307262566Sdes		break;
1308262566Sdes
130957429Smarkm	case oEscapeChar:
131057429Smarkm		intptr = &options->escape_char;
131165674Skris		arg = strdelim(&s);
131265674Skris		if (!arg || *arg == '\0')
131357429Smarkm			fatal("%.200s line %d: Missing argument.", filename, linenum);
1314295367Sdes		if (strcmp(arg, "none") == 0)
1315295367Sdes			value = SSH_ESCAPECHAR_NONE;
1316295367Sdes		else if (arg[1] == '\0')
1317295367Sdes			value = (u_char) arg[0];
1318295367Sdes		else if (arg[0] == '^' && arg[2] == 0 &&
131976262Sgreen		    (u_char) arg[1] >= 64 && (u_char) arg[1] < 128)
132076262Sgreen			value = (u_char) arg[1] & 31;
132157429Smarkm		else {
132257429Smarkm			fatal("%.200s line %d: Bad escape character.",
132392559Sdes			    filename, linenum);
132457429Smarkm			/* NOTREACHED */
132557429Smarkm			value = 0;	/* Avoid compiler warning. */
132657429Smarkm		}
132757429Smarkm		if (*activep && *intptr == -1)
132857429Smarkm			*intptr = value;
132957429Smarkm		break;
133057429Smarkm
1331124211Sdes	case oAddressFamily:
1332124211Sdes		intptr = &options->address_family;
1333262566Sdes		multistate_ptr = multistate_addressfamily;
1334262566Sdes		goto parse_multistate;
1335124211Sdes
1336113911Sdes	case oEnableSSHKeysign:
1337113911Sdes		intptr = &options->enable_ssh_keysign;
1338113911Sdes		goto parse_flag;
1339113911Sdes
1340128460Sdes	case oIdentitiesOnly:
1341128460Sdes		intptr = &options->identities_only;
1342128460Sdes		goto parse_flag;
1343128460Sdes
1344126277Sdes	case oServerAliveInterval:
1345126277Sdes		intptr = &options->server_alive_interval;
1346126277Sdes		goto parse_time;
1347126277Sdes
1348126277Sdes	case oServerAliveCountMax:
1349126277Sdes		intptr = &options->server_alive_count_max;
1350126277Sdes		goto parse_int;
1351126277Sdes
1352137019Sdes	case oSendEnv:
1353137019Sdes		while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1354137019Sdes			if (strchr(arg, '=') != NULL)
1355137019Sdes				fatal("%s line %d: Invalid environment name.",
1356137019Sdes				    filename, linenum);
1357147005Sdes			if (!*activep)
1358147005Sdes				continue;
1359137019Sdes			if (options->num_send_env >= MAX_SEND_ENV)
1360137019Sdes				fatal("%s line %d: too many send env.",
1361137019Sdes				    filename, linenum);
1362137019Sdes			options->send_env[options->num_send_env++] =
1363137019Sdes			    xstrdup(arg);
1364137019Sdes		}
1365137019Sdes		break;
1366137019Sdes
1367137019Sdes	case oControlPath:
1368137019Sdes		charptr = &options->control_path;
1369137019Sdes		goto parse_string;
1370137019Sdes
1371137019Sdes	case oControlMaster:
1372137019Sdes		intptr = &options->control_master;
1373262566Sdes		multistate_ptr = multistate_controlmaster;
1374262566Sdes		goto parse_multistate;
1375137019Sdes
1376215116Sdes	case oControlPersist:
1377215116Sdes		/* no/false/yes/true, or a time spec */
1378215116Sdes		intptr = &options->control_persist;
1379215116Sdes		arg = strdelim(&s);
1380215116Sdes		if (!arg || *arg == '\0')
1381215116Sdes			fatal("%.200s line %d: Missing ControlPersist"
1382215116Sdes			    " argument.", filename, linenum);
1383215116Sdes		value = 0;
1384215116Sdes		value2 = 0;	/* timeout */
1385215116Sdes		if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
1386215116Sdes			value = 0;
1387215116Sdes		else if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
1388215116Sdes			value = 1;
1389215116Sdes		else if ((value2 = convtime(arg)) >= 0)
1390215116Sdes			value = 1;
1391215116Sdes		else
1392215116Sdes			fatal("%.200s line %d: Bad ControlPersist argument.",
1393215116Sdes			    filename, linenum);
1394215116Sdes		if (*activep && *intptr == -1) {
1395215116Sdes			*intptr = value;
1396215116Sdes			options->control_persist_timeout = value2;
1397215116Sdes		}
1398215116Sdes		break;
1399215116Sdes
1400147005Sdes	case oHashKnownHosts:
1401147005Sdes		intptr = &options->hash_known_hosts;
1402147005Sdes		goto parse_flag;
1403147005Sdes
1404157019Sdes	case oTunnel:
1405157019Sdes		intptr = &options->tun_open;
1406262566Sdes		multistate_ptr = multistate_tunnel;
1407262566Sdes		goto parse_multistate;
1408157019Sdes
1409157019Sdes	case oTunnelDevice:
1410157019Sdes		arg = strdelim(&s);
1411157019Sdes		if (!arg || *arg == '\0')
1412157019Sdes			fatal("%.200s line %d: Missing argument.", filename, linenum);
1413157019Sdes		value = a2tun(arg, &value2);
1414157019Sdes		if (value == SSH_TUNID_ERR)
1415157019Sdes			fatal("%.200s line %d: Bad tun device.", filename, linenum);
1416157019Sdes		if (*activep) {
1417157019Sdes			options->tun_local = value;
1418157019Sdes			options->tun_remote = value2;
1419157019Sdes		}
1420157019Sdes		break;
1421157019Sdes
1422157019Sdes	case oLocalCommand:
1423157019Sdes		charptr = &options->local_command;
1424157019Sdes		goto parse_command;
1425157019Sdes
1426157019Sdes	case oPermitLocalCommand:
1427157019Sdes		intptr = &options->permit_local_command;
1428157019Sdes		goto parse_flag;
1429157019Sdes
1430181111Sdes	case oVisualHostKey:
1431181111Sdes		intptr = &options->visual_host_key;
1432181111Sdes		goto parse_flag;
1433181111Sdes
1434221420Sdes	case oIPQoS:
1435221420Sdes		arg = strdelim(&s);
1436221420Sdes		if ((value = parse_ipqos(arg)) == -1)
1437221420Sdes			fatal("%s line %d: Bad IPQoS value: %s",
1438221420Sdes			    filename, linenum, arg);
1439221420Sdes		arg = strdelim(&s);
1440221420Sdes		if (arg == NULL)
1441221420Sdes			value2 = value;
1442221420Sdes		else if ((value2 = parse_ipqos(arg)) == -1)
1443221420Sdes			fatal("%s line %d: Bad IPQoS value: %s",
1444221420Sdes			    filename, linenum, arg);
1445221420Sdes		if (*activep) {
1446221420Sdes			options->ip_qos_interactive = value;
1447221420Sdes			options->ip_qos_bulk = value2;
1448221420Sdes		}
1449221420Sdes		break;
1450221420Sdes
1451226046Sdes	case oRequestTTY:
1452226046Sdes		intptr = &options->request_tty;
1453262566Sdes		multistate_ptr = multistate_requesttty;
1454262566Sdes		goto parse_multistate;
145599048Sdes
1456226046Sdes	case oVersionAddendum:
1457240075Sdes		if (s == NULL)
1458240075Sdes			fatal("%.200s line %d: Missing argument.", filename,
1459240075Sdes			    linenum);
1460240075Sdes		len = strspn(s, WHITESPACE);
1461240075Sdes		if (*activep && options->version_addendum == NULL) {
1462240075Sdes			if (strcasecmp(s + len, "none") == 0)
1463240075Sdes				options->version_addendum = xstrdup("");
1464240075Sdes			else if (strchr(s + len, '\r') != NULL)
1465240075Sdes				fatal("%.200s line %d: Invalid argument",
1466240075Sdes				    filename, linenum);
1467240075Sdes			else
1468240075Sdes				options->version_addendum = xstrdup(s + len);
1469240075Sdes		}
1470240075Sdes		return 0;
1471226046Sdes
1472255767Sdes	case oIgnoreUnknown:
1473255767Sdes		charptr = &options->ignored_unknown;
1474255767Sdes		goto parse_string;
1475255767Sdes
1476262566Sdes	case oProxyUseFdpass:
1477262566Sdes		intptr = &options->proxy_use_fdpass;
1478262566Sdes		goto parse_flag;
1479262566Sdes
1480262566Sdes	case oCanonicalDomains:
1481262566Sdes		value = options->num_canonical_domains != 0;
1482262566Sdes		while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1483262566Sdes			valid_domain(arg, filename, linenum);
1484262566Sdes			if (!*activep || value)
1485262566Sdes				continue;
1486262566Sdes			if (options->num_canonical_domains >= MAX_CANON_DOMAINS)
1487262566Sdes				fatal("%s line %d: too many hostname suffixes.",
1488262566Sdes				    filename, linenum);
1489262566Sdes			options->canonical_domains[
1490262566Sdes			    options->num_canonical_domains++] = xstrdup(arg);
1491262566Sdes		}
1492262566Sdes		break;
1493262566Sdes
1494262566Sdes	case oCanonicalizePermittedCNAMEs:
1495262566Sdes		value = options->num_permitted_cnames != 0;
1496262566Sdes		while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1497262566Sdes			/* Either '*' for everything or 'list:list' */
1498262566Sdes			if (strcmp(arg, "*") == 0)
1499262566Sdes				arg2 = arg;
1500262566Sdes			else {
1501262566Sdes				lowercase(arg);
1502262566Sdes				if ((arg2 = strchr(arg, ':')) == NULL ||
1503262566Sdes				    arg2[1] == '\0') {
1504262566Sdes					fatal("%s line %d: "
1505262566Sdes					    "Invalid permitted CNAME \"%s\"",
1506262566Sdes					    filename, linenum, arg);
1507262566Sdes				}
1508262566Sdes				*arg2 = '\0';
1509262566Sdes				arg2++;
1510262566Sdes			}
1511262566Sdes			if (!*activep || value)
1512262566Sdes				continue;
1513262566Sdes			if (options->num_permitted_cnames >= MAX_CANON_DOMAINS)
1514262566Sdes				fatal("%s line %d: too many permitted CNAMEs.",
1515262566Sdes				    filename, linenum);
1516262566Sdes			cname = options->permitted_cnames +
1517262566Sdes			    options->num_permitted_cnames++;
1518262566Sdes			cname->source_list = xstrdup(arg);
1519262566Sdes			cname->target_list = xstrdup(arg2);
1520262566Sdes		}
1521262566Sdes		break;
1522262566Sdes
1523262566Sdes	case oCanonicalizeHostname:
1524262566Sdes		intptr = &options->canonicalize_hostname;
1525262566Sdes		multistate_ptr = multistate_canonicalizehostname;
1526262566Sdes		goto parse_multistate;
1527262566Sdes
1528262566Sdes	case oCanonicalizeMaxDots:
1529262566Sdes		intptr = &options->canonicalize_max_dots;
1530262566Sdes		goto parse_int;
1531262566Sdes
1532262566Sdes	case oCanonicalizeFallbackLocal:
1533262566Sdes		intptr = &options->canonicalize_fallback_local;
1534262566Sdes		goto parse_flag;
1535262566Sdes
1536295367Sdes	case oStreamLocalBindMask:
1537295367Sdes		arg = strdelim(&s);
1538295367Sdes		if (!arg || *arg == '\0')
1539295367Sdes			fatal("%.200s line %d: Missing StreamLocalBindMask argument.", filename, linenum);
1540295367Sdes		/* Parse mode in octal format */
1541295367Sdes		value = strtol(arg, &endofnumber, 8);
1542295367Sdes		if (arg == endofnumber || value < 0 || value > 0777)
1543295367Sdes			fatal("%.200s line %d: Bad mask.", filename, linenum);
1544295367Sdes		options->fwd_opts.streamlocal_bind_mask = (mode_t)value;
1545295367Sdes		break;
1546295367Sdes
1547295367Sdes	case oStreamLocalBindUnlink:
1548295367Sdes		intptr = &options->fwd_opts.streamlocal_bind_unlink;
1549295367Sdes		goto parse_flag;
1550295367Sdes
1551295367Sdes	case oRevokedHostKeys:
1552295367Sdes		charptr = &options->revoked_host_keys;
1553295367Sdes		goto parse_string;
1554295367Sdes
1555295367Sdes	case oFingerprintHash:
1556295367Sdes		intptr = &options->fingerprint_hash;
1557295367Sdes		arg = strdelim(&s);
1558295367Sdes		if (!arg || *arg == '\0')
1559295367Sdes			fatal("%.200s line %d: Missing argument.",
1560295367Sdes			    filename, linenum);
1561295367Sdes		if ((value = ssh_digest_alg_by_name(arg)) == -1)
1562295367Sdes			fatal("%.200s line %d: Invalid hash algorithm \"%s\".",
1563295367Sdes			    filename, linenum, arg);
1564295367Sdes		if (*activep && *intptr == -1)
1565295367Sdes			*intptr = value;
1566295367Sdes		break;
1567295367Sdes
1568295367Sdes	case oUpdateHostkeys:
1569295367Sdes		intptr = &options->update_hostkeys;
1570295367Sdes		multistate_ptr = multistate_yesnoask;
1571295367Sdes		goto parse_multistate;
1572295367Sdes
1573295367Sdes	case oHostbasedKeyTypes:
1574295367Sdes		charptr = &options->hostbased_key_types;
1575295367Sdes		goto parse_keytypes;
1576295367Sdes
1577295367Sdes	case oPubkeyAcceptedKeyTypes:
1578295367Sdes		charptr = &options->pubkey_key_types;
1579295367Sdes		goto parse_keytypes;
1580295367Sdes
1581296853Sdes	case oAddKeysToAgent:
1582296853Sdes		intptr = &options->add_keys_to_agent;
1583296853Sdes		multistate_ptr = multistate_yesnoaskconfirm;
1584296853Sdes		goto parse_multistate;
1585296853Sdes
158698684Sdes	case oDeprecated:
158798684Sdes		debug("%s line %d: Deprecated option \"%s\"",
158898684Sdes		    filename, linenum, keyword);
158998684Sdes		return 0;
159098684Sdes
1591124211Sdes	case oUnsupported:
1592124211Sdes		error("%s line %d: Unsupported option \"%s\"",
1593124211Sdes		    filename, linenum, keyword);
1594124211Sdes		return 0;
1595124211Sdes
159657429Smarkm	default:
1597295367Sdes		fatal("%s: Unimplemented opcode %d", __func__, opcode);
159857429Smarkm	}
159957429Smarkm
160057429Smarkm	/* Check that there is no garbage at end of line. */
160176262Sgreen	if ((arg = strdelim(&s)) != NULL && *arg != '\0') {
160265674Skris		fatal("%.200s line %d: garbage at end of line; \"%.200s\".",
1603149753Sdes		    filename, linenum, arg);
160465674Skris	}
160557429Smarkm	return 0;
160657429Smarkm}
160757429Smarkm
160857429Smarkm
160957429Smarkm/*
161057429Smarkm * Reads the config file and modifies the options accordingly.  Options
161157429Smarkm * should already be initialized before this call.  This never returns if
161292559Sdes * there is an error.  If the file does not exist, this returns 0.
161357429Smarkm */
161457429Smarkm
161592559Sdesint
1616262566Sdesread_config_file(const char *filename, struct passwd *pw, const char *host,
1617295367Sdes    const char *original_host, Options *options, int flags)
161857429Smarkm{
161957429Smarkm	FILE *f;
162057429Smarkm	char line[1024];
162157429Smarkm	int active, linenum;
162257429Smarkm	int bad_options = 0;
162357429Smarkm
1624137019Sdes	if ((f = fopen(filename, "r")) == NULL)
162592559Sdes		return 0;
162657429Smarkm
1627249839Sdes	if (flags & SSHCONF_CHECKPERM) {
1628137019Sdes		struct stat sb;
1629137019Sdes
1630137019Sdes		if (fstat(fileno(f), &sb) == -1)
1631137019Sdes			fatal("fstat %s: %s", filename, strerror(errno));
1632137019Sdes		if (((sb.st_uid != 0 && sb.st_uid != getuid()) ||
1633137019Sdes		    (sb.st_mode & 022) != 0))
1634137019Sdes			fatal("Bad owner or permissions on %s", filename);
1635137019Sdes	}
1636137019Sdes
163757429Smarkm	debug("Reading configuration data %.200s", filename);
163857429Smarkm
163957429Smarkm	/*
164057429Smarkm	 * Mark that we are now processing the options.  This flag is turned
164157429Smarkm	 * on/off by Host specifications.
164257429Smarkm	 */
164357429Smarkm	active = 1;
164457429Smarkm	linenum = 0;
164557429Smarkm	while (fgets(line, sizeof(line), f)) {
164657429Smarkm		/* Update line number counter. */
164757429Smarkm		linenum++;
1648295367Sdes		if (process_config_line(options, pw, host, original_host,
1649295367Sdes		    line, filename, linenum, &active, flags) != 0)
165057429Smarkm			bad_options++;
165157429Smarkm	}
165257429Smarkm	fclose(f);
165357429Smarkm	if (bad_options > 0)
165476262Sgreen		fatal("%s: terminating, %d bad configuration options",
165592559Sdes		    filename, bad_options);
165692559Sdes	return 1;
165757429Smarkm}
165857429Smarkm
1659264377Sdes/* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */
1660264377Sdesint
1661264377Sdesoption_clear_or_none(const char *o)
1662264377Sdes{
1663264377Sdes	return o == NULL || strcasecmp(o, "none") == 0;
1664264377Sdes}
1665264377Sdes
166657429Smarkm/*
166757429Smarkm * Initializes options to special values that indicate that they have not yet
166857429Smarkm * been set.  Read_config_file will only set options with this value. Options
166957429Smarkm * are processed in the following order: command line, user config file,
167057429Smarkm * system config file.  Last, fill_default_options is called.
167157429Smarkm */
167257429Smarkm
167360576Skrisvoid
167457429Smarkminitialize_options(Options * options)
167557429Smarkm{
167657429Smarkm	memset(options, 'X', sizeof(*options));
1677295367Sdes	options->version_addendum = NULL;
167857429Smarkm	options->forward_agent = -1;
167957429Smarkm	options->forward_x11 = -1;
1680126277Sdes	options->forward_x11_trusted = -1;
1681215116Sdes	options->forward_x11_timeout = -1;
1682162856Sdes	options->exit_on_forward_failure = -1;
168365674Skris	options->xauth_location = NULL;
1684295367Sdes	options->fwd_opts.gateway_ports = -1;
1685295367Sdes	options->fwd_opts.streamlocal_bind_mask = (mode_t)-1;
1686295367Sdes	options->fwd_opts.streamlocal_bind_unlink = -1;
168757429Smarkm	options->use_privileged_port = -1;
168857429Smarkm	options->rsa_authentication = -1;
168976262Sgreen	options->pubkey_authentication = -1;
169092559Sdes	options->challenge_response_authentication = -1;
1691124211Sdes	options->gss_authentication = -1;
1692124211Sdes	options->gss_deleg_creds = -1;
169357429Smarkm	options->password_authentication = -1;
169469591Sgreen	options->kbd_interactive_authentication = -1;
169569591Sgreen	options->kbd_interactive_devices = NULL;
169657429Smarkm	options->rhosts_rsa_authentication = -1;
169776262Sgreen	options->hostbased_authentication = -1;
169857429Smarkm	options->batch_mode = -1;
169957429Smarkm	options->check_host_ip = -1;
170057429Smarkm	options->strict_host_key_checking = -1;
170157429Smarkm	options->compression = -1;
1702126277Sdes	options->tcp_keep_alive = -1;
170357429Smarkm	options->compression_level = -1;
170457429Smarkm	options->port = -1;
1705124211Sdes	options->address_family = -1;
170657429Smarkm	options->connection_attempts = -1;
1707124211Sdes	options->connection_timeout = -1;
170857429Smarkm	options->number_of_password_prompts = -1;
170957429Smarkm	options->cipher = -1;
171060576Skris	options->ciphers = NULL;
171176262Sgreen	options->macs = NULL;
1712221420Sdes	options->kex_algorithms = NULL;
171376262Sgreen	options->hostkeyalgorithms = NULL;
171460576Skris	options->protocol = SSH_PROTO_UNKNOWN;
171557429Smarkm	options->num_identity_files = 0;
1716296853Sdes	options->num_certificate_files = 0;
171757429Smarkm	options->hostname = NULL;
171876262Sgreen	options->host_key_alias = NULL;
171957429Smarkm	options->proxy_command = NULL;
172057429Smarkm	options->user = NULL;
172157429Smarkm	options->escape_char = -1;
1722226046Sdes	options->num_system_hostfiles = 0;
1723226046Sdes	options->num_user_hostfiles = 0;
1724215116Sdes	options->local_forwards = NULL;
172557429Smarkm	options->num_local_forwards = 0;
1726215116Sdes	options->remote_forwards = NULL;
172757429Smarkm	options->num_remote_forwards = 0;
172892559Sdes	options->clear_forwardings = -1;
172992559Sdes	options->log_level = SYSLOG_LEVEL_NOT_SET;
173076262Sgreen	options->preferred_authentications = NULL;
173192559Sdes	options->bind_address = NULL;
1732204917Sdes	options->pkcs11_provider = NULL;
1733113911Sdes	options->enable_ssh_keysign = - 1;
173492559Sdes	options->no_host_authentication_for_localhost = - 1;
1735128460Sdes	options->identities_only = - 1;
1736124211Sdes	options->rekey_limit = - 1;
1737255767Sdes	options->rekey_interval = -1;
1738124211Sdes	options->verify_host_key_dns = -1;
1739126277Sdes	options->server_alive_interval = -1;
1740126277Sdes	options->server_alive_count_max = -1;
1741137019Sdes	options->num_send_env = 0;
1742137019Sdes	options->control_path = NULL;
1743137019Sdes	options->control_master = -1;
1744215116Sdes	options->control_persist = -1;
1745215116Sdes	options->control_persist_timeout = 0;
1746147005Sdes	options->hash_known_hosts = -1;
1747157019Sdes	options->tun_open = -1;
1748157019Sdes	options->tun_local = -1;
1749157019Sdes	options->tun_remote = -1;
1750157019Sdes	options->local_command = NULL;
1751157019Sdes	options->permit_local_command = -1;
1752296853Sdes	options->add_keys_to_agent = -1;
1753181111Sdes	options->visual_host_key = -1;
1754221420Sdes	options->ip_qos_interactive = -1;
1755221420Sdes	options->ip_qos_bulk = -1;
1756226046Sdes	options->request_tty = -1;
1757262566Sdes	options->proxy_use_fdpass = -1;
1758262566Sdes	options->ignored_unknown = NULL;
1759262566Sdes	options->num_canonical_domains = 0;
1760262566Sdes	options->num_permitted_cnames = 0;
1761262566Sdes	options->canonicalize_max_dots = -1;
1762262566Sdes	options->canonicalize_fallback_local = -1;
1763262566Sdes	options->canonicalize_hostname = -1;
1764295367Sdes	options->revoked_host_keys = NULL;
1765295367Sdes	options->fingerprint_hash = -1;
1766295367Sdes	options->update_hostkeys = -1;
1767295367Sdes	options->hostbased_key_types = NULL;
1768295367Sdes	options->pubkey_key_types = NULL;
176957429Smarkm}
177057429Smarkm
177157429Smarkm/*
1772264377Sdes * A petite version of fill_default_options() that just fills the options
1773264377Sdes * needed for hostname canonicalization to proceed.
1774264377Sdes */
1775264377Sdesvoid
1776264377Sdesfill_default_options_for_canonicalization(Options *options)
1777264377Sdes{
1778264377Sdes	if (options->canonicalize_max_dots == -1)
1779264377Sdes		options->canonicalize_max_dots = 1;
1780264377Sdes	if (options->canonicalize_fallback_local == -1)
1781264377Sdes		options->canonicalize_fallback_local = 1;
1782264377Sdes	if (options->canonicalize_hostname == -1)
1783264377Sdes		options->canonicalize_hostname = SSH_CANONICALISE_NO;
1784264377Sdes}
1785264377Sdes
1786264377Sdes/*
178757429Smarkm * Called after processing other sources of option data, this fills those
178857429Smarkm * options for which no value has been specified with their default values.
178957429Smarkm */
179060576Skrisvoid
179157429Smarkmfill_default_options(Options * options)
179257429Smarkm{
179357429Smarkm	if (options->forward_agent == -1)
179461203Skris		options->forward_agent = 0;
179557429Smarkm	if (options->forward_x11 == -1)
179657708Sgreen		options->forward_x11 = 0;
1797126277Sdes	if (options->forward_x11_trusted == -1)
1798126277Sdes		options->forward_x11_trusted = 0;
1799215116Sdes	if (options->forward_x11_timeout == -1)
1800215116Sdes		options->forward_x11_timeout = 1200;
1801162856Sdes	if (options->exit_on_forward_failure == -1)
1802162856Sdes		options->exit_on_forward_failure = 0;
180365674Skris	if (options->xauth_location == NULL)
180492559Sdes		options->xauth_location = _PATH_XAUTH;
1805295367Sdes	if (options->fwd_opts.gateway_ports == -1)
1806295367Sdes		options->fwd_opts.gateway_ports = 0;
1807295367Sdes	if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1)
1808295367Sdes		options->fwd_opts.streamlocal_bind_mask = 0177;
1809295367Sdes	if (options->fwd_opts.streamlocal_bind_unlink == -1)
1810295367Sdes		options->fwd_opts.streamlocal_bind_unlink = 0;
181157429Smarkm	if (options->use_privileged_port == -1)
181276262Sgreen		options->use_privileged_port = 0;
181357429Smarkm	if (options->rsa_authentication == -1)
181457429Smarkm		options->rsa_authentication = 1;
181576262Sgreen	if (options->pubkey_authentication == -1)
181676262Sgreen		options->pubkey_authentication = 1;
181792559Sdes	if (options->challenge_response_authentication == -1)
181892559Sdes		options->challenge_response_authentication = 1;
1819124211Sdes	if (options->gss_authentication == -1)
1820126277Sdes		options->gss_authentication = 0;
1821124211Sdes	if (options->gss_deleg_creds == -1)
1822124211Sdes		options->gss_deleg_creds = 0;
182357429Smarkm	if (options->password_authentication == -1)
182457429Smarkm		options->password_authentication = 1;
182569591Sgreen	if (options->kbd_interactive_authentication == -1)
182676262Sgreen		options->kbd_interactive_authentication = 1;
182757429Smarkm	if (options->rhosts_rsa_authentication == -1)
182898684Sdes		options->rhosts_rsa_authentication = 0;
182976262Sgreen	if (options->hostbased_authentication == -1)
183076262Sgreen		options->hostbased_authentication = 0;
183157429Smarkm	if (options->batch_mode == -1)
183257429Smarkm		options->batch_mode = 0;
183357429Smarkm	if (options->check_host_ip == -1)
183499048Sdes		options->check_host_ip = 0;
183557429Smarkm	if (options->strict_host_key_checking == -1)
183657429Smarkm		options->strict_host_key_checking = 2;	/* 2 is default */
183757429Smarkm	if (options->compression == -1)
183857429Smarkm		options->compression = 0;
1839126277Sdes	if (options->tcp_keep_alive == -1)
1840126277Sdes		options->tcp_keep_alive = 1;
184157429Smarkm	if (options->compression_level == -1)
184257429Smarkm		options->compression_level = 6;
184357429Smarkm	if (options->port == -1)
184457429Smarkm		options->port = 0;	/* Filled in ssh_connect. */
1845124211Sdes	if (options->address_family == -1)
1846124211Sdes		options->address_family = AF_UNSPEC;
184757429Smarkm	if (options->connection_attempts == -1)
184892559Sdes		options->connection_attempts = 1;
184957429Smarkm	if (options->number_of_password_prompts == -1)
185057429Smarkm		options->number_of_password_prompts = 3;
185157429Smarkm	/* Selected in ssh_login(). */
185257429Smarkm	if (options->cipher == -1)
185357429Smarkm		options->cipher = SSH_CIPHER_NOT_SET;
185476262Sgreen	/* options->hostkeyalgorithms, default set in myproposals.h */
185560576Skris	if (options->protocol == SSH_PROTO_UNKNOWN)
1856204917Sdes		options->protocol = SSH_PROTO_2;
1857296853Sdes	if (options->add_keys_to_agent == -1)
1858296853Sdes		options->add_keys_to_agent = 0;
185957429Smarkm	if (options->num_identity_files == 0) {
186076262Sgreen		if (options->protocol & SSH_PROTO_1) {
1861249839Sdes			add_identity_file(options, "~/",
1862249839Sdes			    _PATH_SSH_CLIENT_IDENTITY, 0);
186376262Sgreen		}
186476262Sgreen		if (options->protocol & SSH_PROTO_2) {
1865249839Sdes			add_identity_file(options, "~/",
1866249839Sdes			    _PATH_SSH_CLIENT_ID_RSA, 0);
1867249839Sdes			add_identity_file(options, "~/",
1868249839Sdes			    _PATH_SSH_CLIENT_ID_DSA, 0);
1869221420Sdes#ifdef OPENSSL_HAS_ECC
1870249839Sdes			add_identity_file(options, "~/",
1871249839Sdes			    _PATH_SSH_CLIENT_ID_ECDSA, 0);
1872221420Sdes#endif
1873262566Sdes			add_identity_file(options, "~/",
1874262566Sdes			    _PATH_SSH_CLIENT_ID_ED25519, 0);
187576262Sgreen		}
187657429Smarkm	}
187757429Smarkm	if (options->escape_char == -1)
187857429Smarkm		options->escape_char = '~';
1879226046Sdes	if (options->num_system_hostfiles == 0) {
1880226046Sdes		options->system_hostfiles[options->num_system_hostfiles++] =
1881226046Sdes		    xstrdup(_PATH_SSH_SYSTEM_HOSTFILE);
1882226046Sdes		options->system_hostfiles[options->num_system_hostfiles++] =
1883226046Sdes		    xstrdup(_PATH_SSH_SYSTEM_HOSTFILE2);
1884226046Sdes	}
1885226046Sdes	if (options->num_user_hostfiles == 0) {
1886226046Sdes		options->user_hostfiles[options->num_user_hostfiles++] =
1887226046Sdes		    xstrdup(_PATH_SSH_USER_HOSTFILE);
1888226046Sdes		options->user_hostfiles[options->num_user_hostfiles++] =
1889226046Sdes		    xstrdup(_PATH_SSH_USER_HOSTFILE2);
1890226046Sdes	}
189192559Sdes	if (options->log_level == SYSLOG_LEVEL_NOT_SET)
189257429Smarkm		options->log_level = SYSLOG_LEVEL_INFO;
189392559Sdes	if (options->clear_forwardings == 1)
189492559Sdes		clear_forwardings(options);
189592559Sdes	if (options->no_host_authentication_for_localhost == - 1)
189692559Sdes		options->no_host_authentication_for_localhost = 0;
1897128460Sdes	if (options->identities_only == -1)
1898128460Sdes		options->identities_only = 0;
1899113911Sdes	if (options->enable_ssh_keysign == -1)
1900113911Sdes		options->enable_ssh_keysign = 0;
1901124211Sdes	if (options->rekey_limit == -1)
1902124211Sdes		options->rekey_limit = 0;
1903255767Sdes	if (options->rekey_interval == -1)
1904255767Sdes		options->rekey_interval = 0;
1905255461Sdes#if HAVE_LDNS
1906124211Sdes	if (options->verify_host_key_dns == -1)
1907255461Sdes		/* automatically trust a verified SSHFP record */
1908255461Sdes		options->verify_host_key_dns = 1;
1909255461Sdes#else
1910255461Sdes	if (options->verify_host_key_dns == -1)
1911124211Sdes		options->verify_host_key_dns = 0;
1912255461Sdes#endif
1913126277Sdes	if (options->server_alive_interval == -1)
1914126277Sdes		options->server_alive_interval = 0;
1915126277Sdes	if (options->server_alive_count_max == -1)
1916126277Sdes		options->server_alive_count_max = 3;
1917137019Sdes	if (options->control_master == -1)
1918137019Sdes		options->control_master = 0;
1919215116Sdes	if (options->control_persist == -1) {
1920215116Sdes		options->control_persist = 0;
1921215116Sdes		options->control_persist_timeout = 0;
1922215116Sdes	}
1923147005Sdes	if (options->hash_known_hosts == -1)
1924147005Sdes		options->hash_known_hosts = 0;
1925157019Sdes	if (options->tun_open == -1)
1926157019Sdes		options->tun_open = SSH_TUNMODE_NO;
1927157019Sdes	if (options->tun_local == -1)
1928157019Sdes		options->tun_local = SSH_TUNID_ANY;
1929157019Sdes	if (options->tun_remote == -1)
1930157019Sdes		options->tun_remote = SSH_TUNID_ANY;
1931157019Sdes	if (options->permit_local_command == -1)
1932157019Sdes		options->permit_local_command = 0;
1933181111Sdes	if (options->visual_host_key == -1)
1934181111Sdes		options->visual_host_key = 0;
1935221420Sdes	if (options->ip_qos_interactive == -1)
1936221420Sdes		options->ip_qos_interactive = IPTOS_LOWDELAY;
1937221420Sdes	if (options->ip_qos_bulk == -1)
1938221420Sdes		options->ip_qos_bulk = IPTOS_THROUGHPUT;
1939226046Sdes	if (options->request_tty == -1)
1940226046Sdes		options->request_tty = REQUEST_TTY_AUTO;
1941262566Sdes	if (options->proxy_use_fdpass == -1)
1942262566Sdes		options->proxy_use_fdpass = 0;
1943262566Sdes	if (options->canonicalize_max_dots == -1)
1944262566Sdes		options->canonicalize_max_dots = 1;
1945262566Sdes	if (options->canonicalize_fallback_local == -1)
1946262566Sdes		options->canonicalize_fallback_local = 1;
1947262566Sdes	if (options->canonicalize_hostname == -1)
1948262566Sdes		options->canonicalize_hostname = SSH_CANONICALISE_NO;
1949295367Sdes	if (options->fingerprint_hash == -1)
1950295367Sdes		options->fingerprint_hash = SSH_FP_HASH_DEFAULT;
1951295367Sdes	if (options->update_hostkeys == -1)
1952295367Sdes		options->update_hostkeys = 0;
1953295367Sdes	if (kex_assemble_names(KEX_CLIENT_ENCRYPT, &options->ciphers) != 0 ||
1954295367Sdes	    kex_assemble_names(KEX_CLIENT_MAC, &options->macs) != 0 ||
1955295367Sdes	    kex_assemble_names(KEX_CLIENT_KEX, &options->kex_algorithms) != 0 ||
1956295367Sdes	    kex_assemble_names(KEX_DEFAULT_PK_ALG,
1957295367Sdes	    &options->hostbased_key_types) != 0 ||
1958295367Sdes	    kex_assemble_names(KEX_DEFAULT_PK_ALG,
1959295367Sdes	    &options->pubkey_key_types) != 0)
1960295367Sdes		fatal("%s: kex_assemble_names failed", __func__);
1961295367Sdes
1962262566Sdes#define CLEAR_ON_NONE(v) \
1963262566Sdes	do { \
1964264377Sdes		if (option_clear_or_none(v)) { \
1965262566Sdes			free(v); \
1966262566Sdes			v = NULL; \
1967262566Sdes		} \
1968262566Sdes	} while(0)
1969262566Sdes	CLEAR_ON_NONE(options->local_command);
1970262566Sdes	CLEAR_ON_NONE(options->proxy_command);
1971262566Sdes	CLEAR_ON_NONE(options->control_path);
1972295367Sdes	CLEAR_ON_NONE(options->revoked_host_keys);
197357429Smarkm	/* options->user will be set in the main program if appropriate */
197457429Smarkm	/* options->hostname will be set in the main program if appropriate */
197576262Sgreen	/* options->host_key_alias should not be set by default */
197676262Sgreen	/* options->preferred_authentications will be set in ssh */
1977240075Sdes	if (options->version_addendum == NULL)
1978240075Sdes		options->version_addendum = xstrdup(SSH_VERSION_FREEBSD);
197957429Smarkm}
1980147005Sdes
1981295367Sdesstruct fwdarg {
1982295367Sdes	char *arg;
1983295367Sdes	int ispath;
1984295367Sdes};
1985295367Sdes
1986147005Sdes/*
1987295367Sdes * parse_fwd_field
1988295367Sdes * parses the next field in a port forwarding specification.
1989295367Sdes * sets fwd to the parsed field and advances p past the colon
1990295367Sdes * or sets it to NULL at end of string.
1991295367Sdes * returns 0 on success, else non-zero.
1992295367Sdes */
1993295367Sdesstatic int
1994295367Sdesparse_fwd_field(char **p, struct fwdarg *fwd)
1995295367Sdes{
1996295367Sdes	char *ep, *cp = *p;
1997295367Sdes	int ispath = 0;
1998295367Sdes
1999295367Sdes	if (*cp == '\0') {
2000295367Sdes		*p = NULL;
2001295367Sdes		return -1;	/* end of string */
2002295367Sdes	}
2003295367Sdes
2004295367Sdes	/*
2005295367Sdes	 * A field escaped with square brackets is used literally.
2006295367Sdes	 * XXX - allow ']' to be escaped via backslash?
2007295367Sdes	 */
2008295367Sdes	if (*cp == '[') {
2009295367Sdes		/* find matching ']' */
2010295367Sdes		for (ep = cp + 1; *ep != ']' && *ep != '\0'; ep++) {
2011295367Sdes			if (*ep == '/')
2012295367Sdes				ispath = 1;
2013295367Sdes		}
2014295367Sdes		/* no matching ']' or not at end of field. */
2015295367Sdes		if (ep[0] != ']' || (ep[1] != ':' && ep[1] != '\0'))
2016295367Sdes			return -1;
2017295367Sdes		/* NUL terminate the field and advance p past the colon */
2018295367Sdes		*ep++ = '\0';
2019295367Sdes		if (*ep != '\0')
2020295367Sdes			*ep++ = '\0';
2021295367Sdes		fwd->arg = cp + 1;
2022295367Sdes		fwd->ispath = ispath;
2023295367Sdes		*p = ep;
2024295367Sdes		return 0;
2025295367Sdes	}
2026295367Sdes
2027295367Sdes	for (cp = *p; *cp != '\0'; cp++) {
2028295367Sdes		switch (*cp) {
2029295367Sdes		case '\\':
2030295367Sdes			memmove(cp, cp + 1, strlen(cp + 1) + 1);
2031295367Sdes			if (*cp == '\0')
2032295367Sdes				return -1;
2033295367Sdes			break;
2034295367Sdes		case '/':
2035295367Sdes			ispath = 1;
2036295367Sdes			break;
2037295367Sdes		case ':':
2038295367Sdes			*cp++ = '\0';
2039295367Sdes			goto done;
2040295367Sdes		}
2041295367Sdes	}
2042295367Sdesdone:
2043295367Sdes	fwd->arg = *p;
2044295367Sdes	fwd->ispath = ispath;
2045295367Sdes	*p = cp;
2046295367Sdes	return 0;
2047295367Sdes}
2048295367Sdes
2049295367Sdes/*
2050147005Sdes * parse_forward
2051147005Sdes * parses a string containing a port forwarding specification of the form:
2052192595Sdes *   dynamicfwd == 0
2053295367Sdes *	[listenhost:]listenport|listenpath:connecthost:connectport|connectpath
2054295367Sdes *	listenpath:connectpath
2055192595Sdes *   dynamicfwd == 1
2056192595Sdes *	[listenhost:]listenport
2057147005Sdes * returns number of arguments parsed or zero on error
2058147005Sdes */
2059147005Sdesint
2060295367Sdesparse_forward(struct Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
2061147005Sdes{
2062295367Sdes	struct fwdarg fwdargs[4];
2063295367Sdes	char *p, *cp;
2064147005Sdes	int i;
2065147005Sdes
2066295367Sdes	memset(fwd, 0, sizeof(*fwd));
2067295367Sdes	memset(fwdargs, 0, sizeof(fwdargs));
2068147005Sdes
2069147005Sdes	cp = p = xstrdup(fwdspec);
2070147005Sdes
2071147005Sdes	/* skip leading spaces */
2072262566Sdes	while (isspace((u_char)*cp))
2073147005Sdes		cp++;
2074147005Sdes
2075295367Sdes	for (i = 0; i < 4; ++i) {
2076295367Sdes		if (parse_fwd_field(&cp, &fwdargs[i]) != 0)
2077147005Sdes			break;
2078295367Sdes	}
2079147005Sdes
2080192595Sdes	/* Check for trailing garbage */
2081295367Sdes	if (cp != NULL && *cp != '\0') {
2082147005Sdes		i = 0;	/* failure */
2083295367Sdes	}
2084147005Sdes
2085147005Sdes	switch (i) {
2086192595Sdes	case 1:
2087295367Sdes		if (fwdargs[0].ispath) {
2088295367Sdes			fwd->listen_path = xstrdup(fwdargs[0].arg);
2089295367Sdes			fwd->listen_port = PORT_STREAMLOCAL;
2090295367Sdes		} else {
2091295367Sdes			fwd->listen_host = NULL;
2092295367Sdes			fwd->listen_port = a2port(fwdargs[0].arg);
2093295367Sdes		}
2094192595Sdes		fwd->connect_host = xstrdup("socks");
2095192595Sdes		break;
2096192595Sdes
2097192595Sdes	case 2:
2098295367Sdes		if (fwdargs[0].ispath && fwdargs[1].ispath) {
2099295367Sdes			fwd->listen_path = xstrdup(fwdargs[0].arg);
2100295367Sdes			fwd->listen_port = PORT_STREAMLOCAL;
2101295367Sdes			fwd->connect_path = xstrdup(fwdargs[1].arg);
2102295367Sdes			fwd->connect_port = PORT_STREAMLOCAL;
2103295367Sdes		} else if (fwdargs[1].ispath) {
2104295367Sdes			fwd->listen_host = NULL;
2105295367Sdes			fwd->listen_port = a2port(fwdargs[0].arg);
2106295367Sdes			fwd->connect_path = xstrdup(fwdargs[1].arg);
2107295367Sdes			fwd->connect_port = PORT_STREAMLOCAL;
2108295367Sdes		} else {
2109295367Sdes			fwd->listen_host = xstrdup(fwdargs[0].arg);
2110295367Sdes			fwd->listen_port = a2port(fwdargs[1].arg);
2111295367Sdes			fwd->connect_host = xstrdup("socks");
2112295367Sdes		}
2113192595Sdes		break;
2114192595Sdes
2115147005Sdes	case 3:
2116295367Sdes		if (fwdargs[0].ispath) {
2117295367Sdes			fwd->listen_path = xstrdup(fwdargs[0].arg);
2118295367Sdes			fwd->listen_port = PORT_STREAMLOCAL;
2119295367Sdes			fwd->connect_host = xstrdup(fwdargs[1].arg);
2120295367Sdes			fwd->connect_port = a2port(fwdargs[2].arg);
2121295367Sdes		} else if (fwdargs[2].ispath) {
2122295367Sdes			fwd->listen_host = xstrdup(fwdargs[0].arg);
2123295367Sdes			fwd->listen_port = a2port(fwdargs[1].arg);
2124295367Sdes			fwd->connect_path = xstrdup(fwdargs[2].arg);
2125295367Sdes			fwd->connect_port = PORT_STREAMLOCAL;
2126295367Sdes		} else {
2127295367Sdes			fwd->listen_host = NULL;
2128295367Sdes			fwd->listen_port = a2port(fwdargs[0].arg);
2129295367Sdes			fwd->connect_host = xstrdup(fwdargs[1].arg);
2130295367Sdes			fwd->connect_port = a2port(fwdargs[2].arg);
2131295367Sdes		}
2132147005Sdes		break;
2133147005Sdes
2134147005Sdes	case 4:
2135295367Sdes		fwd->listen_host = xstrdup(fwdargs[0].arg);
2136295367Sdes		fwd->listen_port = a2port(fwdargs[1].arg);
2137295367Sdes		fwd->connect_host = xstrdup(fwdargs[2].arg);
2138295367Sdes		fwd->connect_port = a2port(fwdargs[3].arg);
2139147005Sdes		break;
2140147005Sdes	default:
2141147005Sdes		i = 0; /* failure */
2142147005Sdes	}
2143147005Sdes
2144255767Sdes	free(p);
2145147005Sdes
2146192595Sdes	if (dynamicfwd) {
2147192595Sdes		if (!(i == 1 || i == 2))
2148192595Sdes			goto fail_free;
2149192595Sdes	} else {
2150295367Sdes		if (!(i == 3 || i == 4)) {
2151295367Sdes			if (fwd->connect_path == NULL &&
2152295367Sdes			    fwd->listen_path == NULL)
2153295367Sdes				goto fail_free;
2154295367Sdes		}
2155295367Sdes		if (fwd->connect_port <= 0 && fwd->connect_path == NULL)
2156192595Sdes			goto fail_free;
2157192595Sdes	}
2158192595Sdes
2159295367Sdes	if ((fwd->listen_port < 0 && fwd->listen_path == NULL) ||
2160295367Sdes	    (!remotefwd && fwd->listen_port == 0))
2161147005Sdes		goto fail_free;
2162147005Sdes	if (fwd->connect_host != NULL &&
2163147005Sdes	    strlen(fwd->connect_host) >= NI_MAXHOST)
2164147005Sdes		goto fail_free;
2165295367Sdes	/* XXX - if connecting to a remote socket, max sun len may not match this host */
2166295367Sdes	if (fwd->connect_path != NULL &&
2167295367Sdes	    strlen(fwd->connect_path) >= PATH_MAX_SUN)
2168295367Sdes		goto fail_free;
2169192595Sdes	if (fwd->listen_host != NULL &&
2170192595Sdes	    strlen(fwd->listen_host) >= NI_MAXHOST)
2171192595Sdes		goto fail_free;
2172295367Sdes	if (fwd->listen_path != NULL &&
2173295367Sdes	    strlen(fwd->listen_path) >= PATH_MAX_SUN)
2174295367Sdes		goto fail_free;
2175147005Sdes
2176147005Sdes	return (i);
2177147005Sdes
2178147005Sdes fail_free:
2179255767Sdes	free(fwd->connect_host);
2180255767Sdes	fwd->connect_host = NULL;
2181295367Sdes	free(fwd->connect_path);
2182295367Sdes	fwd->connect_path = NULL;
2183255767Sdes	free(fwd->listen_host);
2184255767Sdes	fwd->listen_host = NULL;
2185295367Sdes	free(fwd->listen_path);
2186295367Sdes	fwd->listen_path = NULL;
2187147005Sdes	return (0);
2188147005Sdes}
2189295367Sdes
2190295367Sdes/* XXX the following is a near-vebatim copy from servconf.c; refactor */
2191295367Sdesstatic const char *
2192295367Sdesfmt_multistate_int(int val, const struct multistate *m)
2193295367Sdes{
2194295367Sdes	u_int i;
2195295367Sdes
2196295367Sdes	for (i = 0; m[i].key != NULL; i++) {
2197295367Sdes		if (m[i].value == val)
2198295367Sdes			return m[i].key;
2199295367Sdes	}
2200295367Sdes	return "UNKNOWN";
2201295367Sdes}
2202295367Sdes
2203295367Sdesstatic const char *
2204295367Sdesfmt_intarg(OpCodes code, int val)
2205295367Sdes{
2206295367Sdes	if (val == -1)
2207295367Sdes		return "unset";
2208295367Sdes	switch (code) {
2209295367Sdes	case oAddressFamily:
2210295367Sdes		return fmt_multistate_int(val, multistate_addressfamily);
2211295367Sdes	case oVerifyHostKeyDNS:
2212295367Sdes	case oStrictHostKeyChecking:
2213295367Sdes	case oUpdateHostkeys:
2214295367Sdes		return fmt_multistate_int(val, multistate_yesnoask);
2215295367Sdes	case oControlMaster:
2216295367Sdes		return fmt_multistate_int(val, multistate_controlmaster);
2217295367Sdes	case oTunnel:
2218295367Sdes		return fmt_multistate_int(val, multistate_tunnel);
2219295367Sdes	case oRequestTTY:
2220295367Sdes		return fmt_multistate_int(val, multistate_requesttty);
2221295367Sdes	case oCanonicalizeHostname:
2222295367Sdes		return fmt_multistate_int(val, multistate_canonicalizehostname);
2223295367Sdes	case oFingerprintHash:
2224295367Sdes		return ssh_digest_alg_name(val);
2225295367Sdes	case oProtocol:
2226295367Sdes		switch (val) {
2227295367Sdes		case SSH_PROTO_1:
2228295367Sdes			return "1";
2229295367Sdes		case SSH_PROTO_2:
2230295367Sdes			return "2";
2231295367Sdes		case (SSH_PROTO_1|SSH_PROTO_2):
2232295367Sdes			return "2,1";
2233295367Sdes		default:
2234295367Sdes			return "UNKNOWN";
2235295367Sdes		}
2236295367Sdes	default:
2237295367Sdes		switch (val) {
2238295367Sdes		case 0:
2239295367Sdes			return "no";
2240295367Sdes		case 1:
2241295367Sdes			return "yes";
2242295367Sdes		default:
2243295367Sdes			return "UNKNOWN";
2244295367Sdes		}
2245295367Sdes	}
2246295367Sdes}
2247295367Sdes
2248295367Sdesstatic const char *
2249295367Sdeslookup_opcode_name(OpCodes code)
2250295367Sdes{
2251295367Sdes	u_int i;
2252295367Sdes
2253295367Sdes	for (i = 0; keywords[i].name != NULL; i++)
2254295367Sdes		if (keywords[i].opcode == code)
2255295367Sdes			return(keywords[i].name);
2256295367Sdes	return "UNKNOWN";
2257295367Sdes}
2258295367Sdes
2259295367Sdesstatic void
2260295367Sdesdump_cfg_int(OpCodes code, int val)
2261295367Sdes{
2262295367Sdes	printf("%s %d\n", lookup_opcode_name(code), val);
2263295367Sdes}
2264295367Sdes
2265295367Sdesstatic void
2266295367Sdesdump_cfg_fmtint(OpCodes code, int val)
2267295367Sdes{
2268295367Sdes	printf("%s %s\n", lookup_opcode_name(code), fmt_intarg(code, val));
2269295367Sdes}
2270295367Sdes
2271295367Sdesstatic void
2272295367Sdesdump_cfg_string(OpCodes code, const char *val)
2273295367Sdes{
2274295367Sdes	if (val == NULL)
2275295367Sdes		return;
2276295367Sdes	printf("%s %s\n", lookup_opcode_name(code), val);
2277295367Sdes}
2278295367Sdes
2279295367Sdesstatic void
2280295367Sdesdump_cfg_strarray(OpCodes code, u_int count, char **vals)
2281295367Sdes{
2282295367Sdes	u_int i;
2283295367Sdes
2284295367Sdes	for (i = 0; i < count; i++)
2285295367Sdes		printf("%s %s\n", lookup_opcode_name(code), vals[i]);
2286295367Sdes}
2287295367Sdes
2288295367Sdesstatic void
2289295367Sdesdump_cfg_strarray_oneline(OpCodes code, u_int count, char **vals)
2290295367Sdes{
2291295367Sdes	u_int i;
2292295367Sdes
2293295367Sdes	printf("%s", lookup_opcode_name(code));
2294295367Sdes	for (i = 0; i < count; i++)
2295295367Sdes		printf(" %s",  vals[i]);
2296295367Sdes	printf("\n");
2297295367Sdes}
2298295367Sdes
2299295367Sdesstatic void
2300295367Sdesdump_cfg_forwards(OpCodes code, u_int count, const struct Forward *fwds)
2301295367Sdes{
2302295367Sdes	const struct Forward *fwd;
2303295367Sdes	u_int i;
2304295367Sdes
2305295367Sdes	/* oDynamicForward */
2306295367Sdes	for (i = 0; i < count; i++) {
2307295367Sdes		fwd = &fwds[i];
2308295367Sdes		if (code == oDynamicForward &&
2309295367Sdes		    strcmp(fwd->connect_host, "socks") != 0)
2310295367Sdes			continue;
2311295367Sdes		if (code == oLocalForward &&
2312295367Sdes		    strcmp(fwd->connect_host, "socks") == 0)
2313295367Sdes			continue;
2314295367Sdes		printf("%s", lookup_opcode_name(code));
2315295367Sdes		if (fwd->listen_port == PORT_STREAMLOCAL)
2316295367Sdes			printf(" %s", fwd->listen_path);
2317295367Sdes		else if (fwd->listen_host == NULL)
2318295367Sdes			printf(" %d", fwd->listen_port);
2319295367Sdes		else {
2320295367Sdes			printf(" [%s]:%d",
2321295367Sdes			    fwd->listen_host, fwd->listen_port);
2322295367Sdes		}
2323295367Sdes		if (code != oDynamicForward) {
2324295367Sdes			if (fwd->connect_port == PORT_STREAMLOCAL)
2325295367Sdes				printf(" %s", fwd->connect_path);
2326295367Sdes			else if (fwd->connect_host == NULL)
2327295367Sdes				printf(" %d", fwd->connect_port);
2328295367Sdes			else {
2329295367Sdes				printf(" [%s]:%d",
2330295367Sdes				    fwd->connect_host, fwd->connect_port);
2331295367Sdes			}
2332295367Sdes		}
2333295367Sdes		printf("\n");
2334295367Sdes	}
2335295367Sdes}
2336295367Sdes
2337295367Sdesvoid
2338295367Sdesdump_client_config(Options *o, const char *host)
2339295367Sdes{
2340295367Sdes	int i;
2341295367Sdes	char vbuf[5];
2342295367Sdes
2343296853Sdes	/* This is normally prepared in ssh_kex2 */
2344296853Sdes	if (kex_assemble_names(KEX_DEFAULT_PK_ALG, &o->hostkeyalgorithms) != 0)
2345296853Sdes		fatal("%s: kex_assemble_names failed", __func__);
2346296853Sdes
2347295367Sdes	/* Most interesting options first: user, host, port */
2348295367Sdes	dump_cfg_string(oUser, o->user);
2349295367Sdes	dump_cfg_string(oHostName, host);
2350295367Sdes	dump_cfg_int(oPort, o->port);
2351295367Sdes
2352295367Sdes	/* Flag options */
2353295367Sdes	dump_cfg_fmtint(oAddressFamily, o->address_family);
2354295367Sdes	dump_cfg_fmtint(oBatchMode, o->batch_mode);
2355295367Sdes	dump_cfg_fmtint(oCanonicalizeFallbackLocal, o->canonicalize_fallback_local);
2356295367Sdes	dump_cfg_fmtint(oCanonicalizeHostname, o->canonicalize_hostname);
2357295367Sdes	dump_cfg_fmtint(oChallengeResponseAuthentication, o->challenge_response_authentication);
2358295367Sdes	dump_cfg_fmtint(oCheckHostIP, o->check_host_ip);
2359295367Sdes	dump_cfg_fmtint(oCompression, o->compression);
2360295367Sdes	dump_cfg_fmtint(oControlMaster, o->control_master);
2361295367Sdes	dump_cfg_fmtint(oEnableSSHKeysign, o->enable_ssh_keysign);
2362295367Sdes	dump_cfg_fmtint(oExitOnForwardFailure, o->exit_on_forward_failure);
2363295367Sdes	dump_cfg_fmtint(oFingerprintHash, o->fingerprint_hash);
2364295367Sdes	dump_cfg_fmtint(oForwardAgent, o->forward_agent);
2365295367Sdes	dump_cfg_fmtint(oForwardX11, o->forward_x11);
2366295367Sdes	dump_cfg_fmtint(oForwardX11Trusted, o->forward_x11_trusted);
2367295367Sdes	dump_cfg_fmtint(oGatewayPorts, o->fwd_opts.gateway_ports);
2368295367Sdes#ifdef GSSAPI
2369295367Sdes	dump_cfg_fmtint(oGssAuthentication, o->gss_authentication);
2370295367Sdes	dump_cfg_fmtint(oGssDelegateCreds, o->gss_deleg_creds);
2371295367Sdes#endif /* GSSAPI */
2372295367Sdes	dump_cfg_fmtint(oHashKnownHosts, o->hash_known_hosts);
2373295367Sdes	dump_cfg_fmtint(oHostbasedAuthentication, o->hostbased_authentication);
2374295367Sdes	dump_cfg_fmtint(oIdentitiesOnly, o->identities_only);
2375295367Sdes	dump_cfg_fmtint(oKbdInteractiveAuthentication, o->kbd_interactive_authentication);
2376295367Sdes	dump_cfg_fmtint(oNoHostAuthenticationForLocalhost, o->no_host_authentication_for_localhost);
2377295367Sdes	dump_cfg_fmtint(oPasswordAuthentication, o->password_authentication);
2378295367Sdes	dump_cfg_fmtint(oPermitLocalCommand, o->permit_local_command);
2379295367Sdes	dump_cfg_fmtint(oProtocol, o->protocol);
2380295367Sdes	dump_cfg_fmtint(oProxyUseFdpass, o->proxy_use_fdpass);
2381295367Sdes	dump_cfg_fmtint(oPubkeyAuthentication, o->pubkey_authentication);
2382295367Sdes	dump_cfg_fmtint(oRequestTTY, o->request_tty);
2383295367Sdes	dump_cfg_fmtint(oRhostsRSAAuthentication, o->rhosts_rsa_authentication);
2384295367Sdes	dump_cfg_fmtint(oRSAAuthentication, o->rsa_authentication);
2385295367Sdes	dump_cfg_fmtint(oStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink);
2386295367Sdes	dump_cfg_fmtint(oStrictHostKeyChecking, o->strict_host_key_checking);
2387295367Sdes	dump_cfg_fmtint(oTCPKeepAlive, o->tcp_keep_alive);
2388295367Sdes	dump_cfg_fmtint(oTunnel, o->tun_open);
2389295367Sdes	dump_cfg_fmtint(oUsePrivilegedPort, o->use_privileged_port);
2390295367Sdes	dump_cfg_fmtint(oVerifyHostKeyDNS, o->verify_host_key_dns);
2391295367Sdes	dump_cfg_fmtint(oVisualHostKey, o->visual_host_key);
2392295367Sdes	dump_cfg_fmtint(oUpdateHostkeys, o->update_hostkeys);
2393295367Sdes
2394295367Sdes	/* Integer options */
2395295367Sdes	dump_cfg_int(oCanonicalizeMaxDots, o->canonicalize_max_dots);
2396295367Sdes	dump_cfg_int(oCompressionLevel, o->compression_level);
2397295367Sdes	dump_cfg_int(oConnectionAttempts, o->connection_attempts);
2398295367Sdes	dump_cfg_int(oForwardX11Timeout, o->forward_x11_timeout);
2399295367Sdes	dump_cfg_int(oNumberOfPasswordPrompts, o->number_of_password_prompts);
2400295367Sdes	dump_cfg_int(oServerAliveCountMax, o->server_alive_count_max);
2401295367Sdes	dump_cfg_int(oServerAliveInterval, o->server_alive_interval);
2402295367Sdes
2403295367Sdes	/* String options */
2404295367Sdes	dump_cfg_string(oBindAddress, o->bind_address);
2405295367Sdes	dump_cfg_string(oCiphers, o->ciphers ? o->ciphers : KEX_CLIENT_ENCRYPT);
2406295367Sdes	dump_cfg_string(oControlPath, o->control_path);
2407296853Sdes	dump_cfg_string(oHostKeyAlgorithms, o->hostkeyalgorithms);
2408295367Sdes	dump_cfg_string(oHostKeyAlias, o->host_key_alias);
2409295367Sdes	dump_cfg_string(oHostbasedKeyTypes, o->hostbased_key_types);
2410295367Sdes	dump_cfg_string(oKbdInteractiveDevices, o->kbd_interactive_devices);
2411295367Sdes	dump_cfg_string(oKexAlgorithms, o->kex_algorithms ? o->kex_algorithms : KEX_CLIENT_KEX);
2412295367Sdes	dump_cfg_string(oLocalCommand, o->local_command);
2413295367Sdes	dump_cfg_string(oLogLevel, log_level_name(o->log_level));
2414295367Sdes	dump_cfg_string(oMacs, o->macs ? o->macs : KEX_CLIENT_MAC);
2415295367Sdes	dump_cfg_string(oPKCS11Provider, o->pkcs11_provider);
2416295367Sdes	dump_cfg_string(oPreferredAuthentications, o->preferred_authentications);
2417295367Sdes	dump_cfg_string(oProxyCommand, o->proxy_command);
2418296853Sdes	dump_cfg_string(oPubkeyAcceptedKeyTypes, o->pubkey_key_types);
2419295367Sdes	dump_cfg_string(oRevokedHostKeys, o->revoked_host_keys);
2420295367Sdes	dump_cfg_string(oXAuthLocation, o->xauth_location);
2421295367Sdes
2422295367Sdes	/* Forwards */
2423295367Sdes	dump_cfg_forwards(oDynamicForward, o->num_local_forwards, o->local_forwards);
2424295367Sdes	dump_cfg_forwards(oLocalForward, o->num_local_forwards, o->local_forwards);
2425295367Sdes	dump_cfg_forwards(oRemoteForward, o->num_remote_forwards, o->remote_forwards);
2426295367Sdes
2427295367Sdes	/* String array options */
2428295367Sdes	dump_cfg_strarray(oIdentityFile, o->num_identity_files, o->identity_files);
2429295367Sdes	dump_cfg_strarray_oneline(oCanonicalDomains, o->num_canonical_domains, o->canonical_domains);
2430295367Sdes	dump_cfg_strarray_oneline(oGlobalKnownHostsFile, o->num_system_hostfiles, o->system_hostfiles);
2431295367Sdes	dump_cfg_strarray_oneline(oUserKnownHostsFile, o->num_user_hostfiles, o->user_hostfiles);
2432295367Sdes	dump_cfg_strarray(oSendEnv, o->num_send_env, o->send_env);
2433295367Sdes
2434295367Sdes	/* Special cases */
2435295367Sdes
2436295367Sdes	/* oConnectTimeout */
2437295367Sdes	if (o->connection_timeout == -1)
2438295367Sdes		printf("connecttimeout none\n");
2439295367Sdes	else
2440295367Sdes		dump_cfg_int(oConnectTimeout, o->connection_timeout);
2441295367Sdes
2442295367Sdes	/* oTunnelDevice */
2443295367Sdes	printf("tunneldevice");
2444295367Sdes	if (o->tun_local == SSH_TUNID_ANY)
2445295367Sdes		printf(" any");
2446295367Sdes	else
2447295367Sdes		printf(" %d", o->tun_local);
2448295367Sdes	if (o->tun_remote == SSH_TUNID_ANY)
2449295367Sdes		printf(":any");
2450295367Sdes	else
2451295367Sdes		printf(":%d", o->tun_remote);
2452295367Sdes	printf("\n");
2453295367Sdes
2454295367Sdes	/* oCanonicalizePermittedCNAMEs */
2455295367Sdes	if ( o->num_permitted_cnames > 0) {
2456295367Sdes		printf("canonicalizePermittedcnames");
2457295367Sdes		for (i = 0; i < o->num_permitted_cnames; i++) {
2458295367Sdes			printf(" %s:%s", o->permitted_cnames[i].source_list,
2459295367Sdes			    o->permitted_cnames[i].target_list);
2460295367Sdes		}
2461295367Sdes		printf("\n");
2462295367Sdes	}
2463295367Sdes
2464295367Sdes	/* oCipher */
2465295367Sdes	if (o->cipher != SSH_CIPHER_NOT_SET)
2466295367Sdes		printf("Cipher %s\n", cipher_name(o->cipher));
2467295367Sdes
2468295367Sdes	/* oControlPersist */
2469295367Sdes	if (o->control_persist == 0 || o->control_persist_timeout == 0)
2470295367Sdes		dump_cfg_fmtint(oControlPersist, o->control_persist);
2471295367Sdes	else
2472295367Sdes		dump_cfg_int(oControlPersist, o->control_persist_timeout);
2473295367Sdes
2474295367Sdes	/* oEscapeChar */
2475295367Sdes	if (o->escape_char == SSH_ESCAPECHAR_NONE)
2476295367Sdes		printf("escapechar none\n");
2477295367Sdes	else {
2478295367Sdes		vis(vbuf, o->escape_char, VIS_WHITE, 0);
2479295367Sdes		printf("escapechar %s\n", vbuf);
2480295367Sdes	}
2481295367Sdes
2482295367Sdes	/* oIPQoS */
2483295367Sdes	printf("ipqos %s ", iptos2str(o->ip_qos_interactive));
2484295367Sdes	printf("%s\n", iptos2str(o->ip_qos_bulk));
2485295367Sdes
2486295367Sdes	/* oRekeyLimit */
2487296853Sdes	printf("rekeylimit %llu %d\n",
2488296853Sdes	    (unsigned long long)o->rekey_limit, o->rekey_interval);
2489295367Sdes
2490295367Sdes	/* oStreamLocalBindMask */
2491295367Sdes	printf("streamlocalbindmask 0%o\n",
2492295367Sdes	    o->fwd_opts.streamlocal_bind_mask);
2493295367Sdes}
2494