xref: /dragonfly/crypto/openssh/readconf.c (revision 9f304aaf)
1*9f304aafSPeter Avalos /* $OpenBSD: readconf.c,v 1.190 2010/11/13 23:27:50 djm Exp $ */
218de8d7fSPeter Avalos /*
318de8d7fSPeter Avalos  * Author: Tatu Ylonen <ylo@cs.hut.fi>
418de8d7fSPeter Avalos  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
518de8d7fSPeter Avalos  *                    All rights reserved
618de8d7fSPeter Avalos  * Functions for reading the configuration files.
718de8d7fSPeter Avalos  *
818de8d7fSPeter Avalos  * As far as I am concerned, the code I have written for this software
918de8d7fSPeter Avalos  * can be used freely for any purpose.  Any derived versions of this
1018de8d7fSPeter Avalos  * software must be clearly marked as such, and if the derived work is
1118de8d7fSPeter Avalos  * incompatible with the protocol description in the RFC file, it must be
1218de8d7fSPeter Avalos  * called by a name other than "ssh" or "Secure Shell".
1318de8d7fSPeter Avalos  */
1418de8d7fSPeter Avalos 
1518de8d7fSPeter Avalos #include "includes.h"
1618de8d7fSPeter Avalos 
1718de8d7fSPeter Avalos #include <sys/types.h>
1818de8d7fSPeter Avalos #include <sys/stat.h>
1918de8d7fSPeter Avalos #include <sys/socket.h>
2018de8d7fSPeter Avalos 
2118de8d7fSPeter Avalos #include <netinet/in.h>
22*9f304aafSPeter Avalos #include <netinet/in_systm.h>
23*9f304aafSPeter Avalos #include <netinet/ip.h>
2418de8d7fSPeter Avalos 
2518de8d7fSPeter Avalos #include <ctype.h>
2618de8d7fSPeter Avalos #include <errno.h>
2718de8d7fSPeter Avalos #include <netdb.h>
2818de8d7fSPeter Avalos #include <signal.h>
2918de8d7fSPeter Avalos #include <stdarg.h>
3018de8d7fSPeter Avalos #include <stdio.h>
3118de8d7fSPeter Avalos #include <string.h>
3218de8d7fSPeter Avalos #include <unistd.h>
3318de8d7fSPeter Avalos 
3418de8d7fSPeter Avalos #include "xmalloc.h"
3518de8d7fSPeter Avalos #include "ssh.h"
3618de8d7fSPeter Avalos #include "compat.h"
3718de8d7fSPeter Avalos #include "cipher.h"
3818de8d7fSPeter Avalos #include "pathnames.h"
3918de8d7fSPeter Avalos #include "log.h"
4018de8d7fSPeter Avalos #include "key.h"
4118de8d7fSPeter Avalos #include "readconf.h"
4218de8d7fSPeter Avalos #include "match.h"
4318de8d7fSPeter Avalos #include "misc.h"
4418de8d7fSPeter Avalos #include "buffer.h"
4518de8d7fSPeter Avalos #include "kex.h"
4618de8d7fSPeter Avalos #include "mac.h"
4718de8d7fSPeter Avalos 
4818de8d7fSPeter Avalos /* Format of the configuration file:
4918de8d7fSPeter Avalos 
5018de8d7fSPeter Avalos    # Configuration data is parsed as follows:
5118de8d7fSPeter Avalos    #  1. command line options
5218de8d7fSPeter Avalos    #  2. user-specific file
5318de8d7fSPeter Avalos    #  3. system-wide file
5418de8d7fSPeter Avalos    # Any configuration value is only changed the first time it is set.
5518de8d7fSPeter Avalos    # Thus, host-specific definitions should be at the beginning of the
5618de8d7fSPeter Avalos    # configuration file, and defaults at the end.
5718de8d7fSPeter Avalos 
5818de8d7fSPeter Avalos    # Host-specific declarations.  These may override anything above.  A single
5918de8d7fSPeter Avalos    # host may match multiple declarations; these are processed in the order
6018de8d7fSPeter Avalos    # that they are given in.
6118de8d7fSPeter Avalos 
6218de8d7fSPeter Avalos    Host *.ngs.fi ngs.fi
6318de8d7fSPeter Avalos      User foo
6418de8d7fSPeter Avalos 
6518de8d7fSPeter Avalos    Host fake.com
6618de8d7fSPeter Avalos      HostName another.host.name.real.org
6718de8d7fSPeter Avalos      User blaah
6818de8d7fSPeter Avalos      Port 34289
6918de8d7fSPeter Avalos      ForwardX11 no
7018de8d7fSPeter Avalos      ForwardAgent no
7118de8d7fSPeter Avalos 
7218de8d7fSPeter Avalos    Host books.com
7318de8d7fSPeter Avalos      RemoteForward 9999 shadows.cs.hut.fi:9999
7418de8d7fSPeter Avalos      Cipher 3des
7518de8d7fSPeter Avalos 
7618de8d7fSPeter Avalos    Host fascist.blob.com
7718de8d7fSPeter Avalos      Port 23123
7818de8d7fSPeter Avalos      User tylonen
7918de8d7fSPeter Avalos      PasswordAuthentication no
8018de8d7fSPeter Avalos 
8118de8d7fSPeter Avalos    Host puukko.hut.fi
8218de8d7fSPeter Avalos      User t35124p
8318de8d7fSPeter Avalos      ProxyCommand ssh-proxy %h %p
8418de8d7fSPeter Avalos 
8518de8d7fSPeter Avalos    Host *.fr
8618de8d7fSPeter Avalos      PublicKeyAuthentication no
8718de8d7fSPeter Avalos 
8818de8d7fSPeter Avalos    Host *.su
8918de8d7fSPeter Avalos      Cipher none
9018de8d7fSPeter Avalos      PasswordAuthentication no
9118de8d7fSPeter Avalos 
9218de8d7fSPeter Avalos    Host vpn.fake.com
9318de8d7fSPeter Avalos      Tunnel yes
9418de8d7fSPeter Avalos      TunnelDevice 3
9518de8d7fSPeter Avalos 
9618de8d7fSPeter Avalos    # Defaults for various options
9718de8d7fSPeter Avalos    Host *
9818de8d7fSPeter Avalos      ForwardAgent no
9918de8d7fSPeter Avalos      ForwardX11 no
10018de8d7fSPeter Avalos      PasswordAuthentication yes
10118de8d7fSPeter Avalos      RSAAuthentication yes
10218de8d7fSPeter Avalos      RhostsRSAAuthentication yes
10318de8d7fSPeter Avalos      StrictHostKeyChecking yes
10418de8d7fSPeter Avalos      TcpKeepAlive no
10518de8d7fSPeter Avalos      IdentityFile ~/.ssh/identity
10618de8d7fSPeter Avalos      Port 22
10718de8d7fSPeter Avalos      EscapeChar ~
10818de8d7fSPeter Avalos 
10918de8d7fSPeter Avalos */
11018de8d7fSPeter Avalos 
11118de8d7fSPeter Avalos /* Keyword tokens. */
11218de8d7fSPeter Avalos 
11318de8d7fSPeter Avalos typedef enum {
11418de8d7fSPeter Avalos 	oBadOption,
115856ea928SPeter Avalos 	oForwardAgent, oForwardX11, oForwardX11Trusted, oForwardX11Timeout,
116856ea928SPeter Avalos 	oGatewayPorts, oExitOnForwardFailure,
11718de8d7fSPeter Avalos 	oPasswordAuthentication, oRSAAuthentication,
11818de8d7fSPeter Avalos 	oChallengeResponseAuthentication, oXAuthLocation,
11918de8d7fSPeter Avalos 	oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward,
12018de8d7fSPeter Avalos 	oUser, oHost, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
12118de8d7fSPeter Avalos 	oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
12218de8d7fSPeter Avalos 	oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
12318de8d7fSPeter Avalos 	oCompressionLevel, oTCPKeepAlive, oNumberOfPasswordPrompts,
12418de8d7fSPeter Avalos 	oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oMacs,
12518de8d7fSPeter Avalos 	oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication,
12618de8d7fSPeter Avalos 	oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
12718de8d7fSPeter Avalos 	oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
128856ea928SPeter Avalos 	oHostKeyAlgorithms, oBindAddress, oPKCS11Provider,
12918de8d7fSPeter Avalos 	oClearAllForwardings, oNoHostAuthenticationForLocalhost,
13018de8d7fSPeter Avalos 	oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
13118de8d7fSPeter Avalos 	oAddressFamily, oGssAuthentication, oGssDelegateCreds,
13218de8d7fSPeter Avalos 	oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
133856ea928SPeter Avalos 	oSendEnv, oControlPath, oControlMaster, oControlPersist,
134856ea928SPeter Avalos 	oHashKnownHosts,
13518de8d7fSPeter Avalos 	oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand,
13640c002afSPeter Avalos 	oVisualHostKey, oUseRoaming, oZeroKnowledgePasswordAuthentication,
137*9f304aafSPeter Avalos 	oKexAlgorithms, oIPQoS,
13818de8d7fSPeter Avalos 	oDeprecated, oUnsupported
13918de8d7fSPeter Avalos } OpCodes;
14018de8d7fSPeter Avalos 
14118de8d7fSPeter Avalos /* Textual representations of the tokens. */
14218de8d7fSPeter Avalos 
14318de8d7fSPeter Avalos static struct {
14418de8d7fSPeter Avalos 	const char *name;
14518de8d7fSPeter Avalos 	OpCodes opcode;
14618de8d7fSPeter Avalos } keywords[] = {
14718de8d7fSPeter Avalos 	{ "forwardagent", oForwardAgent },
14818de8d7fSPeter Avalos 	{ "forwardx11", oForwardX11 },
14918de8d7fSPeter Avalos 	{ "forwardx11trusted", oForwardX11Trusted },
150856ea928SPeter Avalos 	{ "forwardx11timeout", oForwardX11Timeout },
15118de8d7fSPeter Avalos 	{ "exitonforwardfailure", oExitOnForwardFailure },
15218de8d7fSPeter Avalos 	{ "xauthlocation", oXAuthLocation },
15318de8d7fSPeter Avalos 	{ "gatewayports", oGatewayPorts },
15418de8d7fSPeter Avalos 	{ "useprivilegedport", oUsePrivilegedPort },
15518de8d7fSPeter Avalos 	{ "rhostsauthentication", oDeprecated },
15618de8d7fSPeter Avalos 	{ "passwordauthentication", oPasswordAuthentication },
15718de8d7fSPeter Avalos 	{ "kbdinteractiveauthentication", oKbdInteractiveAuthentication },
15818de8d7fSPeter Avalos 	{ "kbdinteractivedevices", oKbdInteractiveDevices },
15918de8d7fSPeter Avalos 	{ "rsaauthentication", oRSAAuthentication },
16018de8d7fSPeter Avalos 	{ "pubkeyauthentication", oPubkeyAuthentication },
16118de8d7fSPeter Avalos 	{ "dsaauthentication", oPubkeyAuthentication },		    /* alias */
16218de8d7fSPeter Avalos 	{ "rhostsrsaauthentication", oRhostsRSAAuthentication },
16318de8d7fSPeter Avalos 	{ "hostbasedauthentication", oHostbasedAuthentication },
16418de8d7fSPeter Avalos 	{ "challengeresponseauthentication", oChallengeResponseAuthentication },
16518de8d7fSPeter Avalos 	{ "skeyauthentication", oChallengeResponseAuthentication }, /* alias */
16618de8d7fSPeter Avalos 	{ "tisauthentication", oChallengeResponseAuthentication },  /* alias */
16718de8d7fSPeter Avalos 	{ "kerberosauthentication", oUnsupported },
16818de8d7fSPeter Avalos 	{ "kerberostgtpassing", oUnsupported },
16918de8d7fSPeter Avalos 	{ "afstokenpassing", oUnsupported },
17018de8d7fSPeter Avalos #if defined(GSSAPI)
17118de8d7fSPeter Avalos 	{ "gssapiauthentication", oGssAuthentication },
17218de8d7fSPeter Avalos 	{ "gssapidelegatecredentials", oGssDelegateCreds },
17318de8d7fSPeter Avalos #else
17418de8d7fSPeter Avalos 	{ "gssapiauthentication", oUnsupported },
17518de8d7fSPeter Avalos 	{ "gssapidelegatecredentials", oUnsupported },
17618de8d7fSPeter Avalos #endif
17718de8d7fSPeter Avalos 	{ "fallbacktorsh", oDeprecated },
17818de8d7fSPeter Avalos 	{ "usersh", oDeprecated },
17918de8d7fSPeter Avalos 	{ "identityfile", oIdentityFile },
180cb5eb4f1SPeter Avalos 	{ "identityfile2", oIdentityFile },			/* obsolete */
18118de8d7fSPeter Avalos 	{ "identitiesonly", oIdentitiesOnly },
18218de8d7fSPeter Avalos 	{ "hostname", oHostName },
18318de8d7fSPeter Avalos 	{ "hostkeyalias", oHostKeyAlias },
18418de8d7fSPeter Avalos 	{ "proxycommand", oProxyCommand },
18518de8d7fSPeter Avalos 	{ "port", oPort },
18618de8d7fSPeter Avalos 	{ "cipher", oCipher },
18718de8d7fSPeter Avalos 	{ "ciphers", oCiphers },
18818de8d7fSPeter Avalos 	{ "macs", oMacs },
18918de8d7fSPeter Avalos 	{ "protocol", oProtocol },
19018de8d7fSPeter Avalos 	{ "remoteforward", oRemoteForward },
19118de8d7fSPeter Avalos 	{ "localforward", oLocalForward },
19218de8d7fSPeter Avalos 	{ "user", oUser },
19318de8d7fSPeter Avalos 	{ "host", oHost },
19418de8d7fSPeter Avalos 	{ "escapechar", oEscapeChar },
19518de8d7fSPeter Avalos 	{ "globalknownhostsfile", oGlobalKnownHostsFile },
196cb5eb4f1SPeter Avalos 	{ "globalknownhostsfile2", oGlobalKnownHostsFile2 },	/* obsolete */
197cb5eb4f1SPeter Avalos 	{ "userknownhostsfile", oUserKnownHostsFile },
19818de8d7fSPeter Avalos 	{ "userknownhostsfile2", oUserKnownHostsFile2 },	/* obsolete */
19918de8d7fSPeter Avalos 	{ "connectionattempts", oConnectionAttempts },
20018de8d7fSPeter Avalos 	{ "batchmode", oBatchMode },
20118de8d7fSPeter Avalos 	{ "checkhostip", oCheckHostIP },
20218de8d7fSPeter Avalos 	{ "stricthostkeychecking", oStrictHostKeyChecking },
20318de8d7fSPeter Avalos 	{ "compression", oCompression },
20418de8d7fSPeter Avalos 	{ "compressionlevel", oCompressionLevel },
20518de8d7fSPeter Avalos 	{ "tcpkeepalive", oTCPKeepAlive },
20618de8d7fSPeter Avalos 	{ "keepalive", oTCPKeepAlive },				/* obsolete */
20718de8d7fSPeter Avalos 	{ "numberofpasswordprompts", oNumberOfPasswordPrompts },
20818de8d7fSPeter Avalos 	{ "loglevel", oLogLevel },
20918de8d7fSPeter Avalos 	{ "dynamicforward", oDynamicForward },
21018de8d7fSPeter Avalos 	{ "preferredauthentications", oPreferredAuthentications },
21118de8d7fSPeter Avalos 	{ "hostkeyalgorithms", oHostKeyAlgorithms },
21218de8d7fSPeter Avalos 	{ "bindaddress", oBindAddress },
213856ea928SPeter Avalos #ifdef ENABLE_PKCS11
214856ea928SPeter Avalos 	{ "smartcarddevice", oPKCS11Provider },
215856ea928SPeter Avalos 	{ "pkcs11provider", oPKCS11Provider },
21618de8d7fSPeter Avalos #else
21718de8d7fSPeter Avalos 	{ "smartcarddevice", oUnsupported },
218856ea928SPeter Avalos 	{ "pkcs11provider", oUnsupported },
21918de8d7fSPeter Avalos #endif
22018de8d7fSPeter Avalos 	{ "clearallforwardings", oClearAllForwardings },
22118de8d7fSPeter Avalos 	{ "enablesshkeysign", oEnableSSHKeysign },
22218de8d7fSPeter Avalos 	{ "verifyhostkeydns", oVerifyHostKeyDNS },
22318de8d7fSPeter Avalos 	{ "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
22418de8d7fSPeter Avalos 	{ "rekeylimit", oRekeyLimit },
22518de8d7fSPeter Avalos 	{ "connecttimeout", oConnectTimeout },
22618de8d7fSPeter Avalos 	{ "addressfamily", oAddressFamily },
22718de8d7fSPeter Avalos 	{ "serveraliveinterval", oServerAliveInterval },
22818de8d7fSPeter Avalos 	{ "serveralivecountmax", oServerAliveCountMax },
22918de8d7fSPeter Avalos 	{ "sendenv", oSendEnv },
23018de8d7fSPeter Avalos 	{ "controlpath", oControlPath },
23118de8d7fSPeter Avalos 	{ "controlmaster", oControlMaster },
232856ea928SPeter Avalos 	{ "controlpersist", oControlPersist },
23318de8d7fSPeter Avalos 	{ "hashknownhosts", oHashKnownHosts },
23418de8d7fSPeter Avalos 	{ "tunnel", oTunnel },
23518de8d7fSPeter Avalos 	{ "tunneldevice", oTunnelDevice },
23618de8d7fSPeter Avalos 	{ "localcommand", oLocalCommand },
23718de8d7fSPeter Avalos 	{ "permitlocalcommand", oPermitLocalCommand },
23818de8d7fSPeter Avalos 	{ "visualhostkey", oVisualHostKey },
23940c002afSPeter Avalos 	{ "useroaming", oUseRoaming },
240cb5eb4f1SPeter Avalos #ifdef JPAKE
241cb5eb4f1SPeter Avalos 	{ "zeroknowledgepasswordauthentication",
242cb5eb4f1SPeter Avalos 	    oZeroKnowledgePasswordAuthentication },
243cb5eb4f1SPeter Avalos #else
244cb5eb4f1SPeter Avalos 	{ "zeroknowledgepasswordauthentication", oUnsupported },
245cb5eb4f1SPeter Avalos #endif
246*9f304aafSPeter Avalos 	{ "kexalgorithms", oKexAlgorithms },
247*9f304aafSPeter Avalos 	{ "ipqos", oIPQoS },
248cb5eb4f1SPeter Avalos 
24918de8d7fSPeter Avalos 	{ NULL, oBadOption }
25018de8d7fSPeter Avalos };
25118de8d7fSPeter Avalos 
25218de8d7fSPeter Avalos /*
25318de8d7fSPeter Avalos  * Adds a local TCP/IP port forward to options.  Never returns if there is an
25418de8d7fSPeter Avalos  * error.
25518de8d7fSPeter Avalos  */
25618de8d7fSPeter Avalos 
25718de8d7fSPeter Avalos void
25818de8d7fSPeter Avalos add_local_forward(Options *options, const Forward *newfwd)
25918de8d7fSPeter Avalos {
26018de8d7fSPeter Avalos 	Forward *fwd;
26118de8d7fSPeter Avalos #ifndef NO_IPPORT_RESERVED_CONCEPT
26218de8d7fSPeter Avalos 	extern uid_t original_real_uid;
26318de8d7fSPeter Avalos 	if (newfwd->listen_port < IPPORT_RESERVED && original_real_uid != 0)
26418de8d7fSPeter Avalos 		fatal("Privileged ports can only be forwarded by root.");
26518de8d7fSPeter Avalos #endif
266856ea928SPeter Avalos 	options->local_forwards = xrealloc(options->local_forwards,
267856ea928SPeter Avalos 	    options->num_local_forwards + 1,
268856ea928SPeter Avalos 	    sizeof(*options->local_forwards));
26918de8d7fSPeter Avalos 	fwd = &options->local_forwards[options->num_local_forwards++];
27018de8d7fSPeter Avalos 
271cb5eb4f1SPeter Avalos 	fwd->listen_host = newfwd->listen_host;
27218de8d7fSPeter Avalos 	fwd->listen_port = newfwd->listen_port;
273cb5eb4f1SPeter Avalos 	fwd->connect_host = newfwd->connect_host;
27418de8d7fSPeter Avalos 	fwd->connect_port = newfwd->connect_port;
27518de8d7fSPeter Avalos }
27618de8d7fSPeter Avalos 
27718de8d7fSPeter Avalos /*
27818de8d7fSPeter Avalos  * Adds a remote TCP/IP port forward to options.  Never returns if there is
27918de8d7fSPeter Avalos  * an error.
28018de8d7fSPeter Avalos  */
28118de8d7fSPeter Avalos 
28218de8d7fSPeter Avalos void
28318de8d7fSPeter Avalos add_remote_forward(Options *options, const Forward *newfwd)
28418de8d7fSPeter Avalos {
28518de8d7fSPeter Avalos 	Forward *fwd;
286856ea928SPeter Avalos 
287856ea928SPeter Avalos 	options->remote_forwards = xrealloc(options->remote_forwards,
288856ea928SPeter Avalos 	    options->num_remote_forwards + 1,
289856ea928SPeter Avalos 	    sizeof(*options->remote_forwards));
29018de8d7fSPeter Avalos 	fwd = &options->remote_forwards[options->num_remote_forwards++];
29118de8d7fSPeter Avalos 
292cb5eb4f1SPeter Avalos 	fwd->listen_host = newfwd->listen_host;
29318de8d7fSPeter Avalos 	fwd->listen_port = newfwd->listen_port;
294cb5eb4f1SPeter Avalos 	fwd->connect_host = newfwd->connect_host;
29518de8d7fSPeter Avalos 	fwd->connect_port = newfwd->connect_port;
296856ea928SPeter Avalos 	fwd->allocated_port = 0;
29718de8d7fSPeter Avalos }
29818de8d7fSPeter Avalos 
29918de8d7fSPeter Avalos static void
30018de8d7fSPeter Avalos clear_forwardings(Options *options)
30118de8d7fSPeter Avalos {
30218de8d7fSPeter Avalos 	int i;
30318de8d7fSPeter Avalos 
30418de8d7fSPeter Avalos 	for (i = 0; i < options->num_local_forwards; i++) {
30518de8d7fSPeter Avalos 		if (options->local_forwards[i].listen_host != NULL)
30618de8d7fSPeter Avalos 			xfree(options->local_forwards[i].listen_host);
30718de8d7fSPeter Avalos 		xfree(options->local_forwards[i].connect_host);
30818de8d7fSPeter Avalos 	}
309856ea928SPeter Avalos 	if (options->num_local_forwards > 0) {
310856ea928SPeter Avalos 		xfree(options->local_forwards);
311856ea928SPeter Avalos 		options->local_forwards = NULL;
312856ea928SPeter Avalos 	}
31318de8d7fSPeter Avalos 	options->num_local_forwards = 0;
31418de8d7fSPeter Avalos 	for (i = 0; i < options->num_remote_forwards; i++) {
31518de8d7fSPeter Avalos 		if (options->remote_forwards[i].listen_host != NULL)
31618de8d7fSPeter Avalos 			xfree(options->remote_forwards[i].listen_host);
31718de8d7fSPeter Avalos 		xfree(options->remote_forwards[i].connect_host);
31818de8d7fSPeter Avalos 	}
319856ea928SPeter Avalos 	if (options->num_remote_forwards > 0) {
320856ea928SPeter Avalos 		xfree(options->remote_forwards);
321856ea928SPeter Avalos 		options->remote_forwards = NULL;
322856ea928SPeter Avalos 	}
32318de8d7fSPeter Avalos 	options->num_remote_forwards = 0;
32418de8d7fSPeter Avalos 	options->tun_open = SSH_TUNMODE_NO;
32518de8d7fSPeter Avalos }
32618de8d7fSPeter Avalos 
32718de8d7fSPeter Avalos /*
32818de8d7fSPeter Avalos  * Returns the number of the token pointed to by cp or oBadOption.
32918de8d7fSPeter Avalos  */
33018de8d7fSPeter Avalos 
33118de8d7fSPeter Avalos static OpCodes
33218de8d7fSPeter Avalos parse_token(const char *cp, const char *filename, int linenum)
33318de8d7fSPeter Avalos {
33418de8d7fSPeter Avalos 	u_int i;
33518de8d7fSPeter Avalos 
33618de8d7fSPeter Avalos 	for (i = 0; keywords[i].name; i++)
33718de8d7fSPeter Avalos 		if (strcasecmp(cp, keywords[i].name) == 0)
33818de8d7fSPeter Avalos 			return keywords[i].opcode;
33918de8d7fSPeter Avalos 
34018de8d7fSPeter Avalos 	error("%s: line %d: Bad configuration option: %s",
34118de8d7fSPeter Avalos 	    filename, linenum, cp);
34218de8d7fSPeter Avalos 	return oBadOption;
34318de8d7fSPeter Avalos }
34418de8d7fSPeter Avalos 
34518de8d7fSPeter Avalos /*
34618de8d7fSPeter Avalos  * Processes a single option line as used in the configuration files. This
34718de8d7fSPeter Avalos  * only sets those values that have not already been set.
34818de8d7fSPeter Avalos  */
34918de8d7fSPeter Avalos #define WHITESPACE " \t\r\n"
35018de8d7fSPeter Avalos 
35118de8d7fSPeter Avalos int
35218de8d7fSPeter Avalos process_config_line(Options *options, const char *host,
35318de8d7fSPeter Avalos 		    char *line, const char *filename, int linenum,
35418de8d7fSPeter Avalos 		    int *activep)
35518de8d7fSPeter Avalos {
35618de8d7fSPeter Avalos 	char *s, **charptr, *endofnumber, *keyword, *arg, *arg2, fwdarg[256];
35718de8d7fSPeter Avalos 	int opcode, *intptr, value, value2, scale;
35818de8d7fSPeter Avalos 	LogLevel *log_level_ptr;
35918de8d7fSPeter Avalos 	long long orig, val64;
36018de8d7fSPeter Avalos 	size_t len;
36118de8d7fSPeter Avalos 	Forward fwd;
36218de8d7fSPeter Avalos 
36318de8d7fSPeter Avalos 	/* Strip trailing whitespace */
36418de8d7fSPeter Avalos 	for (len = strlen(line) - 1; len > 0; len--) {
36518de8d7fSPeter Avalos 		if (strchr(WHITESPACE, line[len]) == NULL)
36618de8d7fSPeter Avalos 			break;
36718de8d7fSPeter Avalos 		line[len] = '\0';
36818de8d7fSPeter Avalos 	}
36918de8d7fSPeter Avalos 
37018de8d7fSPeter Avalos 	s = line;
37118de8d7fSPeter Avalos 	/* Get the keyword. (Each line is supposed to begin with a keyword). */
37218de8d7fSPeter Avalos 	if ((keyword = strdelim(&s)) == NULL)
37318de8d7fSPeter Avalos 		return 0;
37418de8d7fSPeter Avalos 	/* Ignore leading whitespace. */
37518de8d7fSPeter Avalos 	if (*keyword == '\0')
37618de8d7fSPeter Avalos 		keyword = strdelim(&s);
37718de8d7fSPeter Avalos 	if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#')
37818de8d7fSPeter Avalos 		return 0;
37918de8d7fSPeter Avalos 
38018de8d7fSPeter Avalos 	opcode = parse_token(keyword, filename, linenum);
38118de8d7fSPeter Avalos 
38218de8d7fSPeter Avalos 	switch (opcode) {
38318de8d7fSPeter Avalos 	case oBadOption:
38418de8d7fSPeter Avalos 		/* don't panic, but count bad options */
38518de8d7fSPeter Avalos 		return -1;
38618de8d7fSPeter Avalos 		/* NOTREACHED */
38718de8d7fSPeter Avalos 	case oConnectTimeout:
38818de8d7fSPeter Avalos 		intptr = &options->connection_timeout;
38918de8d7fSPeter Avalos parse_time:
39018de8d7fSPeter Avalos 		arg = strdelim(&s);
39118de8d7fSPeter Avalos 		if (!arg || *arg == '\0')
39218de8d7fSPeter Avalos 			fatal("%s line %d: missing time value.",
39318de8d7fSPeter Avalos 			    filename, linenum);
39418de8d7fSPeter Avalos 		if ((value = convtime(arg)) == -1)
39518de8d7fSPeter Avalos 			fatal("%s line %d: invalid time value.",
39618de8d7fSPeter Avalos 			    filename, linenum);
39718de8d7fSPeter Avalos 		if (*activep && *intptr == -1)
39818de8d7fSPeter Avalos 			*intptr = value;
39918de8d7fSPeter Avalos 		break;
40018de8d7fSPeter Avalos 
40118de8d7fSPeter Avalos 	case oForwardAgent:
40218de8d7fSPeter Avalos 		intptr = &options->forward_agent;
40318de8d7fSPeter Avalos parse_flag:
40418de8d7fSPeter Avalos 		arg = strdelim(&s);
40518de8d7fSPeter Avalos 		if (!arg || *arg == '\0')
40618de8d7fSPeter Avalos 			fatal("%.200s line %d: Missing yes/no argument.", filename, linenum);
40718de8d7fSPeter Avalos 		value = 0;	/* To avoid compiler warning... */
40818de8d7fSPeter Avalos 		if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
40918de8d7fSPeter Avalos 			value = 1;
41018de8d7fSPeter Avalos 		else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
41118de8d7fSPeter Avalos 			value = 0;
41218de8d7fSPeter Avalos 		else
41318de8d7fSPeter Avalos 			fatal("%.200s line %d: Bad yes/no argument.", filename, linenum);
41418de8d7fSPeter Avalos 		if (*activep && *intptr == -1)
41518de8d7fSPeter Avalos 			*intptr = value;
41618de8d7fSPeter Avalos 		break;
41718de8d7fSPeter Avalos 
41818de8d7fSPeter Avalos 	case oForwardX11:
41918de8d7fSPeter Avalos 		intptr = &options->forward_x11;
42018de8d7fSPeter Avalos 		goto parse_flag;
42118de8d7fSPeter Avalos 
42218de8d7fSPeter Avalos 	case oForwardX11Trusted:
42318de8d7fSPeter Avalos 		intptr = &options->forward_x11_trusted;
42418de8d7fSPeter Avalos 		goto parse_flag;
42518de8d7fSPeter Avalos 
426856ea928SPeter Avalos 	case oForwardX11Timeout:
427856ea928SPeter Avalos 		intptr = &options->forward_x11_timeout;
428856ea928SPeter Avalos 		goto parse_time;
429856ea928SPeter Avalos 
43018de8d7fSPeter Avalos 	case oGatewayPorts:
43118de8d7fSPeter Avalos 		intptr = &options->gateway_ports;
43218de8d7fSPeter Avalos 		goto parse_flag;
43318de8d7fSPeter Avalos 
43418de8d7fSPeter Avalos 	case oExitOnForwardFailure:
43518de8d7fSPeter Avalos 		intptr = &options->exit_on_forward_failure;
43618de8d7fSPeter Avalos 		goto parse_flag;
43718de8d7fSPeter Avalos 
43818de8d7fSPeter Avalos 	case oUsePrivilegedPort:
43918de8d7fSPeter Avalos 		intptr = &options->use_privileged_port;
44018de8d7fSPeter Avalos 		goto parse_flag;
44118de8d7fSPeter Avalos 
44218de8d7fSPeter Avalos 	case oPasswordAuthentication:
44318de8d7fSPeter Avalos 		intptr = &options->password_authentication;
44418de8d7fSPeter Avalos 		goto parse_flag;
44518de8d7fSPeter Avalos 
446cb5eb4f1SPeter Avalos 	case oZeroKnowledgePasswordAuthentication:
447cb5eb4f1SPeter Avalos 		intptr = &options->zero_knowledge_password_authentication;
448cb5eb4f1SPeter Avalos 		goto parse_flag;
449cb5eb4f1SPeter Avalos 
45018de8d7fSPeter Avalos 	case oKbdInteractiveAuthentication:
45118de8d7fSPeter Avalos 		intptr = &options->kbd_interactive_authentication;
45218de8d7fSPeter Avalos 		goto parse_flag;
45318de8d7fSPeter Avalos 
45418de8d7fSPeter Avalos 	case oKbdInteractiveDevices:
45518de8d7fSPeter Avalos 		charptr = &options->kbd_interactive_devices;
45618de8d7fSPeter Avalos 		goto parse_string;
45718de8d7fSPeter Avalos 
45818de8d7fSPeter Avalos 	case oPubkeyAuthentication:
45918de8d7fSPeter Avalos 		intptr = &options->pubkey_authentication;
46018de8d7fSPeter Avalos 		goto parse_flag;
46118de8d7fSPeter Avalos 
46218de8d7fSPeter Avalos 	case oRSAAuthentication:
46318de8d7fSPeter Avalos 		intptr = &options->rsa_authentication;
46418de8d7fSPeter Avalos 		goto parse_flag;
46518de8d7fSPeter Avalos 
46618de8d7fSPeter Avalos 	case oRhostsRSAAuthentication:
46718de8d7fSPeter Avalos 		intptr = &options->rhosts_rsa_authentication;
46818de8d7fSPeter Avalos 		goto parse_flag;
46918de8d7fSPeter Avalos 
47018de8d7fSPeter Avalos 	case oHostbasedAuthentication:
47118de8d7fSPeter Avalos 		intptr = &options->hostbased_authentication;
47218de8d7fSPeter Avalos 		goto parse_flag;
47318de8d7fSPeter Avalos 
47418de8d7fSPeter Avalos 	case oChallengeResponseAuthentication:
47518de8d7fSPeter Avalos 		intptr = &options->challenge_response_authentication;
47618de8d7fSPeter Avalos 		goto parse_flag;
47718de8d7fSPeter Avalos 
47818de8d7fSPeter Avalos 	case oGssAuthentication:
47918de8d7fSPeter Avalos 		intptr = &options->gss_authentication;
48018de8d7fSPeter Avalos 		goto parse_flag;
48118de8d7fSPeter Avalos 
48218de8d7fSPeter Avalos 	case oGssDelegateCreds:
48318de8d7fSPeter Avalos 		intptr = &options->gss_deleg_creds;
48418de8d7fSPeter Avalos 		goto parse_flag;
48518de8d7fSPeter Avalos 
48618de8d7fSPeter Avalos 	case oBatchMode:
48718de8d7fSPeter Avalos 		intptr = &options->batch_mode;
48818de8d7fSPeter Avalos 		goto parse_flag;
48918de8d7fSPeter Avalos 
49018de8d7fSPeter Avalos 	case oCheckHostIP:
49118de8d7fSPeter Avalos 		intptr = &options->check_host_ip;
49218de8d7fSPeter Avalos 		goto parse_flag;
49318de8d7fSPeter Avalos 
49418de8d7fSPeter Avalos 	case oVerifyHostKeyDNS:
49518de8d7fSPeter Avalos 		intptr = &options->verify_host_key_dns;
49618de8d7fSPeter Avalos 		goto parse_yesnoask;
49718de8d7fSPeter Avalos 
49818de8d7fSPeter Avalos 	case oStrictHostKeyChecking:
49918de8d7fSPeter Avalos 		intptr = &options->strict_host_key_checking;
50018de8d7fSPeter Avalos parse_yesnoask:
50118de8d7fSPeter Avalos 		arg = strdelim(&s);
50218de8d7fSPeter Avalos 		if (!arg || *arg == '\0')
50318de8d7fSPeter Avalos 			fatal("%.200s line %d: Missing yes/no/ask argument.",
50418de8d7fSPeter Avalos 			    filename, linenum);
50518de8d7fSPeter Avalos 		value = 0;	/* To avoid compiler warning... */
50618de8d7fSPeter Avalos 		if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
50718de8d7fSPeter Avalos 			value = 1;
50818de8d7fSPeter Avalos 		else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
50918de8d7fSPeter Avalos 			value = 0;
51018de8d7fSPeter Avalos 		else if (strcmp(arg, "ask") == 0)
51118de8d7fSPeter Avalos 			value = 2;
51218de8d7fSPeter Avalos 		else
51318de8d7fSPeter Avalos 			fatal("%.200s line %d: Bad yes/no/ask argument.", filename, linenum);
51418de8d7fSPeter Avalos 		if (*activep && *intptr == -1)
51518de8d7fSPeter Avalos 			*intptr = value;
51618de8d7fSPeter Avalos 		break;
51718de8d7fSPeter Avalos 
51818de8d7fSPeter Avalos 	case oCompression:
51918de8d7fSPeter Avalos 		intptr = &options->compression;
52018de8d7fSPeter Avalos 		goto parse_flag;
52118de8d7fSPeter Avalos 
52218de8d7fSPeter Avalos 	case oTCPKeepAlive:
52318de8d7fSPeter Avalos 		intptr = &options->tcp_keep_alive;
52418de8d7fSPeter Avalos 		goto parse_flag;
52518de8d7fSPeter Avalos 
52618de8d7fSPeter Avalos 	case oNoHostAuthenticationForLocalhost:
52718de8d7fSPeter Avalos 		intptr = &options->no_host_authentication_for_localhost;
52818de8d7fSPeter Avalos 		goto parse_flag;
52918de8d7fSPeter Avalos 
53018de8d7fSPeter Avalos 	case oNumberOfPasswordPrompts:
53118de8d7fSPeter Avalos 		intptr = &options->number_of_password_prompts;
53218de8d7fSPeter Avalos 		goto parse_int;
53318de8d7fSPeter Avalos 
53418de8d7fSPeter Avalos 	case oCompressionLevel:
53518de8d7fSPeter Avalos 		intptr = &options->compression_level;
53618de8d7fSPeter Avalos 		goto parse_int;
53718de8d7fSPeter Avalos 
53818de8d7fSPeter Avalos 	case oRekeyLimit:
53918de8d7fSPeter Avalos 		arg = strdelim(&s);
54018de8d7fSPeter Avalos 		if (!arg || *arg == '\0')
54118de8d7fSPeter Avalos 			fatal("%.200s line %d: Missing argument.", filename, linenum);
54218de8d7fSPeter Avalos 		if (arg[0] < '0' || arg[0] > '9')
54318de8d7fSPeter Avalos 			fatal("%.200s line %d: Bad number.", filename, linenum);
54418de8d7fSPeter Avalos 		orig = val64 = strtoll(arg, &endofnumber, 10);
54518de8d7fSPeter Avalos 		if (arg == endofnumber)
54618de8d7fSPeter Avalos 			fatal("%.200s line %d: Bad number.", filename, linenum);
54718de8d7fSPeter Avalos 		switch (toupper(*endofnumber)) {
54818de8d7fSPeter Avalos 		case '\0':
54918de8d7fSPeter Avalos 			scale = 1;
55018de8d7fSPeter Avalos 			break;
55118de8d7fSPeter Avalos 		case 'K':
55218de8d7fSPeter Avalos 			scale = 1<<10;
55318de8d7fSPeter Avalos 			break;
55418de8d7fSPeter Avalos 		case 'M':
55518de8d7fSPeter Avalos 			scale = 1<<20;
55618de8d7fSPeter Avalos 			break;
55718de8d7fSPeter Avalos 		case 'G':
55818de8d7fSPeter Avalos 			scale = 1<<30;
55918de8d7fSPeter Avalos 			break;
56018de8d7fSPeter Avalos 		default:
56118de8d7fSPeter Avalos 			fatal("%.200s line %d: Invalid RekeyLimit suffix",
56218de8d7fSPeter Avalos 			    filename, linenum);
56318de8d7fSPeter Avalos 		}
56418de8d7fSPeter Avalos 		val64 *= scale;
56518de8d7fSPeter Avalos 		/* detect integer wrap and too-large limits */
56618de8d7fSPeter Avalos 		if ((val64 / scale) != orig || val64 > UINT_MAX)
56718de8d7fSPeter Avalos 			fatal("%.200s line %d: RekeyLimit too large",
56818de8d7fSPeter Avalos 			    filename, linenum);
56918de8d7fSPeter Avalos 		if (val64 < 16)
57018de8d7fSPeter Avalos 			fatal("%.200s line %d: RekeyLimit too small",
57118de8d7fSPeter Avalos 			    filename, linenum);
57218de8d7fSPeter Avalos 		if (*activep && options->rekey_limit == -1)
57318de8d7fSPeter Avalos 			options->rekey_limit = (u_int32_t)val64;
57418de8d7fSPeter Avalos 		break;
57518de8d7fSPeter Avalos 
57618de8d7fSPeter Avalos 	case oIdentityFile:
57718de8d7fSPeter Avalos 		arg = strdelim(&s);
57818de8d7fSPeter Avalos 		if (!arg || *arg == '\0')
57918de8d7fSPeter Avalos 			fatal("%.200s line %d: Missing argument.", filename, linenum);
58018de8d7fSPeter Avalos 		if (*activep) {
58118de8d7fSPeter Avalos 			intptr = &options->num_identity_files;
58218de8d7fSPeter Avalos 			if (*intptr >= SSH_MAX_IDENTITY_FILES)
58318de8d7fSPeter Avalos 				fatal("%.200s line %d: Too many identity files specified (max %d).",
58418de8d7fSPeter Avalos 				    filename, linenum, SSH_MAX_IDENTITY_FILES);
58518de8d7fSPeter Avalos 			charptr = &options->identity_files[*intptr];
58618de8d7fSPeter Avalos 			*charptr = xstrdup(arg);
58718de8d7fSPeter Avalos 			*intptr = *intptr + 1;
58818de8d7fSPeter Avalos 		}
58918de8d7fSPeter Avalos 		break;
59018de8d7fSPeter Avalos 
59118de8d7fSPeter Avalos 	case oXAuthLocation:
59218de8d7fSPeter Avalos 		charptr=&options->xauth_location;
59318de8d7fSPeter Avalos 		goto parse_string;
59418de8d7fSPeter Avalos 
59518de8d7fSPeter Avalos 	case oUser:
59618de8d7fSPeter Avalos 		charptr = &options->user;
59718de8d7fSPeter Avalos parse_string:
59818de8d7fSPeter Avalos 		arg = strdelim(&s);
59918de8d7fSPeter Avalos 		if (!arg || *arg == '\0')
60018de8d7fSPeter Avalos 			fatal("%.200s line %d: Missing argument.", filename, linenum);
60118de8d7fSPeter Avalos 		if (*activep && *charptr == NULL)
60218de8d7fSPeter Avalos 			*charptr = xstrdup(arg);
60318de8d7fSPeter Avalos 		break;
60418de8d7fSPeter Avalos 
60518de8d7fSPeter Avalos 	case oGlobalKnownHostsFile:
60618de8d7fSPeter Avalos 		charptr = &options->system_hostfile;
60718de8d7fSPeter Avalos 		goto parse_string;
60818de8d7fSPeter Avalos 
60918de8d7fSPeter Avalos 	case oUserKnownHostsFile:
61018de8d7fSPeter Avalos 		charptr = &options->user_hostfile;
61118de8d7fSPeter Avalos 		goto parse_string;
61218de8d7fSPeter Avalos 
61318de8d7fSPeter Avalos 	case oGlobalKnownHostsFile2:
61418de8d7fSPeter Avalos 		charptr = &options->system_hostfile2;
61518de8d7fSPeter Avalos 		goto parse_string;
61618de8d7fSPeter Avalos 
61718de8d7fSPeter Avalos 	case oUserKnownHostsFile2:
61818de8d7fSPeter Avalos 		charptr = &options->user_hostfile2;
61918de8d7fSPeter Avalos 		goto parse_string;
62018de8d7fSPeter Avalos 
62118de8d7fSPeter Avalos 	case oHostName:
62218de8d7fSPeter Avalos 		charptr = &options->hostname;
62318de8d7fSPeter Avalos 		goto parse_string;
62418de8d7fSPeter Avalos 
62518de8d7fSPeter Avalos 	case oHostKeyAlias:
62618de8d7fSPeter Avalos 		charptr = &options->host_key_alias;
62718de8d7fSPeter Avalos 		goto parse_string;
62818de8d7fSPeter Avalos 
62918de8d7fSPeter Avalos 	case oPreferredAuthentications:
63018de8d7fSPeter Avalos 		charptr = &options->preferred_authentications;
63118de8d7fSPeter Avalos 		goto parse_string;
63218de8d7fSPeter Avalos 
63318de8d7fSPeter Avalos 	case oBindAddress:
63418de8d7fSPeter Avalos 		charptr = &options->bind_address;
63518de8d7fSPeter Avalos 		goto parse_string;
63618de8d7fSPeter Avalos 
637856ea928SPeter Avalos 	case oPKCS11Provider:
638856ea928SPeter Avalos 		charptr = &options->pkcs11_provider;
63918de8d7fSPeter Avalos 		goto parse_string;
64018de8d7fSPeter Avalos 
64118de8d7fSPeter Avalos 	case oProxyCommand:
64218de8d7fSPeter Avalos 		charptr = &options->proxy_command;
64318de8d7fSPeter Avalos parse_command:
64418de8d7fSPeter Avalos 		if (s == NULL)
64518de8d7fSPeter Avalos 			fatal("%.200s line %d: Missing argument.", filename, linenum);
64618de8d7fSPeter Avalos 		len = strspn(s, WHITESPACE "=");
64718de8d7fSPeter Avalos 		if (*activep && *charptr == NULL)
64818de8d7fSPeter Avalos 			*charptr = xstrdup(s + len);
64918de8d7fSPeter Avalos 		return 0;
65018de8d7fSPeter Avalos 
65118de8d7fSPeter Avalos 	case oPort:
65218de8d7fSPeter Avalos 		intptr = &options->port;
65318de8d7fSPeter Avalos parse_int:
65418de8d7fSPeter Avalos 		arg = strdelim(&s);
65518de8d7fSPeter Avalos 		if (!arg || *arg == '\0')
65618de8d7fSPeter Avalos 			fatal("%.200s line %d: Missing argument.", filename, linenum);
65718de8d7fSPeter Avalos 		if (arg[0] < '0' || arg[0] > '9')
65818de8d7fSPeter Avalos 			fatal("%.200s line %d: Bad number.", filename, linenum);
65918de8d7fSPeter Avalos 
66018de8d7fSPeter Avalos 		/* Octal, decimal, or hex format? */
66118de8d7fSPeter Avalos 		value = strtol(arg, &endofnumber, 0);
66218de8d7fSPeter Avalos 		if (arg == endofnumber)
66318de8d7fSPeter Avalos 			fatal("%.200s line %d: Bad number.", filename, linenum);
66418de8d7fSPeter Avalos 		if (*activep && *intptr == -1)
66518de8d7fSPeter Avalos 			*intptr = value;
66618de8d7fSPeter Avalos 		break;
66718de8d7fSPeter Avalos 
66818de8d7fSPeter Avalos 	case oConnectionAttempts:
66918de8d7fSPeter Avalos 		intptr = &options->connection_attempts;
67018de8d7fSPeter Avalos 		goto parse_int;
67118de8d7fSPeter Avalos 
67218de8d7fSPeter Avalos 	case oCipher:
67318de8d7fSPeter Avalos 		intptr = &options->cipher;
67418de8d7fSPeter Avalos 		arg = strdelim(&s);
67518de8d7fSPeter Avalos 		if (!arg || *arg == '\0')
67618de8d7fSPeter Avalos 			fatal("%.200s line %d: Missing argument.", filename, linenum);
67718de8d7fSPeter Avalos 		value = cipher_number(arg);
67818de8d7fSPeter Avalos 		if (value == -1)
67918de8d7fSPeter Avalos 			fatal("%.200s line %d: Bad cipher '%s'.",
68018de8d7fSPeter Avalos 			    filename, linenum, arg ? arg : "<NONE>");
68118de8d7fSPeter Avalos 		if (*activep && *intptr == -1)
68218de8d7fSPeter Avalos 			*intptr = value;
68318de8d7fSPeter Avalos 		break;
68418de8d7fSPeter Avalos 
68518de8d7fSPeter Avalos 	case oCiphers:
68618de8d7fSPeter Avalos 		arg = strdelim(&s);
68718de8d7fSPeter Avalos 		if (!arg || *arg == '\0')
68818de8d7fSPeter Avalos 			fatal("%.200s line %d: Missing argument.", filename, linenum);
68918de8d7fSPeter Avalos 		if (!ciphers_valid(arg))
69018de8d7fSPeter Avalos 			fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.",
69118de8d7fSPeter Avalos 			    filename, linenum, arg ? arg : "<NONE>");
69218de8d7fSPeter Avalos 		if (*activep && options->ciphers == NULL)
69318de8d7fSPeter Avalos 			options->ciphers = xstrdup(arg);
69418de8d7fSPeter Avalos 		break;
69518de8d7fSPeter Avalos 
69618de8d7fSPeter Avalos 	case oMacs:
69718de8d7fSPeter Avalos 		arg = strdelim(&s);
69818de8d7fSPeter Avalos 		if (!arg || *arg == '\0')
69918de8d7fSPeter Avalos 			fatal("%.200s line %d: Missing argument.", filename, linenum);
70018de8d7fSPeter Avalos 		if (!mac_valid(arg))
70118de8d7fSPeter Avalos 			fatal("%.200s line %d: Bad SSH2 Mac spec '%s'.",
70218de8d7fSPeter Avalos 			    filename, linenum, arg ? arg : "<NONE>");
70318de8d7fSPeter Avalos 		if (*activep && options->macs == NULL)
70418de8d7fSPeter Avalos 			options->macs = xstrdup(arg);
70518de8d7fSPeter Avalos 		break;
70618de8d7fSPeter Avalos 
707*9f304aafSPeter Avalos 	case oKexAlgorithms:
708*9f304aafSPeter Avalos 		arg = strdelim(&s);
709*9f304aafSPeter Avalos 		if (!arg || *arg == '\0')
710*9f304aafSPeter Avalos 			fatal("%.200s line %d: Missing argument.",
711*9f304aafSPeter Avalos 			    filename, linenum);
712*9f304aafSPeter Avalos 		if (!kex_names_valid(arg))
713*9f304aafSPeter Avalos 			fatal("%.200s line %d: Bad SSH2 KexAlgorithms '%s'.",
714*9f304aafSPeter Avalos 			    filename, linenum, arg ? arg : "<NONE>");
715*9f304aafSPeter Avalos 		if (*activep && options->kex_algorithms == NULL)
716*9f304aafSPeter Avalos 			options->kex_algorithms = xstrdup(arg);
717*9f304aafSPeter Avalos 		break;
718*9f304aafSPeter Avalos 
71918de8d7fSPeter Avalos 	case oHostKeyAlgorithms:
72018de8d7fSPeter Avalos 		arg = strdelim(&s);
72118de8d7fSPeter Avalos 		if (!arg || *arg == '\0')
72218de8d7fSPeter Avalos 			fatal("%.200s line %d: Missing argument.", filename, linenum);
72318de8d7fSPeter Avalos 		if (!key_names_valid2(arg))
72418de8d7fSPeter Avalos 			fatal("%.200s line %d: Bad protocol 2 host key algorithms '%s'.",
72518de8d7fSPeter Avalos 			    filename, linenum, arg ? arg : "<NONE>");
72618de8d7fSPeter Avalos 		if (*activep && options->hostkeyalgorithms == NULL)
72718de8d7fSPeter Avalos 			options->hostkeyalgorithms = xstrdup(arg);
72818de8d7fSPeter Avalos 		break;
72918de8d7fSPeter Avalos 
73018de8d7fSPeter Avalos 	case oProtocol:
73118de8d7fSPeter Avalos 		intptr = &options->protocol;
73218de8d7fSPeter Avalos 		arg = strdelim(&s);
73318de8d7fSPeter Avalos 		if (!arg || *arg == '\0')
73418de8d7fSPeter Avalos 			fatal("%.200s line %d: Missing argument.", filename, linenum);
73518de8d7fSPeter Avalos 		value = proto_spec(arg);
73618de8d7fSPeter Avalos 		if (value == SSH_PROTO_UNKNOWN)
73718de8d7fSPeter Avalos 			fatal("%.200s line %d: Bad protocol spec '%s'.",
73818de8d7fSPeter Avalos 			    filename, linenum, arg ? arg : "<NONE>");
73918de8d7fSPeter Avalos 		if (*activep && *intptr == SSH_PROTO_UNKNOWN)
74018de8d7fSPeter Avalos 			*intptr = value;
74118de8d7fSPeter Avalos 		break;
74218de8d7fSPeter Avalos 
74318de8d7fSPeter Avalos 	case oLogLevel:
74418de8d7fSPeter Avalos 		log_level_ptr = &options->log_level;
74518de8d7fSPeter Avalos 		arg = strdelim(&s);
74618de8d7fSPeter Avalos 		value = log_level_number(arg);
74718de8d7fSPeter Avalos 		if (value == SYSLOG_LEVEL_NOT_SET)
74818de8d7fSPeter Avalos 			fatal("%.200s line %d: unsupported log level '%s'",
74918de8d7fSPeter Avalos 			    filename, linenum, arg ? arg : "<NONE>");
75018de8d7fSPeter Avalos 		if (*activep && *log_level_ptr == SYSLOG_LEVEL_NOT_SET)
75118de8d7fSPeter Avalos 			*log_level_ptr = (LogLevel) value;
75218de8d7fSPeter Avalos 		break;
75318de8d7fSPeter Avalos 
75418de8d7fSPeter Avalos 	case oLocalForward:
75518de8d7fSPeter Avalos 	case oRemoteForward:
756cb5eb4f1SPeter Avalos 	case oDynamicForward:
75718de8d7fSPeter Avalos 		arg = strdelim(&s);
75818de8d7fSPeter Avalos 		if (arg == NULL || *arg == '\0')
75918de8d7fSPeter Avalos 			fatal("%.200s line %d: Missing port argument.",
76018de8d7fSPeter Avalos 			    filename, linenum);
761cb5eb4f1SPeter Avalos 
762cb5eb4f1SPeter Avalos 		if (opcode == oLocalForward ||
763cb5eb4f1SPeter Avalos 		    opcode == oRemoteForward) {
76418de8d7fSPeter Avalos 			arg2 = strdelim(&s);
76518de8d7fSPeter Avalos 			if (arg2 == NULL || *arg2 == '\0')
76618de8d7fSPeter Avalos 				fatal("%.200s line %d: Missing target argument.",
76718de8d7fSPeter Avalos 				    filename, linenum);
76818de8d7fSPeter Avalos 
76918de8d7fSPeter Avalos 			/* construct a string for parse_forward */
77018de8d7fSPeter Avalos 			snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg, arg2);
771cb5eb4f1SPeter Avalos 		} else if (opcode == oDynamicForward) {
772cb5eb4f1SPeter Avalos 			strlcpy(fwdarg, arg, sizeof(fwdarg));
773cb5eb4f1SPeter Avalos 		}
77418de8d7fSPeter Avalos 
775cb5eb4f1SPeter Avalos 		if (parse_forward(&fwd, fwdarg,
776cb5eb4f1SPeter Avalos 		    opcode == oDynamicForward ? 1 : 0,
777cb5eb4f1SPeter Avalos 		    opcode == oRemoteForward ? 1 : 0) == 0)
77818de8d7fSPeter Avalos 			fatal("%.200s line %d: Bad forwarding specification.",
77918de8d7fSPeter Avalos 			    filename, linenum);
78018de8d7fSPeter Avalos 
78118de8d7fSPeter Avalos 		if (*activep) {
782cb5eb4f1SPeter Avalos 			if (opcode == oLocalForward ||
783cb5eb4f1SPeter Avalos 			    opcode == oDynamicForward)
78418de8d7fSPeter Avalos 				add_local_forward(options, &fwd);
78518de8d7fSPeter Avalos 			else if (opcode == oRemoteForward)
78618de8d7fSPeter Avalos 				add_remote_forward(options, &fwd);
78718de8d7fSPeter Avalos 		}
78818de8d7fSPeter Avalos 		break;
78918de8d7fSPeter Avalos 
79018de8d7fSPeter Avalos 	case oClearAllForwardings:
79118de8d7fSPeter Avalos 		intptr = &options->clear_forwardings;
79218de8d7fSPeter Avalos 		goto parse_flag;
79318de8d7fSPeter Avalos 
79418de8d7fSPeter Avalos 	case oHost:
79518de8d7fSPeter Avalos 		*activep = 0;
79618de8d7fSPeter Avalos 		while ((arg = strdelim(&s)) != NULL && *arg != '\0')
79718de8d7fSPeter Avalos 			if (match_pattern(host, arg)) {
79818de8d7fSPeter Avalos 				debug("Applying options for %.100s", arg);
79918de8d7fSPeter Avalos 				*activep = 1;
80018de8d7fSPeter Avalos 				break;
80118de8d7fSPeter Avalos 			}
80218de8d7fSPeter Avalos 		/* Avoid garbage check below, as strdelim is done. */
80318de8d7fSPeter Avalos 		return 0;
80418de8d7fSPeter Avalos 
80518de8d7fSPeter Avalos 	case oEscapeChar:
80618de8d7fSPeter Avalos 		intptr = &options->escape_char;
80718de8d7fSPeter Avalos 		arg = strdelim(&s);
80818de8d7fSPeter Avalos 		if (!arg || *arg == '\0')
80918de8d7fSPeter Avalos 			fatal("%.200s line %d: Missing argument.", filename, linenum);
81018de8d7fSPeter Avalos 		if (arg[0] == '^' && arg[2] == 0 &&
81118de8d7fSPeter Avalos 		    (u_char) arg[1] >= 64 && (u_char) arg[1] < 128)
81218de8d7fSPeter Avalos 			value = (u_char) arg[1] & 31;
81318de8d7fSPeter Avalos 		else if (strlen(arg) == 1)
81418de8d7fSPeter Avalos 			value = (u_char) arg[0];
81518de8d7fSPeter Avalos 		else if (strcmp(arg, "none") == 0)
81618de8d7fSPeter Avalos 			value = SSH_ESCAPECHAR_NONE;
81718de8d7fSPeter Avalos 		else {
81818de8d7fSPeter Avalos 			fatal("%.200s line %d: Bad escape character.",
81918de8d7fSPeter Avalos 			    filename, linenum);
82018de8d7fSPeter Avalos 			/* NOTREACHED */
82118de8d7fSPeter Avalos 			value = 0;	/* Avoid compiler warning. */
82218de8d7fSPeter Avalos 		}
82318de8d7fSPeter Avalos 		if (*activep && *intptr == -1)
82418de8d7fSPeter Avalos 			*intptr = value;
82518de8d7fSPeter Avalos 		break;
82618de8d7fSPeter Avalos 
82718de8d7fSPeter Avalos 	case oAddressFamily:
82818de8d7fSPeter Avalos 		arg = strdelim(&s);
82918de8d7fSPeter Avalos 		if (!arg || *arg == '\0')
83018de8d7fSPeter Avalos 			fatal("%s line %d: missing address family.",
83118de8d7fSPeter Avalos 			    filename, linenum);
83218de8d7fSPeter Avalos 		intptr = &options->address_family;
83318de8d7fSPeter Avalos 		if (strcasecmp(arg, "inet") == 0)
83418de8d7fSPeter Avalos 			value = AF_INET;
83518de8d7fSPeter Avalos 		else if (strcasecmp(arg, "inet6") == 0)
83618de8d7fSPeter Avalos 			value = AF_INET6;
83718de8d7fSPeter Avalos 		else if (strcasecmp(arg, "any") == 0)
83818de8d7fSPeter Avalos 			value = AF_UNSPEC;
83918de8d7fSPeter Avalos 		else
84018de8d7fSPeter Avalos 			fatal("Unsupported AddressFamily \"%s\"", arg);
84118de8d7fSPeter Avalos 		if (*activep && *intptr == -1)
84218de8d7fSPeter Avalos 			*intptr = value;
84318de8d7fSPeter Avalos 		break;
84418de8d7fSPeter Avalos 
84518de8d7fSPeter Avalos 	case oEnableSSHKeysign:
84618de8d7fSPeter Avalos 		intptr = &options->enable_ssh_keysign;
84718de8d7fSPeter Avalos 		goto parse_flag;
84818de8d7fSPeter Avalos 
84918de8d7fSPeter Avalos 	case oIdentitiesOnly:
85018de8d7fSPeter Avalos 		intptr = &options->identities_only;
85118de8d7fSPeter Avalos 		goto parse_flag;
85218de8d7fSPeter Avalos 
85318de8d7fSPeter Avalos 	case oServerAliveInterval:
85418de8d7fSPeter Avalos 		intptr = &options->server_alive_interval;
85518de8d7fSPeter Avalos 		goto parse_time;
85618de8d7fSPeter Avalos 
85718de8d7fSPeter Avalos 	case oServerAliveCountMax:
85818de8d7fSPeter Avalos 		intptr = &options->server_alive_count_max;
85918de8d7fSPeter Avalos 		goto parse_int;
86018de8d7fSPeter Avalos 
86118de8d7fSPeter Avalos 	case oSendEnv:
86218de8d7fSPeter Avalos 		while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
86318de8d7fSPeter Avalos 			if (strchr(arg, '=') != NULL)
86418de8d7fSPeter Avalos 				fatal("%s line %d: Invalid environment name.",
86518de8d7fSPeter Avalos 				    filename, linenum);
86618de8d7fSPeter Avalos 			if (!*activep)
86718de8d7fSPeter Avalos 				continue;
86818de8d7fSPeter Avalos 			if (options->num_send_env >= MAX_SEND_ENV)
86918de8d7fSPeter Avalos 				fatal("%s line %d: too many send env.",
87018de8d7fSPeter Avalos 				    filename, linenum);
87118de8d7fSPeter Avalos 			options->send_env[options->num_send_env++] =
87218de8d7fSPeter Avalos 			    xstrdup(arg);
87318de8d7fSPeter Avalos 		}
87418de8d7fSPeter Avalos 		break;
87518de8d7fSPeter Avalos 
87618de8d7fSPeter Avalos 	case oControlPath:
87718de8d7fSPeter Avalos 		charptr = &options->control_path;
87818de8d7fSPeter Avalos 		goto parse_string;
87918de8d7fSPeter Avalos 
88018de8d7fSPeter Avalos 	case oControlMaster:
88118de8d7fSPeter Avalos 		intptr = &options->control_master;
88218de8d7fSPeter Avalos 		arg = strdelim(&s);
88318de8d7fSPeter Avalos 		if (!arg || *arg == '\0')
88418de8d7fSPeter Avalos 			fatal("%.200s line %d: Missing ControlMaster argument.",
88518de8d7fSPeter Avalos 			    filename, linenum);
88618de8d7fSPeter Avalos 		value = 0;	/* To avoid compiler warning... */
88718de8d7fSPeter Avalos 		if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
88818de8d7fSPeter Avalos 			value = SSHCTL_MASTER_YES;
88918de8d7fSPeter Avalos 		else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
89018de8d7fSPeter Avalos 			value = SSHCTL_MASTER_NO;
89118de8d7fSPeter Avalos 		else if (strcmp(arg, "auto") == 0)
89218de8d7fSPeter Avalos 			value = SSHCTL_MASTER_AUTO;
89318de8d7fSPeter Avalos 		else if (strcmp(arg, "ask") == 0)
89418de8d7fSPeter Avalos 			value = SSHCTL_MASTER_ASK;
89518de8d7fSPeter Avalos 		else if (strcmp(arg, "autoask") == 0)
89618de8d7fSPeter Avalos 			value = SSHCTL_MASTER_AUTO_ASK;
89718de8d7fSPeter Avalos 		else
89818de8d7fSPeter Avalos 			fatal("%.200s line %d: Bad ControlMaster argument.",
89918de8d7fSPeter Avalos 			    filename, linenum);
90018de8d7fSPeter Avalos 		if (*activep && *intptr == -1)
90118de8d7fSPeter Avalos 			*intptr = value;
90218de8d7fSPeter Avalos 		break;
90318de8d7fSPeter Avalos 
904856ea928SPeter Avalos 	case oControlPersist:
905856ea928SPeter Avalos 		/* no/false/yes/true, or a time spec */
906856ea928SPeter Avalos 		intptr = &options->control_persist;
907856ea928SPeter Avalos 		arg = strdelim(&s);
908856ea928SPeter Avalos 		if (!arg || *arg == '\0')
909856ea928SPeter Avalos 			fatal("%.200s line %d: Missing ControlPersist"
910856ea928SPeter Avalos 			    " argument.", filename, linenum);
911856ea928SPeter Avalos 		value = 0;
912856ea928SPeter Avalos 		value2 = 0;	/* timeout */
913856ea928SPeter Avalos 		if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
914856ea928SPeter Avalos 			value = 0;
915856ea928SPeter Avalos 		else if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
916856ea928SPeter Avalos 			value = 1;
917856ea928SPeter Avalos 		else if ((value2 = convtime(arg)) >= 0)
918856ea928SPeter Avalos 			value = 1;
919856ea928SPeter Avalos 		else
920856ea928SPeter Avalos 			fatal("%.200s line %d: Bad ControlPersist argument.",
921856ea928SPeter Avalos 			    filename, linenum);
922856ea928SPeter Avalos 		if (*activep && *intptr == -1) {
923856ea928SPeter Avalos 			*intptr = value;
924856ea928SPeter Avalos 			options->control_persist_timeout = value2;
925856ea928SPeter Avalos 		}
926856ea928SPeter Avalos 		break;
927856ea928SPeter Avalos 
92818de8d7fSPeter Avalos 	case oHashKnownHosts:
92918de8d7fSPeter Avalos 		intptr = &options->hash_known_hosts;
93018de8d7fSPeter Avalos 		goto parse_flag;
93118de8d7fSPeter Avalos 
93218de8d7fSPeter Avalos 	case oTunnel:
93318de8d7fSPeter Avalos 		intptr = &options->tun_open;
93418de8d7fSPeter Avalos 		arg = strdelim(&s);
93518de8d7fSPeter Avalos 		if (!arg || *arg == '\0')
93618de8d7fSPeter Avalos 			fatal("%s line %d: Missing yes/point-to-point/"
93718de8d7fSPeter Avalos 			    "ethernet/no argument.", filename, linenum);
93818de8d7fSPeter Avalos 		value = 0;	/* silence compiler */
93918de8d7fSPeter Avalos 		if (strcasecmp(arg, "ethernet") == 0)
94018de8d7fSPeter Avalos 			value = SSH_TUNMODE_ETHERNET;
94118de8d7fSPeter Avalos 		else if (strcasecmp(arg, "point-to-point") == 0)
94218de8d7fSPeter Avalos 			value = SSH_TUNMODE_POINTOPOINT;
94318de8d7fSPeter Avalos 		else if (strcasecmp(arg, "yes") == 0)
94418de8d7fSPeter Avalos 			value = SSH_TUNMODE_DEFAULT;
94518de8d7fSPeter Avalos 		else if (strcasecmp(arg, "no") == 0)
94618de8d7fSPeter Avalos 			value = SSH_TUNMODE_NO;
94718de8d7fSPeter Avalos 		else
94818de8d7fSPeter Avalos 			fatal("%s line %d: Bad yes/point-to-point/ethernet/"
94918de8d7fSPeter Avalos 			    "no argument: %s", filename, linenum, arg);
95018de8d7fSPeter Avalos 		if (*activep)
95118de8d7fSPeter Avalos 			*intptr = value;
95218de8d7fSPeter Avalos 		break;
95318de8d7fSPeter Avalos 
95418de8d7fSPeter Avalos 	case oTunnelDevice:
95518de8d7fSPeter Avalos 		arg = strdelim(&s);
95618de8d7fSPeter Avalos 		if (!arg || *arg == '\0')
95718de8d7fSPeter Avalos 			fatal("%.200s line %d: Missing argument.", filename, linenum);
95818de8d7fSPeter Avalos 		value = a2tun(arg, &value2);
95918de8d7fSPeter Avalos 		if (value == SSH_TUNID_ERR)
96018de8d7fSPeter Avalos 			fatal("%.200s line %d: Bad tun device.", filename, linenum);
96118de8d7fSPeter Avalos 		if (*activep) {
96218de8d7fSPeter Avalos 			options->tun_local = value;
96318de8d7fSPeter Avalos 			options->tun_remote = value2;
96418de8d7fSPeter Avalos 		}
96518de8d7fSPeter Avalos 		break;
96618de8d7fSPeter Avalos 
96718de8d7fSPeter Avalos 	case oLocalCommand:
96818de8d7fSPeter Avalos 		charptr = &options->local_command;
96918de8d7fSPeter Avalos 		goto parse_command;
97018de8d7fSPeter Avalos 
97118de8d7fSPeter Avalos 	case oPermitLocalCommand:
97218de8d7fSPeter Avalos 		intptr = &options->permit_local_command;
97318de8d7fSPeter Avalos 		goto parse_flag;
97418de8d7fSPeter Avalos 
97518de8d7fSPeter Avalos 	case oVisualHostKey:
97618de8d7fSPeter Avalos 		intptr = &options->visual_host_key;
97718de8d7fSPeter Avalos 		goto parse_flag;
97818de8d7fSPeter Avalos 
979*9f304aafSPeter Avalos 	case oIPQoS:
980*9f304aafSPeter Avalos 		arg = strdelim(&s);
981*9f304aafSPeter Avalos 		if ((value = parse_ipqos(arg)) == -1)
982*9f304aafSPeter Avalos 			fatal("%s line %d: Bad IPQoS value: %s",
983*9f304aafSPeter Avalos 			    filename, linenum, arg);
984*9f304aafSPeter Avalos 		arg = strdelim(&s);
985*9f304aafSPeter Avalos 		if (arg == NULL)
986*9f304aafSPeter Avalos 			value2 = value;
987*9f304aafSPeter Avalos 		else if ((value2 = parse_ipqos(arg)) == -1)
988*9f304aafSPeter Avalos 			fatal("%s line %d: Bad IPQoS value: %s",
989*9f304aafSPeter Avalos 			    filename, linenum, arg);
990*9f304aafSPeter Avalos 		if (*activep) {
991*9f304aafSPeter Avalos 			options->ip_qos_interactive = value;
992*9f304aafSPeter Avalos 			options->ip_qos_bulk = value2;
993*9f304aafSPeter Avalos 		}
994*9f304aafSPeter Avalos 		break;
995*9f304aafSPeter Avalos 
99640c002afSPeter Avalos 	case oUseRoaming:
99740c002afSPeter Avalos 		intptr = &options->use_roaming;
99840c002afSPeter Avalos 		goto parse_flag;
99940c002afSPeter Avalos 
100018de8d7fSPeter Avalos 	case oDeprecated:
100118de8d7fSPeter Avalos 		debug("%s line %d: Deprecated option \"%s\"",
100218de8d7fSPeter Avalos 		    filename, linenum, keyword);
100318de8d7fSPeter Avalos 		return 0;
100418de8d7fSPeter Avalos 
100518de8d7fSPeter Avalos 	case oUnsupported:
100618de8d7fSPeter Avalos 		error("%s line %d: Unsupported option \"%s\"",
100718de8d7fSPeter Avalos 		    filename, linenum, keyword);
100818de8d7fSPeter Avalos 		return 0;
100918de8d7fSPeter Avalos 
101018de8d7fSPeter Avalos 	default:
101118de8d7fSPeter Avalos 		fatal("process_config_line: Unimplemented opcode %d", opcode);
101218de8d7fSPeter Avalos 	}
101318de8d7fSPeter Avalos 
101418de8d7fSPeter Avalos 	/* Check that there is no garbage at end of line. */
101518de8d7fSPeter Avalos 	if ((arg = strdelim(&s)) != NULL && *arg != '\0') {
101618de8d7fSPeter Avalos 		fatal("%.200s line %d: garbage at end of line; \"%.200s\".",
101718de8d7fSPeter Avalos 		    filename, linenum, arg);
101818de8d7fSPeter Avalos 	}
101918de8d7fSPeter Avalos 	return 0;
102018de8d7fSPeter Avalos }
102118de8d7fSPeter Avalos 
102218de8d7fSPeter Avalos 
102318de8d7fSPeter Avalos /*
102418de8d7fSPeter Avalos  * Reads the config file and modifies the options accordingly.  Options
102518de8d7fSPeter Avalos  * should already be initialized before this call.  This never returns if
102618de8d7fSPeter Avalos  * there is an error.  If the file does not exist, this returns 0.
102718de8d7fSPeter Avalos  */
102818de8d7fSPeter Avalos 
102918de8d7fSPeter Avalos int
103018de8d7fSPeter Avalos read_config_file(const char *filename, const char *host, Options *options,
103118de8d7fSPeter Avalos     int checkperm)
103218de8d7fSPeter Avalos {
103318de8d7fSPeter Avalos 	FILE *f;
103418de8d7fSPeter Avalos 	char line[1024];
103518de8d7fSPeter Avalos 	int active, linenum;
103618de8d7fSPeter Avalos 	int bad_options = 0;
103718de8d7fSPeter Avalos 
103818de8d7fSPeter Avalos 	if ((f = fopen(filename, "r")) == NULL)
103918de8d7fSPeter Avalos 		return 0;
104018de8d7fSPeter Avalos 
104118de8d7fSPeter Avalos 	if (checkperm) {
104218de8d7fSPeter Avalos 		struct stat sb;
104318de8d7fSPeter Avalos 
104418de8d7fSPeter Avalos 		if (fstat(fileno(f), &sb) == -1)
104518de8d7fSPeter Avalos 			fatal("fstat %s: %s", filename, strerror(errno));
104618de8d7fSPeter Avalos 		if (((sb.st_uid != 0 && sb.st_uid != getuid()) ||
104718de8d7fSPeter Avalos 		    (sb.st_mode & 022) != 0))
104818de8d7fSPeter Avalos 			fatal("Bad owner or permissions on %s", filename);
104918de8d7fSPeter Avalos 	}
105018de8d7fSPeter Avalos 
105118de8d7fSPeter Avalos 	debug("Reading configuration data %.200s", filename);
105218de8d7fSPeter Avalos 
105318de8d7fSPeter Avalos 	/*
105418de8d7fSPeter Avalos 	 * Mark that we are now processing the options.  This flag is turned
105518de8d7fSPeter Avalos 	 * on/off by Host specifications.
105618de8d7fSPeter Avalos 	 */
105718de8d7fSPeter Avalos 	active = 1;
105818de8d7fSPeter Avalos 	linenum = 0;
105918de8d7fSPeter Avalos 	while (fgets(line, sizeof(line), f)) {
106018de8d7fSPeter Avalos 		/* Update line number counter. */
106118de8d7fSPeter Avalos 		linenum++;
106218de8d7fSPeter Avalos 		if (process_config_line(options, host, line, filename, linenum, &active) != 0)
106318de8d7fSPeter Avalos 			bad_options++;
106418de8d7fSPeter Avalos 	}
106518de8d7fSPeter Avalos 	fclose(f);
106618de8d7fSPeter Avalos 	if (bad_options > 0)
106718de8d7fSPeter Avalos 		fatal("%s: terminating, %d bad configuration options",
106818de8d7fSPeter Avalos 		    filename, bad_options);
106918de8d7fSPeter Avalos 	return 1;
107018de8d7fSPeter Avalos }
107118de8d7fSPeter Avalos 
107218de8d7fSPeter Avalos /*
107318de8d7fSPeter Avalos  * Initializes options to special values that indicate that they have not yet
107418de8d7fSPeter Avalos  * been set.  Read_config_file will only set options with this value. Options
107518de8d7fSPeter Avalos  * are processed in the following order: command line, user config file,
107618de8d7fSPeter Avalos  * system config file.  Last, fill_default_options is called.
107718de8d7fSPeter Avalos  */
107818de8d7fSPeter Avalos 
107918de8d7fSPeter Avalos void
108018de8d7fSPeter Avalos initialize_options(Options * options)
108118de8d7fSPeter Avalos {
108218de8d7fSPeter Avalos 	memset(options, 'X', sizeof(*options));
108318de8d7fSPeter Avalos 	options->forward_agent = -1;
108418de8d7fSPeter Avalos 	options->forward_x11 = -1;
108518de8d7fSPeter Avalos 	options->forward_x11_trusted = -1;
1086856ea928SPeter Avalos 	options->forward_x11_timeout = -1;
108718de8d7fSPeter Avalos 	options->exit_on_forward_failure = -1;
108818de8d7fSPeter Avalos 	options->xauth_location = NULL;
108918de8d7fSPeter Avalos 	options->gateway_ports = -1;
109018de8d7fSPeter Avalos 	options->use_privileged_port = -1;
109118de8d7fSPeter Avalos 	options->rsa_authentication = -1;
109218de8d7fSPeter Avalos 	options->pubkey_authentication = -1;
109318de8d7fSPeter Avalos 	options->challenge_response_authentication = -1;
109418de8d7fSPeter Avalos 	options->gss_authentication = -1;
109518de8d7fSPeter Avalos 	options->gss_deleg_creds = -1;
109618de8d7fSPeter Avalos 	options->password_authentication = -1;
109718de8d7fSPeter Avalos 	options->kbd_interactive_authentication = -1;
109818de8d7fSPeter Avalos 	options->kbd_interactive_devices = NULL;
109918de8d7fSPeter Avalos 	options->rhosts_rsa_authentication = -1;
110018de8d7fSPeter Avalos 	options->hostbased_authentication = -1;
110118de8d7fSPeter Avalos 	options->batch_mode = -1;
110218de8d7fSPeter Avalos 	options->check_host_ip = -1;
110318de8d7fSPeter Avalos 	options->strict_host_key_checking = -1;
110418de8d7fSPeter Avalos 	options->compression = -1;
110518de8d7fSPeter Avalos 	options->tcp_keep_alive = -1;
110618de8d7fSPeter Avalos 	options->compression_level = -1;
110718de8d7fSPeter Avalos 	options->port = -1;
110818de8d7fSPeter Avalos 	options->address_family = -1;
110918de8d7fSPeter Avalos 	options->connection_attempts = -1;
111018de8d7fSPeter Avalos 	options->connection_timeout = -1;
111118de8d7fSPeter Avalos 	options->number_of_password_prompts = -1;
111218de8d7fSPeter Avalos 	options->cipher = -1;
111318de8d7fSPeter Avalos 	options->ciphers = NULL;
111418de8d7fSPeter Avalos 	options->macs = NULL;
1115*9f304aafSPeter Avalos 	options->kex_algorithms = NULL;
111618de8d7fSPeter Avalos 	options->hostkeyalgorithms = NULL;
111718de8d7fSPeter Avalos 	options->protocol = SSH_PROTO_UNKNOWN;
111818de8d7fSPeter Avalos 	options->num_identity_files = 0;
111918de8d7fSPeter Avalos 	options->hostname = NULL;
112018de8d7fSPeter Avalos 	options->host_key_alias = NULL;
112118de8d7fSPeter Avalos 	options->proxy_command = NULL;
112218de8d7fSPeter Avalos 	options->user = NULL;
112318de8d7fSPeter Avalos 	options->escape_char = -1;
112418de8d7fSPeter Avalos 	options->system_hostfile = NULL;
112518de8d7fSPeter Avalos 	options->user_hostfile = NULL;
112618de8d7fSPeter Avalos 	options->system_hostfile2 = NULL;
112718de8d7fSPeter Avalos 	options->user_hostfile2 = NULL;
1128856ea928SPeter Avalos 	options->local_forwards = NULL;
112918de8d7fSPeter Avalos 	options->num_local_forwards = 0;
1130856ea928SPeter Avalos 	options->remote_forwards = NULL;
113118de8d7fSPeter Avalos 	options->num_remote_forwards = 0;
113218de8d7fSPeter Avalos 	options->clear_forwardings = -1;
113318de8d7fSPeter Avalos 	options->log_level = SYSLOG_LEVEL_NOT_SET;
113418de8d7fSPeter Avalos 	options->preferred_authentications = NULL;
113518de8d7fSPeter Avalos 	options->bind_address = NULL;
1136856ea928SPeter Avalos 	options->pkcs11_provider = NULL;
113718de8d7fSPeter Avalos 	options->enable_ssh_keysign = - 1;
113818de8d7fSPeter Avalos 	options->no_host_authentication_for_localhost = - 1;
113918de8d7fSPeter Avalos 	options->identities_only = - 1;
114018de8d7fSPeter Avalos 	options->rekey_limit = - 1;
114118de8d7fSPeter Avalos 	options->verify_host_key_dns = -1;
114218de8d7fSPeter Avalos 	options->server_alive_interval = -1;
114318de8d7fSPeter Avalos 	options->server_alive_count_max = -1;
114418de8d7fSPeter Avalos 	options->num_send_env = 0;
114518de8d7fSPeter Avalos 	options->control_path = NULL;
114618de8d7fSPeter Avalos 	options->control_master = -1;
1147856ea928SPeter Avalos 	options->control_persist = -1;
1148856ea928SPeter Avalos 	options->control_persist_timeout = 0;
114918de8d7fSPeter Avalos 	options->hash_known_hosts = -1;
115018de8d7fSPeter Avalos 	options->tun_open = -1;
115118de8d7fSPeter Avalos 	options->tun_local = -1;
115218de8d7fSPeter Avalos 	options->tun_remote = -1;
115318de8d7fSPeter Avalos 	options->local_command = NULL;
115418de8d7fSPeter Avalos 	options->permit_local_command = -1;
115540c002afSPeter Avalos 	options->use_roaming = -1;
115618de8d7fSPeter Avalos 	options->visual_host_key = -1;
1157cb5eb4f1SPeter Avalos 	options->zero_knowledge_password_authentication = -1;
1158*9f304aafSPeter Avalos 	options->ip_qos_interactive = -1;
1159*9f304aafSPeter Avalos 	options->ip_qos_bulk = -1;
116018de8d7fSPeter Avalos }
116118de8d7fSPeter Avalos 
116218de8d7fSPeter Avalos /*
116318de8d7fSPeter Avalos  * Called after processing other sources of option data, this fills those
116418de8d7fSPeter Avalos  * options for which no value has been specified with their default values.
116518de8d7fSPeter Avalos  */
116618de8d7fSPeter Avalos 
116718de8d7fSPeter Avalos void
116818de8d7fSPeter Avalos fill_default_options(Options * options)
116918de8d7fSPeter Avalos {
117018de8d7fSPeter Avalos 	int len;
117118de8d7fSPeter Avalos 
117218de8d7fSPeter Avalos 	if (options->forward_agent == -1)
117318de8d7fSPeter Avalos 		options->forward_agent = 0;
117418de8d7fSPeter Avalos 	if (options->forward_x11 == -1)
117518de8d7fSPeter Avalos 		options->forward_x11 = 0;
117618de8d7fSPeter Avalos 	if (options->forward_x11_trusted == -1)
117718de8d7fSPeter Avalos 		options->forward_x11_trusted = 0;
1178856ea928SPeter Avalos 	if (options->forward_x11_timeout == -1)
1179856ea928SPeter Avalos 		options->forward_x11_timeout = 1200;
118018de8d7fSPeter Avalos 	if (options->exit_on_forward_failure == -1)
118118de8d7fSPeter Avalos 		options->exit_on_forward_failure = 0;
118218de8d7fSPeter Avalos 	if (options->xauth_location == NULL)
118318de8d7fSPeter Avalos 		options->xauth_location = _PATH_XAUTH;
118418de8d7fSPeter Avalos 	if (options->gateway_ports == -1)
118518de8d7fSPeter Avalos 		options->gateway_ports = 0;
118618de8d7fSPeter Avalos 	if (options->use_privileged_port == -1)
118718de8d7fSPeter Avalos 		options->use_privileged_port = 0;
118818de8d7fSPeter Avalos 	if (options->rsa_authentication == -1)
118918de8d7fSPeter Avalos 		options->rsa_authentication = 1;
119018de8d7fSPeter Avalos 	if (options->pubkey_authentication == -1)
119118de8d7fSPeter Avalos 		options->pubkey_authentication = 1;
119218de8d7fSPeter Avalos 	if (options->challenge_response_authentication == -1)
119318de8d7fSPeter Avalos 		options->challenge_response_authentication = 1;
119418de8d7fSPeter Avalos 	if (options->gss_authentication == -1)
119518de8d7fSPeter Avalos 		options->gss_authentication = 0;
119618de8d7fSPeter Avalos 	if (options->gss_deleg_creds == -1)
119718de8d7fSPeter Avalos 		options->gss_deleg_creds = 0;
119818de8d7fSPeter Avalos 	if (options->password_authentication == -1)
119918de8d7fSPeter Avalos 		options->password_authentication = 1;
120018de8d7fSPeter Avalos 	if (options->kbd_interactive_authentication == -1)
120118de8d7fSPeter Avalos 		options->kbd_interactive_authentication = 1;
120218de8d7fSPeter Avalos 	if (options->rhosts_rsa_authentication == -1)
120318de8d7fSPeter Avalos 		options->rhosts_rsa_authentication = 0;
120418de8d7fSPeter Avalos 	if (options->hostbased_authentication == -1)
120518de8d7fSPeter Avalos 		options->hostbased_authentication = 0;
120618de8d7fSPeter Avalos 	if (options->batch_mode == -1)
120718de8d7fSPeter Avalos 		options->batch_mode = 0;
120818de8d7fSPeter Avalos 	if (options->check_host_ip == -1)
120918de8d7fSPeter Avalos 		options->check_host_ip = 1;
121018de8d7fSPeter Avalos 	if (options->strict_host_key_checking == -1)
121118de8d7fSPeter Avalos 		options->strict_host_key_checking = 2;	/* 2 is default */
121218de8d7fSPeter Avalos 	if (options->compression == -1)
121318de8d7fSPeter Avalos 		options->compression = 0;
121418de8d7fSPeter Avalos 	if (options->tcp_keep_alive == -1)
121518de8d7fSPeter Avalos 		options->tcp_keep_alive = 1;
121618de8d7fSPeter Avalos 	if (options->compression_level == -1)
121718de8d7fSPeter Avalos 		options->compression_level = 6;
121818de8d7fSPeter Avalos 	if (options->port == -1)
121918de8d7fSPeter Avalos 		options->port = 0;	/* Filled in ssh_connect. */
122018de8d7fSPeter Avalos 	if (options->address_family == -1)
122118de8d7fSPeter Avalos 		options->address_family = AF_UNSPEC;
122218de8d7fSPeter Avalos 	if (options->connection_attempts == -1)
122318de8d7fSPeter Avalos 		options->connection_attempts = 1;
122418de8d7fSPeter Avalos 	if (options->number_of_password_prompts == -1)
122518de8d7fSPeter Avalos 		options->number_of_password_prompts = 3;
122618de8d7fSPeter Avalos 	/* Selected in ssh_login(). */
122718de8d7fSPeter Avalos 	if (options->cipher == -1)
122818de8d7fSPeter Avalos 		options->cipher = SSH_CIPHER_NOT_SET;
122918de8d7fSPeter Avalos 	/* options->ciphers, default set in myproposals.h */
123018de8d7fSPeter Avalos 	/* options->macs, default set in myproposals.h */
1231*9f304aafSPeter Avalos 	/* options->kex_algorithms, default set in myproposals.h */
123218de8d7fSPeter Avalos 	/* options->hostkeyalgorithms, default set in myproposals.h */
123318de8d7fSPeter Avalos 	if (options->protocol == SSH_PROTO_UNKNOWN)
1234856ea928SPeter Avalos 		options->protocol = SSH_PROTO_2;
123518de8d7fSPeter Avalos 	if (options->num_identity_files == 0) {
123618de8d7fSPeter Avalos 		if (options->protocol & SSH_PROTO_1) {
123718de8d7fSPeter Avalos 			len = 2 + strlen(_PATH_SSH_CLIENT_IDENTITY) + 1;
123818de8d7fSPeter Avalos 			options->identity_files[options->num_identity_files] =
123918de8d7fSPeter Avalos 			    xmalloc(len);
124018de8d7fSPeter Avalos 			snprintf(options->identity_files[options->num_identity_files++],
124118de8d7fSPeter Avalos 			    len, "~/%.100s", _PATH_SSH_CLIENT_IDENTITY);
124218de8d7fSPeter Avalos 		}
124318de8d7fSPeter Avalos 		if (options->protocol & SSH_PROTO_2) {
124418de8d7fSPeter Avalos 			len = 2 + strlen(_PATH_SSH_CLIENT_ID_RSA) + 1;
124518de8d7fSPeter Avalos 			options->identity_files[options->num_identity_files] =
124618de8d7fSPeter Avalos 			    xmalloc(len);
124718de8d7fSPeter Avalos 			snprintf(options->identity_files[options->num_identity_files++],
124818de8d7fSPeter Avalos 			    len, "~/%.100s", _PATH_SSH_CLIENT_ID_RSA);
124918de8d7fSPeter Avalos 
125018de8d7fSPeter Avalos 			len = 2 + strlen(_PATH_SSH_CLIENT_ID_DSA) + 1;
125118de8d7fSPeter Avalos 			options->identity_files[options->num_identity_files] =
125218de8d7fSPeter Avalos 			    xmalloc(len);
125318de8d7fSPeter Avalos 			snprintf(options->identity_files[options->num_identity_files++],
125418de8d7fSPeter Avalos 			    len, "~/%.100s", _PATH_SSH_CLIENT_ID_DSA);
1255*9f304aafSPeter Avalos #ifdef OPENSSL_HAS_ECC
1256*9f304aafSPeter Avalos 			len = 2 + strlen(_PATH_SSH_CLIENT_ID_ECDSA) + 1;
1257*9f304aafSPeter Avalos 			options->identity_files[options->num_identity_files] =
1258*9f304aafSPeter Avalos 			    xmalloc(len);
1259*9f304aafSPeter Avalos 			snprintf(options->identity_files[options->num_identity_files++],
1260*9f304aafSPeter Avalos 			    len, "~/%.100s", _PATH_SSH_CLIENT_ID_ECDSA);
1261*9f304aafSPeter Avalos #endif
126218de8d7fSPeter Avalos 		}
126318de8d7fSPeter Avalos 	}
126418de8d7fSPeter Avalos 	if (options->escape_char == -1)
126518de8d7fSPeter Avalos 		options->escape_char = '~';
126618de8d7fSPeter Avalos 	if (options->system_hostfile == NULL)
126718de8d7fSPeter Avalos 		options->system_hostfile = _PATH_SSH_SYSTEM_HOSTFILE;
126818de8d7fSPeter Avalos 	if (options->user_hostfile == NULL)
126918de8d7fSPeter Avalos 		options->user_hostfile = _PATH_SSH_USER_HOSTFILE;
127018de8d7fSPeter Avalos 	if (options->system_hostfile2 == NULL)
127118de8d7fSPeter Avalos 		options->system_hostfile2 = _PATH_SSH_SYSTEM_HOSTFILE2;
127218de8d7fSPeter Avalos 	if (options->user_hostfile2 == NULL)
127318de8d7fSPeter Avalos 		options->user_hostfile2 = _PATH_SSH_USER_HOSTFILE2;
127418de8d7fSPeter Avalos 	if (options->log_level == SYSLOG_LEVEL_NOT_SET)
127518de8d7fSPeter Avalos 		options->log_level = SYSLOG_LEVEL_INFO;
127618de8d7fSPeter Avalos 	if (options->clear_forwardings == 1)
127718de8d7fSPeter Avalos 		clear_forwardings(options);
127818de8d7fSPeter Avalos 	if (options->no_host_authentication_for_localhost == - 1)
127918de8d7fSPeter Avalos 		options->no_host_authentication_for_localhost = 0;
128018de8d7fSPeter Avalos 	if (options->identities_only == -1)
128118de8d7fSPeter Avalos 		options->identities_only = 0;
128218de8d7fSPeter Avalos 	if (options->enable_ssh_keysign == -1)
128318de8d7fSPeter Avalos 		options->enable_ssh_keysign = 0;
128418de8d7fSPeter Avalos 	if (options->rekey_limit == -1)
128518de8d7fSPeter Avalos 		options->rekey_limit = 0;
128618de8d7fSPeter Avalos 	if (options->verify_host_key_dns == -1)
128718de8d7fSPeter Avalos 		options->verify_host_key_dns = 0;
128818de8d7fSPeter Avalos 	if (options->server_alive_interval == -1)
128918de8d7fSPeter Avalos 		options->server_alive_interval = 0;
129018de8d7fSPeter Avalos 	if (options->server_alive_count_max == -1)
129118de8d7fSPeter Avalos 		options->server_alive_count_max = 3;
129218de8d7fSPeter Avalos 	if (options->control_master == -1)
129318de8d7fSPeter Avalos 		options->control_master = 0;
1294856ea928SPeter Avalos 	if (options->control_persist == -1) {
1295856ea928SPeter Avalos 		options->control_persist = 0;
1296856ea928SPeter Avalos 		options->control_persist_timeout = 0;
1297856ea928SPeter Avalos 	}
129818de8d7fSPeter Avalos 	if (options->hash_known_hosts == -1)
129918de8d7fSPeter Avalos 		options->hash_known_hosts = 0;
130018de8d7fSPeter Avalos 	if (options->tun_open == -1)
130118de8d7fSPeter Avalos 		options->tun_open = SSH_TUNMODE_NO;
130218de8d7fSPeter Avalos 	if (options->tun_local == -1)
130318de8d7fSPeter Avalos 		options->tun_local = SSH_TUNID_ANY;
130418de8d7fSPeter Avalos 	if (options->tun_remote == -1)
130518de8d7fSPeter Avalos 		options->tun_remote = SSH_TUNID_ANY;
130618de8d7fSPeter Avalos 	if (options->permit_local_command == -1)
130718de8d7fSPeter Avalos 		options->permit_local_command = 0;
130840c002afSPeter Avalos 	if (options->use_roaming == -1)
130940c002afSPeter Avalos 		options->use_roaming = 1;
131018de8d7fSPeter Avalos 	if (options->visual_host_key == -1)
131118de8d7fSPeter Avalos 		options->visual_host_key = 0;
1312cb5eb4f1SPeter Avalos 	if (options->zero_knowledge_password_authentication == -1)
1313cb5eb4f1SPeter Avalos 		options->zero_knowledge_password_authentication = 0;
1314*9f304aafSPeter Avalos 	if (options->ip_qos_interactive == -1)
1315*9f304aafSPeter Avalos 		options->ip_qos_interactive = IPTOS_LOWDELAY;
1316*9f304aafSPeter Avalos 	if (options->ip_qos_bulk == -1)
1317*9f304aafSPeter Avalos 		options->ip_qos_bulk = IPTOS_THROUGHPUT;
131818de8d7fSPeter Avalos 	/* options->local_command should not be set by default */
131918de8d7fSPeter Avalos 	/* options->proxy_command should not be set by default */
132018de8d7fSPeter Avalos 	/* options->user will be set in the main program if appropriate */
132118de8d7fSPeter Avalos 	/* options->hostname will be set in the main program if appropriate */
132218de8d7fSPeter Avalos 	/* options->host_key_alias should not be set by default */
132318de8d7fSPeter Avalos 	/* options->preferred_authentications will be set in ssh */
132418de8d7fSPeter Avalos }
132518de8d7fSPeter Avalos 
132618de8d7fSPeter Avalos /*
132718de8d7fSPeter Avalos  * parse_forward
132818de8d7fSPeter Avalos  * parses a string containing a port forwarding specification of the form:
1329cb5eb4f1SPeter Avalos  *   dynamicfwd == 0
133018de8d7fSPeter Avalos  *	[listenhost:]listenport:connecthost:connectport
1331cb5eb4f1SPeter Avalos  *   dynamicfwd == 1
1332cb5eb4f1SPeter Avalos  *	[listenhost:]listenport
133318de8d7fSPeter Avalos  * returns number of arguments parsed or zero on error
133418de8d7fSPeter Avalos  */
133518de8d7fSPeter Avalos int
1336cb5eb4f1SPeter Avalos parse_forward(Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
133718de8d7fSPeter Avalos {
133818de8d7fSPeter Avalos 	int i;
133918de8d7fSPeter Avalos 	char *p, *cp, *fwdarg[4];
134018de8d7fSPeter Avalos 
134118de8d7fSPeter Avalos 	memset(fwd, '\0', sizeof(*fwd));
134218de8d7fSPeter Avalos 
134318de8d7fSPeter Avalos 	cp = p = xstrdup(fwdspec);
134418de8d7fSPeter Avalos 
134518de8d7fSPeter Avalos 	/* skip leading spaces */
134618de8d7fSPeter Avalos 	while (isspace(*cp))
134718de8d7fSPeter Avalos 		cp++;
134818de8d7fSPeter Avalos 
134918de8d7fSPeter Avalos 	for (i = 0; i < 4; ++i)
135018de8d7fSPeter Avalos 		if ((fwdarg[i] = hpdelim(&cp)) == NULL)
135118de8d7fSPeter Avalos 			break;
135218de8d7fSPeter Avalos 
1353cb5eb4f1SPeter Avalos 	/* Check for trailing garbage */
135418de8d7fSPeter Avalos 	if (cp != NULL)
135518de8d7fSPeter Avalos 		i = 0;	/* failure */
135618de8d7fSPeter Avalos 
135718de8d7fSPeter Avalos 	switch (i) {
1358cb5eb4f1SPeter Avalos 	case 1:
1359cb5eb4f1SPeter Avalos 		fwd->listen_host = NULL;
1360cb5eb4f1SPeter Avalos 		fwd->listen_port = a2port(fwdarg[0]);
1361cb5eb4f1SPeter Avalos 		fwd->connect_host = xstrdup("socks");
1362cb5eb4f1SPeter Avalos 		break;
1363cb5eb4f1SPeter Avalos 
1364cb5eb4f1SPeter Avalos 	case 2:
1365cb5eb4f1SPeter Avalos 		fwd->listen_host = xstrdup(cleanhostname(fwdarg[0]));
1366cb5eb4f1SPeter Avalos 		fwd->listen_port = a2port(fwdarg[1]);
1367cb5eb4f1SPeter Avalos 		fwd->connect_host = xstrdup("socks");
1368cb5eb4f1SPeter Avalos 		break;
1369cb5eb4f1SPeter Avalos 
137018de8d7fSPeter Avalos 	case 3:
137118de8d7fSPeter Avalos 		fwd->listen_host = NULL;
137218de8d7fSPeter Avalos 		fwd->listen_port = a2port(fwdarg[0]);
137318de8d7fSPeter Avalos 		fwd->connect_host = xstrdup(cleanhostname(fwdarg[1]));
137418de8d7fSPeter Avalos 		fwd->connect_port = a2port(fwdarg[2]);
137518de8d7fSPeter Avalos 		break;
137618de8d7fSPeter Avalos 
137718de8d7fSPeter Avalos 	case 4:
137818de8d7fSPeter Avalos 		fwd->listen_host = xstrdup(cleanhostname(fwdarg[0]));
137918de8d7fSPeter Avalos 		fwd->listen_port = a2port(fwdarg[1]);
138018de8d7fSPeter Avalos 		fwd->connect_host = xstrdup(cleanhostname(fwdarg[2]));
138118de8d7fSPeter Avalos 		fwd->connect_port = a2port(fwdarg[3]);
138218de8d7fSPeter Avalos 		break;
138318de8d7fSPeter Avalos 	default:
138418de8d7fSPeter Avalos 		i = 0; /* failure */
138518de8d7fSPeter Avalos 	}
138618de8d7fSPeter Avalos 
138718de8d7fSPeter Avalos 	xfree(p);
138818de8d7fSPeter Avalos 
1389cb5eb4f1SPeter Avalos 	if (dynamicfwd) {
1390cb5eb4f1SPeter Avalos 		if (!(i == 1 || i == 2))
1391cb5eb4f1SPeter Avalos 			goto fail_free;
1392cb5eb4f1SPeter Avalos 	} else {
1393cb5eb4f1SPeter Avalos 		if (!(i == 3 || i == 4))
1394cb5eb4f1SPeter Avalos 			goto fail_free;
1395cb5eb4f1SPeter Avalos 		if (fwd->connect_port <= 0)
1396cb5eb4f1SPeter Avalos 			goto fail_free;
1397cb5eb4f1SPeter Avalos 	}
1398cb5eb4f1SPeter Avalos 
1399cb5eb4f1SPeter Avalos 	if (fwd->listen_port < 0 || (!remotefwd && fwd->listen_port == 0))
140018de8d7fSPeter Avalos 		goto fail_free;
140118de8d7fSPeter Avalos 
140218de8d7fSPeter Avalos 	if (fwd->connect_host != NULL &&
140318de8d7fSPeter Avalos 	    strlen(fwd->connect_host) >= NI_MAXHOST)
140418de8d7fSPeter Avalos 		goto fail_free;
1405cb5eb4f1SPeter Avalos 	if (fwd->listen_host != NULL &&
1406cb5eb4f1SPeter Avalos 	    strlen(fwd->listen_host) >= NI_MAXHOST)
1407cb5eb4f1SPeter Avalos 		goto fail_free;
1408cb5eb4f1SPeter Avalos 
140918de8d7fSPeter Avalos 
141018de8d7fSPeter Avalos 	return (i);
141118de8d7fSPeter Avalos 
141218de8d7fSPeter Avalos  fail_free:
1413cb5eb4f1SPeter Avalos 	if (fwd->connect_host != NULL) {
141418de8d7fSPeter Avalos 		xfree(fwd->connect_host);
1415cb5eb4f1SPeter Avalos 		fwd->connect_host = NULL;
1416cb5eb4f1SPeter Avalos 	}
1417cb5eb4f1SPeter Avalos 	if (fwd->listen_host != NULL) {
141818de8d7fSPeter Avalos 		xfree(fwd->listen_host);
1419cb5eb4f1SPeter Avalos 		fwd->listen_host = NULL;
1420cb5eb4f1SPeter Avalos 	}
142118de8d7fSPeter Avalos 	return (0);
142218de8d7fSPeter Avalos }
1423