xref: /freebsd/crypto/openssh/readconf.c (revision b15c83408cb1e9b86c1895af0f097de05fc92ccf)
1b15c8340SDag-Erling Smørgrav /* $OpenBSD: readconf.c,v 1.183 2010/02/08 10:50:20 markus Exp $ */
2511b41d2SMark Murray /*
3511b41d2SMark Murray  * Author: Tatu Ylonen <ylo@cs.hut.fi>
4511b41d2SMark Murray  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
5511b41d2SMark Murray  *                    All rights reserved
6511b41d2SMark Murray  * Functions for reading the configuration files.
7511b41d2SMark Murray  *
8c2d3a559SKris Kennaway  * As far as I am concerned, the code I have written for this software
9c2d3a559SKris Kennaway  * can be used freely for any purpose.  Any derived versions of this
10c2d3a559SKris Kennaway  * software must be clearly marked as such, and if the derived work is
11c2d3a559SKris Kennaway  * incompatible with the protocol description in the RFC file, it must be
12c2d3a559SKris Kennaway  * called by a name other than "ssh" or "Secure Shell".
13511b41d2SMark Murray  */
14511b41d2SMark Murray 
15511b41d2SMark Murray #include "includes.h"
16333ee039SDag-Erling Smørgrav __RCSID("$FreeBSD$");
17511b41d2SMark Murray 
18333ee039SDag-Erling Smørgrav #include <sys/types.h>
19333ee039SDag-Erling Smørgrav #include <sys/stat.h>
20333ee039SDag-Erling Smørgrav #include <sys/socket.h>
2103f6c5cdSDag-Erling Smørgrav #include <sys/sysctl.h>
22333ee039SDag-Erling Smørgrav 
23333ee039SDag-Erling Smørgrav #include <netinet/in.h>
24333ee039SDag-Erling Smørgrav 
25333ee039SDag-Erling Smørgrav #include <ctype.h>
26333ee039SDag-Erling Smørgrav #include <errno.h>
27333ee039SDag-Erling Smørgrav #include <netdb.h>
28333ee039SDag-Erling Smørgrav #include <signal.h>
29333ee039SDag-Erling Smørgrav #include <stdarg.h>
30333ee039SDag-Erling Smørgrav #include <stdio.h>
31333ee039SDag-Erling Smørgrav #include <string.h>
32333ee039SDag-Erling Smørgrav #include <unistd.h>
33333ee039SDag-Erling Smørgrav 
34511b41d2SMark Murray #include "xmalloc.h"
35333ee039SDag-Erling Smørgrav #include "ssh.h"
36e8aafc91SKris Kennaway #include "compat.h"
37ca3176e7SBrian Feldman #include "cipher.h"
38ca3176e7SBrian Feldman #include "pathnames.h"
39ca3176e7SBrian Feldman #include "log.h"
40333ee039SDag-Erling Smørgrav #include "key.h"
41ca3176e7SBrian Feldman #include "readconf.h"
42ca3176e7SBrian Feldman #include "match.h"
43ca3176e7SBrian Feldman #include "misc.h"
44333ee039SDag-Erling Smørgrav #include "buffer.h"
45ca3176e7SBrian Feldman #include "kex.h"
46ca3176e7SBrian Feldman #include "mac.h"
47cce7d346SDag-Erling Smørgrav #include "version.h"
48511b41d2SMark Murray 
49511b41d2SMark Murray /* Format of the configuration file:
50511b41d2SMark Murray 
51511b41d2SMark Murray    # Configuration data is parsed as follows:
52511b41d2SMark Murray    #  1. command line options
53511b41d2SMark Murray    #  2. user-specific file
54511b41d2SMark Murray    #  3. system-wide file
55511b41d2SMark Murray    # Any configuration value is only changed the first time it is set.
56511b41d2SMark Murray    # Thus, host-specific definitions should be at the beginning of the
57511b41d2SMark Murray    # configuration file, and defaults at the end.
58511b41d2SMark Murray 
59511b41d2SMark Murray    # Host-specific declarations.  These may override anything above.  A single
60511b41d2SMark Murray    # host may match multiple declarations; these are processed in the order
61511b41d2SMark Murray    # that they are given in.
62511b41d2SMark Murray 
63511b41d2SMark Murray    Host *.ngs.fi ngs.fi
6480628bacSDag-Erling Smørgrav      User foo
65511b41d2SMark Murray 
66511b41d2SMark Murray    Host fake.com
67511b41d2SMark Murray      HostName another.host.name.real.org
68511b41d2SMark Murray      User blaah
69511b41d2SMark Murray      Port 34289
70511b41d2SMark Murray      ForwardX11 no
71511b41d2SMark Murray      ForwardAgent no
72511b41d2SMark Murray 
73511b41d2SMark Murray    Host books.com
74511b41d2SMark Murray      RemoteForward 9999 shadows.cs.hut.fi:9999
75511b41d2SMark Murray      Cipher 3des
76511b41d2SMark Murray 
77511b41d2SMark Murray    Host fascist.blob.com
78511b41d2SMark Murray      Port 23123
79511b41d2SMark Murray      User tylonen
80511b41d2SMark Murray      PasswordAuthentication no
81511b41d2SMark Murray 
82511b41d2SMark Murray    Host puukko.hut.fi
83511b41d2SMark Murray      User t35124p
84511b41d2SMark Murray      ProxyCommand ssh-proxy %h %p
85511b41d2SMark Murray 
86511b41d2SMark Murray    Host *.fr
8780628bacSDag-Erling Smørgrav      PublicKeyAuthentication no
88511b41d2SMark Murray 
89511b41d2SMark Murray    Host *.su
90511b41d2SMark Murray      Cipher none
91511b41d2SMark Murray      PasswordAuthentication no
92511b41d2SMark Murray 
93b74df5b2SDag-Erling Smørgrav    Host vpn.fake.com
94b74df5b2SDag-Erling Smørgrav      Tunnel yes
95b74df5b2SDag-Erling Smørgrav      TunnelDevice 3
96b74df5b2SDag-Erling Smørgrav 
97511b41d2SMark Murray    # Defaults for various options
98511b41d2SMark Murray    Host *
99511b41d2SMark Murray      ForwardAgent no
100ca3176e7SBrian Feldman      ForwardX11 no
101511b41d2SMark Murray      PasswordAuthentication yes
102511b41d2SMark Murray      RSAAuthentication yes
103511b41d2SMark Murray      RhostsRSAAuthentication yes
104511b41d2SMark Murray      StrictHostKeyChecking yes
1051ec0d754SDag-Erling Smørgrav      TcpKeepAlive no
106511b41d2SMark Murray      IdentityFile ~/.ssh/identity
107511b41d2SMark Murray      Port 22
108511b41d2SMark Murray      EscapeChar ~
109511b41d2SMark Murray 
110511b41d2SMark Murray */
111511b41d2SMark Murray 
112511b41d2SMark Murray /* Keyword tokens. */
113511b41d2SMark Murray 
114511b41d2SMark Murray typedef enum {
115511b41d2SMark Murray 	oBadOption,
1161ec0d754SDag-Erling Smørgrav 	oForwardAgent, oForwardX11, oForwardX11Trusted, oGatewayPorts,
117333ee039SDag-Erling Smørgrav 	oExitOnForwardFailure,
11880628bacSDag-Erling Smørgrav 	oPasswordAuthentication, oRSAAuthentication,
119ca3176e7SBrian Feldman 	oChallengeResponseAuthentication, oXAuthLocation,
120511b41d2SMark Murray 	oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward,
121511b41d2SMark Murray 	oUser, oHost, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
122511b41d2SMark Murray 	oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
123511b41d2SMark Murray 	oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
1241ec0d754SDag-Erling Smørgrav 	oCompressionLevel, oTCPKeepAlive, oNumberOfPasswordPrompts,
125ca3176e7SBrian Feldman 	oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oMacs,
126ca3176e7SBrian Feldman 	oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication,
127ca3176e7SBrian Feldman 	oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
128ca3176e7SBrian Feldman 	oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
129b15c8340SDag-Erling Smørgrav 	oHostKeyAlgorithms, oBindAddress, oPKCS11Provider,
1309e2cbe04SDag-Erling Smørgrav 	oClearAllForwardings, oNoHostAuthenticationForLocalhost,
131cf2b5f3bSDag-Erling Smørgrav 	oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
132cf2b5f3bSDag-Erling Smørgrav 	oAddressFamily, oGssAuthentication, oGssDelegateCreds,
1335962c0e9SDag-Erling Smørgrav 	oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
134aa49c926SDag-Erling Smørgrav 	oSendEnv, oControlPath, oControlMaster, oHashKnownHosts,
135b74df5b2SDag-Erling Smørgrav 	oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand,
1367aee6ffeSDag-Erling Smørgrav 	oVisualHostKey, oUseRoaming, oZeroKnowledgePasswordAuthentication,
137cfa59440SDag-Erling Smørgrav 	oVersionAddendum,
138cf2b5f3bSDag-Erling Smørgrav 	oDeprecated, oUnsupported
139511b41d2SMark Murray } OpCodes;
140511b41d2SMark Murray 
141511b41d2SMark Murray /* Textual representations of the tokens. */
142511b41d2SMark Murray 
143511b41d2SMark Murray static struct {
144511b41d2SMark Murray 	const char *name;
145511b41d2SMark Murray 	OpCodes opcode;
146511b41d2SMark Murray } keywords[] = {
147511b41d2SMark Murray 	{ "forwardagent", oForwardAgent },
148511b41d2SMark Murray 	{ "forwardx11", oForwardX11 },
1491ec0d754SDag-Erling Smørgrav 	{ "forwardx11trusted", oForwardX11Trusted },
150333ee039SDag-Erling Smørgrav 	{ "exitonforwardfailure", oExitOnForwardFailure },
151c2d3a559SKris Kennaway 	{ "xauthlocation", oXAuthLocation },
152511b41d2SMark Murray 	{ "gatewayports", oGatewayPorts },
153511b41d2SMark Murray 	{ "useprivilegedport", oUsePrivilegedPort },
154cf2b5f3bSDag-Erling Smørgrav 	{ "rhostsauthentication", oDeprecated },
155511b41d2SMark Murray 	{ "passwordauthentication", oPasswordAuthentication },
15609958426SBrian Feldman 	{ "kbdinteractiveauthentication", oKbdInteractiveAuthentication },
15709958426SBrian Feldman 	{ "kbdinteractivedevices", oKbdInteractiveDevices },
158511b41d2SMark Murray 	{ "rsaauthentication", oRSAAuthentication },
159ca3176e7SBrian Feldman 	{ "pubkeyauthentication", oPubkeyAuthentication },
160ca3176e7SBrian Feldman 	{ "dsaauthentication", oPubkeyAuthentication },		    /* alias */
161ca3176e7SBrian Feldman 	{ "rhostsrsaauthentication", oRhostsRSAAuthentication },
162ca3176e7SBrian Feldman 	{ "hostbasedauthentication", oHostbasedAuthentication },
163ca3176e7SBrian Feldman 	{ "challengeresponseauthentication", oChallengeResponseAuthentication },
164ca3176e7SBrian Feldman 	{ "skeyauthentication", oChallengeResponseAuthentication }, /* alias */
165ca3176e7SBrian Feldman 	{ "tisauthentication", oChallengeResponseAuthentication },  /* alias */
166cf2b5f3bSDag-Erling Smørgrav 	{ "kerberosauthentication", oUnsupported },
167cf2b5f3bSDag-Erling Smørgrav 	{ "kerberostgtpassing", oUnsupported },
168cf2b5f3bSDag-Erling Smørgrav 	{ "afstokenpassing", oUnsupported },
169cf2b5f3bSDag-Erling Smørgrav #if defined(GSSAPI)
170cf2b5f3bSDag-Erling Smørgrav 	{ "gssapiauthentication", oGssAuthentication },
171cf2b5f3bSDag-Erling Smørgrav 	{ "gssapidelegatecredentials", oGssDelegateCreds },
172cf2b5f3bSDag-Erling Smørgrav #else
173cf2b5f3bSDag-Erling Smørgrav 	{ "gssapiauthentication", oUnsupported },
174cf2b5f3bSDag-Erling Smørgrav 	{ "gssapidelegatecredentials", oUnsupported },
175511b41d2SMark Murray #endif
17680628bacSDag-Erling Smørgrav 	{ "fallbacktorsh", oDeprecated },
17780628bacSDag-Erling Smørgrav 	{ "usersh", oDeprecated },
178511b41d2SMark Murray 	{ "identityfile", oIdentityFile },
179cce7d346SDag-Erling Smørgrav 	{ "identityfile2", oIdentityFile },			/* obsolete */
1805962c0e9SDag-Erling Smørgrav 	{ "identitiesonly", oIdentitiesOnly },
181511b41d2SMark Murray 	{ "hostname", oHostName },
182ca3176e7SBrian Feldman 	{ "hostkeyalias", oHostKeyAlias },
183511b41d2SMark Murray 	{ "proxycommand", oProxyCommand },
184511b41d2SMark Murray 	{ "port", oPort },
185511b41d2SMark Murray 	{ "cipher", oCipher },
186e8aafc91SKris Kennaway 	{ "ciphers", oCiphers },
187ca3176e7SBrian Feldman 	{ "macs", oMacs },
188e8aafc91SKris Kennaway 	{ "protocol", oProtocol },
189511b41d2SMark Murray 	{ "remoteforward", oRemoteForward },
190511b41d2SMark Murray 	{ "localforward", oLocalForward },
191511b41d2SMark Murray 	{ "user", oUser },
192511b41d2SMark Murray 	{ "host", oHost },
193511b41d2SMark Murray 	{ "escapechar", oEscapeChar },
194511b41d2SMark Murray 	{ "globalknownhostsfile", oGlobalKnownHostsFile },
195cce7d346SDag-Erling Smørgrav 	{ "globalknownhostsfile2", oGlobalKnownHostsFile2 },	/* obsolete */
196cce7d346SDag-Erling Smørgrav 	{ "userknownhostsfile", oUserKnownHostsFile },
197af12a3e7SDag-Erling Smørgrav 	{ "userknownhostsfile2", oUserKnownHostsFile2 },	/* obsolete */
198511b41d2SMark Murray 	{ "connectionattempts", oConnectionAttempts },
199511b41d2SMark Murray 	{ "batchmode", oBatchMode },
200511b41d2SMark Murray 	{ "checkhostip", oCheckHostIP },
201511b41d2SMark Murray 	{ "stricthostkeychecking", oStrictHostKeyChecking },
202511b41d2SMark Murray 	{ "compression", oCompression },
203511b41d2SMark Murray 	{ "compressionlevel", oCompressionLevel },
2041ec0d754SDag-Erling Smørgrav 	{ "tcpkeepalive", oTCPKeepAlive },
2051ec0d754SDag-Erling Smørgrav 	{ "keepalive", oTCPKeepAlive },				/* obsolete */
206511b41d2SMark Murray 	{ "numberofpasswordprompts", oNumberOfPasswordPrompts },
207511b41d2SMark Murray 	{ "loglevel", oLogLevel },
208ca3176e7SBrian Feldman 	{ "dynamicforward", oDynamicForward },
209ca3176e7SBrian Feldman 	{ "preferredauthentications", oPreferredAuthentications },
210ca3176e7SBrian Feldman 	{ "hostkeyalgorithms", oHostKeyAlgorithms },
211af12a3e7SDag-Erling Smørgrav 	{ "bindaddress", oBindAddress },
212b15c8340SDag-Erling Smørgrav #ifdef ENABLE_PKCS11
213b15c8340SDag-Erling Smørgrav 	{ "smartcarddevice", oPKCS11Provider },
214b15c8340SDag-Erling Smørgrav 	{ "pkcs11provider", oPKCS11Provider },
215cf2b5f3bSDag-Erling Smørgrav #else
216cf2b5f3bSDag-Erling Smørgrav 	{ "smartcarddevice", oUnsupported },
217b15c8340SDag-Erling Smørgrav 	{ "pkcs11provider", oUnsupported },
218cf2b5f3bSDag-Erling Smørgrav #endif
219af12a3e7SDag-Erling Smørgrav 	{ "clearallforwardings", oClearAllForwardings },
220e73e9afaSDag-Erling Smørgrav 	{ "enablesshkeysign", oEnableSSHKeysign },
221cf2b5f3bSDag-Erling Smørgrav 	{ "verifyhostkeydns", oVerifyHostKeyDNS },
222af12a3e7SDag-Erling Smørgrav 	{ "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
223cf2b5f3bSDag-Erling Smørgrav 	{ "rekeylimit", oRekeyLimit },
224cf2b5f3bSDag-Erling Smørgrav 	{ "connecttimeout", oConnectTimeout },
225cf2b5f3bSDag-Erling Smørgrav 	{ "addressfamily", oAddressFamily },
2261ec0d754SDag-Erling Smørgrav 	{ "serveraliveinterval", oServerAliveInterval },
2271ec0d754SDag-Erling Smørgrav 	{ "serveralivecountmax", oServerAliveCountMax },
22821e764dfSDag-Erling Smørgrav 	{ "sendenv", oSendEnv },
22921e764dfSDag-Erling Smørgrav 	{ "controlpath", oControlPath },
23021e764dfSDag-Erling Smørgrav 	{ "controlmaster", oControlMaster },
231aa49c926SDag-Erling Smørgrav 	{ "hashknownhosts", oHashKnownHosts },
232b74df5b2SDag-Erling Smørgrav 	{ "tunnel", oTunnel },
233b74df5b2SDag-Erling Smørgrav 	{ "tunneldevice", oTunnelDevice },
234b74df5b2SDag-Erling Smørgrav 	{ "localcommand", oLocalCommand },
235b74df5b2SDag-Erling Smørgrav 	{ "permitlocalcommand", oPermitLocalCommand },
236d4af9e69SDag-Erling Smørgrav 	{ "visualhostkey", oVisualHostKey },
2377aee6ffeSDag-Erling Smørgrav 	{ "useroaming", oUseRoaming },
238cce7d346SDag-Erling Smørgrav #ifdef JPAKE
239cce7d346SDag-Erling Smørgrav 	{ "zeroknowledgepasswordauthentication",
240cce7d346SDag-Erling Smørgrav 	    oZeroKnowledgePasswordAuthentication },
241cce7d346SDag-Erling Smørgrav #else
242cce7d346SDag-Erling Smørgrav 	{ "zeroknowledgepasswordauthentication", oUnsupported },
243cce7d346SDag-Erling Smørgrav #endif
244cce7d346SDag-Erling Smørgrav 
245975616f0SDag-Erling Smørgrav 	{ "versionaddendum", oVersionAddendum },
246af12a3e7SDag-Erling Smørgrav 	{ NULL, oBadOption }
247511b41d2SMark Murray };
248511b41d2SMark Murray 
249511b41d2SMark Murray /*
250511b41d2SMark Murray  * Adds a local TCP/IP port forward to options.  Never returns if there is an
251511b41d2SMark Murray  * error.
252511b41d2SMark Murray  */
253511b41d2SMark Murray 
254511b41d2SMark Murray void
255aa49c926SDag-Erling Smørgrav add_local_forward(Options *options, const Forward *newfwd)
256511b41d2SMark Murray {
257511b41d2SMark Murray 	Forward *fwd;
258f388f5efSDag-Erling Smørgrav #ifndef NO_IPPORT_RESERVED_CONCEPT
259511b41d2SMark Murray 	extern uid_t original_real_uid;
26003f6c5cdSDag-Erling Smørgrav 	int ipport_reserved;
26103f6c5cdSDag-Erling Smørgrav #ifdef __FreeBSD__
26203f6c5cdSDag-Erling Smørgrav 	size_t len_ipport_reserved = sizeof(ipport_reserved);
26303f6c5cdSDag-Erling Smørgrav 
26403f6c5cdSDag-Erling Smørgrav 	if (sysctlbyname("net.inet.ip.portrange.reservedhigh",
26503f6c5cdSDag-Erling Smørgrav 	    &ipport_reserved, &len_ipport_reserved, NULL, 0) != 0)
26603f6c5cdSDag-Erling Smørgrav 		ipport_reserved = IPPORT_RESERVED;
26703f6c5cdSDag-Erling Smørgrav 	else
26803f6c5cdSDag-Erling Smørgrav 		ipport_reserved++;
26903f6c5cdSDag-Erling Smørgrav #else
27003f6c5cdSDag-Erling Smørgrav 	ipport_reserved = IPPORT_RESERVED;
27103f6c5cdSDag-Erling Smørgrav #endif
27203f6c5cdSDag-Erling Smørgrav 	if (newfwd->listen_port < ipport_reserved && original_real_uid != 0)
273ca3176e7SBrian Feldman 		fatal("Privileged ports can only be forwarded by root.");
274989dd127SDag-Erling Smørgrav #endif
275511b41d2SMark Murray 	if (options->num_local_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
276511b41d2SMark Murray 		fatal("Too many local forwards (max %d).", SSH_MAX_FORWARDS_PER_DIRECTION);
277511b41d2SMark Murray 	fwd = &options->local_forwards[options->num_local_forwards++];
278aa49c926SDag-Erling Smørgrav 
279cce7d346SDag-Erling Smørgrav 	fwd->listen_host = newfwd->listen_host;
280aa49c926SDag-Erling Smørgrav 	fwd->listen_port = newfwd->listen_port;
281cce7d346SDag-Erling Smørgrav 	fwd->connect_host = newfwd->connect_host;
282aa49c926SDag-Erling Smørgrav 	fwd->connect_port = newfwd->connect_port;
283511b41d2SMark Murray }
284511b41d2SMark Murray 
285511b41d2SMark Murray /*
286511b41d2SMark Murray  * Adds a remote TCP/IP port forward to options.  Never returns if there is
287511b41d2SMark Murray  * an error.
288511b41d2SMark Murray  */
289511b41d2SMark Murray 
290511b41d2SMark Murray void
291aa49c926SDag-Erling Smørgrav add_remote_forward(Options *options, const Forward *newfwd)
292511b41d2SMark Murray {
293511b41d2SMark Murray 	Forward *fwd;
294511b41d2SMark Murray 	if (options->num_remote_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
295511b41d2SMark Murray 		fatal("Too many remote forwards (max %d).",
296511b41d2SMark Murray 		    SSH_MAX_FORWARDS_PER_DIRECTION);
297511b41d2SMark Murray 	fwd = &options->remote_forwards[options->num_remote_forwards++];
298aa49c926SDag-Erling Smørgrav 
299cce7d346SDag-Erling Smørgrav 	fwd->listen_host = newfwd->listen_host;
300aa49c926SDag-Erling Smørgrav 	fwd->listen_port = newfwd->listen_port;
301cce7d346SDag-Erling Smørgrav 	fwd->connect_host = newfwd->connect_host;
302aa49c926SDag-Erling Smørgrav 	fwd->connect_port = newfwd->connect_port;
303511b41d2SMark Murray }
304511b41d2SMark Murray 
305af12a3e7SDag-Erling Smørgrav static void
306af12a3e7SDag-Erling Smørgrav clear_forwardings(Options *options)
307af12a3e7SDag-Erling Smørgrav {
308af12a3e7SDag-Erling Smørgrav 	int i;
309af12a3e7SDag-Erling Smørgrav 
310aa49c926SDag-Erling Smørgrav 	for (i = 0; i < options->num_local_forwards; i++) {
311aa49c926SDag-Erling Smørgrav 		if (options->local_forwards[i].listen_host != NULL)
312aa49c926SDag-Erling Smørgrav 			xfree(options->local_forwards[i].listen_host);
313aa49c926SDag-Erling Smørgrav 		xfree(options->local_forwards[i].connect_host);
314aa49c926SDag-Erling Smørgrav 	}
315af12a3e7SDag-Erling Smørgrav 	options->num_local_forwards = 0;
316aa49c926SDag-Erling Smørgrav 	for (i = 0; i < options->num_remote_forwards; i++) {
317aa49c926SDag-Erling Smørgrav 		if (options->remote_forwards[i].listen_host != NULL)
318aa49c926SDag-Erling Smørgrav 			xfree(options->remote_forwards[i].listen_host);
319aa49c926SDag-Erling Smørgrav 		xfree(options->remote_forwards[i].connect_host);
320aa49c926SDag-Erling Smørgrav 	}
321af12a3e7SDag-Erling Smørgrav 	options->num_remote_forwards = 0;
322b74df5b2SDag-Erling Smørgrav 	options->tun_open = SSH_TUNMODE_NO;
323af12a3e7SDag-Erling Smørgrav }
324af12a3e7SDag-Erling Smørgrav 
325511b41d2SMark Murray /*
326ca3176e7SBrian Feldman  * Returns the number of the token pointed to by cp or oBadOption.
327511b41d2SMark Murray  */
328511b41d2SMark Murray 
329511b41d2SMark Murray static OpCodes
330511b41d2SMark Murray parse_token(const char *cp, const char *filename, int linenum)
331511b41d2SMark Murray {
332ca3176e7SBrian Feldman 	u_int i;
333511b41d2SMark Murray 
334511b41d2SMark Murray 	for (i = 0; keywords[i].name; i++)
335511b41d2SMark Murray 		if (strcasecmp(cp, keywords[i].name) == 0)
336511b41d2SMark Murray 			return keywords[i].opcode;
337511b41d2SMark Murray 
338ca3176e7SBrian Feldman 	error("%s: line %d: Bad configuration option: %s",
339511b41d2SMark Murray 	    filename, linenum, cp);
340511b41d2SMark Murray 	return oBadOption;
341511b41d2SMark Murray }
342511b41d2SMark Murray 
343511b41d2SMark Murray /*
344511b41d2SMark Murray  * Processes a single option line as used in the configuration files. This
345511b41d2SMark Murray  * only sets those values that have not already been set.
346511b41d2SMark Murray  */
347e73e9afaSDag-Erling Smørgrav #define WHITESPACE " \t\r\n"
348511b41d2SMark Murray 
349511b41d2SMark Murray int
350511b41d2SMark Murray process_config_line(Options *options, const char *host,
351511b41d2SMark Murray 		    char *line, const char *filename, int linenum,
352511b41d2SMark Murray 		    int *activep)
353511b41d2SMark Murray {
354aa49c926SDag-Erling Smørgrav 	char *s, **charptr, *endofnumber, *keyword, *arg, *arg2, fwdarg[256];
355333ee039SDag-Erling Smørgrav 	int opcode, *intptr, value, value2, scale;
356d4af9e69SDag-Erling Smørgrav 	LogLevel *log_level_ptr;
357333ee039SDag-Erling Smørgrav 	long long orig, val64;
358e73e9afaSDag-Erling Smørgrav 	size_t len;
359aa49c926SDag-Erling Smørgrav 	Forward fwd;
360511b41d2SMark Murray 
361cf2b5f3bSDag-Erling Smørgrav 	/* Strip trailing whitespace */
362cf2b5f3bSDag-Erling Smørgrav 	for (len = strlen(line) - 1; len > 0; len--) {
363cf2b5f3bSDag-Erling Smørgrav 		if (strchr(WHITESPACE, line[len]) == NULL)
364cf2b5f3bSDag-Erling Smørgrav 			break;
365cf2b5f3bSDag-Erling Smørgrav 		line[len] = '\0';
366cf2b5f3bSDag-Erling Smørgrav 	}
367cf2b5f3bSDag-Erling Smørgrav 
368c2d3a559SKris Kennaway 	s = line;
369c2d3a559SKris Kennaway 	/* Get the keyword. (Each line is supposed to begin with a keyword). */
370333ee039SDag-Erling Smørgrav 	if ((keyword = strdelim(&s)) == NULL)
371333ee039SDag-Erling Smørgrav 		return 0;
372c2d3a559SKris Kennaway 	/* Ignore leading whitespace. */
373c2d3a559SKris Kennaway 	if (*keyword == '\0')
374c2d3a559SKris Kennaway 		keyword = strdelim(&s);
375ca3176e7SBrian Feldman 	if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#')
376511b41d2SMark Murray 		return 0;
377511b41d2SMark Murray 
378c2d3a559SKris Kennaway 	opcode = parse_token(keyword, filename, linenum);
379511b41d2SMark Murray 
380511b41d2SMark Murray 	switch (opcode) {
381511b41d2SMark Murray 	case oBadOption:
382511b41d2SMark Murray 		/* don't panic, but count bad options */
383511b41d2SMark Murray 		return -1;
384511b41d2SMark Murray 		/* NOTREACHED */
385cf2b5f3bSDag-Erling Smørgrav 	case oConnectTimeout:
386cf2b5f3bSDag-Erling Smørgrav 		intptr = &options->connection_timeout;
3871ec0d754SDag-Erling Smørgrav parse_time:
388cf2b5f3bSDag-Erling Smørgrav 		arg = strdelim(&s);
389cf2b5f3bSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
390cf2b5f3bSDag-Erling Smørgrav 			fatal("%s line %d: missing time value.",
391cf2b5f3bSDag-Erling Smørgrav 			    filename, linenum);
392cf2b5f3bSDag-Erling Smørgrav 		if ((value = convtime(arg)) == -1)
393cf2b5f3bSDag-Erling Smørgrav 			fatal("%s line %d: invalid time value.",
394cf2b5f3bSDag-Erling Smørgrav 			    filename, linenum);
395d4af9e69SDag-Erling Smørgrav 		if (*activep && *intptr == -1)
396cf2b5f3bSDag-Erling Smørgrav 			*intptr = value;
397cf2b5f3bSDag-Erling Smørgrav 		break;
398cf2b5f3bSDag-Erling Smørgrav 
399511b41d2SMark Murray 	case oForwardAgent:
400511b41d2SMark Murray 		intptr = &options->forward_agent;
401511b41d2SMark Murray parse_flag:
402c2d3a559SKris Kennaway 		arg = strdelim(&s);
403c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
404511b41d2SMark Murray 			fatal("%.200s line %d: Missing yes/no argument.", filename, linenum);
405511b41d2SMark Murray 		value = 0;	/* To avoid compiler warning... */
406c2d3a559SKris Kennaway 		if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
407511b41d2SMark Murray 			value = 1;
408c2d3a559SKris Kennaway 		else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
409511b41d2SMark Murray 			value = 0;
410511b41d2SMark Murray 		else
411511b41d2SMark Murray 			fatal("%.200s line %d: Bad yes/no argument.", filename, linenum);
412511b41d2SMark Murray 		if (*activep && *intptr == -1)
413511b41d2SMark Murray 			*intptr = value;
414511b41d2SMark Murray 		break;
415511b41d2SMark Murray 
416511b41d2SMark Murray 	case oForwardX11:
417511b41d2SMark Murray 		intptr = &options->forward_x11;
418511b41d2SMark Murray 		goto parse_flag;
419511b41d2SMark Murray 
4201ec0d754SDag-Erling Smørgrav 	case oForwardX11Trusted:
4211ec0d754SDag-Erling Smørgrav 		intptr = &options->forward_x11_trusted;
4221ec0d754SDag-Erling Smørgrav 		goto parse_flag;
4231ec0d754SDag-Erling Smørgrav 
424511b41d2SMark Murray 	case oGatewayPorts:
425511b41d2SMark Murray 		intptr = &options->gateway_ports;
426511b41d2SMark Murray 		goto parse_flag;
427511b41d2SMark Murray 
428333ee039SDag-Erling Smørgrav 	case oExitOnForwardFailure:
429333ee039SDag-Erling Smørgrav 		intptr = &options->exit_on_forward_failure;
430333ee039SDag-Erling Smørgrav 		goto parse_flag;
431333ee039SDag-Erling Smørgrav 
432511b41d2SMark Murray 	case oUsePrivilegedPort:
433511b41d2SMark Murray 		intptr = &options->use_privileged_port;
434511b41d2SMark Murray 		goto parse_flag;
435511b41d2SMark Murray 
436511b41d2SMark Murray 	case oPasswordAuthentication:
437511b41d2SMark Murray 		intptr = &options->password_authentication;
438511b41d2SMark Murray 		goto parse_flag;
439511b41d2SMark Murray 
440cce7d346SDag-Erling Smørgrav 	case oZeroKnowledgePasswordAuthentication:
441cce7d346SDag-Erling Smørgrav 		intptr = &options->zero_knowledge_password_authentication;
442cce7d346SDag-Erling Smørgrav 		goto parse_flag;
443cce7d346SDag-Erling Smørgrav 
44409958426SBrian Feldman 	case oKbdInteractiveAuthentication:
44509958426SBrian Feldman 		intptr = &options->kbd_interactive_authentication;
44609958426SBrian Feldman 		goto parse_flag;
44709958426SBrian Feldman 
44809958426SBrian Feldman 	case oKbdInteractiveDevices:
44909958426SBrian Feldman 		charptr = &options->kbd_interactive_devices;
45009958426SBrian Feldman 		goto parse_string;
45109958426SBrian Feldman 
452ca3176e7SBrian Feldman 	case oPubkeyAuthentication:
453ca3176e7SBrian Feldman 		intptr = &options->pubkey_authentication;
454e8aafc91SKris Kennaway 		goto parse_flag;
455e8aafc91SKris Kennaway 
456511b41d2SMark Murray 	case oRSAAuthentication:
457511b41d2SMark Murray 		intptr = &options->rsa_authentication;
458511b41d2SMark Murray 		goto parse_flag;
459511b41d2SMark Murray 
460511b41d2SMark Murray 	case oRhostsRSAAuthentication:
461511b41d2SMark Murray 		intptr = &options->rhosts_rsa_authentication;
462511b41d2SMark Murray 		goto parse_flag;
463511b41d2SMark Murray 
464ca3176e7SBrian Feldman 	case oHostbasedAuthentication:
465ca3176e7SBrian Feldman 		intptr = &options->hostbased_authentication;
466511b41d2SMark Murray 		goto parse_flag;
467511b41d2SMark Murray 
468af12a3e7SDag-Erling Smørgrav 	case oChallengeResponseAuthentication:
469af12a3e7SDag-Erling Smørgrav 		intptr = &options->challenge_response_authentication;
470af12a3e7SDag-Erling Smørgrav 		goto parse_flag;
471cf2b5f3bSDag-Erling Smørgrav 
472cf2b5f3bSDag-Erling Smørgrav 	case oGssAuthentication:
473cf2b5f3bSDag-Erling Smørgrav 		intptr = &options->gss_authentication;
474511b41d2SMark Murray 		goto parse_flag;
475cf2b5f3bSDag-Erling Smørgrav 
476cf2b5f3bSDag-Erling Smørgrav 	case oGssDelegateCreds:
477cf2b5f3bSDag-Erling Smørgrav 		intptr = &options->gss_deleg_creds;
478ca3176e7SBrian Feldman 		goto parse_flag;
479cf2b5f3bSDag-Erling Smørgrav 
480511b41d2SMark Murray 	case oBatchMode:
481511b41d2SMark Murray 		intptr = &options->batch_mode;
482511b41d2SMark Murray 		goto parse_flag;
483511b41d2SMark Murray 
484511b41d2SMark Murray 	case oCheckHostIP:
485511b41d2SMark Murray 		intptr = &options->check_host_ip;
486511b41d2SMark Murray 		goto parse_flag;
487511b41d2SMark Murray 
488cf2b5f3bSDag-Erling Smørgrav 	case oVerifyHostKeyDNS:
489cf2b5f3bSDag-Erling Smørgrav 		intptr = &options->verify_host_key_dns;
4901ec0d754SDag-Erling Smørgrav 		goto parse_yesnoask;
491cf2b5f3bSDag-Erling Smørgrav 
492511b41d2SMark Murray 	case oStrictHostKeyChecking:
493511b41d2SMark Murray 		intptr = &options->strict_host_key_checking;
4941ec0d754SDag-Erling Smørgrav parse_yesnoask:
495c2d3a559SKris Kennaway 		arg = strdelim(&s);
496c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
497ca3176e7SBrian Feldman 			fatal("%.200s line %d: Missing yes/no/ask argument.",
498511b41d2SMark Murray 			    filename, linenum);
499511b41d2SMark Murray 		value = 0;	/* To avoid compiler warning... */
500c2d3a559SKris Kennaway 		if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
501511b41d2SMark Murray 			value = 1;
502c2d3a559SKris Kennaway 		else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
503511b41d2SMark Murray 			value = 0;
504c2d3a559SKris Kennaway 		else if (strcmp(arg, "ask") == 0)
505511b41d2SMark Murray 			value = 2;
506511b41d2SMark Murray 		else
507511b41d2SMark Murray 			fatal("%.200s line %d: Bad yes/no/ask argument.", filename, linenum);
508511b41d2SMark Murray 		if (*activep && *intptr == -1)
509511b41d2SMark Murray 			*intptr = value;
510511b41d2SMark Murray 		break;
511511b41d2SMark Murray 
512511b41d2SMark Murray 	case oCompression:
513511b41d2SMark Murray 		intptr = &options->compression;
514511b41d2SMark Murray 		goto parse_flag;
515511b41d2SMark Murray 
5161ec0d754SDag-Erling Smørgrav 	case oTCPKeepAlive:
5171ec0d754SDag-Erling Smørgrav 		intptr = &options->tcp_keep_alive;
518511b41d2SMark Murray 		goto parse_flag;
519511b41d2SMark Murray 
520af12a3e7SDag-Erling Smørgrav 	case oNoHostAuthenticationForLocalhost:
521af12a3e7SDag-Erling Smørgrav 		intptr = &options->no_host_authentication_for_localhost;
522af12a3e7SDag-Erling Smørgrav 		goto parse_flag;
523af12a3e7SDag-Erling Smørgrav 
524511b41d2SMark Murray 	case oNumberOfPasswordPrompts:
525511b41d2SMark Murray 		intptr = &options->number_of_password_prompts;
526511b41d2SMark Murray 		goto parse_int;
527511b41d2SMark Murray 
528511b41d2SMark Murray 	case oCompressionLevel:
529511b41d2SMark Murray 		intptr = &options->compression_level;
530511b41d2SMark Murray 		goto parse_int;
531511b41d2SMark Murray 
532cf2b5f3bSDag-Erling Smørgrav 	case oRekeyLimit:
533cf2b5f3bSDag-Erling Smørgrav 		arg = strdelim(&s);
534cf2b5f3bSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
535cf2b5f3bSDag-Erling Smørgrav 			fatal("%.200s line %d: Missing argument.", filename, linenum);
536cf2b5f3bSDag-Erling Smørgrav 		if (arg[0] < '0' || arg[0] > '9')
537cf2b5f3bSDag-Erling Smørgrav 			fatal("%.200s line %d: Bad number.", filename, linenum);
538333ee039SDag-Erling Smørgrav 		orig = val64 = strtoll(arg, &endofnumber, 10);
539cf2b5f3bSDag-Erling Smørgrav 		if (arg == endofnumber)
540cf2b5f3bSDag-Erling Smørgrav 			fatal("%.200s line %d: Bad number.", filename, linenum);
541cf2b5f3bSDag-Erling Smørgrav 		switch (toupper(*endofnumber)) {
542333ee039SDag-Erling Smørgrav 		case '\0':
543333ee039SDag-Erling Smørgrav 			scale = 1;
544333ee039SDag-Erling Smørgrav 			break;
545cf2b5f3bSDag-Erling Smørgrav 		case 'K':
546333ee039SDag-Erling Smørgrav 			scale = 1<<10;
547cf2b5f3bSDag-Erling Smørgrav 			break;
548cf2b5f3bSDag-Erling Smørgrav 		case 'M':
549333ee039SDag-Erling Smørgrav 			scale = 1<<20;
550cf2b5f3bSDag-Erling Smørgrav 			break;
551cf2b5f3bSDag-Erling Smørgrav 		case 'G':
552333ee039SDag-Erling Smørgrav 			scale = 1<<30;
553cf2b5f3bSDag-Erling Smørgrav 			break;
554333ee039SDag-Erling Smørgrav 		default:
555333ee039SDag-Erling Smørgrav 			fatal("%.200s line %d: Invalid RekeyLimit suffix",
556333ee039SDag-Erling Smørgrav 			    filename, linenum);
557cf2b5f3bSDag-Erling Smørgrav 		}
558333ee039SDag-Erling Smørgrav 		val64 *= scale;
559333ee039SDag-Erling Smørgrav 		/* detect integer wrap and too-large limits */
560d4af9e69SDag-Erling Smørgrav 		if ((val64 / scale) != orig || val64 > UINT_MAX)
561333ee039SDag-Erling Smørgrav 			fatal("%.200s line %d: RekeyLimit too large",
562333ee039SDag-Erling Smørgrav 			    filename, linenum);
563333ee039SDag-Erling Smørgrav 		if (val64 < 16)
564333ee039SDag-Erling Smørgrav 			fatal("%.200s line %d: RekeyLimit too small",
565333ee039SDag-Erling Smørgrav 			    filename, linenum);
566d4af9e69SDag-Erling Smørgrav 		if (*activep && options->rekey_limit == -1)
567d4af9e69SDag-Erling Smørgrav 			options->rekey_limit = (u_int32_t)val64;
568cf2b5f3bSDag-Erling Smørgrav 		break;
569cf2b5f3bSDag-Erling Smørgrav 
570511b41d2SMark Murray 	case oIdentityFile:
571c2d3a559SKris Kennaway 		arg = strdelim(&s);
572c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
573511b41d2SMark Murray 			fatal("%.200s line %d: Missing argument.", filename, linenum);
574511b41d2SMark Murray 		if (*activep) {
575ca3176e7SBrian Feldman 			intptr = &options->num_identity_files;
576e8aafc91SKris Kennaway 			if (*intptr >= SSH_MAX_IDENTITY_FILES)
577511b41d2SMark Murray 				fatal("%.200s line %d: Too many identity files specified (max %d).",
578511b41d2SMark Murray 				    filename, linenum, SSH_MAX_IDENTITY_FILES);
579ca3176e7SBrian Feldman 			charptr = &options->identity_files[*intptr];
580c2d3a559SKris Kennaway 			*charptr = xstrdup(arg);
581e8aafc91SKris Kennaway 			*intptr = *intptr + 1;
582511b41d2SMark Murray 		}
583511b41d2SMark Murray 		break;
584511b41d2SMark Murray 
585c2d3a559SKris Kennaway 	case oXAuthLocation:
586c2d3a559SKris Kennaway 		charptr=&options->xauth_location;
587c2d3a559SKris Kennaway 		goto parse_string;
588c2d3a559SKris Kennaway 
589511b41d2SMark Murray 	case oUser:
590511b41d2SMark Murray 		charptr = &options->user;
591511b41d2SMark Murray parse_string:
592c2d3a559SKris Kennaway 		arg = strdelim(&s);
593c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
594511b41d2SMark Murray 			fatal("%.200s line %d: Missing argument.", filename, linenum);
595511b41d2SMark Murray 		if (*activep && *charptr == NULL)
596c2d3a559SKris Kennaway 			*charptr = xstrdup(arg);
597511b41d2SMark Murray 		break;
598511b41d2SMark Murray 
599511b41d2SMark Murray 	case oGlobalKnownHostsFile:
600511b41d2SMark Murray 		charptr = &options->system_hostfile;
601511b41d2SMark Murray 		goto parse_string;
602511b41d2SMark Murray 
603511b41d2SMark Murray 	case oUserKnownHostsFile:
604511b41d2SMark Murray 		charptr = &options->user_hostfile;
605511b41d2SMark Murray 		goto parse_string;
606511b41d2SMark Murray 
607e8aafc91SKris Kennaway 	case oGlobalKnownHostsFile2:
608e8aafc91SKris Kennaway 		charptr = &options->system_hostfile2;
609e8aafc91SKris Kennaway 		goto parse_string;
610e8aafc91SKris Kennaway 
611e8aafc91SKris Kennaway 	case oUserKnownHostsFile2:
612e8aafc91SKris Kennaway 		charptr = &options->user_hostfile2;
613e8aafc91SKris Kennaway 		goto parse_string;
614e8aafc91SKris Kennaway 
615511b41d2SMark Murray 	case oHostName:
616511b41d2SMark Murray 		charptr = &options->hostname;
617511b41d2SMark Murray 		goto parse_string;
618511b41d2SMark Murray 
619ca3176e7SBrian Feldman 	case oHostKeyAlias:
620ca3176e7SBrian Feldman 		charptr = &options->host_key_alias;
621ca3176e7SBrian Feldman 		goto parse_string;
622ca3176e7SBrian Feldman 
623ca3176e7SBrian Feldman 	case oPreferredAuthentications:
624ca3176e7SBrian Feldman 		charptr = &options->preferred_authentications;
625ca3176e7SBrian Feldman 		goto parse_string;
626ca3176e7SBrian Feldman 
627af12a3e7SDag-Erling Smørgrav 	case oBindAddress:
628af12a3e7SDag-Erling Smørgrav 		charptr = &options->bind_address;
629af12a3e7SDag-Erling Smørgrav 		goto parse_string;
630af12a3e7SDag-Erling Smørgrav 
631b15c8340SDag-Erling Smørgrav 	case oPKCS11Provider:
632b15c8340SDag-Erling Smørgrav 		charptr = &options->pkcs11_provider;
633af12a3e7SDag-Erling Smørgrav 		goto parse_string;
634af12a3e7SDag-Erling Smørgrav 
635511b41d2SMark Murray 	case oProxyCommand:
636b74df5b2SDag-Erling Smørgrav 		charptr = &options->proxy_command;
637b74df5b2SDag-Erling Smørgrav parse_command:
638cf2b5f3bSDag-Erling Smørgrav 		if (s == NULL)
639cf2b5f3bSDag-Erling Smørgrav 			fatal("%.200s line %d: Missing argument.", filename, linenum);
640e73e9afaSDag-Erling Smørgrav 		len = strspn(s, WHITESPACE "=");
641511b41d2SMark Murray 		if (*activep && *charptr == NULL)
642e73e9afaSDag-Erling Smørgrav 			*charptr = xstrdup(s + len);
643511b41d2SMark Murray 		return 0;
644511b41d2SMark Murray 
645511b41d2SMark Murray 	case oPort:
646511b41d2SMark Murray 		intptr = &options->port;
647511b41d2SMark Murray parse_int:
648c2d3a559SKris Kennaway 		arg = strdelim(&s);
649c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
650511b41d2SMark Murray 			fatal("%.200s line %d: Missing argument.", filename, linenum);
651c2d3a559SKris Kennaway 		if (arg[0] < '0' || arg[0] > '9')
652511b41d2SMark Murray 			fatal("%.200s line %d: Bad number.", filename, linenum);
653511b41d2SMark Murray 
654511b41d2SMark Murray 		/* Octal, decimal, or hex format? */
655c2d3a559SKris Kennaway 		value = strtol(arg, &endofnumber, 0);
656c2d3a559SKris Kennaway 		if (arg == endofnumber)
657511b41d2SMark Murray 			fatal("%.200s line %d: Bad number.", filename, linenum);
658511b41d2SMark Murray 		if (*activep && *intptr == -1)
659511b41d2SMark Murray 			*intptr = value;
660511b41d2SMark Murray 		break;
661511b41d2SMark Murray 
662511b41d2SMark Murray 	case oConnectionAttempts:
663511b41d2SMark Murray 		intptr = &options->connection_attempts;
664511b41d2SMark Murray 		goto parse_int;
665511b41d2SMark Murray 
666511b41d2SMark Murray 	case oCipher:
667511b41d2SMark Murray 		intptr = &options->cipher;
668c2d3a559SKris Kennaway 		arg = strdelim(&s);
669c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
670db1cb46cSKris Kennaway 			fatal("%.200s line %d: Missing argument.", filename, linenum);
671c2d3a559SKris Kennaway 		value = cipher_number(arg);
672511b41d2SMark Murray 		if (value == -1)
673511b41d2SMark Murray 			fatal("%.200s line %d: Bad cipher '%s'.",
674c2d3a559SKris Kennaway 			    filename, linenum, arg ? arg : "<NONE>");
675511b41d2SMark Murray 		if (*activep && *intptr == -1)
676511b41d2SMark Murray 			*intptr = value;
677511b41d2SMark Murray 		break;
678511b41d2SMark Murray 
679e8aafc91SKris Kennaway 	case oCiphers:
680c2d3a559SKris Kennaway 		arg = strdelim(&s);
681c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
682db1cb46cSKris Kennaway 			fatal("%.200s line %d: Missing argument.", filename, linenum);
683c2d3a559SKris Kennaway 		if (!ciphers_valid(arg))
684e8aafc91SKris Kennaway 			fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.",
685c2d3a559SKris Kennaway 			    filename, linenum, arg ? arg : "<NONE>");
686e8aafc91SKris Kennaway 		if (*activep && options->ciphers == NULL)
687c2d3a559SKris Kennaway 			options->ciphers = xstrdup(arg);
688e8aafc91SKris Kennaway 		break;
689e8aafc91SKris Kennaway 
690ca3176e7SBrian Feldman 	case oMacs:
691ca3176e7SBrian Feldman 		arg = strdelim(&s);
692ca3176e7SBrian Feldman 		if (!arg || *arg == '\0')
693ca3176e7SBrian Feldman 			fatal("%.200s line %d: Missing argument.", filename, linenum);
694ca3176e7SBrian Feldman 		if (!mac_valid(arg))
695ca3176e7SBrian Feldman 			fatal("%.200s line %d: Bad SSH2 Mac spec '%s'.",
696ca3176e7SBrian Feldman 			    filename, linenum, arg ? arg : "<NONE>");
697ca3176e7SBrian Feldman 		if (*activep && options->macs == NULL)
698ca3176e7SBrian Feldman 			options->macs = xstrdup(arg);
699ca3176e7SBrian Feldman 		break;
700ca3176e7SBrian Feldman 
701ca3176e7SBrian Feldman 	case oHostKeyAlgorithms:
702ca3176e7SBrian Feldman 		arg = strdelim(&s);
703ca3176e7SBrian Feldman 		if (!arg || *arg == '\0')
704ca3176e7SBrian Feldman 			fatal("%.200s line %d: Missing argument.", filename, linenum);
705ca3176e7SBrian Feldman 		if (!key_names_valid2(arg))
706ca3176e7SBrian Feldman 			fatal("%.200s line %d: Bad protocol 2 host key algorithms '%s'.",
707ca3176e7SBrian Feldman 			    filename, linenum, arg ? arg : "<NONE>");
708ca3176e7SBrian Feldman 		if (*activep && options->hostkeyalgorithms == NULL)
709ca3176e7SBrian Feldman 			options->hostkeyalgorithms = xstrdup(arg);
710ca3176e7SBrian Feldman 		break;
711ca3176e7SBrian Feldman 
712e8aafc91SKris Kennaway 	case oProtocol:
713e8aafc91SKris Kennaway 		intptr = &options->protocol;
714c2d3a559SKris Kennaway 		arg = strdelim(&s);
715c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
716db1cb46cSKris Kennaway 			fatal("%.200s line %d: Missing argument.", filename, linenum);
717c2d3a559SKris Kennaway 		value = proto_spec(arg);
718e8aafc91SKris Kennaway 		if (value == SSH_PROTO_UNKNOWN)
719e8aafc91SKris Kennaway 			fatal("%.200s line %d: Bad protocol spec '%s'.",
720c2d3a559SKris Kennaway 			    filename, linenum, arg ? arg : "<NONE>");
721e8aafc91SKris Kennaway 		if (*activep && *intptr == SSH_PROTO_UNKNOWN)
722e8aafc91SKris Kennaway 			*intptr = value;
723e8aafc91SKris Kennaway 		break;
724e8aafc91SKris Kennaway 
725511b41d2SMark Murray 	case oLogLevel:
726d4af9e69SDag-Erling Smørgrav 		log_level_ptr = &options->log_level;
727c2d3a559SKris Kennaway 		arg = strdelim(&s);
728c2d3a559SKris Kennaway 		value = log_level_number(arg);
729af12a3e7SDag-Erling Smørgrav 		if (value == SYSLOG_LEVEL_NOT_SET)
730ca3176e7SBrian Feldman 			fatal("%.200s line %d: unsupported log level '%s'",
731c2d3a559SKris Kennaway 			    filename, linenum, arg ? arg : "<NONE>");
732d4af9e69SDag-Erling Smørgrav 		if (*activep && *log_level_ptr == SYSLOG_LEVEL_NOT_SET)
733d4af9e69SDag-Erling Smørgrav 			*log_level_ptr = (LogLevel) value;
734511b41d2SMark Murray 		break;
735511b41d2SMark Murray 
736af12a3e7SDag-Erling Smørgrav 	case oLocalForward:
737511b41d2SMark Murray 	case oRemoteForward:
738cce7d346SDag-Erling Smørgrav 	case oDynamicForward:
739c2d3a559SKris Kennaway 		arg = strdelim(&s);
740aa49c926SDag-Erling Smørgrav 		if (arg == NULL || *arg == '\0')
741af12a3e7SDag-Erling Smørgrav 			fatal("%.200s line %d: Missing port argument.",
742af12a3e7SDag-Erling Smørgrav 			    filename, linenum);
743cce7d346SDag-Erling Smørgrav 
744cce7d346SDag-Erling Smørgrav 		if (opcode == oLocalForward ||
745cce7d346SDag-Erling Smørgrav 		    opcode == oRemoteForward) {
746aa49c926SDag-Erling Smørgrav 			arg2 = strdelim(&s);
747aa49c926SDag-Erling Smørgrav 			if (arg2 == NULL || *arg2 == '\0')
748aa49c926SDag-Erling Smørgrav 				fatal("%.200s line %d: Missing target argument.",
749511b41d2SMark Murray 				    filename, linenum);
750aa49c926SDag-Erling Smørgrav 
751aa49c926SDag-Erling Smørgrav 			/* construct a string for parse_forward */
752aa49c926SDag-Erling Smørgrav 			snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg, arg2);
753cce7d346SDag-Erling Smørgrav 		} else if (opcode == oDynamicForward) {
754cce7d346SDag-Erling Smørgrav 			strlcpy(fwdarg, arg, sizeof(fwdarg));
755cce7d346SDag-Erling Smørgrav 		}
756aa49c926SDag-Erling Smørgrav 
757cce7d346SDag-Erling Smørgrav 		if (parse_forward(&fwd, fwdarg,
758cce7d346SDag-Erling Smørgrav 		    opcode == oDynamicForward ? 1 : 0,
759cce7d346SDag-Erling Smørgrav 		    opcode == oRemoteForward ? 1 : 0) == 0)
760af12a3e7SDag-Erling Smørgrav 			fatal("%.200s line %d: Bad forwarding specification.",
761511b41d2SMark Murray 			    filename, linenum);
762aa49c926SDag-Erling Smørgrav 
763af12a3e7SDag-Erling Smørgrav 		if (*activep) {
764cce7d346SDag-Erling Smørgrav 			if (opcode == oLocalForward ||
765cce7d346SDag-Erling Smørgrav 			    opcode == oDynamicForward)
766aa49c926SDag-Erling Smørgrav 				add_local_forward(options, &fwd);
767af12a3e7SDag-Erling Smørgrav 			else if (opcode == oRemoteForward)
768aa49c926SDag-Erling Smørgrav 				add_remote_forward(options, &fwd);
769af12a3e7SDag-Erling Smørgrav 		}
770511b41d2SMark Murray 		break;
771511b41d2SMark Murray 
772af12a3e7SDag-Erling Smørgrav 	case oClearAllForwardings:
773af12a3e7SDag-Erling Smørgrav 		intptr = &options->clear_forwardings;
774af12a3e7SDag-Erling Smørgrav 		goto parse_flag;
775af12a3e7SDag-Erling Smørgrav 
776511b41d2SMark Murray 	case oHost:
777511b41d2SMark Murray 		*activep = 0;
778c2d3a559SKris Kennaway 		while ((arg = strdelim(&s)) != NULL && *arg != '\0')
779c2d3a559SKris Kennaway 			if (match_pattern(host, arg)) {
780c2d3a559SKris Kennaway 				debug("Applying options for %.100s", arg);
781511b41d2SMark Murray 				*activep = 1;
782511b41d2SMark Murray 				break;
783511b41d2SMark Murray 			}
784c2d3a559SKris Kennaway 		/* Avoid garbage check below, as strdelim is done. */
785511b41d2SMark Murray 		return 0;
786511b41d2SMark Murray 
787511b41d2SMark Murray 	case oEscapeChar:
788511b41d2SMark Murray 		intptr = &options->escape_char;
789c2d3a559SKris Kennaway 		arg = strdelim(&s);
790c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
791511b41d2SMark Murray 			fatal("%.200s line %d: Missing argument.", filename, linenum);
792c2d3a559SKris Kennaway 		if (arg[0] == '^' && arg[2] == 0 &&
793ca3176e7SBrian Feldman 		    (u_char) arg[1] >= 64 && (u_char) arg[1] < 128)
794ca3176e7SBrian Feldman 			value = (u_char) arg[1] & 31;
795c2d3a559SKris Kennaway 		else if (strlen(arg) == 1)
796ca3176e7SBrian Feldman 			value = (u_char) arg[0];
797c2d3a559SKris Kennaway 		else if (strcmp(arg, "none") == 0)
798af12a3e7SDag-Erling Smørgrav 			value = SSH_ESCAPECHAR_NONE;
799511b41d2SMark Murray 		else {
800511b41d2SMark Murray 			fatal("%.200s line %d: Bad escape character.",
801511b41d2SMark Murray 			    filename, linenum);
802511b41d2SMark Murray 			/* NOTREACHED */
803511b41d2SMark Murray 			value = 0;	/* Avoid compiler warning. */
804511b41d2SMark Murray 		}
805511b41d2SMark Murray 		if (*activep && *intptr == -1)
806511b41d2SMark Murray 			*intptr = value;
807511b41d2SMark Murray 		break;
808511b41d2SMark Murray 
809cf2b5f3bSDag-Erling Smørgrav 	case oAddressFamily:
810cf2b5f3bSDag-Erling Smørgrav 		arg = strdelim(&s);
811d4ecd108SDag-Erling Smørgrav 		if (!arg || *arg == '\0')
812d4ecd108SDag-Erling Smørgrav 			fatal("%s line %d: missing address family.",
813d4ecd108SDag-Erling Smørgrav 			    filename, linenum);
814cf2b5f3bSDag-Erling Smørgrav 		intptr = &options->address_family;
815cf2b5f3bSDag-Erling Smørgrav 		if (strcasecmp(arg, "inet") == 0)
816cf2b5f3bSDag-Erling Smørgrav 			value = AF_INET;
817cf2b5f3bSDag-Erling Smørgrav 		else if (strcasecmp(arg, "inet6") == 0)
818cf2b5f3bSDag-Erling Smørgrav 			value = AF_INET6;
819cf2b5f3bSDag-Erling Smørgrav 		else if (strcasecmp(arg, "any") == 0)
820cf2b5f3bSDag-Erling Smørgrav 			value = AF_UNSPEC;
821cf2b5f3bSDag-Erling Smørgrav 		else
822cf2b5f3bSDag-Erling Smørgrav 			fatal("Unsupported AddressFamily \"%s\"", arg);
823cf2b5f3bSDag-Erling Smørgrav 		if (*activep && *intptr == -1)
824cf2b5f3bSDag-Erling Smørgrav 			*intptr = value;
825cf2b5f3bSDag-Erling Smørgrav 		break;
826cf2b5f3bSDag-Erling Smørgrav 
827e73e9afaSDag-Erling Smørgrav 	case oEnableSSHKeysign:
828e73e9afaSDag-Erling Smørgrav 		intptr = &options->enable_ssh_keysign;
829e73e9afaSDag-Erling Smørgrav 		goto parse_flag;
830e73e9afaSDag-Erling Smørgrav 
8315962c0e9SDag-Erling Smørgrav 	case oIdentitiesOnly:
8325962c0e9SDag-Erling Smørgrav 		intptr = &options->identities_only;
8335962c0e9SDag-Erling Smørgrav 		goto parse_flag;
8345962c0e9SDag-Erling Smørgrav 
8351ec0d754SDag-Erling Smørgrav 	case oServerAliveInterval:
8361ec0d754SDag-Erling Smørgrav 		intptr = &options->server_alive_interval;
8371ec0d754SDag-Erling Smørgrav 		goto parse_time;
8381ec0d754SDag-Erling Smørgrav 
8391ec0d754SDag-Erling Smørgrav 	case oServerAliveCountMax:
8401ec0d754SDag-Erling Smørgrav 		intptr = &options->server_alive_count_max;
8411ec0d754SDag-Erling Smørgrav 		goto parse_int;
8421ec0d754SDag-Erling Smørgrav 
84321e764dfSDag-Erling Smørgrav 	case oSendEnv:
84421e764dfSDag-Erling Smørgrav 		while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
84521e764dfSDag-Erling Smørgrav 			if (strchr(arg, '=') != NULL)
84621e764dfSDag-Erling Smørgrav 				fatal("%s line %d: Invalid environment name.",
84721e764dfSDag-Erling Smørgrav 				    filename, linenum);
848aa49c926SDag-Erling Smørgrav 			if (!*activep)
849aa49c926SDag-Erling Smørgrav 				continue;
85021e764dfSDag-Erling Smørgrav 			if (options->num_send_env >= MAX_SEND_ENV)
85121e764dfSDag-Erling Smørgrav 				fatal("%s line %d: too many send env.",
85221e764dfSDag-Erling Smørgrav 				    filename, linenum);
85321e764dfSDag-Erling Smørgrav 			options->send_env[options->num_send_env++] =
85421e764dfSDag-Erling Smørgrav 			    xstrdup(arg);
85521e764dfSDag-Erling Smørgrav 		}
85621e764dfSDag-Erling Smørgrav 		break;
85721e764dfSDag-Erling Smørgrav 
85821e764dfSDag-Erling Smørgrav 	case oControlPath:
85921e764dfSDag-Erling Smørgrav 		charptr = &options->control_path;
86021e764dfSDag-Erling Smørgrav 		goto parse_string;
86121e764dfSDag-Erling Smørgrav 
86221e764dfSDag-Erling Smørgrav 	case oControlMaster:
86321e764dfSDag-Erling Smørgrav 		intptr = &options->control_master;
864d4ecd108SDag-Erling Smørgrav 		arg = strdelim(&s);
865d4ecd108SDag-Erling Smørgrav 		if (!arg || *arg == '\0')
866d4ecd108SDag-Erling Smørgrav 			fatal("%.200s line %d: Missing ControlMaster argument.",
867d4ecd108SDag-Erling Smørgrav 			    filename, linenum);
868d4ecd108SDag-Erling Smørgrav 		value = 0;	/* To avoid compiler warning... */
869d4ecd108SDag-Erling Smørgrav 		if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
870d4ecd108SDag-Erling Smørgrav 			value = SSHCTL_MASTER_YES;
871d4ecd108SDag-Erling Smørgrav 		else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
872d4ecd108SDag-Erling Smørgrav 			value = SSHCTL_MASTER_NO;
873d4ecd108SDag-Erling Smørgrav 		else if (strcmp(arg, "auto") == 0)
874d4ecd108SDag-Erling Smørgrav 			value = SSHCTL_MASTER_AUTO;
875d4ecd108SDag-Erling Smørgrav 		else if (strcmp(arg, "ask") == 0)
876d4ecd108SDag-Erling Smørgrav 			value = SSHCTL_MASTER_ASK;
877d4ecd108SDag-Erling Smørgrav 		else if (strcmp(arg, "autoask") == 0)
878d4ecd108SDag-Erling Smørgrav 			value = SSHCTL_MASTER_AUTO_ASK;
879d4ecd108SDag-Erling Smørgrav 		else
880d4ecd108SDag-Erling Smørgrav 			fatal("%.200s line %d: Bad ControlMaster argument.",
881d4ecd108SDag-Erling Smørgrav 			    filename, linenum);
882d4ecd108SDag-Erling Smørgrav 		if (*activep && *intptr == -1)
883d4ecd108SDag-Erling Smørgrav 			*intptr = value;
884d4ecd108SDag-Erling Smørgrav 		break;
88521e764dfSDag-Erling Smørgrav 
886aa49c926SDag-Erling Smørgrav 	case oHashKnownHosts:
887aa49c926SDag-Erling Smørgrav 		intptr = &options->hash_known_hosts;
888aa49c926SDag-Erling Smørgrav 		goto parse_flag;
889aa49c926SDag-Erling Smørgrav 
890b74df5b2SDag-Erling Smørgrav 	case oTunnel:
891b74df5b2SDag-Erling Smørgrav 		intptr = &options->tun_open;
892b74df5b2SDag-Erling Smørgrav 		arg = strdelim(&s);
893b74df5b2SDag-Erling Smørgrav 		if (!arg || *arg == '\0')
894b74df5b2SDag-Erling Smørgrav 			fatal("%s line %d: Missing yes/point-to-point/"
895b74df5b2SDag-Erling Smørgrav 			    "ethernet/no argument.", filename, linenum);
896b74df5b2SDag-Erling Smørgrav 		value = 0;	/* silence compiler */
897b74df5b2SDag-Erling Smørgrav 		if (strcasecmp(arg, "ethernet") == 0)
898b74df5b2SDag-Erling Smørgrav 			value = SSH_TUNMODE_ETHERNET;
899b74df5b2SDag-Erling Smørgrav 		else if (strcasecmp(arg, "point-to-point") == 0)
900b74df5b2SDag-Erling Smørgrav 			value = SSH_TUNMODE_POINTOPOINT;
901b74df5b2SDag-Erling Smørgrav 		else if (strcasecmp(arg, "yes") == 0)
902b74df5b2SDag-Erling Smørgrav 			value = SSH_TUNMODE_DEFAULT;
903b74df5b2SDag-Erling Smørgrav 		else if (strcasecmp(arg, "no") == 0)
904b74df5b2SDag-Erling Smørgrav 			value = SSH_TUNMODE_NO;
905b74df5b2SDag-Erling Smørgrav 		else
906b74df5b2SDag-Erling Smørgrav 			fatal("%s line %d: Bad yes/point-to-point/ethernet/"
907b74df5b2SDag-Erling Smørgrav 			    "no argument: %s", filename, linenum, arg);
908b74df5b2SDag-Erling Smørgrav 		if (*activep)
909b74df5b2SDag-Erling Smørgrav 			*intptr = value;
910b74df5b2SDag-Erling Smørgrav 		break;
911b74df5b2SDag-Erling Smørgrav 
912b74df5b2SDag-Erling Smørgrav 	case oTunnelDevice:
913b74df5b2SDag-Erling Smørgrav 		arg = strdelim(&s);
914b74df5b2SDag-Erling Smørgrav 		if (!arg || *arg == '\0')
915b74df5b2SDag-Erling Smørgrav 			fatal("%.200s line %d: Missing argument.", filename, linenum);
916b74df5b2SDag-Erling Smørgrav 		value = a2tun(arg, &value2);
917b74df5b2SDag-Erling Smørgrav 		if (value == SSH_TUNID_ERR)
918b74df5b2SDag-Erling Smørgrav 			fatal("%.200s line %d: Bad tun device.", filename, linenum);
919b74df5b2SDag-Erling Smørgrav 		if (*activep) {
920b74df5b2SDag-Erling Smørgrav 			options->tun_local = value;
921b74df5b2SDag-Erling Smørgrav 			options->tun_remote = value2;
922b74df5b2SDag-Erling Smørgrav 		}
923b74df5b2SDag-Erling Smørgrav 		break;
924b74df5b2SDag-Erling Smørgrav 
925b74df5b2SDag-Erling Smørgrav 	case oLocalCommand:
926b74df5b2SDag-Erling Smørgrav 		charptr = &options->local_command;
927b74df5b2SDag-Erling Smørgrav 		goto parse_command;
928b74df5b2SDag-Erling Smørgrav 
929b74df5b2SDag-Erling Smørgrav 	case oPermitLocalCommand:
930b74df5b2SDag-Erling Smørgrav 		intptr = &options->permit_local_command;
931b74df5b2SDag-Erling Smørgrav 		goto parse_flag;
932b74df5b2SDag-Erling Smørgrav 
933d4af9e69SDag-Erling Smørgrav 	case oVisualHostKey:
934d4af9e69SDag-Erling Smørgrav 		intptr = &options->visual_host_key;
935d4af9e69SDag-Erling Smørgrav 		goto parse_flag;
936d4af9e69SDag-Erling Smørgrav 
9377aee6ffeSDag-Erling Smørgrav 	case oUseRoaming:
9387aee6ffeSDag-Erling Smørgrav 		intptr = &options->use_roaming;
9397aee6ffeSDag-Erling Smørgrav 		goto parse_flag;
9407aee6ffeSDag-Erling Smørgrav 
941975616f0SDag-Erling Smørgrav 	case oVersionAddendum:
942975616f0SDag-Erling Smørgrav 		ssh_version_set_addendum(strtok(s, "\n"));
943975616f0SDag-Erling Smørgrav 		do {
944975616f0SDag-Erling Smørgrav 			arg = strdelim(&s);
945975616f0SDag-Erling Smørgrav 		} while (arg != NULL && *arg != '\0');
946975616f0SDag-Erling Smørgrav 		break;
947975616f0SDag-Erling Smørgrav 
94880628bacSDag-Erling Smørgrav 	case oDeprecated:
94980628bacSDag-Erling Smørgrav 		debug("%s line %d: Deprecated option \"%s\"",
95080628bacSDag-Erling Smørgrav 		    filename, linenum, keyword);
95180628bacSDag-Erling Smørgrav 		return 0;
95280628bacSDag-Erling Smørgrav 
953cf2b5f3bSDag-Erling Smørgrav 	case oUnsupported:
954cf2b5f3bSDag-Erling Smørgrav 		error("%s line %d: Unsupported option \"%s\"",
955cf2b5f3bSDag-Erling Smørgrav 		    filename, linenum, keyword);
956cf2b5f3bSDag-Erling Smørgrav 		return 0;
957cf2b5f3bSDag-Erling Smørgrav 
958511b41d2SMark Murray 	default:
959511b41d2SMark Murray 		fatal("process_config_line: Unimplemented opcode %d", opcode);
960511b41d2SMark Murray 	}
961511b41d2SMark Murray 
962511b41d2SMark Murray 	/* Check that there is no garbage at end of line. */
963ca3176e7SBrian Feldman 	if ((arg = strdelim(&s)) != NULL && *arg != '\0') {
964c2d3a559SKris Kennaway 		fatal("%.200s line %d: garbage at end of line; \"%.200s\".",
965c2d3a559SKris Kennaway 		    filename, linenum, arg);
966c2d3a559SKris Kennaway 	}
967511b41d2SMark Murray 	return 0;
968511b41d2SMark Murray }
969511b41d2SMark Murray 
970511b41d2SMark Murray 
971511b41d2SMark Murray /*
972511b41d2SMark Murray  * Reads the config file and modifies the options accordingly.  Options
973511b41d2SMark Murray  * should already be initialized before this call.  This never returns if
974af12a3e7SDag-Erling Smørgrav  * there is an error.  If the file does not exist, this returns 0.
975511b41d2SMark Murray  */
976511b41d2SMark Murray 
977af12a3e7SDag-Erling Smørgrav int
97821e764dfSDag-Erling Smørgrav read_config_file(const char *filename, const char *host, Options *options,
97921e764dfSDag-Erling Smørgrav     int checkperm)
980511b41d2SMark Murray {
981511b41d2SMark Murray 	FILE *f;
982511b41d2SMark Murray 	char line[1024];
983511b41d2SMark Murray 	int active, linenum;
984511b41d2SMark Murray 	int bad_options = 0;
985511b41d2SMark Murray 
98621e764dfSDag-Erling Smørgrav 	if ((f = fopen(filename, "r")) == NULL)
987af12a3e7SDag-Erling Smørgrav 		return 0;
988511b41d2SMark Murray 
98921e764dfSDag-Erling Smørgrav 	if (checkperm) {
99021e764dfSDag-Erling Smørgrav 		struct stat sb;
99121e764dfSDag-Erling Smørgrav 
99221e764dfSDag-Erling Smørgrav 		if (fstat(fileno(f), &sb) == -1)
99321e764dfSDag-Erling Smørgrav 			fatal("fstat %s: %s", filename, strerror(errno));
99421e764dfSDag-Erling Smørgrav 		if (((sb.st_uid != 0 && sb.st_uid != getuid()) ||
99521e764dfSDag-Erling Smørgrav 		    (sb.st_mode & 022) != 0))
99621e764dfSDag-Erling Smørgrav 			fatal("Bad owner or permissions on %s", filename);
99721e764dfSDag-Erling Smørgrav 	}
99821e764dfSDag-Erling Smørgrav 
999511b41d2SMark Murray 	debug("Reading configuration data %.200s", filename);
1000511b41d2SMark Murray 
1001511b41d2SMark Murray 	/*
1002511b41d2SMark Murray 	 * Mark that we are now processing the options.  This flag is turned
1003511b41d2SMark Murray 	 * on/off by Host specifications.
1004511b41d2SMark Murray 	 */
1005511b41d2SMark Murray 	active = 1;
1006511b41d2SMark Murray 	linenum = 0;
1007511b41d2SMark Murray 	while (fgets(line, sizeof(line), f)) {
1008511b41d2SMark Murray 		/* Update line number counter. */
1009511b41d2SMark Murray 		linenum++;
1010511b41d2SMark Murray 		if (process_config_line(options, host, line, filename, linenum, &active) != 0)
1011511b41d2SMark Murray 			bad_options++;
1012511b41d2SMark Murray 	}
1013511b41d2SMark Murray 	fclose(f);
1014511b41d2SMark Murray 	if (bad_options > 0)
1015ca3176e7SBrian Feldman 		fatal("%s: terminating, %d bad configuration options",
1016511b41d2SMark Murray 		    filename, bad_options);
1017af12a3e7SDag-Erling Smørgrav 	return 1;
1018511b41d2SMark Murray }
1019511b41d2SMark Murray 
1020511b41d2SMark Murray /*
1021511b41d2SMark Murray  * Initializes options to special values that indicate that they have not yet
1022511b41d2SMark Murray  * been set.  Read_config_file will only set options with this value. Options
1023511b41d2SMark Murray  * are processed in the following order: command line, user config file,
1024511b41d2SMark Murray  * system config file.  Last, fill_default_options is called.
1025511b41d2SMark Murray  */
1026511b41d2SMark Murray 
1027511b41d2SMark Murray void
1028511b41d2SMark Murray initialize_options(Options * options)
1029511b41d2SMark Murray {
1030511b41d2SMark Murray 	memset(options, 'X', sizeof(*options));
1031511b41d2SMark Murray 	options->forward_agent = -1;
1032511b41d2SMark Murray 	options->forward_x11 = -1;
10331ec0d754SDag-Erling Smørgrav 	options->forward_x11_trusted = -1;
1034333ee039SDag-Erling Smørgrav 	options->exit_on_forward_failure = -1;
1035c2d3a559SKris Kennaway 	options->xauth_location = NULL;
1036511b41d2SMark Murray 	options->gateway_ports = -1;
1037511b41d2SMark Murray 	options->use_privileged_port = -1;
1038511b41d2SMark Murray 	options->rsa_authentication = -1;
1039ca3176e7SBrian Feldman 	options->pubkey_authentication = -1;
1040af12a3e7SDag-Erling Smørgrav 	options->challenge_response_authentication = -1;
1041cf2b5f3bSDag-Erling Smørgrav 	options->gss_authentication = -1;
1042cf2b5f3bSDag-Erling Smørgrav 	options->gss_deleg_creds = -1;
1043511b41d2SMark Murray 	options->password_authentication = -1;
104409958426SBrian Feldman 	options->kbd_interactive_authentication = -1;
104509958426SBrian Feldman 	options->kbd_interactive_devices = NULL;
1046511b41d2SMark Murray 	options->rhosts_rsa_authentication = -1;
1047ca3176e7SBrian Feldman 	options->hostbased_authentication = -1;
1048511b41d2SMark Murray 	options->batch_mode = -1;
1049511b41d2SMark Murray 	options->check_host_ip = -1;
1050511b41d2SMark Murray 	options->strict_host_key_checking = -1;
1051511b41d2SMark Murray 	options->compression = -1;
10521ec0d754SDag-Erling Smørgrav 	options->tcp_keep_alive = -1;
1053511b41d2SMark Murray 	options->compression_level = -1;
1054511b41d2SMark Murray 	options->port = -1;
1055cf2b5f3bSDag-Erling Smørgrav 	options->address_family = -1;
1056511b41d2SMark Murray 	options->connection_attempts = -1;
1057cf2b5f3bSDag-Erling Smørgrav 	options->connection_timeout = -1;
1058511b41d2SMark Murray 	options->number_of_password_prompts = -1;
1059511b41d2SMark Murray 	options->cipher = -1;
1060e8aafc91SKris Kennaway 	options->ciphers = NULL;
1061ca3176e7SBrian Feldman 	options->macs = NULL;
1062ca3176e7SBrian Feldman 	options->hostkeyalgorithms = NULL;
1063e8aafc91SKris Kennaway 	options->protocol = SSH_PROTO_UNKNOWN;
1064511b41d2SMark Murray 	options->num_identity_files = 0;
1065511b41d2SMark Murray 	options->hostname = NULL;
1066ca3176e7SBrian Feldman 	options->host_key_alias = NULL;
1067511b41d2SMark Murray 	options->proxy_command = NULL;
1068511b41d2SMark Murray 	options->user = NULL;
1069511b41d2SMark Murray 	options->escape_char = -1;
1070511b41d2SMark Murray 	options->system_hostfile = NULL;
1071511b41d2SMark Murray 	options->user_hostfile = NULL;
1072e8aafc91SKris Kennaway 	options->system_hostfile2 = NULL;
1073e8aafc91SKris Kennaway 	options->user_hostfile2 = NULL;
1074511b41d2SMark Murray 	options->num_local_forwards = 0;
1075511b41d2SMark Murray 	options->num_remote_forwards = 0;
1076af12a3e7SDag-Erling Smørgrav 	options->clear_forwardings = -1;
1077af12a3e7SDag-Erling Smørgrav 	options->log_level = SYSLOG_LEVEL_NOT_SET;
1078ca3176e7SBrian Feldman 	options->preferred_authentications = NULL;
1079af12a3e7SDag-Erling Smørgrav 	options->bind_address = NULL;
1080b15c8340SDag-Erling Smørgrav 	options->pkcs11_provider = NULL;
1081e73e9afaSDag-Erling Smørgrav 	options->enable_ssh_keysign = - 1;
1082af12a3e7SDag-Erling Smørgrav 	options->no_host_authentication_for_localhost = - 1;
10835962c0e9SDag-Erling Smørgrav 	options->identities_only = - 1;
1084cf2b5f3bSDag-Erling Smørgrav 	options->rekey_limit = - 1;
1085cf2b5f3bSDag-Erling Smørgrav 	options->verify_host_key_dns = -1;
10861ec0d754SDag-Erling Smørgrav 	options->server_alive_interval = -1;
10871ec0d754SDag-Erling Smørgrav 	options->server_alive_count_max = -1;
108821e764dfSDag-Erling Smørgrav 	options->num_send_env = 0;
108921e764dfSDag-Erling Smørgrav 	options->control_path = NULL;
109021e764dfSDag-Erling Smørgrav 	options->control_master = -1;
1091aa49c926SDag-Erling Smørgrav 	options->hash_known_hosts = -1;
1092b74df5b2SDag-Erling Smørgrav 	options->tun_open = -1;
1093b74df5b2SDag-Erling Smørgrav 	options->tun_local = -1;
1094b74df5b2SDag-Erling Smørgrav 	options->tun_remote = -1;
1095b74df5b2SDag-Erling Smørgrav 	options->local_command = NULL;
1096b74df5b2SDag-Erling Smørgrav 	options->permit_local_command = -1;
10977aee6ffeSDag-Erling Smørgrav 	options->use_roaming = -1;
1098d4af9e69SDag-Erling Smørgrav 	options->visual_host_key = -1;
1099cce7d346SDag-Erling Smørgrav 	options->zero_knowledge_password_authentication = -1;
1100511b41d2SMark Murray }
1101511b41d2SMark Murray 
1102511b41d2SMark Murray /*
1103511b41d2SMark Murray  * Called after processing other sources of option data, this fills those
1104511b41d2SMark Murray  * options for which no value has been specified with their default values.
1105511b41d2SMark Murray  */
1106511b41d2SMark Murray 
1107511b41d2SMark Murray void
1108511b41d2SMark Murray fill_default_options(Options * options)
1109511b41d2SMark Murray {
1110ca3176e7SBrian Feldman 	int len;
1111ca3176e7SBrian Feldman 
1112511b41d2SMark Murray 	if (options->forward_agent == -1)
1113db1cb46cSKris Kennaway 		options->forward_agent = 0;
1114511b41d2SMark Murray 	if (options->forward_x11 == -1)
11155dc73ebeSBrian Feldman 		options->forward_x11 = 0;
11161ec0d754SDag-Erling Smørgrav 	if (options->forward_x11_trusted == -1)
11171ec0d754SDag-Erling Smørgrav 		options->forward_x11_trusted = 0;
1118333ee039SDag-Erling Smørgrav 	if (options->exit_on_forward_failure == -1)
1119333ee039SDag-Erling Smørgrav 		options->exit_on_forward_failure = 0;
1120c2d3a559SKris Kennaway 	if (options->xauth_location == NULL)
1121af12a3e7SDag-Erling Smørgrav 		options->xauth_location = _PATH_XAUTH;
1122511b41d2SMark Murray 	if (options->gateway_ports == -1)
1123511b41d2SMark Murray 		options->gateway_ports = 0;
1124511b41d2SMark Murray 	if (options->use_privileged_port == -1)
1125ca3176e7SBrian Feldman 		options->use_privileged_port = 0;
1126511b41d2SMark Murray 	if (options->rsa_authentication == -1)
1127511b41d2SMark Murray 		options->rsa_authentication = 1;
1128ca3176e7SBrian Feldman 	if (options->pubkey_authentication == -1)
1129ca3176e7SBrian Feldman 		options->pubkey_authentication = 1;
1130af12a3e7SDag-Erling Smørgrav 	if (options->challenge_response_authentication == -1)
1131af12a3e7SDag-Erling Smørgrav 		options->challenge_response_authentication = 1;
1132cf2b5f3bSDag-Erling Smørgrav 	if (options->gss_authentication == -1)
11331ec0d754SDag-Erling Smørgrav 		options->gss_authentication = 0;
1134cf2b5f3bSDag-Erling Smørgrav 	if (options->gss_deleg_creds == -1)
1135cf2b5f3bSDag-Erling Smørgrav 		options->gss_deleg_creds = 0;
1136511b41d2SMark Murray 	if (options->password_authentication == -1)
1137511b41d2SMark Murray 		options->password_authentication = 1;
113809958426SBrian Feldman 	if (options->kbd_interactive_authentication == -1)
1139ca3176e7SBrian Feldman 		options->kbd_interactive_authentication = 1;
1140511b41d2SMark Murray 	if (options->rhosts_rsa_authentication == -1)
114180628bacSDag-Erling Smørgrav 		options->rhosts_rsa_authentication = 0;
1142ca3176e7SBrian Feldman 	if (options->hostbased_authentication == -1)
1143ca3176e7SBrian Feldman 		options->hostbased_authentication = 0;
1144511b41d2SMark Murray 	if (options->batch_mode == -1)
1145511b41d2SMark Murray 		options->batch_mode = 0;
1146511b41d2SMark Murray 	if (options->check_host_ip == -1)
1147975616f0SDag-Erling Smørgrav 		options->check_host_ip = 0;
1148511b41d2SMark Murray 	if (options->strict_host_key_checking == -1)
1149511b41d2SMark Murray 		options->strict_host_key_checking = 2;	/* 2 is default */
1150511b41d2SMark Murray 	if (options->compression == -1)
1151511b41d2SMark Murray 		options->compression = 0;
11521ec0d754SDag-Erling Smørgrav 	if (options->tcp_keep_alive == -1)
11531ec0d754SDag-Erling Smørgrav 		options->tcp_keep_alive = 1;
1154511b41d2SMark Murray 	if (options->compression_level == -1)
1155511b41d2SMark Murray 		options->compression_level = 6;
1156511b41d2SMark Murray 	if (options->port == -1)
1157511b41d2SMark Murray 		options->port = 0;	/* Filled in ssh_connect. */
1158cf2b5f3bSDag-Erling Smørgrav 	if (options->address_family == -1)
1159cf2b5f3bSDag-Erling Smørgrav 		options->address_family = AF_UNSPEC;
1160511b41d2SMark Murray 	if (options->connection_attempts == -1)
1161af12a3e7SDag-Erling Smørgrav 		options->connection_attempts = 1;
1162511b41d2SMark Murray 	if (options->number_of_password_prompts == -1)
1163511b41d2SMark Murray 		options->number_of_password_prompts = 3;
1164511b41d2SMark Murray 	/* Selected in ssh_login(). */
1165511b41d2SMark Murray 	if (options->cipher == -1)
1166511b41d2SMark Murray 		options->cipher = SSH_CIPHER_NOT_SET;
1167e8aafc91SKris Kennaway 	/* options->ciphers, default set in myproposals.h */
1168ca3176e7SBrian Feldman 	/* options->macs, default set in myproposals.h */
1169ca3176e7SBrian Feldman 	/* options->hostkeyalgorithms, default set in myproposals.h */
1170e8aafc91SKris Kennaway 	if (options->protocol == SSH_PROTO_UNKNOWN)
1171b15c8340SDag-Erling Smørgrav 		options->protocol = SSH_PROTO_2;
1172511b41d2SMark Murray 	if (options->num_identity_files == 0) {
1173ca3176e7SBrian Feldman 		if (options->protocol & SSH_PROTO_1) {
1174ca3176e7SBrian Feldman 			len = 2 + strlen(_PATH_SSH_CLIENT_IDENTITY) + 1;
1175ca3176e7SBrian Feldman 			options->identity_files[options->num_identity_files] =
1176ca3176e7SBrian Feldman 			    xmalloc(len);
1177ca3176e7SBrian Feldman 			snprintf(options->identity_files[options->num_identity_files++],
1178ca3176e7SBrian Feldman 			    len, "~/%.100s", _PATH_SSH_CLIENT_IDENTITY);
1179511b41d2SMark Murray 		}
1180ca3176e7SBrian Feldman 		if (options->protocol & SSH_PROTO_2) {
1181ca3176e7SBrian Feldman 			len = 2 + strlen(_PATH_SSH_CLIENT_ID_RSA) + 1;
1182ca3176e7SBrian Feldman 			options->identity_files[options->num_identity_files] =
1183ca3176e7SBrian Feldman 			    xmalloc(len);
1184ca3176e7SBrian Feldman 			snprintf(options->identity_files[options->num_identity_files++],
1185ca3176e7SBrian Feldman 			    len, "~/%.100s", _PATH_SSH_CLIENT_ID_RSA);
1186ca3176e7SBrian Feldman 
1187ca3176e7SBrian Feldman 			len = 2 + strlen(_PATH_SSH_CLIENT_ID_DSA) + 1;
1188ca3176e7SBrian Feldman 			options->identity_files[options->num_identity_files] =
1189ca3176e7SBrian Feldman 			    xmalloc(len);
1190ca3176e7SBrian Feldman 			snprintf(options->identity_files[options->num_identity_files++],
1191ca3176e7SBrian Feldman 			    len, "~/%.100s", _PATH_SSH_CLIENT_ID_DSA);
1192ca3176e7SBrian Feldman 		}
1193e8aafc91SKris Kennaway 	}
1194511b41d2SMark Murray 	if (options->escape_char == -1)
1195511b41d2SMark Murray 		options->escape_char = '~';
1196511b41d2SMark Murray 	if (options->system_hostfile == NULL)
1197ca3176e7SBrian Feldman 		options->system_hostfile = _PATH_SSH_SYSTEM_HOSTFILE;
1198511b41d2SMark Murray 	if (options->user_hostfile == NULL)
1199ca3176e7SBrian Feldman 		options->user_hostfile = _PATH_SSH_USER_HOSTFILE;
1200e8aafc91SKris Kennaway 	if (options->system_hostfile2 == NULL)
1201ca3176e7SBrian Feldman 		options->system_hostfile2 = _PATH_SSH_SYSTEM_HOSTFILE2;
1202e8aafc91SKris Kennaway 	if (options->user_hostfile2 == NULL)
1203ca3176e7SBrian Feldman 		options->user_hostfile2 = _PATH_SSH_USER_HOSTFILE2;
1204af12a3e7SDag-Erling Smørgrav 	if (options->log_level == SYSLOG_LEVEL_NOT_SET)
1205511b41d2SMark Murray 		options->log_level = SYSLOG_LEVEL_INFO;
1206af12a3e7SDag-Erling Smørgrav 	if (options->clear_forwardings == 1)
1207af12a3e7SDag-Erling Smørgrav 		clear_forwardings(options);
1208af12a3e7SDag-Erling Smørgrav 	if (options->no_host_authentication_for_localhost == - 1)
1209af12a3e7SDag-Erling Smørgrav 		options->no_host_authentication_for_localhost = 0;
12105962c0e9SDag-Erling Smørgrav 	if (options->identities_only == -1)
12115962c0e9SDag-Erling Smørgrav 		options->identities_only = 0;
1212e73e9afaSDag-Erling Smørgrav 	if (options->enable_ssh_keysign == -1)
1213e73e9afaSDag-Erling Smørgrav 		options->enable_ssh_keysign = 0;
1214cf2b5f3bSDag-Erling Smørgrav 	if (options->rekey_limit == -1)
1215cf2b5f3bSDag-Erling Smørgrav 		options->rekey_limit = 0;
1216cf2b5f3bSDag-Erling Smørgrav 	if (options->verify_host_key_dns == -1)
1217cf2b5f3bSDag-Erling Smørgrav 		options->verify_host_key_dns = 0;
12181ec0d754SDag-Erling Smørgrav 	if (options->server_alive_interval == -1)
12191ec0d754SDag-Erling Smørgrav 		options->server_alive_interval = 0;
12201ec0d754SDag-Erling Smørgrav 	if (options->server_alive_count_max == -1)
12211ec0d754SDag-Erling Smørgrav 		options->server_alive_count_max = 3;
122221e764dfSDag-Erling Smørgrav 	if (options->control_master == -1)
122321e764dfSDag-Erling Smørgrav 		options->control_master = 0;
1224aa49c926SDag-Erling Smørgrav 	if (options->hash_known_hosts == -1)
1225aa49c926SDag-Erling Smørgrav 		options->hash_known_hosts = 0;
1226b74df5b2SDag-Erling Smørgrav 	if (options->tun_open == -1)
1227b74df5b2SDag-Erling Smørgrav 		options->tun_open = SSH_TUNMODE_NO;
1228b74df5b2SDag-Erling Smørgrav 	if (options->tun_local == -1)
1229b74df5b2SDag-Erling Smørgrav 		options->tun_local = SSH_TUNID_ANY;
1230b74df5b2SDag-Erling Smørgrav 	if (options->tun_remote == -1)
1231b74df5b2SDag-Erling Smørgrav 		options->tun_remote = SSH_TUNID_ANY;
1232b74df5b2SDag-Erling Smørgrav 	if (options->permit_local_command == -1)
1233b74df5b2SDag-Erling Smørgrav 		options->permit_local_command = 0;
12347aee6ffeSDag-Erling Smørgrav 	if (options->use_roaming == -1)
12357aee6ffeSDag-Erling Smørgrav 		options->use_roaming = 1;
1236d4af9e69SDag-Erling Smørgrav 	if (options->visual_host_key == -1)
1237d4af9e69SDag-Erling Smørgrav 		options->visual_host_key = 0;
1238cce7d346SDag-Erling Smørgrav 	if (options->zero_knowledge_password_authentication == -1)
1239cce7d346SDag-Erling Smørgrav 		options->zero_knowledge_password_authentication = 0;
1240b74df5b2SDag-Erling Smørgrav 	/* options->local_command should not be set by default */
1241511b41d2SMark Murray 	/* options->proxy_command should not be set by default */
1242511b41d2SMark Murray 	/* options->user will be set in the main program if appropriate */
1243511b41d2SMark Murray 	/* options->hostname will be set in the main program if appropriate */
1244ca3176e7SBrian Feldman 	/* options->host_key_alias should not be set by default */
1245ca3176e7SBrian Feldman 	/* options->preferred_authentications will be set in ssh */
1246511b41d2SMark Murray }
1247aa49c926SDag-Erling Smørgrav 
1248aa49c926SDag-Erling Smørgrav /*
1249aa49c926SDag-Erling Smørgrav  * parse_forward
1250aa49c926SDag-Erling Smørgrav  * parses a string containing a port forwarding specification of the form:
1251cce7d346SDag-Erling Smørgrav  *   dynamicfwd == 0
1252aa49c926SDag-Erling Smørgrav  *	[listenhost:]listenport:connecthost:connectport
1253cce7d346SDag-Erling Smørgrav  *   dynamicfwd == 1
1254cce7d346SDag-Erling Smørgrav  *	[listenhost:]listenport
1255aa49c926SDag-Erling Smørgrav  * returns number of arguments parsed or zero on error
1256aa49c926SDag-Erling Smørgrav  */
1257aa49c926SDag-Erling Smørgrav int
1258cce7d346SDag-Erling Smørgrav parse_forward(Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
1259aa49c926SDag-Erling Smørgrav {
1260aa49c926SDag-Erling Smørgrav 	int i;
1261aa49c926SDag-Erling Smørgrav 	char *p, *cp, *fwdarg[4];
1262aa49c926SDag-Erling Smørgrav 
1263aa49c926SDag-Erling Smørgrav 	memset(fwd, '\0', sizeof(*fwd));
1264aa49c926SDag-Erling Smørgrav 
1265aa49c926SDag-Erling Smørgrav 	cp = p = xstrdup(fwdspec);
1266aa49c926SDag-Erling Smørgrav 
1267aa49c926SDag-Erling Smørgrav 	/* skip leading spaces */
1268d4af9e69SDag-Erling Smørgrav 	while (isspace(*cp))
1269aa49c926SDag-Erling Smørgrav 		cp++;
1270aa49c926SDag-Erling Smørgrav 
1271aa49c926SDag-Erling Smørgrav 	for (i = 0; i < 4; ++i)
1272aa49c926SDag-Erling Smørgrav 		if ((fwdarg[i] = hpdelim(&cp)) == NULL)
1273aa49c926SDag-Erling Smørgrav 			break;
1274aa49c926SDag-Erling Smørgrav 
1275cce7d346SDag-Erling Smørgrav 	/* Check for trailing garbage */
1276aa49c926SDag-Erling Smørgrav 	if (cp != NULL)
1277aa49c926SDag-Erling Smørgrav 		i = 0;	/* failure */
1278aa49c926SDag-Erling Smørgrav 
1279aa49c926SDag-Erling Smørgrav 	switch (i) {
1280cce7d346SDag-Erling Smørgrav 	case 1:
1281cce7d346SDag-Erling Smørgrav 		fwd->listen_host = NULL;
1282cce7d346SDag-Erling Smørgrav 		fwd->listen_port = a2port(fwdarg[0]);
1283cce7d346SDag-Erling Smørgrav 		fwd->connect_host = xstrdup("socks");
1284cce7d346SDag-Erling Smørgrav 		break;
1285cce7d346SDag-Erling Smørgrav 
1286cce7d346SDag-Erling Smørgrav 	case 2:
1287cce7d346SDag-Erling Smørgrav 		fwd->listen_host = xstrdup(cleanhostname(fwdarg[0]));
1288cce7d346SDag-Erling Smørgrav 		fwd->listen_port = a2port(fwdarg[1]);
1289cce7d346SDag-Erling Smørgrav 		fwd->connect_host = xstrdup("socks");
1290cce7d346SDag-Erling Smørgrav 		break;
1291cce7d346SDag-Erling Smørgrav 
1292aa49c926SDag-Erling Smørgrav 	case 3:
1293aa49c926SDag-Erling Smørgrav 		fwd->listen_host = NULL;
1294aa49c926SDag-Erling Smørgrav 		fwd->listen_port = a2port(fwdarg[0]);
1295aa49c926SDag-Erling Smørgrav 		fwd->connect_host = xstrdup(cleanhostname(fwdarg[1]));
1296aa49c926SDag-Erling Smørgrav 		fwd->connect_port = a2port(fwdarg[2]);
1297aa49c926SDag-Erling Smørgrav 		break;
1298aa49c926SDag-Erling Smørgrav 
1299aa49c926SDag-Erling Smørgrav 	case 4:
1300aa49c926SDag-Erling Smørgrav 		fwd->listen_host = xstrdup(cleanhostname(fwdarg[0]));
1301aa49c926SDag-Erling Smørgrav 		fwd->listen_port = a2port(fwdarg[1]);
1302aa49c926SDag-Erling Smørgrav 		fwd->connect_host = xstrdup(cleanhostname(fwdarg[2]));
1303aa49c926SDag-Erling Smørgrav 		fwd->connect_port = a2port(fwdarg[3]);
1304aa49c926SDag-Erling Smørgrav 		break;
1305aa49c926SDag-Erling Smørgrav 	default:
1306aa49c926SDag-Erling Smørgrav 		i = 0; /* failure */
1307aa49c926SDag-Erling Smørgrav 	}
1308aa49c926SDag-Erling Smørgrav 
1309aa49c926SDag-Erling Smørgrav 	xfree(p);
1310aa49c926SDag-Erling Smørgrav 
1311cce7d346SDag-Erling Smørgrav 	if (dynamicfwd) {
1312cce7d346SDag-Erling Smørgrav 		if (!(i == 1 || i == 2))
1313cce7d346SDag-Erling Smørgrav 			goto fail_free;
1314cce7d346SDag-Erling Smørgrav 	} else {
1315cce7d346SDag-Erling Smørgrav 		if (!(i == 3 || i == 4))
1316cce7d346SDag-Erling Smørgrav 			goto fail_free;
1317cce7d346SDag-Erling Smørgrav 		if (fwd->connect_port <= 0)
1318cce7d346SDag-Erling Smørgrav 			goto fail_free;
1319cce7d346SDag-Erling Smørgrav 	}
1320cce7d346SDag-Erling Smørgrav 
1321cce7d346SDag-Erling Smørgrav 	if (fwd->listen_port < 0 || (!remotefwd && fwd->listen_port == 0))
1322aa49c926SDag-Erling Smørgrav 		goto fail_free;
1323aa49c926SDag-Erling Smørgrav 
1324aa49c926SDag-Erling Smørgrav 	if (fwd->connect_host != NULL &&
1325aa49c926SDag-Erling Smørgrav 	    strlen(fwd->connect_host) >= NI_MAXHOST)
1326aa49c926SDag-Erling Smørgrav 		goto fail_free;
1327cce7d346SDag-Erling Smørgrav 	if (fwd->listen_host != NULL &&
1328cce7d346SDag-Erling Smørgrav 	    strlen(fwd->listen_host) >= NI_MAXHOST)
1329cce7d346SDag-Erling Smørgrav 		goto fail_free;
1330cce7d346SDag-Erling Smørgrav 
1331aa49c926SDag-Erling Smørgrav 
1332aa49c926SDag-Erling Smørgrav 	return (i);
1333aa49c926SDag-Erling Smørgrav 
1334aa49c926SDag-Erling Smørgrav  fail_free:
1335cce7d346SDag-Erling Smørgrav 	if (fwd->connect_host != NULL) {
1336aa49c926SDag-Erling Smørgrav 		xfree(fwd->connect_host);
1337cce7d346SDag-Erling Smørgrav 		fwd->connect_host = NULL;
1338cce7d346SDag-Erling Smørgrav 	}
1339cce7d346SDag-Erling Smørgrav 	if (fwd->listen_host != NULL) {
1340aa49c926SDag-Erling Smørgrav 		xfree(fwd->listen_host);
1341cce7d346SDag-Erling Smørgrav 		fwd->listen_host = NULL;
1342cce7d346SDag-Erling Smørgrav 	}
1343aa49c926SDag-Erling Smørgrav 	return (0);
1344aa49c926SDag-Erling Smørgrav }
1345