readconf.c revision 162856
1162856Sdes/* $OpenBSD: readconf.c,v 1.159 2006/08/03 03:34:42 deraadt Exp $ */
257429Smarkm/*
357429Smarkm * Author: Tatu Ylonen <ylo@cs.hut.fi>
457429Smarkm * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
557429Smarkm *                    All rights reserved
657429Smarkm * Functions for reading the configuration files.
760576Skris *
865674Skris * As far as I am concerned, the code I have written for this software
965674Skris * can be used freely for any purpose.  Any derived versions of this
1065674Skris * software must be clearly marked as such, and if the derived work is
1165674Skris * incompatible with the protocol description in the RFC file, it must be
1265674Skris * called by a name other than "ssh" or "Secure Shell".
1357429Smarkm */
1457429Smarkm
1557429Smarkm#include "includes.h"
16162856Sdes__RCSID("$FreeBSD: head/crypto/openssh/readconf.c 162856 2006-09-30 13:38:06Z des $");
1757429Smarkm
18162856Sdes#include <sys/types.h>
19162856Sdes#include <sys/stat.h>
20162856Sdes#include <sys/socket.h>
21162856Sdes
22162856Sdes#include <netinet/in.h>
23162856Sdes
24162856Sdes#include <ctype.h>
25162856Sdes#include <errno.h>
26162856Sdes#include <netdb.h>
27162856Sdes#include <signal.h>
28162856Sdes#include <stdarg.h>
29162856Sdes#include <stdio.h>
30162856Sdes#include <string.h>
31162856Sdes#include <unistd.h>
32162856Sdes
33162856Sdes#include "xmalloc.h"
3457429Smarkm#include "ssh.h"
3576262Sgreen#include "compat.h"
3676262Sgreen#include "cipher.h"
3776262Sgreen#include "pathnames.h"
3876262Sgreen#include "log.h"
39162856Sdes#include "key.h"
4057429Smarkm#include "readconf.h"
4160576Skris#include "match.h"
4276262Sgreen#include "misc.h"
43162856Sdes#include "buffer.h"
4476262Sgreen#include "kex.h"
4576262Sgreen#include "mac.h"
4657429Smarkm
4757429Smarkm/* Format of the configuration file:
4857429Smarkm
4957429Smarkm   # Configuration data is parsed as follows:
5057429Smarkm   #  1. command line options
5157429Smarkm   #  2. user-specific file
5257429Smarkm   #  3. system-wide file
5357429Smarkm   # Any configuration value is only changed the first time it is set.
5457429Smarkm   # Thus, host-specific definitions should be at the beginning of the
5557429Smarkm   # configuration file, and defaults at the end.
5657429Smarkm
5757429Smarkm   # Host-specific declarations.  These may override anything above.  A single
5857429Smarkm   # host may match multiple declarations; these are processed in the order
5957429Smarkm   # that they are given in.
6057429Smarkm
6157429Smarkm   Host *.ngs.fi ngs.fi
6298684Sdes     User foo
6357429Smarkm
6457429Smarkm   Host fake.com
6557429Smarkm     HostName another.host.name.real.org
6657429Smarkm     User blaah
6757429Smarkm     Port 34289
6857429Smarkm     ForwardX11 no
6957429Smarkm     ForwardAgent no
7057429Smarkm
7157429Smarkm   Host books.com
7257429Smarkm     RemoteForward 9999 shadows.cs.hut.fi:9999
7357429Smarkm     Cipher 3des
7457429Smarkm
7557429Smarkm   Host fascist.blob.com
7657429Smarkm     Port 23123
7757429Smarkm     User tylonen
7857429Smarkm     PasswordAuthentication no
7957429Smarkm
8057429Smarkm   Host puukko.hut.fi
8157429Smarkm     User t35124p
8257429Smarkm     ProxyCommand ssh-proxy %h %p
8357429Smarkm
8457429Smarkm   Host *.fr
8598684Sdes     PublicKeyAuthentication no
8657429Smarkm
8757429Smarkm   Host *.su
8857429Smarkm     Cipher none
8957429Smarkm     PasswordAuthentication no
9057429Smarkm
91157019Sdes   Host vpn.fake.com
92157019Sdes     Tunnel yes
93157019Sdes     TunnelDevice 3
94157019Sdes
9557429Smarkm   # Defaults for various options
9657429Smarkm   Host *
9757429Smarkm     ForwardAgent no
9876262Sgreen     ForwardX11 no
9957429Smarkm     PasswordAuthentication yes
10057429Smarkm     RSAAuthentication yes
10157429Smarkm     RhostsRSAAuthentication yes
10257429Smarkm     StrictHostKeyChecking yes
103126277Sdes     TcpKeepAlive no
10457429Smarkm     IdentityFile ~/.ssh/identity
10557429Smarkm     Port 22
10657429Smarkm     EscapeChar ~
10757429Smarkm
10857429Smarkm*/
10957429Smarkm
11057429Smarkm/* Keyword tokens. */
11157429Smarkm
11257429Smarkmtypedef enum {
11357429Smarkm	oBadOption,
114126277Sdes	oForwardAgent, oForwardX11, oForwardX11Trusted, oGatewayPorts,
115162856Sdes	oExitOnForwardFailure,
11698684Sdes	oPasswordAuthentication, oRSAAuthentication,
11776262Sgreen	oChallengeResponseAuthentication, oXAuthLocation,
11857429Smarkm	oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward,
11957429Smarkm	oUser, oHost, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
12057429Smarkm	oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
12157429Smarkm	oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
122126277Sdes	oCompressionLevel, oTCPKeepAlive, oNumberOfPasswordPrompts,
12376262Sgreen	oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oMacs,
12476262Sgreen	oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication,
12576262Sgreen	oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
12676262Sgreen	oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
12792559Sdes	oHostKeyAlgorithms, oBindAddress, oSmartcardDevice,
12893698Sdes	oClearAllForwardings, oNoHostAuthenticationForLocalhost,
129124211Sdes	oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
130124211Sdes	oAddressFamily, oGssAuthentication, oGssDelegateCreds,
131128461Sdes	oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
132147005Sdes	oSendEnv, oControlPath, oControlMaster, oHashKnownHosts,
133157019Sdes	oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand,
13499048Sdes	oVersionAddendum,
135124211Sdes	oDeprecated, oUnsupported
13657429Smarkm} OpCodes;
13757429Smarkm
13857429Smarkm/* Textual representations of the tokens. */
13957429Smarkm
14057429Smarkmstatic struct {
14157429Smarkm	const char *name;
14257429Smarkm	OpCodes opcode;
14357429Smarkm} keywords[] = {
14457429Smarkm	{ "forwardagent", oForwardAgent },
14557429Smarkm	{ "forwardx11", oForwardX11 },
146126277Sdes	{ "forwardx11trusted", oForwardX11Trusted },
147162856Sdes	{ "exitonforwardfailure", oExitOnForwardFailure },
14865674Skris	{ "xauthlocation", oXAuthLocation },
14957429Smarkm	{ "gatewayports", oGatewayPorts },
15057429Smarkm	{ "useprivilegedport", oUsePrivilegedPort },
151124211Sdes	{ "rhostsauthentication", oDeprecated },
15257429Smarkm	{ "passwordauthentication", oPasswordAuthentication },
15369591Sgreen	{ "kbdinteractiveauthentication", oKbdInteractiveAuthentication },
15469591Sgreen	{ "kbdinteractivedevices", oKbdInteractiveDevices },
15557429Smarkm	{ "rsaauthentication", oRSAAuthentication },
15676262Sgreen	{ "pubkeyauthentication", oPubkeyAuthentication },
15776262Sgreen	{ "dsaauthentication", oPubkeyAuthentication },		    /* alias */
15876262Sgreen	{ "rhostsrsaauthentication", oRhostsRSAAuthentication },
15976262Sgreen	{ "hostbasedauthentication", oHostbasedAuthentication },
16076262Sgreen	{ "challengeresponseauthentication", oChallengeResponseAuthentication },
16176262Sgreen	{ "skeyauthentication", oChallengeResponseAuthentication }, /* alias */
16276262Sgreen	{ "tisauthentication", oChallengeResponseAuthentication },  /* alias */
163124211Sdes	{ "kerberosauthentication", oUnsupported },
164124211Sdes	{ "kerberostgtpassing", oUnsupported },
165124211Sdes	{ "afstokenpassing", oUnsupported },
166124211Sdes#if defined(GSSAPI)
167124211Sdes	{ "gssapiauthentication", oGssAuthentication },
168124211Sdes	{ "gssapidelegatecredentials", oGssDelegateCreds },
169124211Sdes#else
170124211Sdes	{ "gssapiauthentication", oUnsupported },
171124211Sdes	{ "gssapidelegatecredentials", oUnsupported },
17292559Sdes#endif
17398684Sdes	{ "fallbacktorsh", oDeprecated },
17498684Sdes	{ "usersh", oDeprecated },
17557429Smarkm	{ "identityfile", oIdentityFile },
17676262Sgreen	{ "identityfile2", oIdentityFile },			/* alias */
177128460Sdes	{ "identitiesonly", oIdentitiesOnly },
17857429Smarkm	{ "hostname", oHostName },
17976262Sgreen	{ "hostkeyalias", oHostKeyAlias },
18057429Smarkm	{ "proxycommand", oProxyCommand },
18157429Smarkm	{ "port", oPort },
18257429Smarkm	{ "cipher", oCipher },
18360576Skris	{ "ciphers", oCiphers },
18476262Sgreen	{ "macs", oMacs },
18560576Skris	{ "protocol", oProtocol },
18657429Smarkm	{ "remoteforward", oRemoteForward },
18757429Smarkm	{ "localforward", oLocalForward },
18857429Smarkm	{ "user", oUser },
18957429Smarkm	{ "host", oHost },
19057429Smarkm	{ "escapechar", oEscapeChar },
19157429Smarkm	{ "globalknownhostsfile", oGlobalKnownHostsFile },
19292559Sdes	{ "userknownhostsfile", oUserKnownHostsFile },		/* obsolete */
19360576Skris	{ "globalknownhostsfile2", oGlobalKnownHostsFile2 },
19492559Sdes	{ "userknownhostsfile2", oUserKnownHostsFile2 },	/* obsolete */
19557429Smarkm	{ "connectionattempts", oConnectionAttempts },
19657429Smarkm	{ "batchmode", oBatchMode },
19757429Smarkm	{ "checkhostip", oCheckHostIP },
19857429Smarkm	{ "stricthostkeychecking", oStrictHostKeyChecking },
19957429Smarkm	{ "compression", oCompression },
20057429Smarkm	{ "compressionlevel", oCompressionLevel },
201126277Sdes	{ "tcpkeepalive", oTCPKeepAlive },
202126277Sdes	{ "keepalive", oTCPKeepAlive },				/* obsolete */
20357429Smarkm	{ "numberofpasswordprompts", oNumberOfPasswordPrompts },
20457429Smarkm	{ "loglevel", oLogLevel },
20576262Sgreen	{ "dynamicforward", oDynamicForward },
20676262Sgreen	{ "preferredauthentications", oPreferredAuthentications },
20776262Sgreen	{ "hostkeyalgorithms", oHostKeyAlgorithms },
20892559Sdes	{ "bindaddress", oBindAddress },
209124211Sdes#ifdef SMARTCARD
21092559Sdes	{ "smartcarddevice", oSmartcardDevice },
211124211Sdes#else
212124211Sdes	{ "smartcarddevice", oUnsupported },
213124211Sdes#endif
21492559Sdes	{ "clearallforwardings", oClearAllForwardings },
215113911Sdes	{ "enablesshkeysign", oEnableSSHKeysign },
216124211Sdes	{ "verifyhostkeydns", oVerifyHostKeyDNS },
21792559Sdes	{ "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
218124211Sdes	{ "rekeylimit", oRekeyLimit },
219124211Sdes	{ "connecttimeout", oConnectTimeout },
220124211Sdes	{ "addressfamily", oAddressFamily },
221126277Sdes	{ "serveraliveinterval", oServerAliveInterval },
222126277Sdes	{ "serveralivecountmax", oServerAliveCountMax },
223137019Sdes	{ "sendenv", oSendEnv },
224137019Sdes	{ "controlpath", oControlPath },
225137019Sdes	{ "controlmaster", oControlMaster },
226147005Sdes	{ "hashknownhosts", oHashKnownHosts },
227157019Sdes	{ "tunnel", oTunnel },
228157019Sdes	{ "tunneldevice", oTunnelDevice },
229157019Sdes	{ "localcommand", oLocalCommand },
230157019Sdes	{ "permitlocalcommand", oPermitLocalCommand },
23199048Sdes	{ "versionaddendum", oVersionAddendum },
23292559Sdes	{ NULL, oBadOption }
23357429Smarkm};
23457429Smarkm
23557429Smarkm/*
23657429Smarkm * Adds a local TCP/IP port forward to options.  Never returns if there is an
23757429Smarkm * error.
23857429Smarkm */
23957429Smarkm
24060576Skrisvoid
241147005Sdesadd_local_forward(Options *options, const Forward *newfwd)
24257429Smarkm{
24357429Smarkm	Forward *fwd;
244106130Sdes#ifndef NO_IPPORT_RESERVED_CONCEPT
24557429Smarkm	extern uid_t original_real_uid;
246147005Sdes	if (newfwd->listen_port < IPPORT_RESERVED && original_real_uid != 0)
24776262Sgreen		fatal("Privileged ports can only be forwarded by root.");
24898941Sdes#endif
24957429Smarkm	if (options->num_local_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
25057429Smarkm		fatal("Too many local forwards (max %d).", SSH_MAX_FORWARDS_PER_DIRECTION);
25157429Smarkm	fwd = &options->local_forwards[options->num_local_forwards++];
252147005Sdes
253147005Sdes	fwd->listen_host = (newfwd->listen_host == NULL) ?
254147005Sdes	    NULL : xstrdup(newfwd->listen_host);
255147005Sdes	fwd->listen_port = newfwd->listen_port;
256147005Sdes	fwd->connect_host = xstrdup(newfwd->connect_host);
257147005Sdes	fwd->connect_port = newfwd->connect_port;
25857429Smarkm}
25957429Smarkm
26057429Smarkm/*
26157429Smarkm * Adds a remote TCP/IP port forward to options.  Never returns if there is
26257429Smarkm * an error.
26357429Smarkm */
26457429Smarkm
26560576Skrisvoid
266147005Sdesadd_remote_forward(Options *options, const Forward *newfwd)
26757429Smarkm{
26857429Smarkm	Forward *fwd;
26957429Smarkm	if (options->num_remote_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
27057429Smarkm		fatal("Too many remote forwards (max %d).",
27192559Sdes		    SSH_MAX_FORWARDS_PER_DIRECTION);
27257429Smarkm	fwd = &options->remote_forwards[options->num_remote_forwards++];
273147005Sdes
274147005Sdes	fwd->listen_host = (newfwd->listen_host == NULL) ?
275147005Sdes	    NULL : xstrdup(newfwd->listen_host);
276147005Sdes	fwd->listen_port = newfwd->listen_port;
277147005Sdes	fwd->connect_host = xstrdup(newfwd->connect_host);
278147005Sdes	fwd->connect_port = newfwd->connect_port;
27957429Smarkm}
28057429Smarkm
28192559Sdesstatic void
28292559Sdesclear_forwardings(Options *options)
28392559Sdes{
28492559Sdes	int i;
28592559Sdes
286147005Sdes	for (i = 0; i < options->num_local_forwards; i++) {
287147005Sdes		if (options->local_forwards[i].listen_host != NULL)
288147005Sdes			xfree(options->local_forwards[i].listen_host);
289147005Sdes		xfree(options->local_forwards[i].connect_host);
290147005Sdes	}
29192559Sdes	options->num_local_forwards = 0;
292147005Sdes	for (i = 0; i < options->num_remote_forwards; i++) {
293147005Sdes		if (options->remote_forwards[i].listen_host != NULL)
294147005Sdes			xfree(options->remote_forwards[i].listen_host);
295147005Sdes		xfree(options->remote_forwards[i].connect_host);
296147005Sdes	}
29792559Sdes	options->num_remote_forwards = 0;
298157019Sdes	options->tun_open = SSH_TUNMODE_NO;
29992559Sdes}
30092559Sdes
30157429Smarkm/*
30276262Sgreen * Returns the number of the token pointed to by cp or oBadOption.
30357429Smarkm */
30457429Smarkm
30560576Skrisstatic OpCodes
30657429Smarkmparse_token(const char *cp, const char *filename, int linenum)
30757429Smarkm{
30876262Sgreen	u_int i;
30957429Smarkm
31057429Smarkm	for (i = 0; keywords[i].name; i++)
31157429Smarkm		if (strcasecmp(cp, keywords[i].name) == 0)
31257429Smarkm			return keywords[i].opcode;
31357429Smarkm
31476262Sgreen	error("%s: line %d: Bad configuration option: %s",
31576262Sgreen	    filename, linenum, cp);
31657429Smarkm	return oBadOption;
31757429Smarkm}
31857429Smarkm
31957429Smarkm/*
32057429Smarkm * Processes a single option line as used in the configuration files. This
32157429Smarkm * only sets those values that have not already been set.
32257429Smarkm */
323113911Sdes#define WHITESPACE " \t\r\n"
32457429Smarkm
32557429Smarkmint
32657429Smarkmprocess_config_line(Options *options, const char *host,
32757429Smarkm		    char *line, const char *filename, int linenum,
32857429Smarkm		    int *activep)
32957429Smarkm{
330147005Sdes	char *s, **charptr, *endofnumber, *keyword, *arg, *arg2, fwdarg[256];
331162856Sdes	int opcode, *intptr, value, value2, scale;
332162856Sdes	long long orig, val64;
333113911Sdes	size_t len;
334147005Sdes	Forward fwd;
33557429Smarkm
336124211Sdes	/* Strip trailing whitespace */
337147005Sdes	for (len = strlen(line) - 1; len > 0; len--) {
338124211Sdes		if (strchr(WHITESPACE, line[len]) == NULL)
339124211Sdes			break;
340124211Sdes		line[len] = '\0';
341124211Sdes	}
342124211Sdes
34365674Skris	s = line;
34465674Skris	/* Get the keyword. (Each line is supposed to begin with a keyword). */
345162856Sdes	if ((keyword = strdelim(&s)) == NULL)
346162856Sdes		return 0;
34765674Skris	/* Ignore leading whitespace. */
34865674Skris	if (*keyword == '\0')
34965674Skris		keyword = strdelim(&s);
35076262Sgreen	if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#')
35157429Smarkm		return 0;
35257429Smarkm
35365674Skris	opcode = parse_token(keyword, filename, linenum);
35457429Smarkm
35557429Smarkm	switch (opcode) {
35657429Smarkm	case oBadOption:
35757429Smarkm		/* don't panic, but count bad options */
35857429Smarkm		return -1;
35957429Smarkm		/* NOTREACHED */
360124211Sdes	case oConnectTimeout:
361124211Sdes		intptr = &options->connection_timeout;
362126277Sdesparse_time:
363124211Sdes		arg = strdelim(&s);
364124211Sdes		if (!arg || *arg == '\0')
365124211Sdes			fatal("%s line %d: missing time value.",
366124211Sdes			    filename, linenum);
367124211Sdes		if ((value = convtime(arg)) == -1)
368124211Sdes			fatal("%s line %d: invalid time value.",
369124211Sdes			    filename, linenum);
370124211Sdes		if (*intptr == -1)
371124211Sdes			*intptr = value;
372124211Sdes		break;
373124211Sdes
37457429Smarkm	case oForwardAgent:
37557429Smarkm		intptr = &options->forward_agent;
37657429Smarkmparse_flag:
37765674Skris		arg = strdelim(&s);
37865674Skris		if (!arg || *arg == '\0')
37957429Smarkm			fatal("%.200s line %d: Missing yes/no argument.", filename, linenum);
38057429Smarkm		value = 0;	/* To avoid compiler warning... */
38165674Skris		if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
38257429Smarkm			value = 1;
38365674Skris		else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
38457429Smarkm			value = 0;
38557429Smarkm		else
38657429Smarkm			fatal("%.200s line %d: Bad yes/no argument.", filename, linenum);
38757429Smarkm		if (*activep && *intptr == -1)
38857429Smarkm			*intptr = value;
38957429Smarkm		break;
39057429Smarkm
39157429Smarkm	case oForwardX11:
39257429Smarkm		intptr = &options->forward_x11;
39357429Smarkm		goto parse_flag;
39457429Smarkm
395126277Sdes	case oForwardX11Trusted:
396126277Sdes		intptr = &options->forward_x11_trusted;
397126277Sdes		goto parse_flag;
398126277Sdes
39957429Smarkm	case oGatewayPorts:
40057429Smarkm		intptr = &options->gateway_ports;
40157429Smarkm		goto parse_flag;
40257429Smarkm
403162856Sdes	case oExitOnForwardFailure:
404162856Sdes		intptr = &options->exit_on_forward_failure;
405162856Sdes		goto parse_flag;
406162856Sdes
40757429Smarkm	case oUsePrivilegedPort:
40857429Smarkm		intptr = &options->use_privileged_port;
40957429Smarkm		goto parse_flag;
41057429Smarkm
41157429Smarkm	case oPasswordAuthentication:
41257429Smarkm		intptr = &options->password_authentication;
41357429Smarkm		goto parse_flag;
41457429Smarkm
41569591Sgreen	case oKbdInteractiveAuthentication:
41669591Sgreen		intptr = &options->kbd_interactive_authentication;
41769591Sgreen		goto parse_flag;
41869591Sgreen
41969591Sgreen	case oKbdInteractiveDevices:
42069591Sgreen		charptr = &options->kbd_interactive_devices;
42169591Sgreen		goto parse_string;
42269591Sgreen
42376262Sgreen	case oPubkeyAuthentication:
42476262Sgreen		intptr = &options->pubkey_authentication;
42560576Skris		goto parse_flag;
42660576Skris
42757429Smarkm	case oRSAAuthentication:
42857429Smarkm		intptr = &options->rsa_authentication;
42957429Smarkm		goto parse_flag;
43057429Smarkm
43157429Smarkm	case oRhostsRSAAuthentication:
43257429Smarkm		intptr = &options->rhosts_rsa_authentication;
43357429Smarkm		goto parse_flag;
43457429Smarkm
43576262Sgreen	case oHostbasedAuthentication:
43676262Sgreen		intptr = &options->hostbased_authentication;
43757429Smarkm		goto parse_flag;
43857429Smarkm
43992559Sdes	case oChallengeResponseAuthentication:
44092559Sdes		intptr = &options->challenge_response_authentication;
44192559Sdes		goto parse_flag;
442124211Sdes
443124211Sdes	case oGssAuthentication:
444124211Sdes		intptr = &options->gss_authentication;
44557429Smarkm		goto parse_flag;
446124211Sdes
447124211Sdes	case oGssDelegateCreds:
448124211Sdes		intptr = &options->gss_deleg_creds;
44976262Sgreen		goto parse_flag;
450124211Sdes
45157429Smarkm	case oBatchMode:
45257429Smarkm		intptr = &options->batch_mode;
45357429Smarkm		goto parse_flag;
45457429Smarkm
45557429Smarkm	case oCheckHostIP:
45657429Smarkm		intptr = &options->check_host_ip;
45757429Smarkm		goto parse_flag;
45857429Smarkm
459124211Sdes	case oVerifyHostKeyDNS:
460124211Sdes		intptr = &options->verify_host_key_dns;
461126277Sdes		goto parse_yesnoask;
462124211Sdes
46357429Smarkm	case oStrictHostKeyChecking:
46457429Smarkm		intptr = &options->strict_host_key_checking;
465126277Sdesparse_yesnoask:
46665674Skris		arg = strdelim(&s);
46765674Skris		if (!arg || *arg == '\0')
46876262Sgreen			fatal("%.200s line %d: Missing yes/no/ask argument.",
46992559Sdes			    filename, linenum);
47057429Smarkm		value = 0;	/* To avoid compiler warning... */
47165674Skris		if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
47257429Smarkm			value = 1;
47365674Skris		else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
47457429Smarkm			value = 0;
47565674Skris		else if (strcmp(arg, "ask") == 0)
47657429Smarkm			value = 2;
47757429Smarkm		else
47857429Smarkm			fatal("%.200s line %d: Bad yes/no/ask argument.", filename, linenum);
47957429Smarkm		if (*activep && *intptr == -1)
48057429Smarkm			*intptr = value;
48157429Smarkm		break;
48257429Smarkm
48357429Smarkm	case oCompression:
48457429Smarkm		intptr = &options->compression;
48557429Smarkm		goto parse_flag;
48657429Smarkm
487126277Sdes	case oTCPKeepAlive:
488126277Sdes		intptr = &options->tcp_keep_alive;
48957429Smarkm		goto parse_flag;
49057429Smarkm
49192559Sdes	case oNoHostAuthenticationForLocalhost:
49292559Sdes		intptr = &options->no_host_authentication_for_localhost;
49392559Sdes		goto parse_flag;
49492559Sdes
49557429Smarkm	case oNumberOfPasswordPrompts:
49657429Smarkm		intptr = &options->number_of_password_prompts;
49757429Smarkm		goto parse_int;
49857429Smarkm
49957429Smarkm	case oCompressionLevel:
50057429Smarkm		intptr = &options->compression_level;
50157429Smarkm		goto parse_int;
50257429Smarkm
503124211Sdes	case oRekeyLimit:
504124211Sdes		intptr = &options->rekey_limit;
505124211Sdes		arg = strdelim(&s);
506124211Sdes		if (!arg || *arg == '\0')
507124211Sdes			fatal("%.200s line %d: Missing argument.", filename, linenum);
508124211Sdes		if (arg[0] < '0' || arg[0] > '9')
509124211Sdes			fatal("%.200s line %d: Bad number.", filename, linenum);
510162856Sdes		orig = val64 = strtoll(arg, &endofnumber, 10);
511124211Sdes		if (arg == endofnumber)
512124211Sdes			fatal("%.200s line %d: Bad number.", filename, linenum);
513124211Sdes		switch (toupper(*endofnumber)) {
514162856Sdes		case '\0':
515162856Sdes			scale = 1;
516162856Sdes			break;
517124211Sdes		case 'K':
518162856Sdes			scale = 1<<10;
519124211Sdes			break;
520124211Sdes		case 'M':
521162856Sdes			scale = 1<<20;
522124211Sdes			break;
523124211Sdes		case 'G':
524162856Sdes			scale = 1<<30;
525124211Sdes			break;
526162856Sdes		default:
527162856Sdes			fatal("%.200s line %d: Invalid RekeyLimit suffix",
528162856Sdes			    filename, linenum);
529124211Sdes		}
530162856Sdes		val64 *= scale;
531162856Sdes		/* detect integer wrap and too-large limits */
532162856Sdes		if ((val64 / scale) != orig || val64 > INT_MAX)
533162856Sdes			fatal("%.200s line %d: RekeyLimit too large",
534162856Sdes			    filename, linenum);
535162856Sdes		if (val64 < 16)
536162856Sdes			fatal("%.200s line %d: RekeyLimit too small",
537162856Sdes			    filename, linenum);
538124211Sdes		if (*activep && *intptr == -1)
539162856Sdes			*intptr = (int)val64;
540124211Sdes		break;
541124211Sdes
54257429Smarkm	case oIdentityFile:
54365674Skris		arg = strdelim(&s);
54465674Skris		if (!arg || *arg == '\0')
54557429Smarkm			fatal("%.200s line %d: Missing argument.", filename, linenum);
54657429Smarkm		if (*activep) {
54776262Sgreen			intptr = &options->num_identity_files;
54860576Skris			if (*intptr >= SSH_MAX_IDENTITY_FILES)
54957429Smarkm				fatal("%.200s line %d: Too many identity files specified (max %d).",
55092559Sdes				    filename, linenum, SSH_MAX_IDENTITY_FILES);
55176262Sgreen			charptr =  &options->identity_files[*intptr];
55265674Skris			*charptr = xstrdup(arg);
55360576Skris			*intptr = *intptr + 1;
55457429Smarkm		}
55557429Smarkm		break;
55657429Smarkm
55765674Skris	case oXAuthLocation:
55865674Skris		charptr=&options->xauth_location;
55965674Skris		goto parse_string;
56065674Skris
56157429Smarkm	case oUser:
56257429Smarkm		charptr = &options->user;
56357429Smarkmparse_string:
56465674Skris		arg = strdelim(&s);
56565674Skris		if (!arg || *arg == '\0')
56657429Smarkm			fatal("%.200s line %d: Missing argument.", filename, linenum);
56757429Smarkm		if (*activep && *charptr == NULL)
56865674Skris			*charptr = xstrdup(arg);
56957429Smarkm		break;
57057429Smarkm
57157429Smarkm	case oGlobalKnownHostsFile:
57257429Smarkm		charptr = &options->system_hostfile;
57357429Smarkm		goto parse_string;
57457429Smarkm
57557429Smarkm	case oUserKnownHostsFile:
57657429Smarkm		charptr = &options->user_hostfile;
57757429Smarkm		goto parse_string;
57857429Smarkm
57960576Skris	case oGlobalKnownHostsFile2:
58060576Skris		charptr = &options->system_hostfile2;
58160576Skris		goto parse_string;
58260576Skris
58360576Skris	case oUserKnownHostsFile2:
58460576Skris		charptr = &options->user_hostfile2;
58560576Skris		goto parse_string;
58660576Skris
58757429Smarkm	case oHostName:
58857429Smarkm		charptr = &options->hostname;
58957429Smarkm		goto parse_string;
59057429Smarkm
59176262Sgreen	case oHostKeyAlias:
59276262Sgreen		charptr = &options->host_key_alias;
59376262Sgreen		goto parse_string;
59476262Sgreen
59576262Sgreen	case oPreferredAuthentications:
59676262Sgreen		charptr = &options->preferred_authentications;
59776262Sgreen		goto parse_string;
59876262Sgreen
59992559Sdes	case oBindAddress:
60092559Sdes		charptr = &options->bind_address;
60192559Sdes		goto parse_string;
60292559Sdes
60392559Sdes	case oSmartcardDevice:
60492559Sdes		charptr = &options->smartcard_device;
60592559Sdes		goto parse_string;
60692559Sdes
60757429Smarkm	case oProxyCommand:
608157019Sdes		charptr = &options->proxy_command;
609157019Sdesparse_command:
610124211Sdes		if (s == NULL)
611124211Sdes			fatal("%.200s line %d: Missing argument.", filename, linenum);
612113911Sdes		len = strspn(s, WHITESPACE "=");
61357429Smarkm		if (*activep && *charptr == NULL)
614113911Sdes			*charptr = xstrdup(s + len);
61557429Smarkm		return 0;
61657429Smarkm
61757429Smarkm	case oPort:
61857429Smarkm		intptr = &options->port;
61957429Smarkmparse_int:
62065674Skris		arg = strdelim(&s);
62165674Skris		if (!arg || *arg == '\0')
62257429Smarkm			fatal("%.200s line %d: Missing argument.", filename, linenum);
62365674Skris		if (arg[0] < '0' || arg[0] > '9')
62457429Smarkm			fatal("%.200s line %d: Bad number.", filename, linenum);
62557429Smarkm
62657429Smarkm		/* Octal, decimal, or hex format? */
62765674Skris		value = strtol(arg, &endofnumber, 0);
62865674Skris		if (arg == endofnumber)
62957429Smarkm			fatal("%.200s line %d: Bad number.", filename, linenum);
63057429Smarkm		if (*activep && *intptr == -1)
63157429Smarkm			*intptr = value;
63257429Smarkm		break;
63357429Smarkm
63457429Smarkm	case oConnectionAttempts:
63557429Smarkm		intptr = &options->connection_attempts;
63657429Smarkm		goto parse_int;
63757429Smarkm
63857429Smarkm	case oCipher:
63957429Smarkm		intptr = &options->cipher;
64065674Skris		arg = strdelim(&s);
64165674Skris		if (!arg || *arg == '\0')
64261203Skris			fatal("%.200s line %d: Missing argument.", filename, linenum);
64365674Skris		value = cipher_number(arg);
64457429Smarkm		if (value == -1)
64557429Smarkm			fatal("%.200s line %d: Bad cipher '%s'.",
64692559Sdes			    filename, linenum, arg ? arg : "<NONE>");
64757429Smarkm		if (*activep && *intptr == -1)
64857429Smarkm			*intptr = value;
64957429Smarkm		break;
65057429Smarkm
65160576Skris	case oCiphers:
65265674Skris		arg = strdelim(&s);
65365674Skris		if (!arg || *arg == '\0')
65461203Skris			fatal("%.200s line %d: Missing argument.", filename, linenum);
65565674Skris		if (!ciphers_valid(arg))
65660576Skris			fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.",
65792559Sdes			    filename, linenum, arg ? arg : "<NONE>");
65860576Skris		if (*activep && options->ciphers == NULL)
65965674Skris			options->ciphers = xstrdup(arg);
66060576Skris		break;
66160576Skris
66276262Sgreen	case oMacs:
66376262Sgreen		arg = strdelim(&s);
66476262Sgreen		if (!arg || *arg == '\0')
66576262Sgreen			fatal("%.200s line %d: Missing argument.", filename, linenum);
66676262Sgreen		if (!mac_valid(arg))
66776262Sgreen			fatal("%.200s line %d: Bad SSH2 Mac spec '%s'.",
66892559Sdes			    filename, linenum, arg ? arg : "<NONE>");
66976262Sgreen		if (*activep && options->macs == NULL)
67076262Sgreen			options->macs = xstrdup(arg);
67176262Sgreen		break;
67276262Sgreen
67376262Sgreen	case oHostKeyAlgorithms:
67476262Sgreen		arg = strdelim(&s);
67576262Sgreen		if (!arg || *arg == '\0')
67676262Sgreen			fatal("%.200s line %d: Missing argument.", filename, linenum);
67776262Sgreen		if (!key_names_valid2(arg))
67876262Sgreen			fatal("%.200s line %d: Bad protocol 2 host key algorithms '%s'.",
67992559Sdes			    filename, linenum, arg ? arg : "<NONE>");
68076262Sgreen		if (*activep && options->hostkeyalgorithms == NULL)
68176262Sgreen			options->hostkeyalgorithms = xstrdup(arg);
68276262Sgreen		break;
68376262Sgreen
68460576Skris	case oProtocol:
68560576Skris		intptr = &options->protocol;
68665674Skris		arg = strdelim(&s);
68765674Skris		if (!arg || *arg == '\0')
68861203Skris			fatal("%.200s line %d: Missing argument.", filename, linenum);
68965674Skris		value = proto_spec(arg);
69060576Skris		if (value == SSH_PROTO_UNKNOWN)
69160576Skris			fatal("%.200s line %d: Bad protocol spec '%s'.",
69292559Sdes			    filename, linenum, arg ? arg : "<NONE>");
69360576Skris		if (*activep && *intptr == SSH_PROTO_UNKNOWN)
69460576Skris			*intptr = value;
69560576Skris		break;
69660576Skris
69757429Smarkm	case oLogLevel:
69857429Smarkm		intptr = (int *) &options->log_level;
69965674Skris		arg = strdelim(&s);
70065674Skris		value = log_level_number(arg);
70192559Sdes		if (value == SYSLOG_LEVEL_NOT_SET)
70276262Sgreen			fatal("%.200s line %d: unsupported log level '%s'",
70392559Sdes			    filename, linenum, arg ? arg : "<NONE>");
70492559Sdes		if (*activep && (LogLevel) *intptr == SYSLOG_LEVEL_NOT_SET)
70557429Smarkm			*intptr = (LogLevel) value;
70657429Smarkm		break;
70757429Smarkm
70892559Sdes	case oLocalForward:
70957429Smarkm	case oRemoteForward:
71065674Skris		arg = strdelim(&s);
711147005Sdes		if (arg == NULL || *arg == '\0')
71292559Sdes			fatal("%.200s line %d: Missing port argument.",
71392559Sdes			    filename, linenum);
714147005Sdes		arg2 = strdelim(&s);
715147005Sdes		if (arg2 == NULL || *arg2 == '\0')
716147005Sdes			fatal("%.200s line %d: Missing target argument.",
71792559Sdes			    filename, linenum);
718147005Sdes
719147005Sdes		/* construct a string for parse_forward */
720147005Sdes		snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg, arg2);
721147005Sdes
722147005Sdes		if (parse_forward(&fwd, fwdarg) == 0)
72392559Sdes			fatal("%.200s line %d: Bad forwarding specification.",
72492559Sdes			    filename, linenum);
725147005Sdes
72692559Sdes		if (*activep) {
72792559Sdes			if (opcode == oLocalForward)
728147005Sdes				add_local_forward(options, &fwd);
72992559Sdes			else if (opcode == oRemoteForward)
730147005Sdes				add_remote_forward(options, &fwd);
73192559Sdes		}
73257429Smarkm		break;
73357429Smarkm
73476262Sgreen	case oDynamicForward:
73576262Sgreen		arg = strdelim(&s);
73676262Sgreen		if (!arg || *arg == '\0')
73776262Sgreen			fatal("%.200s line %d: Missing port argument.",
73876262Sgreen			    filename, linenum);
739147005Sdes		memset(&fwd, '\0', sizeof(fwd));
740147005Sdes		fwd.connect_host = "socks";
741147005Sdes		fwd.listen_host = hpdelim(&arg);
742147005Sdes		if (fwd.listen_host == NULL ||
743147005Sdes		    strlen(fwd.listen_host) >= NI_MAXHOST)
744147005Sdes			fatal("%.200s line %d: Bad forwarding specification.",
745147005Sdes			    filename, linenum);
746147005Sdes		if (arg) {
747147005Sdes			fwd.listen_port = a2port(arg);
748147005Sdes			fwd.listen_host = cleanhostname(fwd.listen_host);
749147005Sdes		} else {
750147005Sdes			fwd.listen_port = a2port(fwd.listen_host);
751149753Sdes			fwd.listen_host = NULL;
752147005Sdes		}
753147005Sdes		if (fwd.listen_port == 0)
75476262Sgreen			fatal("%.200s line %d: Badly formatted port number.",
75576262Sgreen			    filename, linenum);
75692559Sdes		if (*activep)
757147005Sdes			add_local_forward(options, &fwd);
75876262Sgreen		break;
75976262Sgreen
76092559Sdes	case oClearAllForwardings:
76192559Sdes		intptr = &options->clear_forwardings;
76292559Sdes		goto parse_flag;
76392559Sdes
76457429Smarkm	case oHost:
76557429Smarkm		*activep = 0;
76665674Skris		while ((arg = strdelim(&s)) != NULL && *arg != '\0')
76765674Skris			if (match_pattern(host, arg)) {
76865674Skris				debug("Applying options for %.100s", arg);
76957429Smarkm				*activep = 1;
77057429Smarkm				break;
77157429Smarkm			}
77265674Skris		/* Avoid garbage check below, as strdelim is done. */
77357429Smarkm		return 0;
77457429Smarkm
77557429Smarkm	case oEscapeChar:
77657429Smarkm		intptr = &options->escape_char;
77765674Skris		arg = strdelim(&s);
77865674Skris		if (!arg || *arg == '\0')
77957429Smarkm			fatal("%.200s line %d: Missing argument.", filename, linenum);
78065674Skris		if (arg[0] == '^' && arg[2] == 0 &&
78176262Sgreen		    (u_char) arg[1] >= 64 && (u_char) arg[1] < 128)
78276262Sgreen			value = (u_char) arg[1] & 31;
78365674Skris		else if (strlen(arg) == 1)
78476262Sgreen			value = (u_char) arg[0];
78565674Skris		else if (strcmp(arg, "none") == 0)
78692559Sdes			value = SSH_ESCAPECHAR_NONE;
78757429Smarkm		else {
78857429Smarkm			fatal("%.200s line %d: Bad escape character.",
78992559Sdes			    filename, linenum);
79057429Smarkm			/* NOTREACHED */
79157429Smarkm			value = 0;	/* Avoid compiler warning. */
79257429Smarkm		}
79357429Smarkm		if (*activep && *intptr == -1)
79457429Smarkm			*intptr = value;
79557429Smarkm		break;
79657429Smarkm
797124211Sdes	case oAddressFamily:
798124211Sdes		arg = strdelim(&s);
799149753Sdes		if (!arg || *arg == '\0')
800149753Sdes			fatal("%s line %d: missing address family.",
801149753Sdes			    filename, linenum);
802124211Sdes		intptr = &options->address_family;
803124211Sdes		if (strcasecmp(arg, "inet") == 0)
804124211Sdes			value = AF_INET;
805124211Sdes		else if (strcasecmp(arg, "inet6") == 0)
806124211Sdes			value = AF_INET6;
807124211Sdes		else if (strcasecmp(arg, "any") == 0)
808124211Sdes			value = AF_UNSPEC;
809124211Sdes		else
810124211Sdes			fatal("Unsupported AddressFamily \"%s\"", arg);
811124211Sdes		if (*activep && *intptr == -1)
812124211Sdes			*intptr = value;
813124211Sdes		break;
814124211Sdes
815113911Sdes	case oEnableSSHKeysign:
816113911Sdes		intptr = &options->enable_ssh_keysign;
817113911Sdes		goto parse_flag;
818113911Sdes
819128460Sdes	case oIdentitiesOnly:
820128460Sdes		intptr = &options->identities_only;
821128460Sdes		goto parse_flag;
822128460Sdes
823126277Sdes	case oServerAliveInterval:
824126277Sdes		intptr = &options->server_alive_interval;
825126277Sdes		goto parse_time;
826126277Sdes
827126277Sdes	case oServerAliveCountMax:
828126277Sdes		intptr = &options->server_alive_count_max;
829126277Sdes		goto parse_int;
830126277Sdes
831137019Sdes	case oSendEnv:
832137019Sdes		while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
833137019Sdes			if (strchr(arg, '=') != NULL)
834137019Sdes				fatal("%s line %d: Invalid environment name.",
835137019Sdes				    filename, linenum);
836147005Sdes			if (!*activep)
837147005Sdes				continue;
838137019Sdes			if (options->num_send_env >= MAX_SEND_ENV)
839137019Sdes				fatal("%s line %d: too many send env.",
840137019Sdes				    filename, linenum);
841137019Sdes			options->send_env[options->num_send_env++] =
842137019Sdes			    xstrdup(arg);
843137019Sdes		}
844137019Sdes		break;
845137019Sdes
846137019Sdes	case oControlPath:
847137019Sdes		charptr = &options->control_path;
848137019Sdes		goto parse_string;
849137019Sdes
850137019Sdes	case oControlMaster:
851137019Sdes		intptr = &options->control_master;
852149753Sdes		arg = strdelim(&s);
853149753Sdes		if (!arg || *arg == '\0')
854149753Sdes			fatal("%.200s line %d: Missing ControlMaster argument.",
855149753Sdes			    filename, linenum);
856149753Sdes		value = 0;	/* To avoid compiler warning... */
857149753Sdes		if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
858149753Sdes			value = SSHCTL_MASTER_YES;
859149753Sdes		else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
860149753Sdes			value = SSHCTL_MASTER_NO;
861149753Sdes		else if (strcmp(arg, "auto") == 0)
862149753Sdes			value = SSHCTL_MASTER_AUTO;
863149753Sdes		else if (strcmp(arg, "ask") == 0)
864149753Sdes			value = SSHCTL_MASTER_ASK;
865149753Sdes		else if (strcmp(arg, "autoask") == 0)
866149753Sdes			value = SSHCTL_MASTER_AUTO_ASK;
867149753Sdes		else
868149753Sdes			fatal("%.200s line %d: Bad ControlMaster argument.",
869149753Sdes			    filename, linenum);
870149753Sdes		if (*activep && *intptr == -1)
871149753Sdes			*intptr = value;
872149753Sdes		break;
873137019Sdes
874147005Sdes	case oHashKnownHosts:
875147005Sdes		intptr = &options->hash_known_hosts;
876147005Sdes		goto parse_flag;
877147005Sdes
878157019Sdes	case oTunnel:
879157019Sdes		intptr = &options->tun_open;
880157019Sdes		arg = strdelim(&s);
881157019Sdes		if (!arg || *arg == '\0')
882157019Sdes			fatal("%s line %d: Missing yes/point-to-point/"
883157019Sdes			    "ethernet/no argument.", filename, linenum);
884157019Sdes		value = 0;	/* silence compiler */
885157019Sdes		if (strcasecmp(arg, "ethernet") == 0)
886157019Sdes			value = SSH_TUNMODE_ETHERNET;
887157019Sdes		else if (strcasecmp(arg, "point-to-point") == 0)
888157019Sdes			value = SSH_TUNMODE_POINTOPOINT;
889157019Sdes		else if (strcasecmp(arg, "yes") == 0)
890157019Sdes			value = SSH_TUNMODE_DEFAULT;
891157019Sdes		else if (strcasecmp(arg, "no") == 0)
892157019Sdes			value = SSH_TUNMODE_NO;
893157019Sdes		else
894157019Sdes			fatal("%s line %d: Bad yes/point-to-point/ethernet/"
895157019Sdes			    "no argument: %s", filename, linenum, arg);
896157019Sdes		if (*activep)
897157019Sdes			*intptr = value;
898157019Sdes		break;
899157019Sdes
900157019Sdes	case oTunnelDevice:
901157019Sdes		arg = strdelim(&s);
902157019Sdes		if (!arg || *arg == '\0')
903157019Sdes			fatal("%.200s line %d: Missing argument.", filename, linenum);
904157019Sdes		value = a2tun(arg, &value2);
905157019Sdes		if (value == SSH_TUNID_ERR)
906157019Sdes			fatal("%.200s line %d: Bad tun device.", filename, linenum);
907157019Sdes		if (*activep) {
908157019Sdes			options->tun_local = value;
909157019Sdes			options->tun_remote = value2;
910157019Sdes		}
911157019Sdes		break;
912157019Sdes
913157019Sdes	case oLocalCommand:
914157019Sdes		charptr = &options->local_command;
915157019Sdes		goto parse_command;
916157019Sdes
917157019Sdes	case oPermitLocalCommand:
918157019Sdes		intptr = &options->permit_local_command;
919157019Sdes		goto parse_flag;
920157019Sdes
92199048Sdes	case oVersionAddendum:
92299048Sdes		ssh_version_set_addendum(strtok(s, "\n"));
92399048Sdes		do {
92499048Sdes			arg = strdelim(&s);
92599048Sdes		} while (arg != NULL && *arg != '\0');
92699048Sdes		break;
92799048Sdes
92898684Sdes	case oDeprecated:
92998684Sdes		debug("%s line %d: Deprecated option \"%s\"",
93098684Sdes		    filename, linenum, keyword);
93198684Sdes		return 0;
93298684Sdes
933124211Sdes	case oUnsupported:
934124211Sdes		error("%s line %d: Unsupported option \"%s\"",
935124211Sdes		    filename, linenum, keyword);
936124211Sdes		return 0;
937124211Sdes
93857429Smarkm	default:
93957429Smarkm		fatal("process_config_line: Unimplemented opcode %d", opcode);
94057429Smarkm	}
94157429Smarkm
94257429Smarkm	/* Check that there is no garbage at end of line. */
94376262Sgreen	if ((arg = strdelim(&s)) != NULL && *arg != '\0') {
94465674Skris		fatal("%.200s line %d: garbage at end of line; \"%.200s\".",
945149753Sdes		    filename, linenum, arg);
94665674Skris	}
94757429Smarkm	return 0;
94857429Smarkm}
94957429Smarkm
95057429Smarkm
95157429Smarkm/*
95257429Smarkm * Reads the config file and modifies the options accordingly.  Options
95357429Smarkm * should already be initialized before this call.  This never returns if
95492559Sdes * there is an error.  If the file does not exist, this returns 0.
95557429Smarkm */
95657429Smarkm
95792559Sdesint
958137019Sdesread_config_file(const char *filename, const char *host, Options *options,
959137019Sdes    int checkperm)
96057429Smarkm{
96157429Smarkm	FILE *f;
96257429Smarkm	char line[1024];
96357429Smarkm	int active, linenum;
96457429Smarkm	int bad_options = 0;
96557429Smarkm
96657429Smarkm	/* Open the file. */
967137019Sdes	if ((f = fopen(filename, "r")) == NULL)
96892559Sdes		return 0;
96957429Smarkm
970137019Sdes	if (checkperm) {
971137019Sdes		struct stat sb;
972137019Sdes
973137019Sdes		if (fstat(fileno(f), &sb) == -1)
974137019Sdes			fatal("fstat %s: %s", filename, strerror(errno));
975137019Sdes		if (((sb.st_uid != 0 && sb.st_uid != getuid()) ||
976137019Sdes		    (sb.st_mode & 022) != 0))
977137019Sdes			fatal("Bad owner or permissions on %s", filename);
978137019Sdes	}
979137019Sdes
98057429Smarkm	debug("Reading configuration data %.200s", filename);
98157429Smarkm
98257429Smarkm	/*
98357429Smarkm	 * Mark that we are now processing the options.  This flag is turned
98457429Smarkm	 * on/off by Host specifications.
98557429Smarkm	 */
98657429Smarkm	active = 1;
98757429Smarkm	linenum = 0;
98857429Smarkm	while (fgets(line, sizeof(line), f)) {
98957429Smarkm		/* Update line number counter. */
99057429Smarkm		linenum++;
99157429Smarkm		if (process_config_line(options, host, line, filename, linenum, &active) != 0)
99257429Smarkm			bad_options++;
99357429Smarkm	}
99457429Smarkm	fclose(f);
99557429Smarkm	if (bad_options > 0)
99676262Sgreen		fatal("%s: terminating, %d bad configuration options",
99792559Sdes		    filename, bad_options);
99892559Sdes	return 1;
99957429Smarkm}
100057429Smarkm
100157429Smarkm/*
100257429Smarkm * Initializes options to special values that indicate that they have not yet
100357429Smarkm * been set.  Read_config_file will only set options with this value. Options
100457429Smarkm * are processed in the following order: command line, user config file,
100557429Smarkm * system config file.  Last, fill_default_options is called.
100657429Smarkm */
100757429Smarkm
100860576Skrisvoid
100957429Smarkminitialize_options(Options * options)
101057429Smarkm{
101157429Smarkm	memset(options, 'X', sizeof(*options));
101257429Smarkm	options->forward_agent = -1;
101357429Smarkm	options->forward_x11 = -1;
1014126277Sdes	options->forward_x11_trusted = -1;
1015162856Sdes	options->exit_on_forward_failure = -1;
101665674Skris	options->xauth_location = NULL;
101757429Smarkm	options->gateway_ports = -1;
101857429Smarkm	options->use_privileged_port = -1;
101957429Smarkm	options->rsa_authentication = -1;
102076262Sgreen	options->pubkey_authentication = -1;
102192559Sdes	options->challenge_response_authentication = -1;
1022124211Sdes	options->gss_authentication = -1;
1023124211Sdes	options->gss_deleg_creds = -1;
102457429Smarkm	options->password_authentication = -1;
102569591Sgreen	options->kbd_interactive_authentication = -1;
102669591Sgreen	options->kbd_interactive_devices = NULL;
102757429Smarkm	options->rhosts_rsa_authentication = -1;
102876262Sgreen	options->hostbased_authentication = -1;
102957429Smarkm	options->batch_mode = -1;
103057429Smarkm	options->check_host_ip = -1;
103157429Smarkm	options->strict_host_key_checking = -1;
103257429Smarkm	options->compression = -1;
1033126277Sdes	options->tcp_keep_alive = -1;
103457429Smarkm	options->compression_level = -1;
103557429Smarkm	options->port = -1;
1036124211Sdes	options->address_family = -1;
103757429Smarkm	options->connection_attempts = -1;
1038124211Sdes	options->connection_timeout = -1;
103957429Smarkm	options->number_of_password_prompts = -1;
104057429Smarkm	options->cipher = -1;
104160576Skris	options->ciphers = NULL;
104276262Sgreen	options->macs = NULL;
104376262Sgreen	options->hostkeyalgorithms = NULL;
104460576Skris	options->protocol = SSH_PROTO_UNKNOWN;
104557429Smarkm	options->num_identity_files = 0;
104657429Smarkm	options->hostname = NULL;
104776262Sgreen	options->host_key_alias = NULL;
104857429Smarkm	options->proxy_command = NULL;
104957429Smarkm	options->user = NULL;
105057429Smarkm	options->escape_char = -1;
105157429Smarkm	options->system_hostfile = NULL;
105257429Smarkm	options->user_hostfile = NULL;
105360576Skris	options->system_hostfile2 = NULL;
105460576Skris	options->user_hostfile2 = NULL;
105557429Smarkm	options->num_local_forwards = 0;
105657429Smarkm	options->num_remote_forwards = 0;
105792559Sdes	options->clear_forwardings = -1;
105892559Sdes	options->log_level = SYSLOG_LEVEL_NOT_SET;
105976262Sgreen	options->preferred_authentications = NULL;
106092559Sdes	options->bind_address = NULL;
106192559Sdes	options->smartcard_device = NULL;
1062113911Sdes	options->enable_ssh_keysign = - 1;
106392559Sdes	options->no_host_authentication_for_localhost = - 1;
1064128460Sdes	options->identities_only = - 1;
1065124211Sdes	options->rekey_limit = - 1;
1066124211Sdes	options->verify_host_key_dns = -1;
1067126277Sdes	options->server_alive_interval = -1;
1068126277Sdes	options->server_alive_count_max = -1;
1069137019Sdes	options->num_send_env = 0;
1070137019Sdes	options->control_path = NULL;
1071137019Sdes	options->control_master = -1;
1072147005Sdes	options->hash_known_hosts = -1;
1073157019Sdes	options->tun_open = -1;
1074157019Sdes	options->tun_local = -1;
1075157019Sdes	options->tun_remote = -1;
1076157019Sdes	options->local_command = NULL;
1077157019Sdes	options->permit_local_command = -1;
107857429Smarkm}
107957429Smarkm
108057429Smarkm/*
108157429Smarkm * Called after processing other sources of option data, this fills those
108257429Smarkm * options for which no value has been specified with their default values.
108357429Smarkm */
108457429Smarkm
108560576Skrisvoid
108657429Smarkmfill_default_options(Options * options)
108757429Smarkm{
108876262Sgreen	int len;
108976262Sgreen
109057429Smarkm	if (options->forward_agent == -1)
109161203Skris		options->forward_agent = 0;
109257429Smarkm	if (options->forward_x11 == -1)
109357708Sgreen		options->forward_x11 = 0;
1094126277Sdes	if (options->forward_x11_trusted == -1)
1095126277Sdes		options->forward_x11_trusted = 0;
1096162856Sdes	if (options->exit_on_forward_failure == -1)
1097162856Sdes		options->exit_on_forward_failure = 0;
109865674Skris	if (options->xauth_location == NULL)
109992559Sdes		options->xauth_location = _PATH_XAUTH;
110057429Smarkm	if (options->gateway_ports == -1)
110157429Smarkm		options->gateway_ports = 0;
110257429Smarkm	if (options->use_privileged_port == -1)
110376262Sgreen		options->use_privileged_port = 0;
110457429Smarkm	if (options->rsa_authentication == -1)
110557429Smarkm		options->rsa_authentication = 1;
110676262Sgreen	if (options->pubkey_authentication == -1)
110776262Sgreen		options->pubkey_authentication = 1;
110892559Sdes	if (options->challenge_response_authentication == -1)
110992559Sdes		options->challenge_response_authentication = 1;
1110124211Sdes	if (options->gss_authentication == -1)
1111126277Sdes		options->gss_authentication = 0;
1112124211Sdes	if (options->gss_deleg_creds == -1)
1113124211Sdes		options->gss_deleg_creds = 0;
111457429Smarkm	if (options->password_authentication == -1)
111557429Smarkm		options->password_authentication = 1;
111669591Sgreen	if (options->kbd_interactive_authentication == -1)
111776262Sgreen		options->kbd_interactive_authentication = 1;
111857429Smarkm	if (options->rhosts_rsa_authentication == -1)
111998684Sdes		options->rhosts_rsa_authentication = 0;
112076262Sgreen	if (options->hostbased_authentication == -1)
112176262Sgreen		options->hostbased_authentication = 0;
112257429Smarkm	if (options->batch_mode == -1)
112357429Smarkm		options->batch_mode = 0;
112457429Smarkm	if (options->check_host_ip == -1)
112599048Sdes		options->check_host_ip = 0;
112657429Smarkm	if (options->strict_host_key_checking == -1)
112757429Smarkm		options->strict_host_key_checking = 2;	/* 2 is default */
112857429Smarkm	if (options->compression == -1)
112957429Smarkm		options->compression = 0;
1130126277Sdes	if (options->tcp_keep_alive == -1)
1131126277Sdes		options->tcp_keep_alive = 1;
113257429Smarkm	if (options->compression_level == -1)
113357429Smarkm		options->compression_level = 6;
113457429Smarkm	if (options->port == -1)
113557429Smarkm		options->port = 0;	/* Filled in ssh_connect. */
1136124211Sdes	if (options->address_family == -1)
1137124211Sdes		options->address_family = AF_UNSPEC;
113857429Smarkm	if (options->connection_attempts == -1)
113992559Sdes		options->connection_attempts = 1;
114057429Smarkm	if (options->number_of_password_prompts == -1)
114157429Smarkm		options->number_of_password_prompts = 3;
114257429Smarkm	/* Selected in ssh_login(). */
114357429Smarkm	if (options->cipher == -1)
114457429Smarkm		options->cipher = SSH_CIPHER_NOT_SET;
114560576Skris	/* options->ciphers, default set in myproposals.h */
114676262Sgreen	/* options->macs, default set in myproposals.h */
114776262Sgreen	/* options->hostkeyalgorithms, default set in myproposals.h */
114860576Skris	if (options->protocol == SSH_PROTO_UNKNOWN)
114976262Sgreen		options->protocol = SSH_PROTO_1|SSH_PROTO_2;
115057429Smarkm	if (options->num_identity_files == 0) {
115176262Sgreen		if (options->protocol & SSH_PROTO_1) {
115276262Sgreen			len = 2 + strlen(_PATH_SSH_CLIENT_IDENTITY) + 1;
115376262Sgreen			options->identity_files[options->num_identity_files] =
115476262Sgreen			    xmalloc(len);
115576262Sgreen			snprintf(options->identity_files[options->num_identity_files++],
115676262Sgreen			    len, "~/%.100s", _PATH_SSH_CLIENT_IDENTITY);
115776262Sgreen		}
115876262Sgreen		if (options->protocol & SSH_PROTO_2) {
115976262Sgreen			len = 2 + strlen(_PATH_SSH_CLIENT_ID_RSA) + 1;
116076262Sgreen			options->identity_files[options->num_identity_files] =
116176262Sgreen			    xmalloc(len);
116276262Sgreen			snprintf(options->identity_files[options->num_identity_files++],
116376262Sgreen			    len, "~/%.100s", _PATH_SSH_CLIENT_ID_RSA);
116476262Sgreen
116576262Sgreen			len = 2 + strlen(_PATH_SSH_CLIENT_ID_DSA) + 1;
116676262Sgreen			options->identity_files[options->num_identity_files] =
116776262Sgreen			    xmalloc(len);
116876262Sgreen			snprintf(options->identity_files[options->num_identity_files++],
116976262Sgreen			    len, "~/%.100s", _PATH_SSH_CLIENT_ID_DSA);
117076262Sgreen		}
117157429Smarkm	}
117257429Smarkm	if (options->escape_char == -1)
117357429Smarkm		options->escape_char = '~';
117457429Smarkm	if (options->system_hostfile == NULL)
117576262Sgreen		options->system_hostfile = _PATH_SSH_SYSTEM_HOSTFILE;
117657429Smarkm	if (options->user_hostfile == NULL)
117776262Sgreen		options->user_hostfile = _PATH_SSH_USER_HOSTFILE;
117860576Skris	if (options->system_hostfile2 == NULL)
117976262Sgreen		options->system_hostfile2 = _PATH_SSH_SYSTEM_HOSTFILE2;
118060576Skris	if (options->user_hostfile2 == NULL)
118176262Sgreen		options->user_hostfile2 = _PATH_SSH_USER_HOSTFILE2;
118292559Sdes	if (options->log_level == SYSLOG_LEVEL_NOT_SET)
118357429Smarkm		options->log_level = SYSLOG_LEVEL_INFO;
118492559Sdes	if (options->clear_forwardings == 1)
118592559Sdes		clear_forwardings(options);
118692559Sdes	if (options->no_host_authentication_for_localhost == - 1)
118792559Sdes		options->no_host_authentication_for_localhost = 0;
1188128460Sdes	if (options->identities_only == -1)
1189128460Sdes		options->identities_only = 0;
1190113911Sdes	if (options->enable_ssh_keysign == -1)
1191113911Sdes		options->enable_ssh_keysign = 0;
1192124211Sdes	if (options->rekey_limit == -1)
1193124211Sdes		options->rekey_limit = 0;
1194124211Sdes	if (options->verify_host_key_dns == -1)
1195124211Sdes		options->verify_host_key_dns = 0;
1196126277Sdes	if (options->server_alive_interval == -1)
1197126277Sdes		options->server_alive_interval = 0;
1198126277Sdes	if (options->server_alive_count_max == -1)
1199126277Sdes		options->server_alive_count_max = 3;
1200137019Sdes	if (options->control_master == -1)
1201137019Sdes		options->control_master = 0;
1202147005Sdes	if (options->hash_known_hosts == -1)
1203147005Sdes		options->hash_known_hosts = 0;
1204157019Sdes	if (options->tun_open == -1)
1205157019Sdes		options->tun_open = SSH_TUNMODE_NO;
1206157019Sdes	if (options->tun_local == -1)
1207157019Sdes		options->tun_local = SSH_TUNID_ANY;
1208157019Sdes	if (options->tun_remote == -1)
1209157019Sdes		options->tun_remote = SSH_TUNID_ANY;
1210157019Sdes	if (options->permit_local_command == -1)
1211157019Sdes		options->permit_local_command = 0;
1212157019Sdes	/* options->local_command should not be set by default */
121357429Smarkm	/* options->proxy_command should not be set by default */
121457429Smarkm	/* options->user will be set in the main program if appropriate */
121557429Smarkm	/* options->hostname will be set in the main program if appropriate */
121676262Sgreen	/* options->host_key_alias should not be set by default */
121776262Sgreen	/* options->preferred_authentications will be set in ssh */
121857429Smarkm}
1219147005Sdes
1220147005Sdes/*
1221147005Sdes * parse_forward
1222147005Sdes * parses a string containing a port forwarding specification of the form:
1223147005Sdes *	[listenhost:]listenport:connecthost:connectport
1224147005Sdes * returns number of arguments parsed or zero on error
1225147005Sdes */
1226147005Sdesint
1227147005Sdesparse_forward(Forward *fwd, const char *fwdspec)
1228147005Sdes{
1229147005Sdes	int i;
1230147005Sdes	char *p, *cp, *fwdarg[4];
1231147005Sdes
1232147005Sdes	memset(fwd, '\0', sizeof(*fwd));
1233147005Sdes
1234147005Sdes	cp = p = xstrdup(fwdspec);
1235147005Sdes
1236147005Sdes	/* skip leading spaces */
1237147005Sdes	while (*cp && isspace(*cp))
1238147005Sdes		cp++;
1239147005Sdes
1240147005Sdes	for (i = 0; i < 4; ++i)
1241147005Sdes		if ((fwdarg[i] = hpdelim(&cp)) == NULL)
1242147005Sdes			break;
1243147005Sdes
1244147005Sdes	/* Check for trailing garbage in 4-arg case*/
1245147005Sdes	if (cp != NULL)
1246147005Sdes		i = 0;	/* failure */
1247147005Sdes
1248147005Sdes	switch (i) {
1249147005Sdes	case 3:
1250147005Sdes		fwd->listen_host = NULL;
1251147005Sdes		fwd->listen_port = a2port(fwdarg[0]);
1252147005Sdes		fwd->connect_host = xstrdup(cleanhostname(fwdarg[1]));
1253147005Sdes		fwd->connect_port = a2port(fwdarg[2]);
1254147005Sdes		break;
1255147005Sdes
1256147005Sdes	case 4:
1257147005Sdes		fwd->listen_host = xstrdup(cleanhostname(fwdarg[0]));
1258147005Sdes		fwd->listen_port = a2port(fwdarg[1]);
1259147005Sdes		fwd->connect_host = xstrdup(cleanhostname(fwdarg[2]));
1260147005Sdes		fwd->connect_port = a2port(fwdarg[3]);
1261147005Sdes		break;
1262147005Sdes	default:
1263147005Sdes		i = 0; /* failure */
1264147005Sdes	}
1265147005Sdes
1266147005Sdes	xfree(p);
1267147005Sdes
1268147005Sdes	if (fwd->listen_port == 0 && fwd->connect_port == 0)
1269147005Sdes		goto fail_free;
1270147005Sdes
1271147005Sdes	if (fwd->connect_host != NULL &&
1272147005Sdes	    strlen(fwd->connect_host) >= NI_MAXHOST)
1273147005Sdes		goto fail_free;
1274147005Sdes
1275147005Sdes	return (i);
1276147005Sdes
1277147005Sdes fail_free:
1278147005Sdes	if (fwd->connect_host != NULL)
1279147005Sdes		xfree(fwd->connect_host);
1280147005Sdes	if (fwd->listen_host != NULL)
1281147005Sdes		xfree(fwd->listen_host);
1282147005Sdes	return (0);
1283147005Sdes}
1284