xref: /freebsd/crypto/openssh/readconf.c (revision 03f6c5cd93ecc0414b1b7660decf778c005d662f)
1d4af9e69SDag-Erling Smørgrav /* $OpenBSD: readconf.c,v 1.167 2008/06/26 11:46:31 grunk 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"
47511b41d2SMark Murray 
48511b41d2SMark Murray /* Format of the configuration file:
49511b41d2SMark Murray 
50511b41d2SMark Murray    # Configuration data is parsed as follows:
51511b41d2SMark Murray    #  1. command line options
52511b41d2SMark Murray    #  2. user-specific file
53511b41d2SMark Murray    #  3. system-wide file
54511b41d2SMark Murray    # Any configuration value is only changed the first time it is set.
55511b41d2SMark Murray    # Thus, host-specific definitions should be at the beginning of the
56511b41d2SMark Murray    # configuration file, and defaults at the end.
57511b41d2SMark Murray 
58511b41d2SMark Murray    # Host-specific declarations.  These may override anything above.  A single
59511b41d2SMark Murray    # host may match multiple declarations; these are processed in the order
60511b41d2SMark Murray    # that they are given in.
61511b41d2SMark Murray 
62511b41d2SMark Murray    Host *.ngs.fi ngs.fi
6380628bacSDag-Erling Smørgrav      User foo
64511b41d2SMark Murray 
65511b41d2SMark Murray    Host fake.com
66511b41d2SMark Murray      HostName another.host.name.real.org
67511b41d2SMark Murray      User blaah
68511b41d2SMark Murray      Port 34289
69511b41d2SMark Murray      ForwardX11 no
70511b41d2SMark Murray      ForwardAgent no
71511b41d2SMark Murray 
72511b41d2SMark Murray    Host books.com
73511b41d2SMark Murray      RemoteForward 9999 shadows.cs.hut.fi:9999
74511b41d2SMark Murray      Cipher 3des
75511b41d2SMark Murray 
76511b41d2SMark Murray    Host fascist.blob.com
77511b41d2SMark Murray      Port 23123
78511b41d2SMark Murray      User tylonen
79511b41d2SMark Murray      PasswordAuthentication no
80511b41d2SMark Murray 
81511b41d2SMark Murray    Host puukko.hut.fi
82511b41d2SMark Murray      User t35124p
83511b41d2SMark Murray      ProxyCommand ssh-proxy %h %p
84511b41d2SMark Murray 
85511b41d2SMark Murray    Host *.fr
8680628bacSDag-Erling Smørgrav      PublicKeyAuthentication no
87511b41d2SMark Murray 
88511b41d2SMark Murray    Host *.su
89511b41d2SMark Murray      Cipher none
90511b41d2SMark Murray      PasswordAuthentication no
91511b41d2SMark Murray 
92b74df5b2SDag-Erling Smørgrav    Host vpn.fake.com
93b74df5b2SDag-Erling Smørgrav      Tunnel yes
94b74df5b2SDag-Erling Smørgrav      TunnelDevice 3
95b74df5b2SDag-Erling Smørgrav 
96511b41d2SMark Murray    # Defaults for various options
97511b41d2SMark Murray    Host *
98511b41d2SMark Murray      ForwardAgent no
99ca3176e7SBrian Feldman      ForwardX11 no
100511b41d2SMark Murray      PasswordAuthentication yes
101511b41d2SMark Murray      RSAAuthentication yes
102511b41d2SMark Murray      RhostsRSAAuthentication yes
103511b41d2SMark Murray      StrictHostKeyChecking yes
1041ec0d754SDag-Erling Smørgrav      TcpKeepAlive no
105511b41d2SMark Murray      IdentityFile ~/.ssh/identity
106511b41d2SMark Murray      Port 22
107511b41d2SMark Murray      EscapeChar ~
108511b41d2SMark Murray 
109511b41d2SMark Murray */
110511b41d2SMark Murray 
111511b41d2SMark Murray /* Keyword tokens. */
112511b41d2SMark Murray 
113511b41d2SMark Murray typedef enum {
114511b41d2SMark Murray 	oBadOption,
1151ec0d754SDag-Erling Smørgrav 	oForwardAgent, oForwardX11, oForwardX11Trusted, oGatewayPorts,
116333ee039SDag-Erling Smørgrav 	oExitOnForwardFailure,
11780628bacSDag-Erling Smørgrav 	oPasswordAuthentication, oRSAAuthentication,
118ca3176e7SBrian Feldman 	oChallengeResponseAuthentication, oXAuthLocation,
119511b41d2SMark Murray 	oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward,
120511b41d2SMark Murray 	oUser, oHost, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
121511b41d2SMark Murray 	oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
122511b41d2SMark Murray 	oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
1231ec0d754SDag-Erling Smørgrav 	oCompressionLevel, oTCPKeepAlive, oNumberOfPasswordPrompts,
124ca3176e7SBrian Feldman 	oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oMacs,
125ca3176e7SBrian Feldman 	oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication,
126ca3176e7SBrian Feldman 	oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
127ca3176e7SBrian Feldman 	oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
128af12a3e7SDag-Erling Smørgrav 	oHostKeyAlgorithms, oBindAddress, oSmartcardDevice,
1299e2cbe04SDag-Erling Smørgrav 	oClearAllForwardings, oNoHostAuthenticationForLocalhost,
130cf2b5f3bSDag-Erling Smørgrav 	oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
131cf2b5f3bSDag-Erling Smørgrav 	oAddressFamily, oGssAuthentication, oGssDelegateCreds,
1325962c0e9SDag-Erling Smørgrav 	oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
133aa49c926SDag-Erling Smørgrav 	oSendEnv, oControlPath, oControlMaster, oHashKnownHosts,
134b74df5b2SDag-Erling Smørgrav 	oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand,
135d4af9e69SDag-Erling Smørgrav 	oVisualHostKey,
136cfa59440SDag-Erling Smørgrav 	oVersionAddendum,
137cf2b5f3bSDag-Erling Smørgrav 	oDeprecated, oUnsupported
138511b41d2SMark Murray } OpCodes;
139511b41d2SMark Murray 
140511b41d2SMark Murray /* Textual representations of the tokens. */
141511b41d2SMark Murray 
142511b41d2SMark Murray static struct {
143511b41d2SMark Murray 	const char *name;
144511b41d2SMark Murray 	OpCodes opcode;
145511b41d2SMark Murray } keywords[] = {
146511b41d2SMark Murray 	{ "forwardagent", oForwardAgent },
147511b41d2SMark Murray 	{ "forwardx11", oForwardX11 },
1481ec0d754SDag-Erling Smørgrav 	{ "forwardx11trusted", oForwardX11Trusted },
149333ee039SDag-Erling Smørgrav 	{ "exitonforwardfailure", oExitOnForwardFailure },
150c2d3a559SKris Kennaway 	{ "xauthlocation", oXAuthLocation },
151511b41d2SMark Murray 	{ "gatewayports", oGatewayPorts },
152511b41d2SMark Murray 	{ "useprivilegedport", oUsePrivilegedPort },
153cf2b5f3bSDag-Erling Smørgrav 	{ "rhostsauthentication", oDeprecated },
154511b41d2SMark Murray 	{ "passwordauthentication", oPasswordAuthentication },
15509958426SBrian Feldman 	{ "kbdinteractiveauthentication", oKbdInteractiveAuthentication },
15609958426SBrian Feldman 	{ "kbdinteractivedevices", oKbdInteractiveDevices },
157511b41d2SMark Murray 	{ "rsaauthentication", oRSAAuthentication },
158ca3176e7SBrian Feldman 	{ "pubkeyauthentication", oPubkeyAuthentication },
159ca3176e7SBrian Feldman 	{ "dsaauthentication", oPubkeyAuthentication },		    /* alias */
160ca3176e7SBrian Feldman 	{ "rhostsrsaauthentication", oRhostsRSAAuthentication },
161ca3176e7SBrian Feldman 	{ "hostbasedauthentication", oHostbasedAuthentication },
162ca3176e7SBrian Feldman 	{ "challengeresponseauthentication", oChallengeResponseAuthentication },
163ca3176e7SBrian Feldman 	{ "skeyauthentication", oChallengeResponseAuthentication }, /* alias */
164ca3176e7SBrian Feldman 	{ "tisauthentication", oChallengeResponseAuthentication },  /* alias */
165cf2b5f3bSDag-Erling Smørgrav 	{ "kerberosauthentication", oUnsupported },
166cf2b5f3bSDag-Erling Smørgrav 	{ "kerberostgtpassing", oUnsupported },
167cf2b5f3bSDag-Erling Smørgrav 	{ "afstokenpassing", oUnsupported },
168cf2b5f3bSDag-Erling Smørgrav #if defined(GSSAPI)
169cf2b5f3bSDag-Erling Smørgrav 	{ "gssapiauthentication", oGssAuthentication },
170cf2b5f3bSDag-Erling Smørgrav 	{ "gssapidelegatecredentials", oGssDelegateCreds },
171cf2b5f3bSDag-Erling Smørgrav #else
172cf2b5f3bSDag-Erling Smørgrav 	{ "gssapiauthentication", oUnsupported },
173cf2b5f3bSDag-Erling Smørgrav 	{ "gssapidelegatecredentials", oUnsupported },
174511b41d2SMark Murray #endif
17580628bacSDag-Erling Smørgrav 	{ "fallbacktorsh", oDeprecated },
17680628bacSDag-Erling Smørgrav 	{ "usersh", oDeprecated },
177511b41d2SMark Murray 	{ "identityfile", oIdentityFile },
178ca3176e7SBrian Feldman 	{ "identityfile2", oIdentityFile },			/* alias */
1795962c0e9SDag-Erling Smørgrav 	{ "identitiesonly", oIdentitiesOnly },
180511b41d2SMark Murray 	{ "hostname", oHostName },
181ca3176e7SBrian Feldman 	{ "hostkeyalias", oHostKeyAlias },
182511b41d2SMark Murray 	{ "proxycommand", oProxyCommand },
183511b41d2SMark Murray 	{ "port", oPort },
184511b41d2SMark Murray 	{ "cipher", oCipher },
185e8aafc91SKris Kennaway 	{ "ciphers", oCiphers },
186ca3176e7SBrian Feldman 	{ "macs", oMacs },
187e8aafc91SKris Kennaway 	{ "protocol", oProtocol },
188511b41d2SMark Murray 	{ "remoteforward", oRemoteForward },
189511b41d2SMark Murray 	{ "localforward", oLocalForward },
190511b41d2SMark Murray 	{ "user", oUser },
191511b41d2SMark Murray 	{ "host", oHost },
192511b41d2SMark Murray 	{ "escapechar", oEscapeChar },
193511b41d2SMark Murray 	{ "globalknownhostsfile", oGlobalKnownHostsFile },
194af12a3e7SDag-Erling Smørgrav 	{ "userknownhostsfile", oUserKnownHostsFile },		/* obsolete */
195e8aafc91SKris Kennaway 	{ "globalknownhostsfile2", oGlobalKnownHostsFile2 },
196af12a3e7SDag-Erling Smørgrav 	{ "userknownhostsfile2", oUserKnownHostsFile2 },	/* obsolete */
197511b41d2SMark Murray 	{ "connectionattempts", oConnectionAttempts },
198511b41d2SMark Murray 	{ "batchmode", oBatchMode },
199511b41d2SMark Murray 	{ "checkhostip", oCheckHostIP },
200511b41d2SMark Murray 	{ "stricthostkeychecking", oStrictHostKeyChecking },
201511b41d2SMark Murray 	{ "compression", oCompression },
202511b41d2SMark Murray 	{ "compressionlevel", oCompressionLevel },
2031ec0d754SDag-Erling Smørgrav 	{ "tcpkeepalive", oTCPKeepAlive },
2041ec0d754SDag-Erling Smørgrav 	{ "keepalive", oTCPKeepAlive },				/* obsolete */
205511b41d2SMark Murray 	{ "numberofpasswordprompts", oNumberOfPasswordPrompts },
206511b41d2SMark Murray 	{ "loglevel", oLogLevel },
207ca3176e7SBrian Feldman 	{ "dynamicforward", oDynamicForward },
208ca3176e7SBrian Feldman 	{ "preferredauthentications", oPreferredAuthentications },
209ca3176e7SBrian Feldman 	{ "hostkeyalgorithms", oHostKeyAlgorithms },
210af12a3e7SDag-Erling Smørgrav 	{ "bindaddress", oBindAddress },
211cf2b5f3bSDag-Erling Smørgrav #ifdef SMARTCARD
212af12a3e7SDag-Erling Smørgrav 	{ "smartcarddevice", oSmartcardDevice },
213cf2b5f3bSDag-Erling Smørgrav #else
214cf2b5f3bSDag-Erling Smørgrav 	{ "smartcarddevice", oUnsupported },
215cf2b5f3bSDag-Erling Smørgrav #endif
216af12a3e7SDag-Erling Smørgrav 	{ "clearallforwardings", oClearAllForwardings },
217e73e9afaSDag-Erling Smørgrav 	{ "enablesshkeysign", oEnableSSHKeysign },
218cf2b5f3bSDag-Erling Smørgrav 	{ "verifyhostkeydns", oVerifyHostKeyDNS },
219af12a3e7SDag-Erling Smørgrav 	{ "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
220cf2b5f3bSDag-Erling Smørgrav 	{ "rekeylimit", oRekeyLimit },
221cf2b5f3bSDag-Erling Smørgrav 	{ "connecttimeout", oConnectTimeout },
222cf2b5f3bSDag-Erling Smørgrav 	{ "addressfamily", oAddressFamily },
2231ec0d754SDag-Erling Smørgrav 	{ "serveraliveinterval", oServerAliveInterval },
2241ec0d754SDag-Erling Smørgrav 	{ "serveralivecountmax", oServerAliveCountMax },
22521e764dfSDag-Erling Smørgrav 	{ "sendenv", oSendEnv },
22621e764dfSDag-Erling Smørgrav 	{ "controlpath", oControlPath },
22721e764dfSDag-Erling Smørgrav 	{ "controlmaster", oControlMaster },
228aa49c926SDag-Erling Smørgrav 	{ "hashknownhosts", oHashKnownHosts },
229b74df5b2SDag-Erling Smørgrav 	{ "tunnel", oTunnel },
230b74df5b2SDag-Erling Smørgrav 	{ "tunneldevice", oTunnelDevice },
231b74df5b2SDag-Erling Smørgrav 	{ "localcommand", oLocalCommand },
232b74df5b2SDag-Erling Smørgrav 	{ "permitlocalcommand", oPermitLocalCommand },
233d4af9e69SDag-Erling Smørgrav 	{ "visualhostkey", oVisualHostKey },
234975616f0SDag-Erling Smørgrav 	{ "versionaddendum", oVersionAddendum },
235af12a3e7SDag-Erling Smørgrav 	{ NULL, oBadOption }
236511b41d2SMark Murray };
237511b41d2SMark Murray 
238511b41d2SMark Murray /*
239511b41d2SMark Murray  * Adds a local TCP/IP port forward to options.  Never returns if there is an
240511b41d2SMark Murray  * error.
241511b41d2SMark Murray  */
242511b41d2SMark Murray 
243511b41d2SMark Murray void
244aa49c926SDag-Erling Smørgrav add_local_forward(Options *options, const Forward *newfwd)
245511b41d2SMark Murray {
246511b41d2SMark Murray 	Forward *fwd;
247f388f5efSDag-Erling Smørgrav #ifndef NO_IPPORT_RESERVED_CONCEPT
248511b41d2SMark Murray 	extern uid_t original_real_uid;
24903f6c5cdSDag-Erling Smørgrav 	int ipport_reserved;
25003f6c5cdSDag-Erling Smørgrav #ifdef __FreeBSD__
25103f6c5cdSDag-Erling Smørgrav 	size_t len_ipport_reserved = sizeof(ipport_reserved);
25203f6c5cdSDag-Erling Smørgrav 
25303f6c5cdSDag-Erling Smørgrav 	if (sysctlbyname("net.inet.ip.portrange.reservedhigh",
25403f6c5cdSDag-Erling Smørgrav 	    &ipport_reserved, &len_ipport_reserved, NULL, 0) != 0)
25503f6c5cdSDag-Erling Smørgrav 		ipport_reserved = IPPORT_RESERVED;
25603f6c5cdSDag-Erling Smørgrav 	else
25703f6c5cdSDag-Erling Smørgrav 		ipport_reserved++;
25803f6c5cdSDag-Erling Smørgrav #else
25903f6c5cdSDag-Erling Smørgrav 	ipport_reserved = IPPORT_RESERVED;
26003f6c5cdSDag-Erling Smørgrav #endif
26103f6c5cdSDag-Erling Smørgrav 	if (newfwd->listen_port < ipport_reserved && original_real_uid != 0)
262ca3176e7SBrian Feldman 		fatal("Privileged ports can only be forwarded by root.");
263989dd127SDag-Erling Smørgrav #endif
264511b41d2SMark Murray 	if (options->num_local_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
265511b41d2SMark Murray 		fatal("Too many local forwards (max %d).", SSH_MAX_FORWARDS_PER_DIRECTION);
266511b41d2SMark Murray 	fwd = &options->local_forwards[options->num_local_forwards++];
267aa49c926SDag-Erling Smørgrav 
268aa49c926SDag-Erling Smørgrav 	fwd->listen_host = (newfwd->listen_host == NULL) ?
269aa49c926SDag-Erling Smørgrav 	    NULL : xstrdup(newfwd->listen_host);
270aa49c926SDag-Erling Smørgrav 	fwd->listen_port = newfwd->listen_port;
271aa49c926SDag-Erling Smørgrav 	fwd->connect_host = xstrdup(newfwd->connect_host);
272aa49c926SDag-Erling Smørgrav 	fwd->connect_port = newfwd->connect_port;
273511b41d2SMark Murray }
274511b41d2SMark Murray 
275511b41d2SMark Murray /*
276511b41d2SMark Murray  * Adds a remote TCP/IP port forward to options.  Never returns if there is
277511b41d2SMark Murray  * an error.
278511b41d2SMark Murray  */
279511b41d2SMark Murray 
280511b41d2SMark Murray void
281aa49c926SDag-Erling Smørgrav add_remote_forward(Options *options, const Forward *newfwd)
282511b41d2SMark Murray {
283511b41d2SMark Murray 	Forward *fwd;
284511b41d2SMark Murray 	if (options->num_remote_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
285511b41d2SMark Murray 		fatal("Too many remote forwards (max %d).",
286511b41d2SMark Murray 		    SSH_MAX_FORWARDS_PER_DIRECTION);
287511b41d2SMark Murray 	fwd = &options->remote_forwards[options->num_remote_forwards++];
288aa49c926SDag-Erling Smørgrav 
289aa49c926SDag-Erling Smørgrav 	fwd->listen_host = (newfwd->listen_host == NULL) ?
290aa49c926SDag-Erling Smørgrav 	    NULL : xstrdup(newfwd->listen_host);
291aa49c926SDag-Erling Smørgrav 	fwd->listen_port = newfwd->listen_port;
292aa49c926SDag-Erling Smørgrav 	fwd->connect_host = xstrdup(newfwd->connect_host);
293aa49c926SDag-Erling Smørgrav 	fwd->connect_port = newfwd->connect_port;
294511b41d2SMark Murray }
295511b41d2SMark Murray 
296af12a3e7SDag-Erling Smørgrav static void
297af12a3e7SDag-Erling Smørgrav clear_forwardings(Options *options)
298af12a3e7SDag-Erling Smørgrav {
299af12a3e7SDag-Erling Smørgrav 	int i;
300af12a3e7SDag-Erling Smørgrav 
301aa49c926SDag-Erling Smørgrav 	for (i = 0; i < options->num_local_forwards; i++) {
302aa49c926SDag-Erling Smørgrav 		if (options->local_forwards[i].listen_host != NULL)
303aa49c926SDag-Erling Smørgrav 			xfree(options->local_forwards[i].listen_host);
304aa49c926SDag-Erling Smørgrav 		xfree(options->local_forwards[i].connect_host);
305aa49c926SDag-Erling Smørgrav 	}
306af12a3e7SDag-Erling Smørgrav 	options->num_local_forwards = 0;
307aa49c926SDag-Erling Smørgrav 	for (i = 0; i < options->num_remote_forwards; i++) {
308aa49c926SDag-Erling Smørgrav 		if (options->remote_forwards[i].listen_host != NULL)
309aa49c926SDag-Erling Smørgrav 			xfree(options->remote_forwards[i].listen_host);
310aa49c926SDag-Erling Smørgrav 		xfree(options->remote_forwards[i].connect_host);
311aa49c926SDag-Erling Smørgrav 	}
312af12a3e7SDag-Erling Smørgrav 	options->num_remote_forwards = 0;
313b74df5b2SDag-Erling Smørgrav 	options->tun_open = SSH_TUNMODE_NO;
314af12a3e7SDag-Erling Smørgrav }
315af12a3e7SDag-Erling Smørgrav 
316511b41d2SMark Murray /*
317ca3176e7SBrian Feldman  * Returns the number of the token pointed to by cp or oBadOption.
318511b41d2SMark Murray  */
319511b41d2SMark Murray 
320511b41d2SMark Murray static OpCodes
321511b41d2SMark Murray parse_token(const char *cp, const char *filename, int linenum)
322511b41d2SMark Murray {
323ca3176e7SBrian Feldman 	u_int i;
324511b41d2SMark Murray 
325511b41d2SMark Murray 	for (i = 0; keywords[i].name; i++)
326511b41d2SMark Murray 		if (strcasecmp(cp, keywords[i].name) == 0)
327511b41d2SMark Murray 			return keywords[i].opcode;
328511b41d2SMark Murray 
329ca3176e7SBrian Feldman 	error("%s: line %d: Bad configuration option: %s",
330511b41d2SMark Murray 	    filename, linenum, cp);
331511b41d2SMark Murray 	return oBadOption;
332511b41d2SMark Murray }
333511b41d2SMark Murray 
334511b41d2SMark Murray /*
335511b41d2SMark Murray  * Processes a single option line as used in the configuration files. This
336511b41d2SMark Murray  * only sets those values that have not already been set.
337511b41d2SMark Murray  */
338e73e9afaSDag-Erling Smørgrav #define WHITESPACE " \t\r\n"
339511b41d2SMark Murray 
340511b41d2SMark Murray int
341511b41d2SMark Murray process_config_line(Options *options, const char *host,
342511b41d2SMark Murray 		    char *line, const char *filename, int linenum,
343511b41d2SMark Murray 		    int *activep)
344511b41d2SMark Murray {
345aa49c926SDag-Erling Smørgrav 	char *s, **charptr, *endofnumber, *keyword, *arg, *arg2, fwdarg[256];
346333ee039SDag-Erling Smørgrav 	int opcode, *intptr, value, value2, scale;
347d4af9e69SDag-Erling Smørgrav 	LogLevel *log_level_ptr;
348333ee039SDag-Erling Smørgrav 	long long orig, val64;
349e73e9afaSDag-Erling Smørgrav 	size_t len;
350aa49c926SDag-Erling Smørgrav 	Forward fwd;
351511b41d2SMark Murray 
352cf2b5f3bSDag-Erling Smørgrav 	/* Strip trailing whitespace */
353cf2b5f3bSDag-Erling Smørgrav 	for (len = strlen(line) - 1; len > 0; len--) {
354cf2b5f3bSDag-Erling Smørgrav 		if (strchr(WHITESPACE, line[len]) == NULL)
355cf2b5f3bSDag-Erling Smørgrav 			break;
356cf2b5f3bSDag-Erling Smørgrav 		line[len] = '\0';
357cf2b5f3bSDag-Erling Smørgrav 	}
358cf2b5f3bSDag-Erling Smørgrav 
359c2d3a559SKris Kennaway 	s = line;
360c2d3a559SKris Kennaway 	/* Get the keyword. (Each line is supposed to begin with a keyword). */
361333ee039SDag-Erling Smørgrav 	if ((keyword = strdelim(&s)) == NULL)
362333ee039SDag-Erling Smørgrav 		return 0;
363c2d3a559SKris Kennaway 	/* Ignore leading whitespace. */
364c2d3a559SKris Kennaway 	if (*keyword == '\0')
365c2d3a559SKris Kennaway 		keyword = strdelim(&s);
366ca3176e7SBrian Feldman 	if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#')
367511b41d2SMark Murray 		return 0;
368511b41d2SMark Murray 
369c2d3a559SKris Kennaway 	opcode = parse_token(keyword, filename, linenum);
370511b41d2SMark Murray 
371511b41d2SMark Murray 	switch (opcode) {
372511b41d2SMark Murray 	case oBadOption:
373511b41d2SMark Murray 		/* don't panic, but count bad options */
374511b41d2SMark Murray 		return -1;
375511b41d2SMark Murray 		/* NOTREACHED */
376cf2b5f3bSDag-Erling Smørgrav 	case oConnectTimeout:
377cf2b5f3bSDag-Erling Smørgrav 		intptr = &options->connection_timeout;
3781ec0d754SDag-Erling Smørgrav parse_time:
379cf2b5f3bSDag-Erling Smørgrav 		arg = strdelim(&s);
380cf2b5f3bSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
381cf2b5f3bSDag-Erling Smørgrav 			fatal("%s line %d: missing time value.",
382cf2b5f3bSDag-Erling Smørgrav 			    filename, linenum);
383cf2b5f3bSDag-Erling Smørgrav 		if ((value = convtime(arg)) == -1)
384cf2b5f3bSDag-Erling Smørgrav 			fatal("%s line %d: invalid time value.",
385cf2b5f3bSDag-Erling Smørgrav 			    filename, linenum);
386d4af9e69SDag-Erling Smørgrav 		if (*activep && *intptr == -1)
387cf2b5f3bSDag-Erling Smørgrav 			*intptr = value;
388cf2b5f3bSDag-Erling Smørgrav 		break;
389cf2b5f3bSDag-Erling Smørgrav 
390511b41d2SMark Murray 	case oForwardAgent:
391511b41d2SMark Murray 		intptr = &options->forward_agent;
392511b41d2SMark Murray parse_flag:
393c2d3a559SKris Kennaway 		arg = strdelim(&s);
394c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
395511b41d2SMark Murray 			fatal("%.200s line %d: Missing yes/no argument.", filename, linenum);
396511b41d2SMark Murray 		value = 0;	/* To avoid compiler warning... */
397c2d3a559SKris Kennaway 		if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
398511b41d2SMark Murray 			value = 1;
399c2d3a559SKris Kennaway 		else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
400511b41d2SMark Murray 			value = 0;
401511b41d2SMark Murray 		else
402511b41d2SMark Murray 			fatal("%.200s line %d: Bad yes/no argument.", filename, linenum);
403511b41d2SMark Murray 		if (*activep && *intptr == -1)
404511b41d2SMark Murray 			*intptr = value;
405511b41d2SMark Murray 		break;
406511b41d2SMark Murray 
407511b41d2SMark Murray 	case oForwardX11:
408511b41d2SMark Murray 		intptr = &options->forward_x11;
409511b41d2SMark Murray 		goto parse_flag;
410511b41d2SMark Murray 
4111ec0d754SDag-Erling Smørgrav 	case oForwardX11Trusted:
4121ec0d754SDag-Erling Smørgrav 		intptr = &options->forward_x11_trusted;
4131ec0d754SDag-Erling Smørgrav 		goto parse_flag;
4141ec0d754SDag-Erling Smørgrav 
415511b41d2SMark Murray 	case oGatewayPorts:
416511b41d2SMark Murray 		intptr = &options->gateway_ports;
417511b41d2SMark Murray 		goto parse_flag;
418511b41d2SMark Murray 
419333ee039SDag-Erling Smørgrav 	case oExitOnForwardFailure:
420333ee039SDag-Erling Smørgrav 		intptr = &options->exit_on_forward_failure;
421333ee039SDag-Erling Smørgrav 		goto parse_flag;
422333ee039SDag-Erling Smørgrav 
423511b41d2SMark Murray 	case oUsePrivilegedPort:
424511b41d2SMark Murray 		intptr = &options->use_privileged_port;
425511b41d2SMark Murray 		goto parse_flag;
426511b41d2SMark Murray 
427511b41d2SMark Murray 	case oPasswordAuthentication:
428511b41d2SMark Murray 		intptr = &options->password_authentication;
429511b41d2SMark Murray 		goto parse_flag;
430511b41d2SMark Murray 
43109958426SBrian Feldman 	case oKbdInteractiveAuthentication:
43209958426SBrian Feldman 		intptr = &options->kbd_interactive_authentication;
43309958426SBrian Feldman 		goto parse_flag;
43409958426SBrian Feldman 
43509958426SBrian Feldman 	case oKbdInteractiveDevices:
43609958426SBrian Feldman 		charptr = &options->kbd_interactive_devices;
43709958426SBrian Feldman 		goto parse_string;
43809958426SBrian Feldman 
439ca3176e7SBrian Feldman 	case oPubkeyAuthentication:
440ca3176e7SBrian Feldman 		intptr = &options->pubkey_authentication;
441e8aafc91SKris Kennaway 		goto parse_flag;
442e8aafc91SKris Kennaway 
443511b41d2SMark Murray 	case oRSAAuthentication:
444511b41d2SMark Murray 		intptr = &options->rsa_authentication;
445511b41d2SMark Murray 		goto parse_flag;
446511b41d2SMark Murray 
447511b41d2SMark Murray 	case oRhostsRSAAuthentication:
448511b41d2SMark Murray 		intptr = &options->rhosts_rsa_authentication;
449511b41d2SMark Murray 		goto parse_flag;
450511b41d2SMark Murray 
451ca3176e7SBrian Feldman 	case oHostbasedAuthentication:
452ca3176e7SBrian Feldman 		intptr = &options->hostbased_authentication;
453511b41d2SMark Murray 		goto parse_flag;
454511b41d2SMark Murray 
455af12a3e7SDag-Erling Smørgrav 	case oChallengeResponseAuthentication:
456af12a3e7SDag-Erling Smørgrav 		intptr = &options->challenge_response_authentication;
457af12a3e7SDag-Erling Smørgrav 		goto parse_flag;
458cf2b5f3bSDag-Erling Smørgrav 
459cf2b5f3bSDag-Erling Smørgrav 	case oGssAuthentication:
460cf2b5f3bSDag-Erling Smørgrav 		intptr = &options->gss_authentication;
461511b41d2SMark Murray 		goto parse_flag;
462cf2b5f3bSDag-Erling Smørgrav 
463cf2b5f3bSDag-Erling Smørgrav 	case oGssDelegateCreds:
464cf2b5f3bSDag-Erling Smørgrav 		intptr = &options->gss_deleg_creds;
465ca3176e7SBrian Feldman 		goto parse_flag;
466cf2b5f3bSDag-Erling Smørgrav 
467511b41d2SMark Murray 	case oBatchMode:
468511b41d2SMark Murray 		intptr = &options->batch_mode;
469511b41d2SMark Murray 		goto parse_flag;
470511b41d2SMark Murray 
471511b41d2SMark Murray 	case oCheckHostIP:
472511b41d2SMark Murray 		intptr = &options->check_host_ip;
473511b41d2SMark Murray 		goto parse_flag;
474511b41d2SMark Murray 
475cf2b5f3bSDag-Erling Smørgrav 	case oVerifyHostKeyDNS:
476cf2b5f3bSDag-Erling Smørgrav 		intptr = &options->verify_host_key_dns;
4771ec0d754SDag-Erling Smørgrav 		goto parse_yesnoask;
478cf2b5f3bSDag-Erling Smørgrav 
479511b41d2SMark Murray 	case oStrictHostKeyChecking:
480511b41d2SMark Murray 		intptr = &options->strict_host_key_checking;
4811ec0d754SDag-Erling Smørgrav parse_yesnoask:
482c2d3a559SKris Kennaway 		arg = strdelim(&s);
483c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
484ca3176e7SBrian Feldman 			fatal("%.200s line %d: Missing yes/no/ask argument.",
485511b41d2SMark Murray 			    filename, linenum);
486511b41d2SMark Murray 		value = 0;	/* To avoid compiler warning... */
487c2d3a559SKris Kennaway 		if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
488511b41d2SMark Murray 			value = 1;
489c2d3a559SKris Kennaway 		else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
490511b41d2SMark Murray 			value = 0;
491c2d3a559SKris Kennaway 		else if (strcmp(arg, "ask") == 0)
492511b41d2SMark Murray 			value = 2;
493511b41d2SMark Murray 		else
494511b41d2SMark Murray 			fatal("%.200s line %d: Bad yes/no/ask argument.", filename, linenum);
495511b41d2SMark Murray 		if (*activep && *intptr == -1)
496511b41d2SMark Murray 			*intptr = value;
497511b41d2SMark Murray 		break;
498511b41d2SMark Murray 
499511b41d2SMark Murray 	case oCompression:
500511b41d2SMark Murray 		intptr = &options->compression;
501511b41d2SMark Murray 		goto parse_flag;
502511b41d2SMark Murray 
5031ec0d754SDag-Erling Smørgrav 	case oTCPKeepAlive:
5041ec0d754SDag-Erling Smørgrav 		intptr = &options->tcp_keep_alive;
505511b41d2SMark Murray 		goto parse_flag;
506511b41d2SMark Murray 
507af12a3e7SDag-Erling Smørgrav 	case oNoHostAuthenticationForLocalhost:
508af12a3e7SDag-Erling Smørgrav 		intptr = &options->no_host_authentication_for_localhost;
509af12a3e7SDag-Erling Smørgrav 		goto parse_flag;
510af12a3e7SDag-Erling Smørgrav 
511511b41d2SMark Murray 	case oNumberOfPasswordPrompts:
512511b41d2SMark Murray 		intptr = &options->number_of_password_prompts;
513511b41d2SMark Murray 		goto parse_int;
514511b41d2SMark Murray 
515511b41d2SMark Murray 	case oCompressionLevel:
516511b41d2SMark Murray 		intptr = &options->compression_level;
517511b41d2SMark Murray 		goto parse_int;
518511b41d2SMark Murray 
519cf2b5f3bSDag-Erling Smørgrav 	case oRekeyLimit:
520cf2b5f3bSDag-Erling Smørgrav 		arg = strdelim(&s);
521cf2b5f3bSDag-Erling Smørgrav 		if (!arg || *arg == '\0')
522cf2b5f3bSDag-Erling Smørgrav 			fatal("%.200s line %d: Missing argument.", filename, linenum);
523cf2b5f3bSDag-Erling Smørgrav 		if (arg[0] < '0' || arg[0] > '9')
524cf2b5f3bSDag-Erling Smørgrav 			fatal("%.200s line %d: Bad number.", filename, linenum);
525333ee039SDag-Erling Smørgrav 		orig = val64 = strtoll(arg, &endofnumber, 10);
526cf2b5f3bSDag-Erling Smørgrav 		if (arg == endofnumber)
527cf2b5f3bSDag-Erling Smørgrav 			fatal("%.200s line %d: Bad number.", filename, linenum);
528cf2b5f3bSDag-Erling Smørgrav 		switch (toupper(*endofnumber)) {
529333ee039SDag-Erling Smørgrav 		case '\0':
530333ee039SDag-Erling Smørgrav 			scale = 1;
531333ee039SDag-Erling Smørgrav 			break;
532cf2b5f3bSDag-Erling Smørgrav 		case 'K':
533333ee039SDag-Erling Smørgrav 			scale = 1<<10;
534cf2b5f3bSDag-Erling Smørgrav 			break;
535cf2b5f3bSDag-Erling Smørgrav 		case 'M':
536333ee039SDag-Erling Smørgrav 			scale = 1<<20;
537cf2b5f3bSDag-Erling Smørgrav 			break;
538cf2b5f3bSDag-Erling Smørgrav 		case 'G':
539333ee039SDag-Erling Smørgrav 			scale = 1<<30;
540cf2b5f3bSDag-Erling Smørgrav 			break;
541333ee039SDag-Erling Smørgrav 		default:
542333ee039SDag-Erling Smørgrav 			fatal("%.200s line %d: Invalid RekeyLimit suffix",
543333ee039SDag-Erling Smørgrav 			    filename, linenum);
544cf2b5f3bSDag-Erling Smørgrav 		}
545333ee039SDag-Erling Smørgrav 		val64 *= scale;
546333ee039SDag-Erling Smørgrav 		/* detect integer wrap and too-large limits */
547d4af9e69SDag-Erling Smørgrav 		if ((val64 / scale) != orig || val64 > UINT_MAX)
548333ee039SDag-Erling Smørgrav 			fatal("%.200s line %d: RekeyLimit too large",
549333ee039SDag-Erling Smørgrav 			    filename, linenum);
550333ee039SDag-Erling Smørgrav 		if (val64 < 16)
551333ee039SDag-Erling Smørgrav 			fatal("%.200s line %d: RekeyLimit too small",
552333ee039SDag-Erling Smørgrav 			    filename, linenum);
553d4af9e69SDag-Erling Smørgrav 		if (*activep && options->rekey_limit == -1)
554d4af9e69SDag-Erling Smørgrav 			options->rekey_limit = (u_int32_t)val64;
555cf2b5f3bSDag-Erling Smørgrav 		break;
556cf2b5f3bSDag-Erling Smørgrav 
557511b41d2SMark Murray 	case oIdentityFile:
558c2d3a559SKris Kennaway 		arg = strdelim(&s);
559c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
560511b41d2SMark Murray 			fatal("%.200s line %d: Missing argument.", filename, linenum);
561511b41d2SMark Murray 		if (*activep) {
562ca3176e7SBrian Feldman 			intptr = &options->num_identity_files;
563e8aafc91SKris Kennaway 			if (*intptr >= SSH_MAX_IDENTITY_FILES)
564511b41d2SMark Murray 				fatal("%.200s line %d: Too many identity files specified (max %d).",
565511b41d2SMark Murray 				    filename, linenum, SSH_MAX_IDENTITY_FILES);
566ca3176e7SBrian Feldman 			charptr = &options->identity_files[*intptr];
567c2d3a559SKris Kennaway 			*charptr = xstrdup(arg);
568e8aafc91SKris Kennaway 			*intptr = *intptr + 1;
569511b41d2SMark Murray 		}
570511b41d2SMark Murray 		break;
571511b41d2SMark Murray 
572c2d3a559SKris Kennaway 	case oXAuthLocation:
573c2d3a559SKris Kennaway 		charptr=&options->xauth_location;
574c2d3a559SKris Kennaway 		goto parse_string;
575c2d3a559SKris Kennaway 
576511b41d2SMark Murray 	case oUser:
577511b41d2SMark Murray 		charptr = &options->user;
578511b41d2SMark Murray parse_string:
579c2d3a559SKris Kennaway 		arg = strdelim(&s);
580c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
581511b41d2SMark Murray 			fatal("%.200s line %d: Missing argument.", filename, linenum);
582511b41d2SMark Murray 		if (*activep && *charptr == NULL)
583c2d3a559SKris Kennaway 			*charptr = xstrdup(arg);
584511b41d2SMark Murray 		break;
585511b41d2SMark Murray 
586511b41d2SMark Murray 	case oGlobalKnownHostsFile:
587511b41d2SMark Murray 		charptr = &options->system_hostfile;
588511b41d2SMark Murray 		goto parse_string;
589511b41d2SMark Murray 
590511b41d2SMark Murray 	case oUserKnownHostsFile:
591511b41d2SMark Murray 		charptr = &options->user_hostfile;
592511b41d2SMark Murray 		goto parse_string;
593511b41d2SMark Murray 
594e8aafc91SKris Kennaway 	case oGlobalKnownHostsFile2:
595e8aafc91SKris Kennaway 		charptr = &options->system_hostfile2;
596e8aafc91SKris Kennaway 		goto parse_string;
597e8aafc91SKris Kennaway 
598e8aafc91SKris Kennaway 	case oUserKnownHostsFile2:
599e8aafc91SKris Kennaway 		charptr = &options->user_hostfile2;
600e8aafc91SKris Kennaway 		goto parse_string;
601e8aafc91SKris Kennaway 
602511b41d2SMark Murray 	case oHostName:
603511b41d2SMark Murray 		charptr = &options->hostname;
604511b41d2SMark Murray 		goto parse_string;
605511b41d2SMark Murray 
606ca3176e7SBrian Feldman 	case oHostKeyAlias:
607ca3176e7SBrian Feldman 		charptr = &options->host_key_alias;
608ca3176e7SBrian Feldman 		goto parse_string;
609ca3176e7SBrian Feldman 
610ca3176e7SBrian Feldman 	case oPreferredAuthentications:
611ca3176e7SBrian Feldman 		charptr = &options->preferred_authentications;
612ca3176e7SBrian Feldman 		goto parse_string;
613ca3176e7SBrian Feldman 
614af12a3e7SDag-Erling Smørgrav 	case oBindAddress:
615af12a3e7SDag-Erling Smørgrav 		charptr = &options->bind_address;
616af12a3e7SDag-Erling Smørgrav 		goto parse_string;
617af12a3e7SDag-Erling Smørgrav 
618af12a3e7SDag-Erling Smørgrav 	case oSmartcardDevice:
619af12a3e7SDag-Erling Smørgrav 		charptr = &options->smartcard_device;
620af12a3e7SDag-Erling Smørgrav 		goto parse_string;
621af12a3e7SDag-Erling Smørgrav 
622511b41d2SMark Murray 	case oProxyCommand:
623b74df5b2SDag-Erling Smørgrav 		charptr = &options->proxy_command;
624b74df5b2SDag-Erling Smørgrav parse_command:
625cf2b5f3bSDag-Erling Smørgrav 		if (s == NULL)
626cf2b5f3bSDag-Erling Smørgrav 			fatal("%.200s line %d: Missing argument.", filename, linenum);
627e73e9afaSDag-Erling Smørgrav 		len = strspn(s, WHITESPACE "=");
628511b41d2SMark Murray 		if (*activep && *charptr == NULL)
629e73e9afaSDag-Erling Smørgrav 			*charptr = xstrdup(s + len);
630511b41d2SMark Murray 		return 0;
631511b41d2SMark Murray 
632511b41d2SMark Murray 	case oPort:
633511b41d2SMark Murray 		intptr = &options->port;
634511b41d2SMark Murray parse_int:
635c2d3a559SKris Kennaway 		arg = strdelim(&s);
636c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
637511b41d2SMark Murray 			fatal("%.200s line %d: Missing argument.", filename, linenum);
638c2d3a559SKris Kennaway 		if (arg[0] < '0' || arg[0] > '9')
639511b41d2SMark Murray 			fatal("%.200s line %d: Bad number.", filename, linenum);
640511b41d2SMark Murray 
641511b41d2SMark Murray 		/* Octal, decimal, or hex format? */
642c2d3a559SKris Kennaway 		value = strtol(arg, &endofnumber, 0);
643c2d3a559SKris Kennaway 		if (arg == endofnumber)
644511b41d2SMark Murray 			fatal("%.200s line %d: Bad number.", filename, linenum);
645511b41d2SMark Murray 		if (*activep && *intptr == -1)
646511b41d2SMark Murray 			*intptr = value;
647511b41d2SMark Murray 		break;
648511b41d2SMark Murray 
649511b41d2SMark Murray 	case oConnectionAttempts:
650511b41d2SMark Murray 		intptr = &options->connection_attempts;
651511b41d2SMark Murray 		goto parse_int;
652511b41d2SMark Murray 
653511b41d2SMark Murray 	case oCipher:
654511b41d2SMark Murray 		intptr = &options->cipher;
655c2d3a559SKris Kennaway 		arg = strdelim(&s);
656c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
657db1cb46cSKris Kennaway 			fatal("%.200s line %d: Missing argument.", filename, linenum);
658c2d3a559SKris Kennaway 		value = cipher_number(arg);
659511b41d2SMark Murray 		if (value == -1)
660511b41d2SMark Murray 			fatal("%.200s line %d: Bad cipher '%s'.",
661c2d3a559SKris Kennaway 			    filename, linenum, arg ? arg : "<NONE>");
662511b41d2SMark Murray 		if (*activep && *intptr == -1)
663511b41d2SMark Murray 			*intptr = value;
664511b41d2SMark Murray 		break;
665511b41d2SMark Murray 
666e8aafc91SKris Kennaway 	case oCiphers:
667c2d3a559SKris Kennaway 		arg = strdelim(&s);
668c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
669db1cb46cSKris Kennaway 			fatal("%.200s line %d: Missing argument.", filename, linenum);
670c2d3a559SKris Kennaway 		if (!ciphers_valid(arg))
671e8aafc91SKris Kennaway 			fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.",
672c2d3a559SKris Kennaway 			    filename, linenum, arg ? arg : "<NONE>");
673e8aafc91SKris Kennaway 		if (*activep && options->ciphers == NULL)
674c2d3a559SKris Kennaway 			options->ciphers = xstrdup(arg);
675e8aafc91SKris Kennaway 		break;
676e8aafc91SKris Kennaway 
677ca3176e7SBrian Feldman 	case oMacs:
678ca3176e7SBrian Feldman 		arg = strdelim(&s);
679ca3176e7SBrian Feldman 		if (!arg || *arg == '\0')
680ca3176e7SBrian Feldman 			fatal("%.200s line %d: Missing argument.", filename, linenum);
681ca3176e7SBrian Feldman 		if (!mac_valid(arg))
682ca3176e7SBrian Feldman 			fatal("%.200s line %d: Bad SSH2 Mac spec '%s'.",
683ca3176e7SBrian Feldman 			    filename, linenum, arg ? arg : "<NONE>");
684ca3176e7SBrian Feldman 		if (*activep && options->macs == NULL)
685ca3176e7SBrian Feldman 			options->macs = xstrdup(arg);
686ca3176e7SBrian Feldman 		break;
687ca3176e7SBrian Feldman 
688ca3176e7SBrian Feldman 	case oHostKeyAlgorithms:
689ca3176e7SBrian Feldman 		arg = strdelim(&s);
690ca3176e7SBrian Feldman 		if (!arg || *arg == '\0')
691ca3176e7SBrian Feldman 			fatal("%.200s line %d: Missing argument.", filename, linenum);
692ca3176e7SBrian Feldman 		if (!key_names_valid2(arg))
693ca3176e7SBrian Feldman 			fatal("%.200s line %d: Bad protocol 2 host key algorithms '%s'.",
694ca3176e7SBrian Feldman 			    filename, linenum, arg ? arg : "<NONE>");
695ca3176e7SBrian Feldman 		if (*activep && options->hostkeyalgorithms == NULL)
696ca3176e7SBrian Feldman 			options->hostkeyalgorithms = xstrdup(arg);
697ca3176e7SBrian Feldman 		break;
698ca3176e7SBrian Feldman 
699e8aafc91SKris Kennaway 	case oProtocol:
700e8aafc91SKris Kennaway 		intptr = &options->protocol;
701c2d3a559SKris Kennaway 		arg = strdelim(&s);
702c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
703db1cb46cSKris Kennaway 			fatal("%.200s line %d: Missing argument.", filename, linenum);
704c2d3a559SKris Kennaway 		value = proto_spec(arg);
705e8aafc91SKris Kennaway 		if (value == SSH_PROTO_UNKNOWN)
706e8aafc91SKris Kennaway 			fatal("%.200s line %d: Bad protocol spec '%s'.",
707c2d3a559SKris Kennaway 			    filename, linenum, arg ? arg : "<NONE>");
708e8aafc91SKris Kennaway 		if (*activep && *intptr == SSH_PROTO_UNKNOWN)
709e8aafc91SKris Kennaway 			*intptr = value;
710e8aafc91SKris Kennaway 		break;
711e8aafc91SKris Kennaway 
712511b41d2SMark Murray 	case oLogLevel:
713d4af9e69SDag-Erling Smørgrav 		log_level_ptr = &options->log_level;
714c2d3a559SKris Kennaway 		arg = strdelim(&s);
715c2d3a559SKris Kennaway 		value = log_level_number(arg);
716af12a3e7SDag-Erling Smørgrav 		if (value == SYSLOG_LEVEL_NOT_SET)
717ca3176e7SBrian Feldman 			fatal("%.200s line %d: unsupported log level '%s'",
718c2d3a559SKris Kennaway 			    filename, linenum, arg ? arg : "<NONE>");
719d4af9e69SDag-Erling Smørgrav 		if (*activep && *log_level_ptr == SYSLOG_LEVEL_NOT_SET)
720d4af9e69SDag-Erling Smørgrav 			*log_level_ptr = (LogLevel) value;
721511b41d2SMark Murray 		break;
722511b41d2SMark Murray 
723af12a3e7SDag-Erling Smørgrav 	case oLocalForward:
724511b41d2SMark Murray 	case oRemoteForward:
725c2d3a559SKris Kennaway 		arg = strdelim(&s);
726aa49c926SDag-Erling Smørgrav 		if (arg == NULL || *arg == '\0')
727af12a3e7SDag-Erling Smørgrav 			fatal("%.200s line %d: Missing port argument.",
728af12a3e7SDag-Erling Smørgrav 			    filename, linenum);
729aa49c926SDag-Erling Smørgrav 		arg2 = strdelim(&s);
730aa49c926SDag-Erling Smørgrav 		if (arg2 == NULL || *arg2 == '\0')
731aa49c926SDag-Erling Smørgrav 			fatal("%.200s line %d: Missing target argument.",
732511b41d2SMark Murray 			    filename, linenum);
733aa49c926SDag-Erling Smørgrav 
734aa49c926SDag-Erling Smørgrav 		/* construct a string for parse_forward */
735aa49c926SDag-Erling Smørgrav 		snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg, arg2);
736aa49c926SDag-Erling Smørgrav 
737aa49c926SDag-Erling Smørgrav 		if (parse_forward(&fwd, fwdarg) == 0)
738af12a3e7SDag-Erling Smørgrav 			fatal("%.200s line %d: Bad forwarding specification.",
739511b41d2SMark Murray 			    filename, linenum);
740aa49c926SDag-Erling Smørgrav 
741af12a3e7SDag-Erling Smørgrav 		if (*activep) {
742af12a3e7SDag-Erling Smørgrav 			if (opcode == oLocalForward)
743aa49c926SDag-Erling Smørgrav 				add_local_forward(options, &fwd);
744af12a3e7SDag-Erling Smørgrav 			else if (opcode == oRemoteForward)
745aa49c926SDag-Erling Smørgrav 				add_remote_forward(options, &fwd);
746af12a3e7SDag-Erling Smørgrav 		}
747511b41d2SMark Murray 		break;
748511b41d2SMark Murray 
749ca3176e7SBrian Feldman 	case oDynamicForward:
750ca3176e7SBrian Feldman 		arg = strdelim(&s);
751ca3176e7SBrian Feldman 		if (!arg || *arg == '\0')
752ca3176e7SBrian Feldman 			fatal("%.200s line %d: Missing port argument.",
753ca3176e7SBrian Feldman 			    filename, linenum);
754aa49c926SDag-Erling Smørgrav 		memset(&fwd, '\0', sizeof(fwd));
755aa49c926SDag-Erling Smørgrav 		fwd.connect_host = "socks";
756aa49c926SDag-Erling Smørgrav 		fwd.listen_host = hpdelim(&arg);
757aa49c926SDag-Erling Smørgrav 		if (fwd.listen_host == NULL ||
758aa49c926SDag-Erling Smørgrav 		    strlen(fwd.listen_host) >= NI_MAXHOST)
759aa49c926SDag-Erling Smørgrav 			fatal("%.200s line %d: Bad forwarding specification.",
760aa49c926SDag-Erling Smørgrav 			    filename, linenum);
761aa49c926SDag-Erling Smørgrav 		if (arg) {
762aa49c926SDag-Erling Smørgrav 			fwd.listen_port = a2port(arg);
763aa49c926SDag-Erling Smørgrav 			fwd.listen_host = cleanhostname(fwd.listen_host);
764aa49c926SDag-Erling Smørgrav 		} else {
765aa49c926SDag-Erling Smørgrav 			fwd.listen_port = a2port(fwd.listen_host);
766d4ecd108SDag-Erling Smørgrav 			fwd.listen_host = NULL;
767aa49c926SDag-Erling Smørgrav 		}
768aa49c926SDag-Erling Smørgrav 		if (fwd.listen_port == 0)
769ca3176e7SBrian Feldman 			fatal("%.200s line %d: Badly formatted port number.",
770ca3176e7SBrian Feldman 			    filename, linenum);
771af12a3e7SDag-Erling Smørgrav 		if (*activep)
772aa49c926SDag-Erling Smørgrav 			add_local_forward(options, &fwd);
773ca3176e7SBrian Feldman 		break;
774ca3176e7SBrian Feldman 
775af12a3e7SDag-Erling Smørgrav 	case oClearAllForwardings:
776af12a3e7SDag-Erling Smørgrav 		intptr = &options->clear_forwardings;
777af12a3e7SDag-Erling Smørgrav 		goto parse_flag;
778af12a3e7SDag-Erling Smørgrav 
779511b41d2SMark Murray 	case oHost:
780511b41d2SMark Murray 		*activep = 0;
781c2d3a559SKris Kennaway 		while ((arg = strdelim(&s)) != NULL && *arg != '\0')
782c2d3a559SKris Kennaway 			if (match_pattern(host, arg)) {
783c2d3a559SKris Kennaway 				debug("Applying options for %.100s", arg);
784511b41d2SMark Murray 				*activep = 1;
785511b41d2SMark Murray 				break;
786511b41d2SMark Murray 			}
787c2d3a559SKris Kennaway 		/* Avoid garbage check below, as strdelim is done. */
788511b41d2SMark Murray 		return 0;
789511b41d2SMark Murray 
790511b41d2SMark Murray 	case oEscapeChar:
791511b41d2SMark Murray 		intptr = &options->escape_char;
792c2d3a559SKris Kennaway 		arg = strdelim(&s);
793c2d3a559SKris Kennaway 		if (!arg || *arg == '\0')
794511b41d2SMark Murray 			fatal("%.200s line %d: Missing argument.", filename, linenum);
795c2d3a559SKris Kennaway 		if (arg[0] == '^' && arg[2] == 0 &&
796ca3176e7SBrian Feldman 		    (u_char) arg[1] >= 64 && (u_char) arg[1] < 128)
797ca3176e7SBrian Feldman 			value = (u_char) arg[1] & 31;
798c2d3a559SKris Kennaway 		else if (strlen(arg) == 1)
799ca3176e7SBrian Feldman 			value = (u_char) arg[0];
800c2d3a559SKris Kennaway 		else if (strcmp(arg, "none") == 0)
801af12a3e7SDag-Erling Smørgrav 			value = SSH_ESCAPECHAR_NONE;
802511b41d2SMark Murray 		else {
803511b41d2SMark Murray 			fatal("%.200s line %d: Bad escape character.",
804511b41d2SMark Murray 			    filename, linenum);
805511b41d2SMark Murray 			/* NOTREACHED */
806511b41d2SMark Murray 			value = 0;	/* Avoid compiler warning. */
807511b41d2SMark Murray 		}
808511b41d2SMark Murray 		if (*activep && *intptr == -1)
809511b41d2SMark Murray 			*intptr = value;
810511b41d2SMark Murray 		break;
811511b41d2SMark Murray 
812cf2b5f3bSDag-Erling Smørgrav 	case oAddressFamily:
813cf2b5f3bSDag-Erling Smørgrav 		arg = strdelim(&s);
814d4ecd108SDag-Erling Smørgrav 		if (!arg || *arg == '\0')
815d4ecd108SDag-Erling Smørgrav 			fatal("%s line %d: missing address family.",
816d4ecd108SDag-Erling Smørgrav 			    filename, linenum);
817cf2b5f3bSDag-Erling Smørgrav 		intptr = &options->address_family;
818cf2b5f3bSDag-Erling Smørgrav 		if (strcasecmp(arg, "inet") == 0)
819cf2b5f3bSDag-Erling Smørgrav 			value = AF_INET;
820cf2b5f3bSDag-Erling Smørgrav 		else if (strcasecmp(arg, "inet6") == 0)
821cf2b5f3bSDag-Erling Smørgrav 			value = AF_INET6;
822cf2b5f3bSDag-Erling Smørgrav 		else if (strcasecmp(arg, "any") == 0)
823cf2b5f3bSDag-Erling Smørgrav 			value = AF_UNSPEC;
824cf2b5f3bSDag-Erling Smørgrav 		else
825cf2b5f3bSDag-Erling Smørgrav 			fatal("Unsupported AddressFamily \"%s\"", arg);
826cf2b5f3bSDag-Erling Smørgrav 		if (*activep && *intptr == -1)
827cf2b5f3bSDag-Erling Smørgrav 			*intptr = value;
828cf2b5f3bSDag-Erling Smørgrav 		break;
829cf2b5f3bSDag-Erling Smørgrav 
830e73e9afaSDag-Erling Smørgrav 	case oEnableSSHKeysign:
831e73e9afaSDag-Erling Smørgrav 		intptr = &options->enable_ssh_keysign;
832e73e9afaSDag-Erling Smørgrav 		goto parse_flag;
833e73e9afaSDag-Erling Smørgrav 
8345962c0e9SDag-Erling Smørgrav 	case oIdentitiesOnly:
8355962c0e9SDag-Erling Smørgrav 		intptr = &options->identities_only;
8365962c0e9SDag-Erling Smørgrav 		goto parse_flag;
8375962c0e9SDag-Erling Smørgrav 
8381ec0d754SDag-Erling Smørgrav 	case oServerAliveInterval:
8391ec0d754SDag-Erling Smørgrav 		intptr = &options->server_alive_interval;
8401ec0d754SDag-Erling Smørgrav 		goto parse_time;
8411ec0d754SDag-Erling Smørgrav 
8421ec0d754SDag-Erling Smørgrav 	case oServerAliveCountMax:
8431ec0d754SDag-Erling Smørgrav 		intptr = &options->server_alive_count_max;
8441ec0d754SDag-Erling Smørgrav 		goto parse_int;
8451ec0d754SDag-Erling Smørgrav 
84621e764dfSDag-Erling Smørgrav 	case oSendEnv:
84721e764dfSDag-Erling Smørgrav 		while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
84821e764dfSDag-Erling Smørgrav 			if (strchr(arg, '=') != NULL)
84921e764dfSDag-Erling Smørgrav 				fatal("%s line %d: Invalid environment name.",
85021e764dfSDag-Erling Smørgrav 				    filename, linenum);
851aa49c926SDag-Erling Smørgrav 			if (!*activep)
852aa49c926SDag-Erling Smørgrav 				continue;
85321e764dfSDag-Erling Smørgrav 			if (options->num_send_env >= MAX_SEND_ENV)
85421e764dfSDag-Erling Smørgrav 				fatal("%s line %d: too many send env.",
85521e764dfSDag-Erling Smørgrav 				    filename, linenum);
85621e764dfSDag-Erling Smørgrav 			options->send_env[options->num_send_env++] =
85721e764dfSDag-Erling Smørgrav 			    xstrdup(arg);
85821e764dfSDag-Erling Smørgrav 		}
85921e764dfSDag-Erling Smørgrav 		break;
86021e764dfSDag-Erling Smørgrav 
86121e764dfSDag-Erling Smørgrav 	case oControlPath:
86221e764dfSDag-Erling Smørgrav 		charptr = &options->control_path;
86321e764dfSDag-Erling Smørgrav 		goto parse_string;
86421e764dfSDag-Erling Smørgrav 
86521e764dfSDag-Erling Smørgrav 	case oControlMaster:
86621e764dfSDag-Erling Smørgrav 		intptr = &options->control_master;
867d4ecd108SDag-Erling Smørgrav 		arg = strdelim(&s);
868d4ecd108SDag-Erling Smørgrav 		if (!arg || *arg == '\0')
869d4ecd108SDag-Erling Smørgrav 			fatal("%.200s line %d: Missing ControlMaster argument.",
870d4ecd108SDag-Erling Smørgrav 			    filename, linenum);
871d4ecd108SDag-Erling Smørgrav 		value = 0;	/* To avoid compiler warning... */
872d4ecd108SDag-Erling Smørgrav 		if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
873d4ecd108SDag-Erling Smørgrav 			value = SSHCTL_MASTER_YES;
874d4ecd108SDag-Erling Smørgrav 		else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
875d4ecd108SDag-Erling Smørgrav 			value = SSHCTL_MASTER_NO;
876d4ecd108SDag-Erling Smørgrav 		else if (strcmp(arg, "auto") == 0)
877d4ecd108SDag-Erling Smørgrav 			value = SSHCTL_MASTER_AUTO;
878d4ecd108SDag-Erling Smørgrav 		else if (strcmp(arg, "ask") == 0)
879d4ecd108SDag-Erling Smørgrav 			value = SSHCTL_MASTER_ASK;
880d4ecd108SDag-Erling Smørgrav 		else if (strcmp(arg, "autoask") == 0)
881d4ecd108SDag-Erling Smørgrav 			value = SSHCTL_MASTER_AUTO_ASK;
882d4ecd108SDag-Erling Smørgrav 		else
883d4ecd108SDag-Erling Smørgrav 			fatal("%.200s line %d: Bad ControlMaster argument.",
884d4ecd108SDag-Erling Smørgrav 			    filename, linenum);
885d4ecd108SDag-Erling Smørgrav 		if (*activep && *intptr == -1)
886d4ecd108SDag-Erling Smørgrav 			*intptr = value;
887d4ecd108SDag-Erling Smørgrav 		break;
88821e764dfSDag-Erling Smørgrav 
889aa49c926SDag-Erling Smørgrav 	case oHashKnownHosts:
890aa49c926SDag-Erling Smørgrav 		intptr = &options->hash_known_hosts;
891aa49c926SDag-Erling Smørgrav 		goto parse_flag;
892aa49c926SDag-Erling Smørgrav 
893b74df5b2SDag-Erling Smørgrav 	case oTunnel:
894b74df5b2SDag-Erling Smørgrav 		intptr = &options->tun_open;
895b74df5b2SDag-Erling Smørgrav 		arg = strdelim(&s);
896b74df5b2SDag-Erling Smørgrav 		if (!arg || *arg == '\0')
897b74df5b2SDag-Erling Smørgrav 			fatal("%s line %d: Missing yes/point-to-point/"
898b74df5b2SDag-Erling Smørgrav 			    "ethernet/no argument.", filename, linenum);
899b74df5b2SDag-Erling Smørgrav 		value = 0;	/* silence compiler */
900b74df5b2SDag-Erling Smørgrav 		if (strcasecmp(arg, "ethernet") == 0)
901b74df5b2SDag-Erling Smørgrav 			value = SSH_TUNMODE_ETHERNET;
902b74df5b2SDag-Erling Smørgrav 		else if (strcasecmp(arg, "point-to-point") == 0)
903b74df5b2SDag-Erling Smørgrav 			value = SSH_TUNMODE_POINTOPOINT;
904b74df5b2SDag-Erling Smørgrav 		else if (strcasecmp(arg, "yes") == 0)
905b74df5b2SDag-Erling Smørgrav 			value = SSH_TUNMODE_DEFAULT;
906b74df5b2SDag-Erling Smørgrav 		else if (strcasecmp(arg, "no") == 0)
907b74df5b2SDag-Erling Smørgrav 			value = SSH_TUNMODE_NO;
908b74df5b2SDag-Erling Smørgrav 		else
909b74df5b2SDag-Erling Smørgrav 			fatal("%s line %d: Bad yes/point-to-point/ethernet/"
910b74df5b2SDag-Erling Smørgrav 			    "no argument: %s", filename, linenum, arg);
911b74df5b2SDag-Erling Smørgrav 		if (*activep)
912b74df5b2SDag-Erling Smørgrav 			*intptr = value;
913b74df5b2SDag-Erling Smørgrav 		break;
914b74df5b2SDag-Erling Smørgrav 
915b74df5b2SDag-Erling Smørgrav 	case oTunnelDevice:
916b74df5b2SDag-Erling Smørgrav 		arg = strdelim(&s);
917b74df5b2SDag-Erling Smørgrav 		if (!arg || *arg == '\0')
918b74df5b2SDag-Erling Smørgrav 			fatal("%.200s line %d: Missing argument.", filename, linenum);
919b74df5b2SDag-Erling Smørgrav 		value = a2tun(arg, &value2);
920b74df5b2SDag-Erling Smørgrav 		if (value == SSH_TUNID_ERR)
921b74df5b2SDag-Erling Smørgrav 			fatal("%.200s line %d: Bad tun device.", filename, linenum);
922b74df5b2SDag-Erling Smørgrav 		if (*activep) {
923b74df5b2SDag-Erling Smørgrav 			options->tun_local = value;
924b74df5b2SDag-Erling Smørgrav 			options->tun_remote = value2;
925b74df5b2SDag-Erling Smørgrav 		}
926b74df5b2SDag-Erling Smørgrav 		break;
927b74df5b2SDag-Erling Smørgrav 
928b74df5b2SDag-Erling Smørgrav 	case oLocalCommand:
929b74df5b2SDag-Erling Smørgrav 		charptr = &options->local_command;
930b74df5b2SDag-Erling Smørgrav 		goto parse_command;
931b74df5b2SDag-Erling Smørgrav 
932b74df5b2SDag-Erling Smørgrav 	case oPermitLocalCommand:
933b74df5b2SDag-Erling Smørgrav 		intptr = &options->permit_local_command;
934b74df5b2SDag-Erling Smørgrav 		goto parse_flag;
935b74df5b2SDag-Erling Smørgrav 
936d4af9e69SDag-Erling Smørgrav 	case oVisualHostKey:
937d4af9e69SDag-Erling Smørgrav 		intptr = &options->visual_host_key;
938d4af9e69SDag-Erling Smørgrav 		goto parse_flag;
939d4af9e69SDag-Erling Smørgrav 
940975616f0SDag-Erling Smørgrav 	case oVersionAddendum:
941975616f0SDag-Erling Smørgrav 		ssh_version_set_addendum(strtok(s, "\n"));
942975616f0SDag-Erling Smørgrav 		do {
943975616f0SDag-Erling Smørgrav 			arg = strdelim(&s);
944975616f0SDag-Erling Smørgrav 		} while (arg != NULL && *arg != '\0');
945975616f0SDag-Erling Smørgrav 		break;
946975616f0SDag-Erling Smørgrav 
94780628bacSDag-Erling Smørgrav 	case oDeprecated:
94880628bacSDag-Erling Smørgrav 		debug("%s line %d: Deprecated option \"%s\"",
94980628bacSDag-Erling Smørgrav 		    filename, linenum, keyword);
95080628bacSDag-Erling Smørgrav 		return 0;
95180628bacSDag-Erling Smørgrav 
952cf2b5f3bSDag-Erling Smørgrav 	case oUnsupported:
953cf2b5f3bSDag-Erling Smørgrav 		error("%s line %d: Unsupported option \"%s\"",
954cf2b5f3bSDag-Erling Smørgrav 		    filename, linenum, keyword);
955cf2b5f3bSDag-Erling Smørgrav 		return 0;
956cf2b5f3bSDag-Erling Smørgrav 
957511b41d2SMark Murray 	default:
958511b41d2SMark Murray 		fatal("process_config_line: Unimplemented opcode %d", opcode);
959511b41d2SMark Murray 	}
960511b41d2SMark Murray 
961511b41d2SMark Murray 	/* Check that there is no garbage at end of line. */
962ca3176e7SBrian Feldman 	if ((arg = strdelim(&s)) != NULL && *arg != '\0') {
963c2d3a559SKris Kennaway 		fatal("%.200s line %d: garbage at end of line; \"%.200s\".",
964c2d3a559SKris Kennaway 		    filename, linenum, arg);
965c2d3a559SKris Kennaway 	}
966511b41d2SMark Murray 	return 0;
967511b41d2SMark Murray }
968511b41d2SMark Murray 
969511b41d2SMark Murray 
970511b41d2SMark Murray /*
971511b41d2SMark Murray  * Reads the config file and modifies the options accordingly.  Options
972511b41d2SMark Murray  * should already be initialized before this call.  This never returns if
973af12a3e7SDag-Erling Smørgrav  * there is an error.  If the file does not exist, this returns 0.
974511b41d2SMark Murray  */
975511b41d2SMark Murray 
976af12a3e7SDag-Erling Smørgrav int
97721e764dfSDag-Erling Smørgrav read_config_file(const char *filename, const char *host, Options *options,
97821e764dfSDag-Erling Smørgrav     int checkperm)
979511b41d2SMark Murray {
980511b41d2SMark Murray 	FILE *f;
981511b41d2SMark Murray 	char line[1024];
982511b41d2SMark Murray 	int active, linenum;
983511b41d2SMark Murray 	int bad_options = 0;
984511b41d2SMark Murray 
985511b41d2SMark Murray 	/* Open the file. */
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;
1080af12a3e7SDag-Erling Smørgrav 	options->smartcard_device = 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;
1097d4af9e69SDag-Erling Smørgrav 	options->visual_host_key = -1;
1098511b41d2SMark Murray }
1099511b41d2SMark Murray 
1100511b41d2SMark Murray /*
1101511b41d2SMark Murray  * Called after processing other sources of option data, this fills those
1102511b41d2SMark Murray  * options for which no value has been specified with their default values.
1103511b41d2SMark Murray  */
1104511b41d2SMark Murray 
1105511b41d2SMark Murray void
1106511b41d2SMark Murray fill_default_options(Options * options)
1107511b41d2SMark Murray {
1108ca3176e7SBrian Feldman 	int len;
1109ca3176e7SBrian Feldman 
1110511b41d2SMark Murray 	if (options->forward_agent == -1)
1111db1cb46cSKris Kennaway 		options->forward_agent = 0;
1112511b41d2SMark Murray 	if (options->forward_x11 == -1)
11135dc73ebeSBrian Feldman 		options->forward_x11 = 0;
11141ec0d754SDag-Erling Smørgrav 	if (options->forward_x11_trusted == -1)
11151ec0d754SDag-Erling Smørgrav 		options->forward_x11_trusted = 0;
1116333ee039SDag-Erling Smørgrav 	if (options->exit_on_forward_failure == -1)
1117333ee039SDag-Erling Smørgrav 		options->exit_on_forward_failure = 0;
1118c2d3a559SKris Kennaway 	if (options->xauth_location == NULL)
1119af12a3e7SDag-Erling Smørgrav 		options->xauth_location = _PATH_XAUTH;
1120511b41d2SMark Murray 	if (options->gateway_ports == -1)
1121511b41d2SMark Murray 		options->gateway_ports = 0;
1122511b41d2SMark Murray 	if (options->use_privileged_port == -1)
1123ca3176e7SBrian Feldman 		options->use_privileged_port = 0;
1124511b41d2SMark Murray 	if (options->rsa_authentication == -1)
1125511b41d2SMark Murray 		options->rsa_authentication = 1;
1126ca3176e7SBrian Feldman 	if (options->pubkey_authentication == -1)
1127ca3176e7SBrian Feldman 		options->pubkey_authentication = 1;
1128af12a3e7SDag-Erling Smørgrav 	if (options->challenge_response_authentication == -1)
1129af12a3e7SDag-Erling Smørgrav 		options->challenge_response_authentication = 1;
1130cf2b5f3bSDag-Erling Smørgrav 	if (options->gss_authentication == -1)
11311ec0d754SDag-Erling Smørgrav 		options->gss_authentication = 0;
1132cf2b5f3bSDag-Erling Smørgrav 	if (options->gss_deleg_creds == -1)
1133cf2b5f3bSDag-Erling Smørgrav 		options->gss_deleg_creds = 0;
1134511b41d2SMark Murray 	if (options->password_authentication == -1)
1135511b41d2SMark Murray 		options->password_authentication = 1;
113609958426SBrian Feldman 	if (options->kbd_interactive_authentication == -1)
1137ca3176e7SBrian Feldman 		options->kbd_interactive_authentication = 1;
1138511b41d2SMark Murray 	if (options->rhosts_rsa_authentication == -1)
113980628bacSDag-Erling Smørgrav 		options->rhosts_rsa_authentication = 0;
1140ca3176e7SBrian Feldman 	if (options->hostbased_authentication == -1)
1141ca3176e7SBrian Feldman 		options->hostbased_authentication = 0;
1142511b41d2SMark Murray 	if (options->batch_mode == -1)
1143511b41d2SMark Murray 		options->batch_mode = 0;
1144511b41d2SMark Murray 	if (options->check_host_ip == -1)
1145975616f0SDag-Erling Smørgrav 		options->check_host_ip = 0;
1146511b41d2SMark Murray 	if (options->strict_host_key_checking == -1)
1147511b41d2SMark Murray 		options->strict_host_key_checking = 2;	/* 2 is default */
1148511b41d2SMark Murray 	if (options->compression == -1)
1149511b41d2SMark Murray 		options->compression = 0;
11501ec0d754SDag-Erling Smørgrav 	if (options->tcp_keep_alive == -1)
11511ec0d754SDag-Erling Smørgrav 		options->tcp_keep_alive = 1;
1152511b41d2SMark Murray 	if (options->compression_level == -1)
1153511b41d2SMark Murray 		options->compression_level = 6;
1154511b41d2SMark Murray 	if (options->port == -1)
1155511b41d2SMark Murray 		options->port = 0;	/* Filled in ssh_connect. */
1156cf2b5f3bSDag-Erling Smørgrav 	if (options->address_family == -1)
1157cf2b5f3bSDag-Erling Smørgrav 		options->address_family = AF_UNSPEC;
1158511b41d2SMark Murray 	if (options->connection_attempts == -1)
1159af12a3e7SDag-Erling Smørgrav 		options->connection_attempts = 1;
1160511b41d2SMark Murray 	if (options->number_of_password_prompts == -1)
1161511b41d2SMark Murray 		options->number_of_password_prompts = 3;
1162511b41d2SMark Murray 	/* Selected in ssh_login(). */
1163511b41d2SMark Murray 	if (options->cipher == -1)
1164511b41d2SMark Murray 		options->cipher = SSH_CIPHER_NOT_SET;
1165e8aafc91SKris Kennaway 	/* options->ciphers, default set in myproposals.h */
1166ca3176e7SBrian Feldman 	/* options->macs, default set in myproposals.h */
1167ca3176e7SBrian Feldman 	/* options->hostkeyalgorithms, default set in myproposals.h */
1168e8aafc91SKris Kennaway 	if (options->protocol == SSH_PROTO_UNKNOWN)
1169ca3176e7SBrian Feldman 		options->protocol = SSH_PROTO_1|SSH_PROTO_2;
1170511b41d2SMark Murray 	if (options->num_identity_files == 0) {
1171ca3176e7SBrian Feldman 		if (options->protocol & SSH_PROTO_1) {
1172ca3176e7SBrian Feldman 			len = 2 + strlen(_PATH_SSH_CLIENT_IDENTITY) + 1;
1173ca3176e7SBrian Feldman 			options->identity_files[options->num_identity_files] =
1174ca3176e7SBrian Feldman 			    xmalloc(len);
1175ca3176e7SBrian Feldman 			snprintf(options->identity_files[options->num_identity_files++],
1176ca3176e7SBrian Feldman 			    len, "~/%.100s", _PATH_SSH_CLIENT_IDENTITY);
1177511b41d2SMark Murray 		}
1178ca3176e7SBrian Feldman 		if (options->protocol & SSH_PROTO_2) {
1179ca3176e7SBrian Feldman 			len = 2 + strlen(_PATH_SSH_CLIENT_ID_RSA) + 1;
1180ca3176e7SBrian Feldman 			options->identity_files[options->num_identity_files] =
1181ca3176e7SBrian Feldman 			    xmalloc(len);
1182ca3176e7SBrian Feldman 			snprintf(options->identity_files[options->num_identity_files++],
1183ca3176e7SBrian Feldman 			    len, "~/%.100s", _PATH_SSH_CLIENT_ID_RSA);
1184ca3176e7SBrian Feldman 
1185ca3176e7SBrian Feldman 			len = 2 + strlen(_PATH_SSH_CLIENT_ID_DSA) + 1;
1186ca3176e7SBrian Feldman 			options->identity_files[options->num_identity_files] =
1187ca3176e7SBrian Feldman 			    xmalloc(len);
1188ca3176e7SBrian Feldman 			snprintf(options->identity_files[options->num_identity_files++],
1189ca3176e7SBrian Feldman 			    len, "~/%.100s", _PATH_SSH_CLIENT_ID_DSA);
1190ca3176e7SBrian Feldman 		}
1191e8aafc91SKris Kennaway 	}
1192511b41d2SMark Murray 	if (options->escape_char == -1)
1193511b41d2SMark Murray 		options->escape_char = '~';
1194511b41d2SMark Murray 	if (options->system_hostfile == NULL)
1195ca3176e7SBrian Feldman 		options->system_hostfile = _PATH_SSH_SYSTEM_HOSTFILE;
1196511b41d2SMark Murray 	if (options->user_hostfile == NULL)
1197ca3176e7SBrian Feldman 		options->user_hostfile = _PATH_SSH_USER_HOSTFILE;
1198e8aafc91SKris Kennaway 	if (options->system_hostfile2 == NULL)
1199ca3176e7SBrian Feldman 		options->system_hostfile2 = _PATH_SSH_SYSTEM_HOSTFILE2;
1200e8aafc91SKris Kennaway 	if (options->user_hostfile2 == NULL)
1201ca3176e7SBrian Feldman 		options->user_hostfile2 = _PATH_SSH_USER_HOSTFILE2;
1202af12a3e7SDag-Erling Smørgrav 	if (options->log_level == SYSLOG_LEVEL_NOT_SET)
1203511b41d2SMark Murray 		options->log_level = SYSLOG_LEVEL_INFO;
1204af12a3e7SDag-Erling Smørgrav 	if (options->clear_forwardings == 1)
1205af12a3e7SDag-Erling Smørgrav 		clear_forwardings(options);
1206af12a3e7SDag-Erling Smørgrav 	if (options->no_host_authentication_for_localhost == - 1)
1207af12a3e7SDag-Erling Smørgrav 		options->no_host_authentication_for_localhost = 0;
12085962c0e9SDag-Erling Smørgrav 	if (options->identities_only == -1)
12095962c0e9SDag-Erling Smørgrav 		options->identities_only = 0;
1210e73e9afaSDag-Erling Smørgrav 	if (options->enable_ssh_keysign == -1)
1211e73e9afaSDag-Erling Smørgrav 		options->enable_ssh_keysign = 0;
1212cf2b5f3bSDag-Erling Smørgrav 	if (options->rekey_limit == -1)
1213cf2b5f3bSDag-Erling Smørgrav 		options->rekey_limit = 0;
1214cf2b5f3bSDag-Erling Smørgrav 	if (options->verify_host_key_dns == -1)
1215cf2b5f3bSDag-Erling Smørgrav 		options->verify_host_key_dns = 0;
12161ec0d754SDag-Erling Smørgrav 	if (options->server_alive_interval == -1)
12171ec0d754SDag-Erling Smørgrav 		options->server_alive_interval = 0;
12181ec0d754SDag-Erling Smørgrav 	if (options->server_alive_count_max == -1)
12191ec0d754SDag-Erling Smørgrav 		options->server_alive_count_max = 3;
122021e764dfSDag-Erling Smørgrav 	if (options->control_master == -1)
122121e764dfSDag-Erling Smørgrav 		options->control_master = 0;
1222aa49c926SDag-Erling Smørgrav 	if (options->hash_known_hosts == -1)
1223aa49c926SDag-Erling Smørgrav 		options->hash_known_hosts = 0;
1224b74df5b2SDag-Erling Smørgrav 	if (options->tun_open == -1)
1225b74df5b2SDag-Erling Smørgrav 		options->tun_open = SSH_TUNMODE_NO;
1226b74df5b2SDag-Erling Smørgrav 	if (options->tun_local == -1)
1227b74df5b2SDag-Erling Smørgrav 		options->tun_local = SSH_TUNID_ANY;
1228b74df5b2SDag-Erling Smørgrav 	if (options->tun_remote == -1)
1229b74df5b2SDag-Erling Smørgrav 		options->tun_remote = SSH_TUNID_ANY;
1230b74df5b2SDag-Erling Smørgrav 	if (options->permit_local_command == -1)
1231b74df5b2SDag-Erling Smørgrav 		options->permit_local_command = 0;
1232d4af9e69SDag-Erling Smørgrav 	if (options->visual_host_key == -1)
1233d4af9e69SDag-Erling Smørgrav 		options->visual_host_key = 0;
1234b74df5b2SDag-Erling Smørgrav 	/* options->local_command should not be set by default */
1235511b41d2SMark Murray 	/* options->proxy_command should not be set by default */
1236511b41d2SMark Murray 	/* options->user will be set in the main program if appropriate */
1237511b41d2SMark Murray 	/* options->hostname will be set in the main program if appropriate */
1238ca3176e7SBrian Feldman 	/* options->host_key_alias should not be set by default */
1239ca3176e7SBrian Feldman 	/* options->preferred_authentications will be set in ssh */
1240511b41d2SMark Murray }
1241aa49c926SDag-Erling Smørgrav 
1242aa49c926SDag-Erling Smørgrav /*
1243aa49c926SDag-Erling Smørgrav  * parse_forward
1244aa49c926SDag-Erling Smørgrav  * parses a string containing a port forwarding specification of the form:
1245aa49c926SDag-Erling Smørgrav  *	[listenhost:]listenport:connecthost:connectport
1246aa49c926SDag-Erling Smørgrav  * returns number of arguments parsed or zero on error
1247aa49c926SDag-Erling Smørgrav  */
1248aa49c926SDag-Erling Smørgrav int
1249aa49c926SDag-Erling Smørgrav parse_forward(Forward *fwd, const char *fwdspec)
1250aa49c926SDag-Erling Smørgrav {
1251aa49c926SDag-Erling Smørgrav 	int i;
1252aa49c926SDag-Erling Smørgrav 	char *p, *cp, *fwdarg[4];
1253aa49c926SDag-Erling Smørgrav 
1254aa49c926SDag-Erling Smørgrav 	memset(fwd, '\0', sizeof(*fwd));
1255aa49c926SDag-Erling Smørgrav 
1256aa49c926SDag-Erling Smørgrav 	cp = p = xstrdup(fwdspec);
1257aa49c926SDag-Erling Smørgrav 
1258aa49c926SDag-Erling Smørgrav 	/* skip leading spaces */
1259d4af9e69SDag-Erling Smørgrav 	while (isspace(*cp))
1260aa49c926SDag-Erling Smørgrav 		cp++;
1261aa49c926SDag-Erling Smørgrav 
1262aa49c926SDag-Erling Smørgrav 	for (i = 0; i < 4; ++i)
1263aa49c926SDag-Erling Smørgrav 		if ((fwdarg[i] = hpdelim(&cp)) == NULL)
1264aa49c926SDag-Erling Smørgrav 			break;
1265aa49c926SDag-Erling Smørgrav 
1266aa49c926SDag-Erling Smørgrav 	/* Check for trailing garbage in 4-arg case*/
1267aa49c926SDag-Erling Smørgrav 	if (cp != NULL)
1268aa49c926SDag-Erling Smørgrav 		i = 0;	/* failure */
1269aa49c926SDag-Erling Smørgrav 
1270aa49c926SDag-Erling Smørgrav 	switch (i) {
1271aa49c926SDag-Erling Smørgrav 	case 3:
1272aa49c926SDag-Erling Smørgrav 		fwd->listen_host = NULL;
1273aa49c926SDag-Erling Smørgrav 		fwd->listen_port = a2port(fwdarg[0]);
1274aa49c926SDag-Erling Smørgrav 		fwd->connect_host = xstrdup(cleanhostname(fwdarg[1]));
1275aa49c926SDag-Erling Smørgrav 		fwd->connect_port = a2port(fwdarg[2]);
1276aa49c926SDag-Erling Smørgrav 		break;
1277aa49c926SDag-Erling Smørgrav 
1278aa49c926SDag-Erling Smørgrav 	case 4:
1279aa49c926SDag-Erling Smørgrav 		fwd->listen_host = xstrdup(cleanhostname(fwdarg[0]));
1280aa49c926SDag-Erling Smørgrav 		fwd->listen_port = a2port(fwdarg[1]);
1281aa49c926SDag-Erling Smørgrav 		fwd->connect_host = xstrdup(cleanhostname(fwdarg[2]));
1282aa49c926SDag-Erling Smørgrav 		fwd->connect_port = a2port(fwdarg[3]);
1283aa49c926SDag-Erling Smørgrav 		break;
1284aa49c926SDag-Erling Smørgrav 	default:
1285aa49c926SDag-Erling Smørgrav 		i = 0; /* failure */
1286aa49c926SDag-Erling Smørgrav 	}
1287aa49c926SDag-Erling Smørgrav 
1288aa49c926SDag-Erling Smørgrav 	xfree(p);
1289aa49c926SDag-Erling Smørgrav 
1290d4af9e69SDag-Erling Smørgrav 	if (fwd->listen_port == 0 || fwd->connect_port == 0)
1291aa49c926SDag-Erling Smørgrav 		goto fail_free;
1292aa49c926SDag-Erling Smørgrav 
1293aa49c926SDag-Erling Smørgrav 	if (fwd->connect_host != NULL &&
1294aa49c926SDag-Erling Smørgrav 	    strlen(fwd->connect_host) >= NI_MAXHOST)
1295aa49c926SDag-Erling Smørgrav 		goto fail_free;
1296aa49c926SDag-Erling Smørgrav 
1297aa49c926SDag-Erling Smørgrav 	return (i);
1298aa49c926SDag-Erling Smørgrav 
1299aa49c926SDag-Erling Smørgrav  fail_free:
1300aa49c926SDag-Erling Smørgrav 	if (fwd->connect_host != NULL)
1301aa49c926SDag-Erling Smørgrav 		xfree(fwd->connect_host);
1302aa49c926SDag-Erling Smørgrav 	if (fwd->listen_host != NULL)
1303aa49c926SDag-Erling Smørgrav 		xfree(fwd->listen_host);
1304aa49c926SDag-Erling Smørgrav 	return (0);
1305aa49c926SDag-Erling Smørgrav }
1306