readconf.c revision 149753
157429Smarkm/*
257429Smarkm * Author: Tatu Ylonen <ylo@cs.hut.fi>
357429Smarkm * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
457429Smarkm *                    All rights reserved
557429Smarkm * Functions for reading the configuration files.
660576Skris *
765674Skris * As far as I am concerned, the code I have written for this software
865674Skris * can be used freely for any purpose.  Any derived versions of this
965674Skris * software must be clearly marked as such, and if the derived work is
1065674Skris * incompatible with the protocol description in the RFC file, it must be
1165674Skris * called by a name other than "ssh" or "Secure Shell".
1257429Smarkm */
1357429Smarkm
1457429Smarkm#include "includes.h"
15149753SdesRCSID("$OpenBSD: readconf.c,v 1.143 2005/07/30 02:03:47 djm Exp $");
16128460SdesRCSID("$FreeBSD: head/crypto/openssh/readconf.c 149753 2005-09-03 07:04:25Z des $");
1757429Smarkm
1857429Smarkm#include "ssh.h"
1976262Sgreen#include "xmalloc.h"
2076262Sgreen#include "compat.h"
2176262Sgreen#include "cipher.h"
2276262Sgreen#include "pathnames.h"
2376262Sgreen#include "log.h"
2457429Smarkm#include "readconf.h"
2560576Skris#include "match.h"
2676262Sgreen#include "misc.h"
2776262Sgreen#include "kex.h"
2876262Sgreen#include "mac.h"
2957429Smarkm
3057429Smarkm/* Format of the configuration file:
3157429Smarkm
3257429Smarkm   # Configuration data is parsed as follows:
3357429Smarkm   #  1. command line options
3457429Smarkm   #  2. user-specific file
3557429Smarkm   #  3. system-wide file
3657429Smarkm   # Any configuration value is only changed the first time it is set.
3757429Smarkm   # Thus, host-specific definitions should be at the beginning of the
3857429Smarkm   # configuration file, and defaults at the end.
3957429Smarkm
4057429Smarkm   # Host-specific declarations.  These may override anything above.  A single
4157429Smarkm   # host may match multiple declarations; these are processed in the order
4257429Smarkm   # that they are given in.
4357429Smarkm
4457429Smarkm   Host *.ngs.fi ngs.fi
4598684Sdes     User foo
4657429Smarkm
4757429Smarkm   Host fake.com
4857429Smarkm     HostName another.host.name.real.org
4957429Smarkm     User blaah
5057429Smarkm     Port 34289
5157429Smarkm     ForwardX11 no
5257429Smarkm     ForwardAgent no
5357429Smarkm
5457429Smarkm   Host books.com
5557429Smarkm     RemoteForward 9999 shadows.cs.hut.fi:9999
5657429Smarkm     Cipher 3des
5757429Smarkm
5857429Smarkm   Host fascist.blob.com
5957429Smarkm     Port 23123
6057429Smarkm     User tylonen
6157429Smarkm     PasswordAuthentication no
6257429Smarkm
6357429Smarkm   Host puukko.hut.fi
6457429Smarkm     User t35124p
6557429Smarkm     ProxyCommand ssh-proxy %h %p
6657429Smarkm
6757429Smarkm   Host *.fr
6898684Sdes     PublicKeyAuthentication no
6957429Smarkm
7057429Smarkm   Host *.su
7157429Smarkm     Cipher none
7257429Smarkm     PasswordAuthentication no
7357429Smarkm
7457429Smarkm   # Defaults for various options
7557429Smarkm   Host *
7657429Smarkm     ForwardAgent no
7776262Sgreen     ForwardX11 no
7857429Smarkm     PasswordAuthentication yes
7957429Smarkm     RSAAuthentication yes
8057429Smarkm     RhostsRSAAuthentication yes
8157429Smarkm     StrictHostKeyChecking yes
82126277Sdes     TcpKeepAlive no
8357429Smarkm     IdentityFile ~/.ssh/identity
8457429Smarkm     Port 22
8557429Smarkm     EscapeChar ~
8657429Smarkm
8757429Smarkm*/
8857429Smarkm
8957429Smarkm/* Keyword tokens. */
9057429Smarkm
9157429Smarkmtypedef enum {
9257429Smarkm	oBadOption,
93126277Sdes	oForwardAgent, oForwardX11, oForwardX11Trusted, oGatewayPorts,
9498684Sdes	oPasswordAuthentication, oRSAAuthentication,
9576262Sgreen	oChallengeResponseAuthentication, oXAuthLocation,
9657429Smarkm	oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward,
9757429Smarkm	oUser, oHost, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
9857429Smarkm	oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
9957429Smarkm	oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
100126277Sdes	oCompressionLevel, oTCPKeepAlive, oNumberOfPasswordPrompts,
10176262Sgreen	oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oMacs,
10276262Sgreen	oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication,
10376262Sgreen	oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
10476262Sgreen	oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
10592559Sdes	oHostKeyAlgorithms, oBindAddress, oSmartcardDevice,
10693698Sdes	oClearAllForwardings, oNoHostAuthenticationForLocalhost,
107124211Sdes	oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
108124211Sdes	oAddressFamily, oGssAuthentication, oGssDelegateCreds,
109128461Sdes	oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
110147005Sdes	oSendEnv, oControlPath, oControlMaster, oHashKnownHosts,
11199048Sdes	oVersionAddendum,
112124211Sdes	oDeprecated, oUnsupported
11357429Smarkm} OpCodes;
11457429Smarkm
11557429Smarkm/* Textual representations of the tokens. */
11657429Smarkm
11757429Smarkmstatic struct {
11857429Smarkm	const char *name;
11957429Smarkm	OpCodes opcode;
12057429Smarkm} keywords[] = {
12157429Smarkm	{ "forwardagent", oForwardAgent },
12257429Smarkm	{ "forwardx11", oForwardX11 },
123126277Sdes	{ "forwardx11trusted", oForwardX11Trusted },
12465674Skris	{ "xauthlocation", oXAuthLocation },
12557429Smarkm	{ "gatewayports", oGatewayPorts },
12657429Smarkm	{ "useprivilegedport", oUsePrivilegedPort },
127124211Sdes	{ "rhostsauthentication", oDeprecated },
12857429Smarkm	{ "passwordauthentication", oPasswordAuthentication },
12969591Sgreen	{ "kbdinteractiveauthentication", oKbdInteractiveAuthentication },
13069591Sgreen	{ "kbdinteractivedevices", oKbdInteractiveDevices },
13157429Smarkm	{ "rsaauthentication", oRSAAuthentication },
13276262Sgreen	{ "pubkeyauthentication", oPubkeyAuthentication },
13376262Sgreen	{ "dsaauthentication", oPubkeyAuthentication },		    /* alias */
13476262Sgreen	{ "rhostsrsaauthentication", oRhostsRSAAuthentication },
13576262Sgreen	{ "hostbasedauthentication", oHostbasedAuthentication },
13676262Sgreen	{ "challengeresponseauthentication", oChallengeResponseAuthentication },
13776262Sgreen	{ "skeyauthentication", oChallengeResponseAuthentication }, /* alias */
13876262Sgreen	{ "tisauthentication", oChallengeResponseAuthentication },  /* alias */
139124211Sdes	{ "kerberosauthentication", oUnsupported },
140124211Sdes	{ "kerberostgtpassing", oUnsupported },
141124211Sdes	{ "afstokenpassing", oUnsupported },
142124211Sdes#if defined(GSSAPI)
143124211Sdes	{ "gssapiauthentication", oGssAuthentication },
144124211Sdes	{ "gssapidelegatecredentials", oGssDelegateCreds },
145124211Sdes#else
146124211Sdes	{ "gssapiauthentication", oUnsupported },
147124211Sdes	{ "gssapidelegatecredentials", oUnsupported },
14892559Sdes#endif
14998684Sdes	{ "fallbacktorsh", oDeprecated },
15098684Sdes	{ "usersh", oDeprecated },
15157429Smarkm	{ "identityfile", oIdentityFile },
15276262Sgreen	{ "identityfile2", oIdentityFile },			/* alias */
153128460Sdes	{ "identitiesonly", oIdentitiesOnly },
15457429Smarkm	{ "hostname", oHostName },
15576262Sgreen	{ "hostkeyalias", oHostKeyAlias },
15657429Smarkm	{ "proxycommand", oProxyCommand },
15757429Smarkm	{ "port", oPort },
15857429Smarkm	{ "cipher", oCipher },
15960576Skris	{ "ciphers", oCiphers },
16076262Sgreen	{ "macs", oMacs },
16160576Skris	{ "protocol", oProtocol },
16257429Smarkm	{ "remoteforward", oRemoteForward },
16357429Smarkm	{ "localforward", oLocalForward },
16457429Smarkm	{ "user", oUser },
16557429Smarkm	{ "host", oHost },
16657429Smarkm	{ "escapechar", oEscapeChar },
16757429Smarkm	{ "globalknownhostsfile", oGlobalKnownHostsFile },
16892559Sdes	{ "userknownhostsfile", oUserKnownHostsFile },		/* obsolete */
16960576Skris	{ "globalknownhostsfile2", oGlobalKnownHostsFile2 },
17092559Sdes	{ "userknownhostsfile2", oUserKnownHostsFile2 },	/* obsolete */
17157429Smarkm	{ "connectionattempts", oConnectionAttempts },
17257429Smarkm	{ "batchmode", oBatchMode },
17357429Smarkm	{ "checkhostip", oCheckHostIP },
17457429Smarkm	{ "stricthostkeychecking", oStrictHostKeyChecking },
17557429Smarkm	{ "compression", oCompression },
17657429Smarkm	{ "compressionlevel", oCompressionLevel },
177126277Sdes	{ "tcpkeepalive", oTCPKeepAlive },
178126277Sdes	{ "keepalive", oTCPKeepAlive },				/* obsolete */
17957429Smarkm	{ "numberofpasswordprompts", oNumberOfPasswordPrompts },
18057429Smarkm	{ "loglevel", oLogLevel },
18176262Sgreen	{ "dynamicforward", oDynamicForward },
18276262Sgreen	{ "preferredauthentications", oPreferredAuthentications },
18376262Sgreen	{ "hostkeyalgorithms", oHostKeyAlgorithms },
18492559Sdes	{ "bindaddress", oBindAddress },
185124211Sdes#ifdef SMARTCARD
18692559Sdes	{ "smartcarddevice", oSmartcardDevice },
187124211Sdes#else
188124211Sdes	{ "smartcarddevice", oUnsupported },
189124211Sdes#endif
19092559Sdes	{ "clearallforwardings", oClearAllForwardings },
191113911Sdes	{ "enablesshkeysign", oEnableSSHKeysign },
192124211Sdes	{ "verifyhostkeydns", oVerifyHostKeyDNS },
19392559Sdes	{ "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
194124211Sdes	{ "rekeylimit", oRekeyLimit },
195124211Sdes	{ "connecttimeout", oConnectTimeout },
196124211Sdes	{ "addressfamily", oAddressFamily },
197126277Sdes	{ "serveraliveinterval", oServerAliveInterval },
198126277Sdes	{ "serveralivecountmax", oServerAliveCountMax },
199137019Sdes	{ "sendenv", oSendEnv },
200137019Sdes	{ "controlpath", oControlPath },
201137019Sdes	{ "controlmaster", oControlMaster },
202147005Sdes	{ "hashknownhosts", oHashKnownHosts },
20399048Sdes	{ "versionaddendum", oVersionAddendum },
20492559Sdes	{ NULL, oBadOption }
20557429Smarkm};
20657429Smarkm
20757429Smarkm/*
20857429Smarkm * Adds a local TCP/IP port forward to options.  Never returns if there is an
20957429Smarkm * error.
21057429Smarkm */
21157429Smarkm
21260576Skrisvoid
213147005Sdesadd_local_forward(Options *options, const Forward *newfwd)
21457429Smarkm{
21557429Smarkm	Forward *fwd;
216106130Sdes#ifndef NO_IPPORT_RESERVED_CONCEPT
21757429Smarkm	extern uid_t original_real_uid;
218147005Sdes	if (newfwd->listen_port < IPPORT_RESERVED && original_real_uid != 0)
21976262Sgreen		fatal("Privileged ports can only be forwarded by root.");
22098941Sdes#endif
22157429Smarkm	if (options->num_local_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
22257429Smarkm		fatal("Too many local forwards (max %d).", SSH_MAX_FORWARDS_PER_DIRECTION);
22357429Smarkm	fwd = &options->local_forwards[options->num_local_forwards++];
224147005Sdes
225147005Sdes	fwd->listen_host = (newfwd->listen_host == NULL) ?
226147005Sdes	    NULL : xstrdup(newfwd->listen_host);
227147005Sdes	fwd->listen_port = newfwd->listen_port;
228147005Sdes	fwd->connect_host = xstrdup(newfwd->connect_host);
229147005Sdes	fwd->connect_port = newfwd->connect_port;
23057429Smarkm}
23157429Smarkm
23257429Smarkm/*
23357429Smarkm * Adds a remote TCP/IP port forward to options.  Never returns if there is
23457429Smarkm * an error.
23557429Smarkm */
23657429Smarkm
23760576Skrisvoid
238147005Sdesadd_remote_forward(Options *options, const Forward *newfwd)
23957429Smarkm{
24057429Smarkm	Forward *fwd;
24157429Smarkm	if (options->num_remote_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
24257429Smarkm		fatal("Too many remote forwards (max %d).",
24392559Sdes		    SSH_MAX_FORWARDS_PER_DIRECTION);
24457429Smarkm	fwd = &options->remote_forwards[options->num_remote_forwards++];
245147005Sdes
246147005Sdes	fwd->listen_host = (newfwd->listen_host == NULL) ?
247147005Sdes	    NULL : xstrdup(newfwd->listen_host);
248147005Sdes	fwd->listen_port = newfwd->listen_port;
249147005Sdes	fwd->connect_host = xstrdup(newfwd->connect_host);
250147005Sdes	fwd->connect_port = newfwd->connect_port;
25157429Smarkm}
25257429Smarkm
25392559Sdesstatic void
25492559Sdesclear_forwardings(Options *options)
25592559Sdes{
25692559Sdes	int i;
25792559Sdes
258147005Sdes	for (i = 0; i < options->num_local_forwards; i++) {
259147005Sdes		if (options->local_forwards[i].listen_host != NULL)
260147005Sdes			xfree(options->local_forwards[i].listen_host);
261147005Sdes		xfree(options->local_forwards[i].connect_host);
262147005Sdes	}
26392559Sdes	options->num_local_forwards = 0;
264147005Sdes	for (i = 0; i < options->num_remote_forwards; i++) {
265147005Sdes		if (options->remote_forwards[i].listen_host != NULL)
266147005Sdes			xfree(options->remote_forwards[i].listen_host);
267147005Sdes		xfree(options->remote_forwards[i].connect_host);
268147005Sdes	}
26992559Sdes	options->num_remote_forwards = 0;
27092559Sdes}
27192559Sdes
27257429Smarkm/*
27376262Sgreen * Returns the number of the token pointed to by cp or oBadOption.
27457429Smarkm */
27557429Smarkm
27660576Skrisstatic OpCodes
27757429Smarkmparse_token(const char *cp, const char *filename, int linenum)
27857429Smarkm{
27976262Sgreen	u_int i;
28057429Smarkm
28157429Smarkm	for (i = 0; keywords[i].name; i++)
28257429Smarkm		if (strcasecmp(cp, keywords[i].name) == 0)
28357429Smarkm			return keywords[i].opcode;
28457429Smarkm
28576262Sgreen	error("%s: line %d: Bad configuration option: %s",
28676262Sgreen	    filename, linenum, cp);
28757429Smarkm	return oBadOption;
28857429Smarkm}
28957429Smarkm
29057429Smarkm/*
29157429Smarkm * Processes a single option line as used in the configuration files. This
29257429Smarkm * only sets those values that have not already been set.
29357429Smarkm */
294113911Sdes#define WHITESPACE " \t\r\n"
29557429Smarkm
29657429Smarkmint
29757429Smarkmprocess_config_line(Options *options, const char *host,
29857429Smarkm		    char *line, const char *filename, int linenum,
29957429Smarkm		    int *activep)
30057429Smarkm{
301147005Sdes	char *s, **charptr, *endofnumber, *keyword, *arg, *arg2, fwdarg[256];
30257429Smarkm	int opcode, *intptr, value;
303113911Sdes	size_t len;
304147005Sdes	Forward fwd;
30557429Smarkm
306124211Sdes	/* Strip trailing whitespace */
307147005Sdes	for (len = strlen(line) - 1; len > 0; len--) {
308124211Sdes		if (strchr(WHITESPACE, line[len]) == NULL)
309124211Sdes			break;
310124211Sdes		line[len] = '\0';
311124211Sdes	}
312124211Sdes
31365674Skris	s = line;
31465674Skris	/* Get the keyword. (Each line is supposed to begin with a keyword). */
31565674Skris	keyword = strdelim(&s);
31665674Skris	/* Ignore leading whitespace. */
31765674Skris	if (*keyword == '\0')
31865674Skris		keyword = strdelim(&s);
31976262Sgreen	if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#')
32057429Smarkm		return 0;
32157429Smarkm
32265674Skris	opcode = parse_token(keyword, filename, linenum);
32357429Smarkm
32457429Smarkm	switch (opcode) {
32557429Smarkm	case oBadOption:
32657429Smarkm		/* don't panic, but count bad options */
32757429Smarkm		return -1;
32857429Smarkm		/* NOTREACHED */
329124211Sdes	case oConnectTimeout:
330124211Sdes		intptr = &options->connection_timeout;
331126277Sdesparse_time:
332124211Sdes		arg = strdelim(&s);
333124211Sdes		if (!arg || *arg == '\0')
334124211Sdes			fatal("%s line %d: missing time value.",
335124211Sdes			    filename, linenum);
336124211Sdes		if ((value = convtime(arg)) == -1)
337124211Sdes			fatal("%s line %d: invalid time value.",
338124211Sdes			    filename, linenum);
339124211Sdes		if (*intptr == -1)
340124211Sdes			*intptr = value;
341124211Sdes		break;
342124211Sdes
34357429Smarkm	case oForwardAgent:
34457429Smarkm		intptr = &options->forward_agent;
34557429Smarkmparse_flag:
34665674Skris		arg = strdelim(&s);
34765674Skris		if (!arg || *arg == '\0')
34857429Smarkm			fatal("%.200s line %d: Missing yes/no argument.", filename, linenum);
34957429Smarkm		value = 0;	/* To avoid compiler warning... */
35065674Skris		if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
35157429Smarkm			value = 1;
35265674Skris		else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
35357429Smarkm			value = 0;
35457429Smarkm		else
35557429Smarkm			fatal("%.200s line %d: Bad yes/no argument.", filename, linenum);
35657429Smarkm		if (*activep && *intptr == -1)
35757429Smarkm			*intptr = value;
35857429Smarkm		break;
35957429Smarkm
36057429Smarkm	case oForwardX11:
36157429Smarkm		intptr = &options->forward_x11;
36257429Smarkm		goto parse_flag;
36357429Smarkm
364126277Sdes	case oForwardX11Trusted:
365126277Sdes		intptr = &options->forward_x11_trusted;
366126277Sdes		goto parse_flag;
367126277Sdes
36857429Smarkm	case oGatewayPorts:
36957429Smarkm		intptr = &options->gateway_ports;
37057429Smarkm		goto parse_flag;
37157429Smarkm
37257429Smarkm	case oUsePrivilegedPort:
37357429Smarkm		intptr = &options->use_privileged_port;
37457429Smarkm		goto parse_flag;
37557429Smarkm
37657429Smarkm	case oPasswordAuthentication:
37757429Smarkm		intptr = &options->password_authentication;
37857429Smarkm		goto parse_flag;
37957429Smarkm
38069591Sgreen	case oKbdInteractiveAuthentication:
38169591Sgreen		intptr = &options->kbd_interactive_authentication;
38269591Sgreen		goto parse_flag;
38369591Sgreen
38469591Sgreen	case oKbdInteractiveDevices:
38569591Sgreen		charptr = &options->kbd_interactive_devices;
38669591Sgreen		goto parse_string;
38769591Sgreen
38876262Sgreen	case oPubkeyAuthentication:
38976262Sgreen		intptr = &options->pubkey_authentication;
39060576Skris		goto parse_flag;
39160576Skris
39257429Smarkm	case oRSAAuthentication:
39357429Smarkm		intptr = &options->rsa_authentication;
39457429Smarkm		goto parse_flag;
39557429Smarkm
39657429Smarkm	case oRhostsRSAAuthentication:
39757429Smarkm		intptr = &options->rhosts_rsa_authentication;
39857429Smarkm		goto parse_flag;
39957429Smarkm
40076262Sgreen	case oHostbasedAuthentication:
40176262Sgreen		intptr = &options->hostbased_authentication;
40257429Smarkm		goto parse_flag;
40357429Smarkm
40492559Sdes	case oChallengeResponseAuthentication:
40592559Sdes		intptr = &options->challenge_response_authentication;
40692559Sdes		goto parse_flag;
407124211Sdes
408124211Sdes	case oGssAuthentication:
409124211Sdes		intptr = &options->gss_authentication;
41057429Smarkm		goto parse_flag;
411124211Sdes
412124211Sdes	case oGssDelegateCreds:
413124211Sdes		intptr = &options->gss_deleg_creds;
41476262Sgreen		goto parse_flag;
415124211Sdes
41657429Smarkm	case oBatchMode:
41757429Smarkm		intptr = &options->batch_mode;
41857429Smarkm		goto parse_flag;
41957429Smarkm
42057429Smarkm	case oCheckHostIP:
42157429Smarkm		intptr = &options->check_host_ip;
42257429Smarkm		goto parse_flag;
42357429Smarkm
424124211Sdes	case oVerifyHostKeyDNS:
425124211Sdes		intptr = &options->verify_host_key_dns;
426126277Sdes		goto parse_yesnoask;
427124211Sdes
42857429Smarkm	case oStrictHostKeyChecking:
42957429Smarkm		intptr = &options->strict_host_key_checking;
430126277Sdesparse_yesnoask:
43165674Skris		arg = strdelim(&s);
43265674Skris		if (!arg || *arg == '\0')
43376262Sgreen			fatal("%.200s line %d: Missing yes/no/ask argument.",
43492559Sdes			    filename, linenum);
43557429Smarkm		value = 0;	/* To avoid compiler warning... */
43665674Skris		if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
43757429Smarkm			value = 1;
43865674Skris		else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
43957429Smarkm			value = 0;
44065674Skris		else if (strcmp(arg, "ask") == 0)
44157429Smarkm			value = 2;
44257429Smarkm		else
44357429Smarkm			fatal("%.200s line %d: Bad yes/no/ask argument.", filename, linenum);
44457429Smarkm		if (*activep && *intptr == -1)
44557429Smarkm			*intptr = value;
44657429Smarkm		break;
44757429Smarkm
44857429Smarkm	case oCompression:
44957429Smarkm		intptr = &options->compression;
45057429Smarkm		goto parse_flag;
45157429Smarkm
452126277Sdes	case oTCPKeepAlive:
453126277Sdes		intptr = &options->tcp_keep_alive;
45457429Smarkm		goto parse_flag;
45557429Smarkm
45692559Sdes	case oNoHostAuthenticationForLocalhost:
45792559Sdes		intptr = &options->no_host_authentication_for_localhost;
45892559Sdes		goto parse_flag;
45992559Sdes
46057429Smarkm	case oNumberOfPasswordPrompts:
46157429Smarkm		intptr = &options->number_of_password_prompts;
46257429Smarkm		goto parse_int;
46357429Smarkm
46457429Smarkm	case oCompressionLevel:
46557429Smarkm		intptr = &options->compression_level;
46657429Smarkm		goto parse_int;
46757429Smarkm
468124211Sdes	case oRekeyLimit:
469124211Sdes		intptr = &options->rekey_limit;
470124211Sdes		arg = strdelim(&s);
471124211Sdes		if (!arg || *arg == '\0')
472124211Sdes			fatal("%.200s line %d: Missing argument.", filename, linenum);
473124211Sdes		if (arg[0] < '0' || arg[0] > '9')
474124211Sdes			fatal("%.200s line %d: Bad number.", filename, linenum);
475124211Sdes		value = strtol(arg, &endofnumber, 10);
476124211Sdes		if (arg == endofnumber)
477124211Sdes			fatal("%.200s line %d: Bad number.", filename, linenum);
478124211Sdes		switch (toupper(*endofnumber)) {
479124211Sdes		case 'K':
480124211Sdes			value *= 1<<10;
481124211Sdes			break;
482124211Sdes		case 'M':
483124211Sdes			value *= 1<<20;
484124211Sdes			break;
485124211Sdes		case 'G':
486124211Sdes			value *= 1<<30;
487124211Sdes			break;
488124211Sdes		}
489124211Sdes		if (*activep && *intptr == -1)
490124211Sdes			*intptr = value;
491124211Sdes		break;
492124211Sdes
49357429Smarkm	case oIdentityFile:
49465674Skris		arg = strdelim(&s);
49565674Skris		if (!arg || *arg == '\0')
49657429Smarkm			fatal("%.200s line %d: Missing argument.", filename, linenum);
49757429Smarkm		if (*activep) {
49876262Sgreen			intptr = &options->num_identity_files;
49960576Skris			if (*intptr >= SSH_MAX_IDENTITY_FILES)
50057429Smarkm				fatal("%.200s line %d: Too many identity files specified (max %d).",
50192559Sdes				    filename, linenum, SSH_MAX_IDENTITY_FILES);
50276262Sgreen			charptr =  &options->identity_files[*intptr];
50365674Skris			*charptr = xstrdup(arg);
50460576Skris			*intptr = *intptr + 1;
50557429Smarkm		}
50657429Smarkm		break;
50757429Smarkm
50865674Skris	case oXAuthLocation:
50965674Skris		charptr=&options->xauth_location;
51065674Skris		goto parse_string;
51165674Skris
51257429Smarkm	case oUser:
51357429Smarkm		charptr = &options->user;
51457429Smarkmparse_string:
51565674Skris		arg = strdelim(&s);
51665674Skris		if (!arg || *arg == '\0')
51757429Smarkm			fatal("%.200s line %d: Missing argument.", filename, linenum);
51857429Smarkm		if (*activep && *charptr == NULL)
51965674Skris			*charptr = xstrdup(arg);
52057429Smarkm		break;
52157429Smarkm
52257429Smarkm	case oGlobalKnownHostsFile:
52357429Smarkm		charptr = &options->system_hostfile;
52457429Smarkm		goto parse_string;
52557429Smarkm
52657429Smarkm	case oUserKnownHostsFile:
52757429Smarkm		charptr = &options->user_hostfile;
52857429Smarkm		goto parse_string;
52957429Smarkm
53060576Skris	case oGlobalKnownHostsFile2:
53160576Skris		charptr = &options->system_hostfile2;
53260576Skris		goto parse_string;
53360576Skris
53460576Skris	case oUserKnownHostsFile2:
53560576Skris		charptr = &options->user_hostfile2;
53660576Skris		goto parse_string;
53760576Skris
53857429Smarkm	case oHostName:
53957429Smarkm		charptr = &options->hostname;
54057429Smarkm		goto parse_string;
54157429Smarkm
54276262Sgreen	case oHostKeyAlias:
54376262Sgreen		charptr = &options->host_key_alias;
54476262Sgreen		goto parse_string;
54576262Sgreen
54676262Sgreen	case oPreferredAuthentications:
54776262Sgreen		charptr = &options->preferred_authentications;
54876262Sgreen		goto parse_string;
54976262Sgreen
55092559Sdes	case oBindAddress:
55192559Sdes		charptr = &options->bind_address;
55292559Sdes		goto parse_string;
55392559Sdes
55492559Sdes	case oSmartcardDevice:
55592559Sdes		charptr = &options->smartcard_device;
55692559Sdes		goto parse_string;
55792559Sdes
55857429Smarkm	case oProxyCommand:
559124211Sdes		if (s == NULL)
560124211Sdes			fatal("%.200s line %d: Missing argument.", filename, linenum);
56157429Smarkm		charptr = &options->proxy_command;
562113911Sdes		len = strspn(s, WHITESPACE "=");
56357429Smarkm		if (*activep && *charptr == NULL)
564113911Sdes			*charptr = xstrdup(s + len);
56557429Smarkm		return 0;
56657429Smarkm
56757429Smarkm	case oPort:
56857429Smarkm		intptr = &options->port;
56957429Smarkmparse_int:
57065674Skris		arg = strdelim(&s);
57165674Skris		if (!arg || *arg == '\0')
57257429Smarkm			fatal("%.200s line %d: Missing argument.", filename, linenum);
57365674Skris		if (arg[0] < '0' || arg[0] > '9')
57457429Smarkm			fatal("%.200s line %d: Bad number.", filename, linenum);
57557429Smarkm
57657429Smarkm		/* Octal, decimal, or hex format? */
57765674Skris		value = strtol(arg, &endofnumber, 0);
57865674Skris		if (arg == endofnumber)
57957429Smarkm			fatal("%.200s line %d: Bad number.", filename, linenum);
58057429Smarkm		if (*activep && *intptr == -1)
58157429Smarkm			*intptr = value;
58257429Smarkm		break;
58357429Smarkm
58457429Smarkm	case oConnectionAttempts:
58557429Smarkm		intptr = &options->connection_attempts;
58657429Smarkm		goto parse_int;
58757429Smarkm
58857429Smarkm	case oCipher:
58957429Smarkm		intptr = &options->cipher;
59065674Skris		arg = strdelim(&s);
59165674Skris		if (!arg || *arg == '\0')
59261203Skris			fatal("%.200s line %d: Missing argument.", filename, linenum);
59365674Skris		value = cipher_number(arg);
59457429Smarkm		if (value == -1)
59557429Smarkm			fatal("%.200s line %d: Bad cipher '%s'.",
59692559Sdes			    filename, linenum, arg ? arg : "<NONE>");
59757429Smarkm		if (*activep && *intptr == -1)
59857429Smarkm			*intptr = value;
59957429Smarkm		break;
60057429Smarkm
60160576Skris	case oCiphers:
60265674Skris		arg = strdelim(&s);
60365674Skris		if (!arg || *arg == '\0')
60461203Skris			fatal("%.200s line %d: Missing argument.", filename, linenum);
60565674Skris		if (!ciphers_valid(arg))
60660576Skris			fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.",
60792559Sdes			    filename, linenum, arg ? arg : "<NONE>");
60860576Skris		if (*activep && options->ciphers == NULL)
60965674Skris			options->ciphers = xstrdup(arg);
61060576Skris		break;
61160576Skris
61276262Sgreen	case oMacs:
61376262Sgreen		arg = strdelim(&s);
61476262Sgreen		if (!arg || *arg == '\0')
61576262Sgreen			fatal("%.200s line %d: Missing argument.", filename, linenum);
61676262Sgreen		if (!mac_valid(arg))
61776262Sgreen			fatal("%.200s line %d: Bad SSH2 Mac spec '%s'.",
61892559Sdes			    filename, linenum, arg ? arg : "<NONE>");
61976262Sgreen		if (*activep && options->macs == NULL)
62076262Sgreen			options->macs = xstrdup(arg);
62176262Sgreen		break;
62276262Sgreen
62376262Sgreen	case oHostKeyAlgorithms:
62476262Sgreen		arg = strdelim(&s);
62576262Sgreen		if (!arg || *arg == '\0')
62676262Sgreen			fatal("%.200s line %d: Missing argument.", filename, linenum);
62776262Sgreen		if (!key_names_valid2(arg))
62876262Sgreen			fatal("%.200s line %d: Bad protocol 2 host key algorithms '%s'.",
62992559Sdes			    filename, linenum, arg ? arg : "<NONE>");
63076262Sgreen		if (*activep && options->hostkeyalgorithms == NULL)
63176262Sgreen			options->hostkeyalgorithms = xstrdup(arg);
63276262Sgreen		break;
63376262Sgreen
63460576Skris	case oProtocol:
63560576Skris		intptr = &options->protocol;
63665674Skris		arg = strdelim(&s);
63765674Skris		if (!arg || *arg == '\0')
63861203Skris			fatal("%.200s line %d: Missing argument.", filename, linenum);
63965674Skris		value = proto_spec(arg);
64060576Skris		if (value == SSH_PROTO_UNKNOWN)
64160576Skris			fatal("%.200s line %d: Bad protocol spec '%s'.",
64292559Sdes			    filename, linenum, arg ? arg : "<NONE>");
64360576Skris		if (*activep && *intptr == SSH_PROTO_UNKNOWN)
64460576Skris			*intptr = value;
64560576Skris		break;
64660576Skris
64757429Smarkm	case oLogLevel:
64857429Smarkm		intptr = (int *) &options->log_level;
64965674Skris		arg = strdelim(&s);
65065674Skris		value = log_level_number(arg);
65192559Sdes		if (value == SYSLOG_LEVEL_NOT_SET)
65276262Sgreen			fatal("%.200s line %d: unsupported log level '%s'",
65392559Sdes			    filename, linenum, arg ? arg : "<NONE>");
65492559Sdes		if (*activep && (LogLevel) *intptr == SYSLOG_LEVEL_NOT_SET)
65557429Smarkm			*intptr = (LogLevel) value;
65657429Smarkm		break;
65757429Smarkm
65892559Sdes	case oLocalForward:
65957429Smarkm	case oRemoteForward:
66065674Skris		arg = strdelim(&s);
661147005Sdes		if (arg == NULL || *arg == '\0')
66292559Sdes			fatal("%.200s line %d: Missing port argument.",
66392559Sdes			    filename, linenum);
664147005Sdes		arg2 = strdelim(&s);
665147005Sdes		if (arg2 == NULL || *arg2 == '\0')
666147005Sdes			fatal("%.200s line %d: Missing target argument.",
66792559Sdes			    filename, linenum);
668147005Sdes
669147005Sdes		/* construct a string for parse_forward */
670147005Sdes		snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg, arg2);
671147005Sdes
672147005Sdes		if (parse_forward(&fwd, fwdarg) == 0)
67392559Sdes			fatal("%.200s line %d: Bad forwarding specification.",
67492559Sdes			    filename, linenum);
675147005Sdes
67692559Sdes		if (*activep) {
67792559Sdes			if (opcode == oLocalForward)
678147005Sdes				add_local_forward(options, &fwd);
67992559Sdes			else if (opcode == oRemoteForward)
680147005Sdes				add_remote_forward(options, &fwd);
68192559Sdes		}
68257429Smarkm		break;
68357429Smarkm
68476262Sgreen	case oDynamicForward:
68576262Sgreen		arg = strdelim(&s);
68676262Sgreen		if (!arg || *arg == '\0')
68776262Sgreen			fatal("%.200s line %d: Missing port argument.",
68876262Sgreen			    filename, linenum);
689147005Sdes		memset(&fwd, '\0', sizeof(fwd));
690147005Sdes		fwd.connect_host = "socks";
691147005Sdes		fwd.listen_host = hpdelim(&arg);
692147005Sdes		if (fwd.listen_host == NULL ||
693147005Sdes		    strlen(fwd.listen_host) >= NI_MAXHOST)
694147005Sdes			fatal("%.200s line %d: Bad forwarding specification.",
695147005Sdes			    filename, linenum);
696147005Sdes		if (arg) {
697147005Sdes			fwd.listen_port = a2port(arg);
698147005Sdes			fwd.listen_host = cleanhostname(fwd.listen_host);
699147005Sdes		} else {
700147005Sdes			fwd.listen_port = a2port(fwd.listen_host);
701149753Sdes			fwd.listen_host = NULL;
702147005Sdes		}
703147005Sdes		if (fwd.listen_port == 0)
70476262Sgreen			fatal("%.200s line %d: Badly formatted port number.",
70576262Sgreen			    filename, linenum);
70692559Sdes		if (*activep)
707147005Sdes			add_local_forward(options, &fwd);
70876262Sgreen		break;
70976262Sgreen
71092559Sdes	case oClearAllForwardings:
71192559Sdes		intptr = &options->clear_forwardings;
71292559Sdes		goto parse_flag;
71392559Sdes
71457429Smarkm	case oHost:
71557429Smarkm		*activep = 0;
71665674Skris		while ((arg = strdelim(&s)) != NULL && *arg != '\0')
71765674Skris			if (match_pattern(host, arg)) {
71865674Skris				debug("Applying options for %.100s", arg);
71957429Smarkm				*activep = 1;
72057429Smarkm				break;
72157429Smarkm			}
72265674Skris		/* Avoid garbage check below, as strdelim is done. */
72357429Smarkm		return 0;
72457429Smarkm
72557429Smarkm	case oEscapeChar:
72657429Smarkm		intptr = &options->escape_char;
72765674Skris		arg = strdelim(&s);
72865674Skris		if (!arg || *arg == '\0')
72957429Smarkm			fatal("%.200s line %d: Missing argument.", filename, linenum);
73065674Skris		if (arg[0] == '^' && arg[2] == 0 &&
73176262Sgreen		    (u_char) arg[1] >= 64 && (u_char) arg[1] < 128)
73276262Sgreen			value = (u_char) arg[1] & 31;
73365674Skris		else if (strlen(arg) == 1)
73476262Sgreen			value = (u_char) arg[0];
73565674Skris		else if (strcmp(arg, "none") == 0)
73692559Sdes			value = SSH_ESCAPECHAR_NONE;
73757429Smarkm		else {
73857429Smarkm			fatal("%.200s line %d: Bad escape character.",
73992559Sdes			    filename, linenum);
74057429Smarkm			/* NOTREACHED */
74157429Smarkm			value = 0;	/* Avoid compiler warning. */
74257429Smarkm		}
74357429Smarkm		if (*activep && *intptr == -1)
74457429Smarkm			*intptr = value;
74557429Smarkm		break;
74657429Smarkm
747124211Sdes	case oAddressFamily:
748124211Sdes		arg = strdelim(&s);
749149753Sdes		if (!arg || *arg == '\0')
750149753Sdes			fatal("%s line %d: missing address family.",
751149753Sdes			    filename, linenum);
752124211Sdes		intptr = &options->address_family;
753124211Sdes		if (strcasecmp(arg, "inet") == 0)
754124211Sdes			value = AF_INET;
755124211Sdes		else if (strcasecmp(arg, "inet6") == 0)
756124211Sdes			value = AF_INET6;
757124211Sdes		else if (strcasecmp(arg, "any") == 0)
758124211Sdes			value = AF_UNSPEC;
759124211Sdes		else
760124211Sdes			fatal("Unsupported AddressFamily \"%s\"", arg);
761124211Sdes		if (*activep && *intptr == -1)
762124211Sdes			*intptr = value;
763124211Sdes		break;
764124211Sdes
765113911Sdes	case oEnableSSHKeysign:
766113911Sdes		intptr = &options->enable_ssh_keysign;
767113911Sdes		goto parse_flag;
768113911Sdes
769128460Sdes	case oIdentitiesOnly:
770128460Sdes		intptr = &options->identities_only;
771128460Sdes		goto parse_flag;
772128460Sdes
773126277Sdes	case oServerAliveInterval:
774126277Sdes		intptr = &options->server_alive_interval;
775126277Sdes		goto parse_time;
776126277Sdes
777126277Sdes	case oServerAliveCountMax:
778126277Sdes		intptr = &options->server_alive_count_max;
779126277Sdes		goto parse_int;
780126277Sdes
781137019Sdes	case oSendEnv:
782137019Sdes		while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
783137019Sdes			if (strchr(arg, '=') != NULL)
784137019Sdes				fatal("%s line %d: Invalid environment name.",
785137019Sdes				    filename, linenum);
786147005Sdes			if (!*activep)
787147005Sdes				continue;
788137019Sdes			if (options->num_send_env >= MAX_SEND_ENV)
789137019Sdes				fatal("%s line %d: too many send env.",
790137019Sdes				    filename, linenum);
791137019Sdes			options->send_env[options->num_send_env++] =
792137019Sdes			    xstrdup(arg);
793137019Sdes		}
794137019Sdes		break;
795137019Sdes
796137019Sdes	case oControlPath:
797137019Sdes		charptr = &options->control_path;
798137019Sdes		goto parse_string;
799137019Sdes
800137019Sdes	case oControlMaster:
801137019Sdes		intptr = &options->control_master;
802149753Sdes		arg = strdelim(&s);
803149753Sdes		if (!arg || *arg == '\0')
804149753Sdes			fatal("%.200s line %d: Missing ControlMaster argument.",
805149753Sdes			    filename, linenum);
806149753Sdes		value = 0;	/* To avoid compiler warning... */
807149753Sdes		if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
808149753Sdes			value = SSHCTL_MASTER_YES;
809149753Sdes		else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
810149753Sdes			value = SSHCTL_MASTER_NO;
811149753Sdes		else if (strcmp(arg, "auto") == 0)
812149753Sdes			value = SSHCTL_MASTER_AUTO;
813149753Sdes		else if (strcmp(arg, "ask") == 0)
814149753Sdes			value = SSHCTL_MASTER_ASK;
815149753Sdes		else if (strcmp(arg, "autoask") == 0)
816149753Sdes			value = SSHCTL_MASTER_AUTO_ASK;
817149753Sdes		else
818149753Sdes			fatal("%.200s line %d: Bad ControlMaster argument.",
819149753Sdes			    filename, linenum);
820149753Sdes		if (*activep && *intptr == -1)
821149753Sdes			*intptr = value;
822149753Sdes		break;
823137019Sdes
824147005Sdes	case oHashKnownHosts:
825147005Sdes		intptr = &options->hash_known_hosts;
826147005Sdes		goto parse_flag;
827147005Sdes
82899048Sdes	case oVersionAddendum:
82999048Sdes		ssh_version_set_addendum(strtok(s, "\n"));
83099048Sdes		do {
83199048Sdes			arg = strdelim(&s);
83299048Sdes		} while (arg != NULL && *arg != '\0');
83399048Sdes		break;
83499048Sdes
83598684Sdes	case oDeprecated:
83698684Sdes		debug("%s line %d: Deprecated option \"%s\"",
83798684Sdes		    filename, linenum, keyword);
83898684Sdes		return 0;
83998684Sdes
840124211Sdes	case oUnsupported:
841124211Sdes		error("%s line %d: Unsupported option \"%s\"",
842124211Sdes		    filename, linenum, keyword);
843124211Sdes		return 0;
844124211Sdes
84557429Smarkm	default:
84657429Smarkm		fatal("process_config_line: Unimplemented opcode %d", opcode);
84757429Smarkm	}
84857429Smarkm
84957429Smarkm	/* Check that there is no garbage at end of line. */
85076262Sgreen	if ((arg = strdelim(&s)) != NULL && *arg != '\0') {
85165674Skris		fatal("%.200s line %d: garbage at end of line; \"%.200s\".",
852149753Sdes		    filename, linenum, arg);
85365674Skris	}
85457429Smarkm	return 0;
85557429Smarkm}
85657429Smarkm
85757429Smarkm
85857429Smarkm/*
85957429Smarkm * Reads the config file and modifies the options accordingly.  Options
86057429Smarkm * should already be initialized before this call.  This never returns if
86192559Sdes * there is an error.  If the file does not exist, this returns 0.
86257429Smarkm */
86357429Smarkm
86492559Sdesint
865137019Sdesread_config_file(const char *filename, const char *host, Options *options,
866137019Sdes    int checkperm)
86757429Smarkm{
86857429Smarkm	FILE *f;
86957429Smarkm	char line[1024];
87057429Smarkm	int active, linenum;
87157429Smarkm	int bad_options = 0;
87257429Smarkm
87357429Smarkm	/* Open the file. */
874137019Sdes	if ((f = fopen(filename, "r")) == NULL)
87592559Sdes		return 0;
87657429Smarkm
877137019Sdes	if (checkperm) {
878137019Sdes		struct stat sb;
879137019Sdes
880137019Sdes		if (fstat(fileno(f), &sb) == -1)
881137019Sdes			fatal("fstat %s: %s", filename, strerror(errno));
882137019Sdes		if (((sb.st_uid != 0 && sb.st_uid != getuid()) ||
883137019Sdes		    (sb.st_mode & 022) != 0))
884137019Sdes			fatal("Bad owner or permissions on %s", filename);
885137019Sdes	}
886137019Sdes
88757429Smarkm	debug("Reading configuration data %.200s", filename);
88857429Smarkm
88957429Smarkm	/*
89057429Smarkm	 * Mark that we are now processing the options.  This flag is turned
89157429Smarkm	 * on/off by Host specifications.
89257429Smarkm	 */
89357429Smarkm	active = 1;
89457429Smarkm	linenum = 0;
89557429Smarkm	while (fgets(line, sizeof(line), f)) {
89657429Smarkm		/* Update line number counter. */
89757429Smarkm		linenum++;
89857429Smarkm		if (process_config_line(options, host, line, filename, linenum, &active) != 0)
89957429Smarkm			bad_options++;
90057429Smarkm	}
90157429Smarkm	fclose(f);
90257429Smarkm	if (bad_options > 0)
90376262Sgreen		fatal("%s: terminating, %d bad configuration options",
90492559Sdes		    filename, bad_options);
90592559Sdes	return 1;
90657429Smarkm}
90757429Smarkm
90857429Smarkm/*
90957429Smarkm * Initializes options to special values that indicate that they have not yet
91057429Smarkm * been set.  Read_config_file will only set options with this value. Options
91157429Smarkm * are processed in the following order: command line, user config file,
91257429Smarkm * system config file.  Last, fill_default_options is called.
91357429Smarkm */
91457429Smarkm
91560576Skrisvoid
91657429Smarkminitialize_options(Options * options)
91757429Smarkm{
91857429Smarkm	memset(options, 'X', sizeof(*options));
91957429Smarkm	options->forward_agent = -1;
92057429Smarkm	options->forward_x11 = -1;
921126277Sdes	options->forward_x11_trusted = -1;
92265674Skris	options->xauth_location = NULL;
92357429Smarkm	options->gateway_ports = -1;
92457429Smarkm	options->use_privileged_port = -1;
92557429Smarkm	options->rsa_authentication = -1;
92676262Sgreen	options->pubkey_authentication = -1;
92792559Sdes	options->challenge_response_authentication = -1;
928124211Sdes	options->gss_authentication = -1;
929124211Sdes	options->gss_deleg_creds = -1;
93057429Smarkm	options->password_authentication = -1;
93169591Sgreen	options->kbd_interactive_authentication = -1;
93269591Sgreen	options->kbd_interactive_devices = NULL;
93357429Smarkm	options->rhosts_rsa_authentication = -1;
93476262Sgreen	options->hostbased_authentication = -1;
93557429Smarkm	options->batch_mode = -1;
93657429Smarkm	options->check_host_ip = -1;
93757429Smarkm	options->strict_host_key_checking = -1;
93857429Smarkm	options->compression = -1;
939126277Sdes	options->tcp_keep_alive = -1;
94057429Smarkm	options->compression_level = -1;
94157429Smarkm	options->port = -1;
942124211Sdes	options->address_family = -1;
94357429Smarkm	options->connection_attempts = -1;
944124211Sdes	options->connection_timeout = -1;
94557429Smarkm	options->number_of_password_prompts = -1;
94657429Smarkm	options->cipher = -1;
94760576Skris	options->ciphers = NULL;
94876262Sgreen	options->macs = NULL;
94976262Sgreen	options->hostkeyalgorithms = NULL;
95060576Skris	options->protocol = SSH_PROTO_UNKNOWN;
95157429Smarkm	options->num_identity_files = 0;
95257429Smarkm	options->hostname = NULL;
95376262Sgreen	options->host_key_alias = NULL;
95457429Smarkm	options->proxy_command = NULL;
95557429Smarkm	options->user = NULL;
95657429Smarkm	options->escape_char = -1;
95757429Smarkm	options->system_hostfile = NULL;
95857429Smarkm	options->user_hostfile = NULL;
95960576Skris	options->system_hostfile2 = NULL;
96060576Skris	options->user_hostfile2 = NULL;
96157429Smarkm	options->num_local_forwards = 0;
96257429Smarkm	options->num_remote_forwards = 0;
96392559Sdes	options->clear_forwardings = -1;
96492559Sdes	options->log_level = SYSLOG_LEVEL_NOT_SET;
96576262Sgreen	options->preferred_authentications = NULL;
96692559Sdes	options->bind_address = NULL;
96792559Sdes	options->smartcard_device = NULL;
968113911Sdes	options->enable_ssh_keysign = - 1;
96992559Sdes	options->no_host_authentication_for_localhost = - 1;
970128460Sdes	options->identities_only = - 1;
971124211Sdes	options->rekey_limit = - 1;
972124211Sdes	options->verify_host_key_dns = -1;
973126277Sdes	options->server_alive_interval = -1;
974126277Sdes	options->server_alive_count_max = -1;
975137019Sdes	options->num_send_env = 0;
976137019Sdes	options->control_path = NULL;
977137019Sdes	options->control_master = -1;
978147005Sdes	options->hash_known_hosts = -1;
97957429Smarkm}
98057429Smarkm
98157429Smarkm/*
98257429Smarkm * Called after processing other sources of option data, this fills those
98357429Smarkm * options for which no value has been specified with their default values.
98457429Smarkm */
98557429Smarkm
98660576Skrisvoid
98757429Smarkmfill_default_options(Options * options)
98857429Smarkm{
98976262Sgreen	int len;
99076262Sgreen
99157429Smarkm	if (options->forward_agent == -1)
99261203Skris		options->forward_agent = 0;
99357429Smarkm	if (options->forward_x11 == -1)
99457708Sgreen		options->forward_x11 = 0;
995126277Sdes	if (options->forward_x11_trusted == -1)
996126277Sdes		options->forward_x11_trusted = 0;
99765674Skris	if (options->xauth_location == NULL)
99892559Sdes		options->xauth_location = _PATH_XAUTH;
99957429Smarkm	if (options->gateway_ports == -1)
100057429Smarkm		options->gateway_ports = 0;
100157429Smarkm	if (options->use_privileged_port == -1)
100276262Sgreen		options->use_privileged_port = 0;
100357429Smarkm	if (options->rsa_authentication == -1)
100457429Smarkm		options->rsa_authentication = 1;
100576262Sgreen	if (options->pubkey_authentication == -1)
100676262Sgreen		options->pubkey_authentication = 1;
100792559Sdes	if (options->challenge_response_authentication == -1)
100892559Sdes		options->challenge_response_authentication = 1;
1009124211Sdes	if (options->gss_authentication == -1)
1010126277Sdes		options->gss_authentication = 0;
1011124211Sdes	if (options->gss_deleg_creds == -1)
1012124211Sdes		options->gss_deleg_creds = 0;
101357429Smarkm	if (options->password_authentication == -1)
101457429Smarkm		options->password_authentication = 1;
101569591Sgreen	if (options->kbd_interactive_authentication == -1)
101676262Sgreen		options->kbd_interactive_authentication = 1;
101757429Smarkm	if (options->rhosts_rsa_authentication == -1)
101898684Sdes		options->rhosts_rsa_authentication = 0;
101976262Sgreen	if (options->hostbased_authentication == -1)
102076262Sgreen		options->hostbased_authentication = 0;
102157429Smarkm	if (options->batch_mode == -1)
102257429Smarkm		options->batch_mode = 0;
102357429Smarkm	if (options->check_host_ip == -1)
102499048Sdes		options->check_host_ip = 0;
102557429Smarkm	if (options->strict_host_key_checking == -1)
102657429Smarkm		options->strict_host_key_checking = 2;	/* 2 is default */
102757429Smarkm	if (options->compression == -1)
102857429Smarkm		options->compression = 0;
1029126277Sdes	if (options->tcp_keep_alive == -1)
1030126277Sdes		options->tcp_keep_alive = 1;
103157429Smarkm	if (options->compression_level == -1)
103257429Smarkm		options->compression_level = 6;
103357429Smarkm	if (options->port == -1)
103457429Smarkm		options->port = 0;	/* Filled in ssh_connect. */
1035124211Sdes	if (options->address_family == -1)
1036124211Sdes		options->address_family = AF_UNSPEC;
103757429Smarkm	if (options->connection_attempts == -1)
103892559Sdes		options->connection_attempts = 1;
103957429Smarkm	if (options->number_of_password_prompts == -1)
104057429Smarkm		options->number_of_password_prompts = 3;
104157429Smarkm	/* Selected in ssh_login(). */
104257429Smarkm	if (options->cipher == -1)
104357429Smarkm		options->cipher = SSH_CIPHER_NOT_SET;
104460576Skris	/* options->ciphers, default set in myproposals.h */
104576262Sgreen	/* options->macs, default set in myproposals.h */
104676262Sgreen	/* options->hostkeyalgorithms, default set in myproposals.h */
104760576Skris	if (options->protocol == SSH_PROTO_UNKNOWN)
104876262Sgreen		options->protocol = SSH_PROTO_1|SSH_PROTO_2;
104957429Smarkm	if (options->num_identity_files == 0) {
105076262Sgreen		if (options->protocol & SSH_PROTO_1) {
105176262Sgreen			len = 2 + strlen(_PATH_SSH_CLIENT_IDENTITY) + 1;
105276262Sgreen			options->identity_files[options->num_identity_files] =
105376262Sgreen			    xmalloc(len);
105476262Sgreen			snprintf(options->identity_files[options->num_identity_files++],
105576262Sgreen			    len, "~/%.100s", _PATH_SSH_CLIENT_IDENTITY);
105676262Sgreen		}
105776262Sgreen		if (options->protocol & SSH_PROTO_2) {
105876262Sgreen			len = 2 + strlen(_PATH_SSH_CLIENT_ID_RSA) + 1;
105976262Sgreen			options->identity_files[options->num_identity_files] =
106076262Sgreen			    xmalloc(len);
106176262Sgreen			snprintf(options->identity_files[options->num_identity_files++],
106276262Sgreen			    len, "~/%.100s", _PATH_SSH_CLIENT_ID_RSA);
106376262Sgreen
106476262Sgreen			len = 2 + strlen(_PATH_SSH_CLIENT_ID_DSA) + 1;
106576262Sgreen			options->identity_files[options->num_identity_files] =
106676262Sgreen			    xmalloc(len);
106776262Sgreen			snprintf(options->identity_files[options->num_identity_files++],
106876262Sgreen			    len, "~/%.100s", _PATH_SSH_CLIENT_ID_DSA);
106976262Sgreen		}
107057429Smarkm	}
107157429Smarkm	if (options->escape_char == -1)
107257429Smarkm		options->escape_char = '~';
107357429Smarkm	if (options->system_hostfile == NULL)
107476262Sgreen		options->system_hostfile = _PATH_SSH_SYSTEM_HOSTFILE;
107557429Smarkm	if (options->user_hostfile == NULL)
107676262Sgreen		options->user_hostfile = _PATH_SSH_USER_HOSTFILE;
107760576Skris	if (options->system_hostfile2 == NULL)
107876262Sgreen		options->system_hostfile2 = _PATH_SSH_SYSTEM_HOSTFILE2;
107960576Skris	if (options->user_hostfile2 == NULL)
108076262Sgreen		options->user_hostfile2 = _PATH_SSH_USER_HOSTFILE2;
108192559Sdes	if (options->log_level == SYSLOG_LEVEL_NOT_SET)
108257429Smarkm		options->log_level = SYSLOG_LEVEL_INFO;
108392559Sdes	if (options->clear_forwardings == 1)
108492559Sdes		clear_forwardings(options);
108592559Sdes	if (options->no_host_authentication_for_localhost == - 1)
108692559Sdes		options->no_host_authentication_for_localhost = 0;
1087128460Sdes	if (options->identities_only == -1)
1088128460Sdes		options->identities_only = 0;
1089113911Sdes	if (options->enable_ssh_keysign == -1)
1090113911Sdes		options->enable_ssh_keysign = 0;
1091124211Sdes	if (options->rekey_limit == -1)
1092124211Sdes		options->rekey_limit = 0;
1093124211Sdes	if (options->verify_host_key_dns == -1)
1094124211Sdes		options->verify_host_key_dns = 0;
1095126277Sdes	if (options->server_alive_interval == -1)
1096126277Sdes		options->server_alive_interval = 0;
1097126277Sdes	if (options->server_alive_count_max == -1)
1098126277Sdes		options->server_alive_count_max = 3;
1099137019Sdes	if (options->control_master == -1)
1100137019Sdes		options->control_master = 0;
1101147005Sdes	if (options->hash_known_hosts == -1)
1102147005Sdes		options->hash_known_hosts = 0;
110357429Smarkm	/* options->proxy_command should not be set by default */
110457429Smarkm	/* options->user will be set in the main program if appropriate */
110557429Smarkm	/* options->hostname will be set in the main program if appropriate */
110676262Sgreen	/* options->host_key_alias should not be set by default */
110776262Sgreen	/* options->preferred_authentications will be set in ssh */
110857429Smarkm}
1109147005Sdes
1110147005Sdes/*
1111147005Sdes * parse_forward
1112147005Sdes * parses a string containing a port forwarding specification of the form:
1113147005Sdes *	[listenhost:]listenport:connecthost:connectport
1114147005Sdes * returns number of arguments parsed or zero on error
1115147005Sdes */
1116147005Sdesint
1117147005Sdesparse_forward(Forward *fwd, const char *fwdspec)
1118147005Sdes{
1119147005Sdes	int i;
1120147005Sdes	char *p, *cp, *fwdarg[4];
1121147005Sdes
1122147005Sdes	memset(fwd, '\0', sizeof(*fwd));
1123147005Sdes
1124147005Sdes	cp = p = xstrdup(fwdspec);
1125147005Sdes
1126147005Sdes	/* skip leading spaces */
1127147005Sdes	while (*cp && isspace(*cp))
1128147005Sdes		cp++;
1129147005Sdes
1130147005Sdes	for (i = 0; i < 4; ++i)
1131147005Sdes		if ((fwdarg[i] = hpdelim(&cp)) == NULL)
1132147005Sdes			break;
1133147005Sdes
1134147005Sdes	/* Check for trailing garbage in 4-arg case*/
1135147005Sdes	if (cp != NULL)
1136147005Sdes		i = 0;	/* failure */
1137147005Sdes
1138147005Sdes	switch (i) {
1139147005Sdes	case 3:
1140147005Sdes		fwd->listen_host = NULL;
1141147005Sdes		fwd->listen_port = a2port(fwdarg[0]);
1142147005Sdes		fwd->connect_host = xstrdup(cleanhostname(fwdarg[1]));
1143147005Sdes		fwd->connect_port = a2port(fwdarg[2]);
1144147005Sdes		break;
1145147005Sdes
1146147005Sdes	case 4:
1147147005Sdes		fwd->listen_host = xstrdup(cleanhostname(fwdarg[0]));
1148147005Sdes		fwd->listen_port = a2port(fwdarg[1]);
1149147005Sdes		fwd->connect_host = xstrdup(cleanhostname(fwdarg[2]));
1150147005Sdes		fwd->connect_port = a2port(fwdarg[3]);
1151147005Sdes		break;
1152147005Sdes	default:
1153147005Sdes		i = 0; /* failure */
1154147005Sdes	}
1155147005Sdes
1156147005Sdes	xfree(p);
1157147005Sdes
1158147005Sdes	if (fwd->listen_port == 0 && fwd->connect_port == 0)
1159147005Sdes		goto fail_free;
1160147005Sdes
1161147005Sdes	if (fwd->connect_host != NULL &&
1162147005Sdes	    strlen(fwd->connect_host) >= NI_MAXHOST)
1163147005Sdes		goto fail_free;
1164147005Sdes
1165147005Sdes	return (i);
1166147005Sdes
1167147005Sdes fail_free:
1168147005Sdes	if (fwd->connect_host != NULL)
1169147005Sdes		xfree(fwd->connect_host);
1170147005Sdes	if (fwd->listen_host != NULL)
1171147005Sdes		xfree(fwd->listen_host);
1172147005Sdes	return (0);
1173147005Sdes}
1174