readconf.c revision 197679
1197679Sdes/* $OpenBSD: readconf.c,v 1.177 2009/06/27 09:35:06 andreas 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 197679 2009-10-01 17:12:52Z des $");
1757429Smarkm
18162856Sdes#include <sys/types.h>
19162856Sdes#include <sys/stat.h>
20162856Sdes#include <sys/socket.h>
21181918Sdes#include <sys/sysctl.h>
22162856Sdes
23162856Sdes#include <netinet/in.h>
24162856Sdes
25162856Sdes#include <ctype.h>
26162856Sdes#include <errno.h>
27162856Sdes#include <netdb.h>
28162856Sdes#include <signal.h>
29162856Sdes#include <stdarg.h>
30162856Sdes#include <stdio.h>
31162856Sdes#include <string.h>
32162856Sdes#include <unistd.h>
33162856Sdes
34162856Sdes#include "xmalloc.h"
3557429Smarkm#include "ssh.h"
3676262Sgreen#include "compat.h"
3776262Sgreen#include "cipher.h"
3876262Sgreen#include "pathnames.h"
3976262Sgreen#include "log.h"
40162856Sdes#include "key.h"
4157429Smarkm#include "readconf.h"
4260576Skris#include "match.h"
4376262Sgreen#include "misc.h"
44162856Sdes#include "buffer.h"
4576262Sgreen#include "kex.h"
4676262Sgreen#include "mac.h"
47192595Sdes#include "version.h"
4857429Smarkm
4957429Smarkm/* Format of the configuration file:
5057429Smarkm
5157429Smarkm   # Configuration data is parsed as follows:
5257429Smarkm   #  1. command line options
5357429Smarkm   #  2. user-specific file
5457429Smarkm   #  3. system-wide file
5557429Smarkm   # Any configuration value is only changed the first time it is set.
5657429Smarkm   # Thus, host-specific definitions should be at the beginning of the
5757429Smarkm   # configuration file, and defaults at the end.
5857429Smarkm
5957429Smarkm   # Host-specific declarations.  These may override anything above.  A single
6057429Smarkm   # host may match multiple declarations; these are processed in the order
6157429Smarkm   # that they are given in.
6257429Smarkm
6357429Smarkm   Host *.ngs.fi ngs.fi
6498684Sdes     User foo
6557429Smarkm
6657429Smarkm   Host fake.com
6757429Smarkm     HostName another.host.name.real.org
6857429Smarkm     User blaah
6957429Smarkm     Port 34289
7057429Smarkm     ForwardX11 no
7157429Smarkm     ForwardAgent no
7257429Smarkm
7357429Smarkm   Host books.com
7457429Smarkm     RemoteForward 9999 shadows.cs.hut.fi:9999
7557429Smarkm     Cipher 3des
7657429Smarkm
7757429Smarkm   Host fascist.blob.com
7857429Smarkm     Port 23123
7957429Smarkm     User tylonen
8057429Smarkm     PasswordAuthentication no
8157429Smarkm
8257429Smarkm   Host puukko.hut.fi
8357429Smarkm     User t35124p
8457429Smarkm     ProxyCommand ssh-proxy %h %p
8557429Smarkm
8657429Smarkm   Host *.fr
8798684Sdes     PublicKeyAuthentication no
8857429Smarkm
8957429Smarkm   Host *.su
9057429Smarkm     Cipher none
9157429Smarkm     PasswordAuthentication no
9257429Smarkm
93157019Sdes   Host vpn.fake.com
94157019Sdes     Tunnel yes
95157019Sdes     TunnelDevice 3
96157019Sdes
9757429Smarkm   # Defaults for various options
9857429Smarkm   Host *
9957429Smarkm     ForwardAgent no
10076262Sgreen     ForwardX11 no
10157429Smarkm     PasswordAuthentication yes
10257429Smarkm     RSAAuthentication yes
10357429Smarkm     RhostsRSAAuthentication yes
10457429Smarkm     StrictHostKeyChecking yes
105126277Sdes     TcpKeepAlive no
10657429Smarkm     IdentityFile ~/.ssh/identity
10757429Smarkm     Port 22
10857429Smarkm     EscapeChar ~
10957429Smarkm
11057429Smarkm*/
11157429Smarkm
11257429Smarkm/* Keyword tokens. */
11357429Smarkm
11457429Smarkmtypedef enum {
11557429Smarkm	oBadOption,
116126277Sdes	oForwardAgent, oForwardX11, oForwardX11Trusted, oGatewayPorts,
117162856Sdes	oExitOnForwardFailure,
11898684Sdes	oPasswordAuthentication, oRSAAuthentication,
11976262Sgreen	oChallengeResponseAuthentication, oXAuthLocation,
12057429Smarkm	oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward,
12157429Smarkm	oUser, oHost, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
12257429Smarkm	oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
12357429Smarkm	oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
124126277Sdes	oCompressionLevel, oTCPKeepAlive, oNumberOfPasswordPrompts,
12576262Sgreen	oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oMacs,
12676262Sgreen	oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication,
12776262Sgreen	oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
12876262Sgreen	oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
12992559Sdes	oHostKeyAlgorithms, oBindAddress, oSmartcardDevice,
13093698Sdes	oClearAllForwardings, oNoHostAuthenticationForLocalhost,
131124211Sdes	oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
132124211Sdes	oAddressFamily, oGssAuthentication, oGssDelegateCreds,
133128461Sdes	oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
134147005Sdes	oSendEnv, oControlPath, oControlMaster, oHashKnownHosts,
135157019Sdes	oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand,
136197679Sdes	oVisualHostKey, oUseRoaming, oZeroKnowledgePasswordAuthentication,
13799048Sdes	oVersionAddendum,
138124211Sdes	oDeprecated, oUnsupported
13957429Smarkm} OpCodes;
14057429Smarkm
14157429Smarkm/* Textual representations of the tokens. */
14257429Smarkm
14357429Smarkmstatic struct {
14457429Smarkm	const char *name;
14557429Smarkm	OpCodes opcode;
14657429Smarkm} keywords[] = {
14757429Smarkm	{ "forwardagent", oForwardAgent },
14857429Smarkm	{ "forwardx11", oForwardX11 },
149126277Sdes	{ "forwardx11trusted", oForwardX11Trusted },
150162856Sdes	{ "exitonforwardfailure", oExitOnForwardFailure },
15165674Skris	{ "xauthlocation", oXAuthLocation },
15257429Smarkm	{ "gatewayports", oGatewayPorts },
15357429Smarkm	{ "useprivilegedport", oUsePrivilegedPort },
154124211Sdes	{ "rhostsauthentication", oDeprecated },
15557429Smarkm	{ "passwordauthentication", oPasswordAuthentication },
15669591Sgreen	{ "kbdinteractiveauthentication", oKbdInteractiveAuthentication },
15769591Sgreen	{ "kbdinteractivedevices", oKbdInteractiveDevices },
15857429Smarkm	{ "rsaauthentication", oRSAAuthentication },
15976262Sgreen	{ "pubkeyauthentication", oPubkeyAuthentication },
16076262Sgreen	{ "dsaauthentication", oPubkeyAuthentication },		    /* alias */
16176262Sgreen	{ "rhostsrsaauthentication", oRhostsRSAAuthentication },
16276262Sgreen	{ "hostbasedauthentication", oHostbasedAuthentication },
16376262Sgreen	{ "challengeresponseauthentication", oChallengeResponseAuthentication },
16476262Sgreen	{ "skeyauthentication", oChallengeResponseAuthentication }, /* alias */
16576262Sgreen	{ "tisauthentication", oChallengeResponseAuthentication },  /* alias */
166124211Sdes	{ "kerberosauthentication", oUnsupported },
167124211Sdes	{ "kerberostgtpassing", oUnsupported },
168124211Sdes	{ "afstokenpassing", oUnsupported },
169124211Sdes#if defined(GSSAPI)
170124211Sdes	{ "gssapiauthentication", oGssAuthentication },
171124211Sdes	{ "gssapidelegatecredentials", oGssDelegateCreds },
172124211Sdes#else
173124211Sdes	{ "gssapiauthentication", oUnsupported },
174124211Sdes	{ "gssapidelegatecredentials", oUnsupported },
17592559Sdes#endif
17698684Sdes	{ "fallbacktorsh", oDeprecated },
17798684Sdes	{ "usersh", oDeprecated },
17857429Smarkm	{ "identityfile", oIdentityFile },
179192595Sdes	{ "identityfile2", oIdentityFile },			/* obsolete */
180128460Sdes	{ "identitiesonly", oIdentitiesOnly },
18157429Smarkm	{ "hostname", oHostName },
18276262Sgreen	{ "hostkeyalias", oHostKeyAlias },
18357429Smarkm	{ "proxycommand", oProxyCommand },
18457429Smarkm	{ "port", oPort },
18557429Smarkm	{ "cipher", oCipher },
18660576Skris	{ "ciphers", oCiphers },
18776262Sgreen	{ "macs", oMacs },
18860576Skris	{ "protocol", oProtocol },
18957429Smarkm	{ "remoteforward", oRemoteForward },
19057429Smarkm	{ "localforward", oLocalForward },
19157429Smarkm	{ "user", oUser },
19257429Smarkm	{ "host", oHost },
19357429Smarkm	{ "escapechar", oEscapeChar },
19457429Smarkm	{ "globalknownhostsfile", oGlobalKnownHostsFile },
195192595Sdes	{ "globalknownhostsfile2", oGlobalKnownHostsFile2 },	/* obsolete */
196192595Sdes	{ "userknownhostsfile", oUserKnownHostsFile },
19792559Sdes	{ "userknownhostsfile2", oUserKnownHostsFile2 },	/* obsolete */
19857429Smarkm	{ "connectionattempts", oConnectionAttempts },
19957429Smarkm	{ "batchmode", oBatchMode },
20057429Smarkm	{ "checkhostip", oCheckHostIP },
20157429Smarkm	{ "stricthostkeychecking", oStrictHostKeyChecking },
20257429Smarkm	{ "compression", oCompression },
20357429Smarkm	{ "compressionlevel", oCompressionLevel },
204126277Sdes	{ "tcpkeepalive", oTCPKeepAlive },
205126277Sdes	{ "keepalive", oTCPKeepAlive },				/* obsolete */
20657429Smarkm	{ "numberofpasswordprompts", oNumberOfPasswordPrompts },
20757429Smarkm	{ "loglevel", oLogLevel },
20876262Sgreen	{ "dynamicforward", oDynamicForward },
20976262Sgreen	{ "preferredauthentications", oPreferredAuthentications },
21076262Sgreen	{ "hostkeyalgorithms", oHostKeyAlgorithms },
21192559Sdes	{ "bindaddress", oBindAddress },
212124211Sdes#ifdef SMARTCARD
21392559Sdes	{ "smartcarddevice", oSmartcardDevice },
214124211Sdes#else
215124211Sdes	{ "smartcarddevice", oUnsupported },
216124211Sdes#endif
21792559Sdes	{ "clearallforwardings", oClearAllForwardings },
218113911Sdes	{ "enablesshkeysign", oEnableSSHKeysign },
219124211Sdes	{ "verifyhostkeydns", oVerifyHostKeyDNS },
22092559Sdes	{ "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
221124211Sdes	{ "rekeylimit", oRekeyLimit },
222124211Sdes	{ "connecttimeout", oConnectTimeout },
223124211Sdes	{ "addressfamily", oAddressFamily },
224126277Sdes	{ "serveraliveinterval", oServerAliveInterval },
225126277Sdes	{ "serveralivecountmax", oServerAliveCountMax },
226137019Sdes	{ "sendenv", oSendEnv },
227137019Sdes	{ "controlpath", oControlPath },
228137019Sdes	{ "controlmaster", oControlMaster },
229147005Sdes	{ "hashknownhosts", oHashKnownHosts },
230157019Sdes	{ "tunnel", oTunnel },
231157019Sdes	{ "tunneldevice", oTunnelDevice },
232157019Sdes	{ "localcommand", oLocalCommand },
233157019Sdes	{ "permitlocalcommand", oPermitLocalCommand },
234181111Sdes	{ "visualhostkey", oVisualHostKey },
235197679Sdes	{ "useroaming", oUseRoaming },
236192595Sdes#ifdef JPAKE
237192595Sdes	{ "zeroknowledgepasswordauthentication",
238192595Sdes	    oZeroKnowledgePasswordAuthentication },
239192595Sdes#else
240192595Sdes	{ "zeroknowledgepasswordauthentication", oUnsupported },
241192595Sdes#endif
242192595Sdes
24399048Sdes	{ "versionaddendum", oVersionAddendum },
24492559Sdes	{ NULL, oBadOption }
24557429Smarkm};
24657429Smarkm
24757429Smarkm/*
24857429Smarkm * Adds a local TCP/IP port forward to options.  Never returns if there is an
24957429Smarkm * error.
25057429Smarkm */
25157429Smarkm
25260576Skrisvoid
253147005Sdesadd_local_forward(Options *options, const Forward *newfwd)
25457429Smarkm{
25557429Smarkm	Forward *fwd;
256106130Sdes#ifndef NO_IPPORT_RESERVED_CONCEPT
25757429Smarkm	extern uid_t original_real_uid;
258181918Sdes	int ipport_reserved;
259181918Sdes#ifdef __FreeBSD__
260181918Sdes	size_t len_ipport_reserved = sizeof(ipport_reserved);
261181918Sdes
262181918Sdes	if (sysctlbyname("net.inet.ip.portrange.reservedhigh",
263181918Sdes	    &ipport_reserved, &len_ipport_reserved, NULL, 0) != 0)
264181918Sdes		ipport_reserved = IPPORT_RESERVED;
265181918Sdes	else
266181918Sdes		ipport_reserved++;
267181918Sdes#else
268181918Sdes	ipport_reserved = IPPORT_RESERVED;
269181918Sdes#endif
270181918Sdes	if (newfwd->listen_port < ipport_reserved && original_real_uid != 0)
27176262Sgreen		fatal("Privileged ports can only be forwarded by root.");
27298941Sdes#endif
27357429Smarkm	if (options->num_local_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
27457429Smarkm		fatal("Too many local forwards (max %d).", SSH_MAX_FORWARDS_PER_DIRECTION);
27557429Smarkm	fwd = &options->local_forwards[options->num_local_forwards++];
276147005Sdes
277192595Sdes	fwd->listen_host = newfwd->listen_host;
278147005Sdes	fwd->listen_port = newfwd->listen_port;
279192595Sdes	fwd->connect_host = newfwd->connect_host;
280147005Sdes	fwd->connect_port = newfwd->connect_port;
28157429Smarkm}
28257429Smarkm
28357429Smarkm/*
28457429Smarkm * Adds a remote TCP/IP port forward to options.  Never returns if there is
28557429Smarkm * an error.
28657429Smarkm */
28757429Smarkm
28860576Skrisvoid
289147005Sdesadd_remote_forward(Options *options, const Forward *newfwd)
29057429Smarkm{
29157429Smarkm	Forward *fwd;
29257429Smarkm	if (options->num_remote_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
29357429Smarkm		fatal("Too many remote forwards (max %d).",
29492559Sdes		    SSH_MAX_FORWARDS_PER_DIRECTION);
29557429Smarkm	fwd = &options->remote_forwards[options->num_remote_forwards++];
296147005Sdes
297192595Sdes	fwd->listen_host = newfwd->listen_host;
298147005Sdes	fwd->listen_port = newfwd->listen_port;
299192595Sdes	fwd->connect_host = newfwd->connect_host;
300147005Sdes	fwd->connect_port = newfwd->connect_port;
30157429Smarkm}
30257429Smarkm
30392559Sdesstatic void
30492559Sdesclear_forwardings(Options *options)
30592559Sdes{
30692559Sdes	int i;
30792559Sdes
308147005Sdes	for (i = 0; i < options->num_local_forwards; i++) {
309147005Sdes		if (options->local_forwards[i].listen_host != NULL)
310147005Sdes			xfree(options->local_forwards[i].listen_host);
311147005Sdes		xfree(options->local_forwards[i].connect_host);
312147005Sdes	}
31392559Sdes	options->num_local_forwards = 0;
314147005Sdes	for (i = 0; i < options->num_remote_forwards; i++) {
315147005Sdes		if (options->remote_forwards[i].listen_host != NULL)
316147005Sdes			xfree(options->remote_forwards[i].listen_host);
317147005Sdes		xfree(options->remote_forwards[i].connect_host);
318147005Sdes	}
31992559Sdes	options->num_remote_forwards = 0;
320157019Sdes	options->tun_open = SSH_TUNMODE_NO;
32192559Sdes}
32292559Sdes
32357429Smarkm/*
32476262Sgreen * Returns the number of the token pointed to by cp or oBadOption.
32557429Smarkm */
32657429Smarkm
32760576Skrisstatic OpCodes
32857429Smarkmparse_token(const char *cp, const char *filename, int linenum)
32957429Smarkm{
33076262Sgreen	u_int i;
33157429Smarkm
33257429Smarkm	for (i = 0; keywords[i].name; i++)
33357429Smarkm		if (strcasecmp(cp, keywords[i].name) == 0)
33457429Smarkm			return keywords[i].opcode;
33557429Smarkm
33676262Sgreen	error("%s: line %d: Bad configuration option: %s",
33776262Sgreen	    filename, linenum, cp);
33857429Smarkm	return oBadOption;
33957429Smarkm}
34057429Smarkm
34157429Smarkm/*
34257429Smarkm * Processes a single option line as used in the configuration files. This
34357429Smarkm * only sets those values that have not already been set.
34457429Smarkm */
345113911Sdes#define WHITESPACE " \t\r\n"
34657429Smarkm
34757429Smarkmint
34857429Smarkmprocess_config_line(Options *options, const char *host,
34957429Smarkm		    char *line, const char *filename, int linenum,
35057429Smarkm		    int *activep)
35157429Smarkm{
352147005Sdes	char *s, **charptr, *endofnumber, *keyword, *arg, *arg2, fwdarg[256];
353162856Sdes	int opcode, *intptr, value, value2, scale;
354181111Sdes	LogLevel *log_level_ptr;
355162856Sdes	long long orig, val64;
356113911Sdes	size_t len;
357147005Sdes	Forward fwd;
35857429Smarkm
359124211Sdes	/* Strip trailing whitespace */
360147005Sdes	for (len = strlen(line) - 1; len > 0; len--) {
361124211Sdes		if (strchr(WHITESPACE, line[len]) == NULL)
362124211Sdes			break;
363124211Sdes		line[len] = '\0';
364124211Sdes	}
365124211Sdes
36665674Skris	s = line;
36765674Skris	/* Get the keyword. (Each line is supposed to begin with a keyword). */
368162856Sdes	if ((keyword = strdelim(&s)) == NULL)
369162856Sdes		return 0;
37065674Skris	/* Ignore leading whitespace. */
37165674Skris	if (*keyword == '\0')
37265674Skris		keyword = strdelim(&s);
37376262Sgreen	if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#')
37457429Smarkm		return 0;
37557429Smarkm
37665674Skris	opcode = parse_token(keyword, filename, linenum);
37757429Smarkm
37857429Smarkm	switch (opcode) {
37957429Smarkm	case oBadOption:
38057429Smarkm		/* don't panic, but count bad options */
38157429Smarkm		return -1;
38257429Smarkm		/* NOTREACHED */
383124211Sdes	case oConnectTimeout:
384124211Sdes		intptr = &options->connection_timeout;
385126277Sdesparse_time:
386124211Sdes		arg = strdelim(&s);
387124211Sdes		if (!arg || *arg == '\0')
388124211Sdes			fatal("%s line %d: missing time value.",
389124211Sdes			    filename, linenum);
390124211Sdes		if ((value = convtime(arg)) == -1)
391124211Sdes			fatal("%s line %d: invalid time value.",
392124211Sdes			    filename, linenum);
393181111Sdes		if (*activep && *intptr == -1)
394124211Sdes			*intptr = value;
395124211Sdes		break;
396124211Sdes
39757429Smarkm	case oForwardAgent:
39857429Smarkm		intptr = &options->forward_agent;
39957429Smarkmparse_flag:
40065674Skris		arg = strdelim(&s);
40165674Skris		if (!arg || *arg == '\0')
40257429Smarkm			fatal("%.200s line %d: Missing yes/no argument.", filename, linenum);
40357429Smarkm		value = 0;	/* To avoid compiler warning... */
40465674Skris		if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
40557429Smarkm			value = 1;
40665674Skris		else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
40757429Smarkm			value = 0;
40857429Smarkm		else
40957429Smarkm			fatal("%.200s line %d: Bad yes/no argument.", filename, linenum);
41057429Smarkm		if (*activep && *intptr == -1)
41157429Smarkm			*intptr = value;
41257429Smarkm		break;
41357429Smarkm
41457429Smarkm	case oForwardX11:
41557429Smarkm		intptr = &options->forward_x11;
41657429Smarkm		goto parse_flag;
41757429Smarkm
418126277Sdes	case oForwardX11Trusted:
419126277Sdes		intptr = &options->forward_x11_trusted;
420126277Sdes		goto parse_flag;
421126277Sdes
42257429Smarkm	case oGatewayPorts:
42357429Smarkm		intptr = &options->gateway_ports;
42457429Smarkm		goto parse_flag;
42557429Smarkm
426162856Sdes	case oExitOnForwardFailure:
427162856Sdes		intptr = &options->exit_on_forward_failure;
428162856Sdes		goto parse_flag;
429162856Sdes
43057429Smarkm	case oUsePrivilegedPort:
43157429Smarkm		intptr = &options->use_privileged_port;
43257429Smarkm		goto parse_flag;
43357429Smarkm
43457429Smarkm	case oPasswordAuthentication:
43557429Smarkm		intptr = &options->password_authentication;
43657429Smarkm		goto parse_flag;
43757429Smarkm
438192595Sdes	case oZeroKnowledgePasswordAuthentication:
439192595Sdes		intptr = &options->zero_knowledge_password_authentication;
440192595Sdes		goto parse_flag;
441192595Sdes
44269591Sgreen	case oKbdInteractiveAuthentication:
44369591Sgreen		intptr = &options->kbd_interactive_authentication;
44469591Sgreen		goto parse_flag;
44569591Sgreen
44669591Sgreen	case oKbdInteractiveDevices:
44769591Sgreen		charptr = &options->kbd_interactive_devices;
44869591Sgreen		goto parse_string;
44969591Sgreen
45076262Sgreen	case oPubkeyAuthentication:
45176262Sgreen		intptr = &options->pubkey_authentication;
45260576Skris		goto parse_flag;
45360576Skris
45457429Smarkm	case oRSAAuthentication:
45557429Smarkm		intptr = &options->rsa_authentication;
45657429Smarkm		goto parse_flag;
45757429Smarkm
45857429Smarkm	case oRhostsRSAAuthentication:
45957429Smarkm		intptr = &options->rhosts_rsa_authentication;
46057429Smarkm		goto parse_flag;
46157429Smarkm
46276262Sgreen	case oHostbasedAuthentication:
46376262Sgreen		intptr = &options->hostbased_authentication;
46457429Smarkm		goto parse_flag;
46557429Smarkm
46692559Sdes	case oChallengeResponseAuthentication:
46792559Sdes		intptr = &options->challenge_response_authentication;
46892559Sdes		goto parse_flag;
469124211Sdes
470124211Sdes	case oGssAuthentication:
471124211Sdes		intptr = &options->gss_authentication;
47257429Smarkm		goto parse_flag;
473124211Sdes
474124211Sdes	case oGssDelegateCreds:
475124211Sdes		intptr = &options->gss_deleg_creds;
47676262Sgreen		goto parse_flag;
477124211Sdes
47857429Smarkm	case oBatchMode:
47957429Smarkm		intptr = &options->batch_mode;
48057429Smarkm		goto parse_flag;
48157429Smarkm
48257429Smarkm	case oCheckHostIP:
48357429Smarkm		intptr = &options->check_host_ip;
48457429Smarkm		goto parse_flag;
48557429Smarkm
486124211Sdes	case oVerifyHostKeyDNS:
487124211Sdes		intptr = &options->verify_host_key_dns;
488126277Sdes		goto parse_yesnoask;
489124211Sdes
49057429Smarkm	case oStrictHostKeyChecking:
49157429Smarkm		intptr = &options->strict_host_key_checking;
492126277Sdesparse_yesnoask:
49365674Skris		arg = strdelim(&s);
49465674Skris		if (!arg || *arg == '\0')
49576262Sgreen			fatal("%.200s line %d: Missing yes/no/ask argument.",
49692559Sdes			    filename, linenum);
49757429Smarkm		value = 0;	/* To avoid compiler warning... */
49865674Skris		if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
49957429Smarkm			value = 1;
50065674Skris		else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
50157429Smarkm			value = 0;
50265674Skris		else if (strcmp(arg, "ask") == 0)
50357429Smarkm			value = 2;
50457429Smarkm		else
50557429Smarkm			fatal("%.200s line %d: Bad yes/no/ask argument.", filename, linenum);
50657429Smarkm		if (*activep && *intptr == -1)
50757429Smarkm			*intptr = value;
50857429Smarkm		break;
50957429Smarkm
51057429Smarkm	case oCompression:
51157429Smarkm		intptr = &options->compression;
51257429Smarkm		goto parse_flag;
51357429Smarkm
514126277Sdes	case oTCPKeepAlive:
515126277Sdes		intptr = &options->tcp_keep_alive;
51657429Smarkm		goto parse_flag;
51757429Smarkm
51892559Sdes	case oNoHostAuthenticationForLocalhost:
51992559Sdes		intptr = &options->no_host_authentication_for_localhost;
52092559Sdes		goto parse_flag;
52192559Sdes
52257429Smarkm	case oNumberOfPasswordPrompts:
52357429Smarkm		intptr = &options->number_of_password_prompts;
52457429Smarkm		goto parse_int;
52557429Smarkm
52657429Smarkm	case oCompressionLevel:
52757429Smarkm		intptr = &options->compression_level;
52857429Smarkm		goto parse_int;
52957429Smarkm
530124211Sdes	case oRekeyLimit:
531124211Sdes		arg = strdelim(&s);
532124211Sdes		if (!arg || *arg == '\0')
533124211Sdes			fatal("%.200s line %d: Missing argument.", filename, linenum);
534124211Sdes		if (arg[0] < '0' || arg[0] > '9')
535124211Sdes			fatal("%.200s line %d: Bad number.", filename, linenum);
536162856Sdes		orig = val64 = strtoll(arg, &endofnumber, 10);
537124211Sdes		if (arg == endofnumber)
538124211Sdes			fatal("%.200s line %d: Bad number.", filename, linenum);
539124211Sdes		switch (toupper(*endofnumber)) {
540162856Sdes		case '\0':
541162856Sdes			scale = 1;
542162856Sdes			break;
543124211Sdes		case 'K':
544162856Sdes			scale = 1<<10;
545124211Sdes			break;
546124211Sdes		case 'M':
547162856Sdes			scale = 1<<20;
548124211Sdes			break;
549124211Sdes		case 'G':
550162856Sdes			scale = 1<<30;
551124211Sdes			break;
552162856Sdes		default:
553162856Sdes			fatal("%.200s line %d: Invalid RekeyLimit suffix",
554162856Sdes			    filename, linenum);
555124211Sdes		}
556162856Sdes		val64 *= scale;
557162856Sdes		/* detect integer wrap and too-large limits */
558181111Sdes		if ((val64 / scale) != orig || val64 > UINT_MAX)
559162856Sdes			fatal("%.200s line %d: RekeyLimit too large",
560162856Sdes			    filename, linenum);
561162856Sdes		if (val64 < 16)
562162856Sdes			fatal("%.200s line %d: RekeyLimit too small",
563162856Sdes			    filename, linenum);
564181111Sdes		if (*activep && options->rekey_limit == -1)
565181111Sdes			options->rekey_limit = (u_int32_t)val64;
566124211Sdes		break;
567124211Sdes
56857429Smarkm	case oIdentityFile:
56965674Skris		arg = strdelim(&s);
57065674Skris		if (!arg || *arg == '\0')
57157429Smarkm			fatal("%.200s line %d: Missing argument.", filename, linenum);
57257429Smarkm		if (*activep) {
57376262Sgreen			intptr = &options->num_identity_files;
57460576Skris			if (*intptr >= SSH_MAX_IDENTITY_FILES)
57557429Smarkm				fatal("%.200s line %d: Too many identity files specified (max %d).",
57692559Sdes				    filename, linenum, SSH_MAX_IDENTITY_FILES);
577181111Sdes			charptr = &options->identity_files[*intptr];
57865674Skris			*charptr = xstrdup(arg);
57960576Skris			*intptr = *intptr + 1;
58057429Smarkm		}
58157429Smarkm		break;
58257429Smarkm
58365674Skris	case oXAuthLocation:
58465674Skris		charptr=&options->xauth_location;
58565674Skris		goto parse_string;
58665674Skris
58757429Smarkm	case oUser:
58857429Smarkm		charptr = &options->user;
58957429Smarkmparse_string:
59065674Skris		arg = strdelim(&s);
59165674Skris		if (!arg || *arg == '\0')
59257429Smarkm			fatal("%.200s line %d: Missing argument.", filename, linenum);
59357429Smarkm		if (*activep && *charptr == NULL)
59465674Skris			*charptr = xstrdup(arg);
59557429Smarkm		break;
59657429Smarkm
59757429Smarkm	case oGlobalKnownHostsFile:
59857429Smarkm		charptr = &options->system_hostfile;
59957429Smarkm		goto parse_string;
60057429Smarkm
60157429Smarkm	case oUserKnownHostsFile:
60257429Smarkm		charptr = &options->user_hostfile;
60357429Smarkm		goto parse_string;
60457429Smarkm
60560576Skris	case oGlobalKnownHostsFile2:
60660576Skris		charptr = &options->system_hostfile2;
60760576Skris		goto parse_string;
60860576Skris
60960576Skris	case oUserKnownHostsFile2:
61060576Skris		charptr = &options->user_hostfile2;
61160576Skris		goto parse_string;
61260576Skris
61357429Smarkm	case oHostName:
61457429Smarkm		charptr = &options->hostname;
61557429Smarkm		goto parse_string;
61657429Smarkm
61776262Sgreen	case oHostKeyAlias:
61876262Sgreen		charptr = &options->host_key_alias;
61976262Sgreen		goto parse_string;
62076262Sgreen
62176262Sgreen	case oPreferredAuthentications:
62276262Sgreen		charptr = &options->preferred_authentications;
62376262Sgreen		goto parse_string;
62476262Sgreen
62592559Sdes	case oBindAddress:
62692559Sdes		charptr = &options->bind_address;
62792559Sdes		goto parse_string;
62892559Sdes
62992559Sdes	case oSmartcardDevice:
63092559Sdes		charptr = &options->smartcard_device;
63192559Sdes		goto parse_string;
63292559Sdes
63357429Smarkm	case oProxyCommand:
634157019Sdes		charptr = &options->proxy_command;
635157019Sdesparse_command:
636124211Sdes		if (s == NULL)
637124211Sdes			fatal("%.200s line %d: Missing argument.", filename, linenum);
638113911Sdes		len = strspn(s, WHITESPACE "=");
63957429Smarkm		if (*activep && *charptr == NULL)
640113911Sdes			*charptr = xstrdup(s + len);
64157429Smarkm		return 0;
64257429Smarkm
64357429Smarkm	case oPort:
64457429Smarkm		intptr = &options->port;
64557429Smarkmparse_int:
64665674Skris		arg = strdelim(&s);
64765674Skris		if (!arg || *arg == '\0')
64857429Smarkm			fatal("%.200s line %d: Missing argument.", filename, linenum);
64965674Skris		if (arg[0] < '0' || arg[0] > '9')
65057429Smarkm			fatal("%.200s line %d: Bad number.", filename, linenum);
65157429Smarkm
65257429Smarkm		/* Octal, decimal, or hex format? */
65365674Skris		value = strtol(arg, &endofnumber, 0);
65465674Skris		if (arg == endofnumber)
65557429Smarkm			fatal("%.200s line %d: Bad number.", filename, linenum);
65657429Smarkm		if (*activep && *intptr == -1)
65757429Smarkm			*intptr = value;
65857429Smarkm		break;
65957429Smarkm
66057429Smarkm	case oConnectionAttempts:
66157429Smarkm		intptr = &options->connection_attempts;
66257429Smarkm		goto parse_int;
66357429Smarkm
66457429Smarkm	case oCipher:
66557429Smarkm		intptr = &options->cipher;
66665674Skris		arg = strdelim(&s);
66765674Skris		if (!arg || *arg == '\0')
66861203Skris			fatal("%.200s line %d: Missing argument.", filename, linenum);
66965674Skris		value = cipher_number(arg);
67057429Smarkm		if (value == -1)
67157429Smarkm			fatal("%.200s line %d: Bad cipher '%s'.",
67292559Sdes			    filename, linenum, arg ? arg : "<NONE>");
67357429Smarkm		if (*activep && *intptr == -1)
67457429Smarkm			*intptr = value;
67557429Smarkm		break;
67657429Smarkm
67760576Skris	case oCiphers:
67865674Skris		arg = strdelim(&s);
67965674Skris		if (!arg || *arg == '\0')
68061203Skris			fatal("%.200s line %d: Missing argument.", filename, linenum);
68165674Skris		if (!ciphers_valid(arg))
68260576Skris			fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.",
68392559Sdes			    filename, linenum, arg ? arg : "<NONE>");
68460576Skris		if (*activep && options->ciphers == NULL)
68565674Skris			options->ciphers = xstrdup(arg);
68660576Skris		break;
68760576Skris
68876262Sgreen	case oMacs:
68976262Sgreen		arg = strdelim(&s);
69076262Sgreen		if (!arg || *arg == '\0')
69176262Sgreen			fatal("%.200s line %d: Missing argument.", filename, linenum);
69276262Sgreen		if (!mac_valid(arg))
69376262Sgreen			fatal("%.200s line %d: Bad SSH2 Mac spec '%s'.",
69492559Sdes			    filename, linenum, arg ? arg : "<NONE>");
69576262Sgreen		if (*activep && options->macs == NULL)
69676262Sgreen			options->macs = xstrdup(arg);
69776262Sgreen		break;
69876262Sgreen
69976262Sgreen	case oHostKeyAlgorithms:
70076262Sgreen		arg = strdelim(&s);
70176262Sgreen		if (!arg || *arg == '\0')
70276262Sgreen			fatal("%.200s line %d: Missing argument.", filename, linenum);
70376262Sgreen		if (!key_names_valid2(arg))
70476262Sgreen			fatal("%.200s line %d: Bad protocol 2 host key algorithms '%s'.",
70592559Sdes			    filename, linenum, arg ? arg : "<NONE>");
70676262Sgreen		if (*activep && options->hostkeyalgorithms == NULL)
70776262Sgreen			options->hostkeyalgorithms = xstrdup(arg);
70876262Sgreen		break;
70976262Sgreen
71060576Skris	case oProtocol:
71160576Skris		intptr = &options->protocol;
71265674Skris		arg = strdelim(&s);
71365674Skris		if (!arg || *arg == '\0')
71461203Skris			fatal("%.200s line %d: Missing argument.", filename, linenum);
71565674Skris		value = proto_spec(arg);
71660576Skris		if (value == SSH_PROTO_UNKNOWN)
71760576Skris			fatal("%.200s line %d: Bad protocol spec '%s'.",
71892559Sdes			    filename, linenum, arg ? arg : "<NONE>");
71960576Skris		if (*activep && *intptr == SSH_PROTO_UNKNOWN)
72060576Skris			*intptr = value;
72160576Skris		break;
72260576Skris
72357429Smarkm	case oLogLevel:
724181111Sdes		log_level_ptr = &options->log_level;
72565674Skris		arg = strdelim(&s);
72665674Skris		value = log_level_number(arg);
72792559Sdes		if (value == SYSLOG_LEVEL_NOT_SET)
72876262Sgreen			fatal("%.200s line %d: unsupported log level '%s'",
72992559Sdes			    filename, linenum, arg ? arg : "<NONE>");
730181111Sdes		if (*activep && *log_level_ptr == SYSLOG_LEVEL_NOT_SET)
731181111Sdes			*log_level_ptr = (LogLevel) value;
73257429Smarkm		break;
73357429Smarkm
73492559Sdes	case oLocalForward:
73557429Smarkm	case oRemoteForward:
736192595Sdes	case oDynamicForward:
73765674Skris		arg = strdelim(&s);
738147005Sdes		if (arg == NULL || *arg == '\0')
73992559Sdes			fatal("%.200s line %d: Missing port argument.",
74092559Sdes			    filename, linenum);
741147005Sdes
742192595Sdes		if (opcode == oLocalForward ||
743192595Sdes		    opcode == oRemoteForward) {
744192595Sdes			arg2 = strdelim(&s);
745192595Sdes			if (arg2 == NULL || *arg2 == '\0')
746192595Sdes				fatal("%.200s line %d: Missing target argument.",
747192595Sdes				    filename, linenum);
748147005Sdes
749192595Sdes			/* construct a string for parse_forward */
750192595Sdes			snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg, arg2);
751192595Sdes		} else if (opcode == oDynamicForward) {
752192595Sdes			strlcpy(fwdarg, arg, sizeof(fwdarg));
753192595Sdes		}
754192595Sdes
755192595Sdes		if (parse_forward(&fwd, fwdarg,
756192595Sdes		    opcode == oDynamicForward ? 1 : 0,
757192595Sdes		    opcode == oRemoteForward ? 1 : 0) == 0)
75892559Sdes			fatal("%.200s line %d: Bad forwarding specification.",
75992559Sdes			    filename, linenum);
760147005Sdes
76192559Sdes		if (*activep) {
762192595Sdes			if (opcode == oLocalForward ||
763192595Sdes			    opcode == oDynamicForward)
764147005Sdes				add_local_forward(options, &fwd);
76592559Sdes			else if (opcode == oRemoteForward)
766147005Sdes				add_remote_forward(options, &fwd);
76792559Sdes		}
76857429Smarkm		break;
76957429Smarkm
77092559Sdes	case oClearAllForwardings:
77192559Sdes		intptr = &options->clear_forwardings;
77292559Sdes		goto parse_flag;
77392559Sdes
77457429Smarkm	case oHost:
77557429Smarkm		*activep = 0;
77665674Skris		while ((arg = strdelim(&s)) != NULL && *arg != '\0')
77765674Skris			if (match_pattern(host, arg)) {
77865674Skris				debug("Applying options for %.100s", arg);
77957429Smarkm				*activep = 1;
78057429Smarkm				break;
78157429Smarkm			}
78265674Skris		/* Avoid garbage check below, as strdelim is done. */
78357429Smarkm		return 0;
78457429Smarkm
78557429Smarkm	case oEscapeChar:
78657429Smarkm		intptr = &options->escape_char;
78765674Skris		arg = strdelim(&s);
78865674Skris		if (!arg || *arg == '\0')
78957429Smarkm			fatal("%.200s line %d: Missing argument.", filename, linenum);
79065674Skris		if (arg[0] == '^' && arg[2] == 0 &&
79176262Sgreen		    (u_char) arg[1] >= 64 && (u_char) arg[1] < 128)
79276262Sgreen			value = (u_char) arg[1] & 31;
79365674Skris		else if (strlen(arg) == 1)
79476262Sgreen			value = (u_char) arg[0];
79565674Skris		else if (strcmp(arg, "none") == 0)
79692559Sdes			value = SSH_ESCAPECHAR_NONE;
79757429Smarkm		else {
79857429Smarkm			fatal("%.200s line %d: Bad escape character.",
79992559Sdes			    filename, linenum);
80057429Smarkm			/* NOTREACHED */
80157429Smarkm			value = 0;	/* Avoid compiler warning. */
80257429Smarkm		}
80357429Smarkm		if (*activep && *intptr == -1)
80457429Smarkm			*intptr = value;
80557429Smarkm		break;
80657429Smarkm
807124211Sdes	case oAddressFamily:
808124211Sdes		arg = strdelim(&s);
809149753Sdes		if (!arg || *arg == '\0')
810149753Sdes			fatal("%s line %d: missing address family.",
811149753Sdes			    filename, linenum);
812124211Sdes		intptr = &options->address_family;
813124211Sdes		if (strcasecmp(arg, "inet") == 0)
814124211Sdes			value = AF_INET;
815124211Sdes		else if (strcasecmp(arg, "inet6") == 0)
816124211Sdes			value = AF_INET6;
817124211Sdes		else if (strcasecmp(arg, "any") == 0)
818124211Sdes			value = AF_UNSPEC;
819124211Sdes		else
820124211Sdes			fatal("Unsupported AddressFamily \"%s\"", arg);
821124211Sdes		if (*activep && *intptr == -1)
822124211Sdes			*intptr = value;
823124211Sdes		break;
824124211Sdes
825113911Sdes	case oEnableSSHKeysign:
826113911Sdes		intptr = &options->enable_ssh_keysign;
827113911Sdes		goto parse_flag;
828113911Sdes
829128460Sdes	case oIdentitiesOnly:
830128460Sdes		intptr = &options->identities_only;
831128460Sdes		goto parse_flag;
832128460Sdes
833126277Sdes	case oServerAliveInterval:
834126277Sdes		intptr = &options->server_alive_interval;
835126277Sdes		goto parse_time;
836126277Sdes
837126277Sdes	case oServerAliveCountMax:
838126277Sdes		intptr = &options->server_alive_count_max;
839126277Sdes		goto parse_int;
840126277Sdes
841137019Sdes	case oSendEnv:
842137019Sdes		while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
843137019Sdes			if (strchr(arg, '=') != NULL)
844137019Sdes				fatal("%s line %d: Invalid environment name.",
845137019Sdes				    filename, linenum);
846147005Sdes			if (!*activep)
847147005Sdes				continue;
848137019Sdes			if (options->num_send_env >= MAX_SEND_ENV)
849137019Sdes				fatal("%s line %d: too many send env.",
850137019Sdes				    filename, linenum);
851137019Sdes			options->send_env[options->num_send_env++] =
852137019Sdes			    xstrdup(arg);
853137019Sdes		}
854137019Sdes		break;
855137019Sdes
856137019Sdes	case oControlPath:
857137019Sdes		charptr = &options->control_path;
858137019Sdes		goto parse_string;
859137019Sdes
860137019Sdes	case oControlMaster:
861137019Sdes		intptr = &options->control_master;
862149753Sdes		arg = strdelim(&s);
863149753Sdes		if (!arg || *arg == '\0')
864149753Sdes			fatal("%.200s line %d: Missing ControlMaster argument.",
865149753Sdes			    filename, linenum);
866149753Sdes		value = 0;	/* To avoid compiler warning... */
867149753Sdes		if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
868149753Sdes			value = SSHCTL_MASTER_YES;
869149753Sdes		else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
870149753Sdes			value = SSHCTL_MASTER_NO;
871149753Sdes		else if (strcmp(arg, "auto") == 0)
872149753Sdes			value = SSHCTL_MASTER_AUTO;
873149753Sdes		else if (strcmp(arg, "ask") == 0)
874149753Sdes			value = SSHCTL_MASTER_ASK;
875149753Sdes		else if (strcmp(arg, "autoask") == 0)
876149753Sdes			value = SSHCTL_MASTER_AUTO_ASK;
877149753Sdes		else
878149753Sdes			fatal("%.200s line %d: Bad ControlMaster argument.",
879149753Sdes			    filename, linenum);
880149753Sdes		if (*activep && *intptr == -1)
881149753Sdes			*intptr = value;
882149753Sdes		break;
883137019Sdes
884147005Sdes	case oHashKnownHosts:
885147005Sdes		intptr = &options->hash_known_hosts;
886147005Sdes		goto parse_flag;
887147005Sdes
888157019Sdes	case oTunnel:
889157019Sdes		intptr = &options->tun_open;
890157019Sdes		arg = strdelim(&s);
891157019Sdes		if (!arg || *arg == '\0')
892157019Sdes			fatal("%s line %d: Missing yes/point-to-point/"
893157019Sdes			    "ethernet/no argument.", filename, linenum);
894157019Sdes		value = 0;	/* silence compiler */
895157019Sdes		if (strcasecmp(arg, "ethernet") == 0)
896157019Sdes			value = SSH_TUNMODE_ETHERNET;
897157019Sdes		else if (strcasecmp(arg, "point-to-point") == 0)
898157019Sdes			value = SSH_TUNMODE_POINTOPOINT;
899157019Sdes		else if (strcasecmp(arg, "yes") == 0)
900157019Sdes			value = SSH_TUNMODE_DEFAULT;
901157019Sdes		else if (strcasecmp(arg, "no") == 0)
902157019Sdes			value = SSH_TUNMODE_NO;
903157019Sdes		else
904157019Sdes			fatal("%s line %d: Bad yes/point-to-point/ethernet/"
905157019Sdes			    "no argument: %s", filename, linenum, arg);
906157019Sdes		if (*activep)
907157019Sdes			*intptr = value;
908157019Sdes		break;
909157019Sdes
910157019Sdes	case oTunnelDevice:
911157019Sdes		arg = strdelim(&s);
912157019Sdes		if (!arg || *arg == '\0')
913157019Sdes			fatal("%.200s line %d: Missing argument.", filename, linenum);
914157019Sdes		value = a2tun(arg, &value2);
915157019Sdes		if (value == SSH_TUNID_ERR)
916157019Sdes			fatal("%.200s line %d: Bad tun device.", filename, linenum);
917157019Sdes		if (*activep) {
918157019Sdes			options->tun_local = value;
919157019Sdes			options->tun_remote = value2;
920157019Sdes		}
921157019Sdes		break;
922157019Sdes
923157019Sdes	case oLocalCommand:
924157019Sdes		charptr = &options->local_command;
925157019Sdes		goto parse_command;
926157019Sdes
927157019Sdes	case oPermitLocalCommand:
928157019Sdes		intptr = &options->permit_local_command;
929157019Sdes		goto parse_flag;
930157019Sdes
931181111Sdes	case oVisualHostKey:
932181111Sdes		intptr = &options->visual_host_key;
933181111Sdes		goto parse_flag;
934181111Sdes
935197679Sdes	case oUseRoaming:
936197679Sdes		intptr = &options->use_roaming;
937197679Sdes		goto parse_flag;
938197679Sdes
93999048Sdes	case oVersionAddendum:
94099048Sdes		ssh_version_set_addendum(strtok(s, "\n"));
94199048Sdes		do {
94299048Sdes			arg = strdelim(&s);
94399048Sdes		} while (arg != NULL && *arg != '\0');
94499048Sdes		break;
94599048Sdes
94698684Sdes	case oDeprecated:
94798684Sdes		debug("%s line %d: Deprecated option \"%s\"",
94898684Sdes		    filename, linenum, keyword);
94998684Sdes		return 0;
95098684Sdes
951124211Sdes	case oUnsupported:
952124211Sdes		error("%s line %d: Unsupported option \"%s\"",
953124211Sdes		    filename, linenum, keyword);
954124211Sdes		return 0;
955124211Sdes
95657429Smarkm	default:
95757429Smarkm		fatal("process_config_line: Unimplemented opcode %d", opcode);
95857429Smarkm	}
95957429Smarkm
96057429Smarkm	/* Check that there is no garbage at end of line. */
96176262Sgreen	if ((arg = strdelim(&s)) != NULL && *arg != '\0') {
96265674Skris		fatal("%.200s line %d: garbage at end of line; \"%.200s\".",
963149753Sdes		    filename, linenum, arg);
96465674Skris	}
96557429Smarkm	return 0;
96657429Smarkm}
96757429Smarkm
96857429Smarkm
96957429Smarkm/*
97057429Smarkm * Reads the config file and modifies the options accordingly.  Options
97157429Smarkm * should already be initialized before this call.  This never returns if
97292559Sdes * there is an error.  If the file does not exist, this returns 0.
97357429Smarkm */
97457429Smarkm
97592559Sdesint
976137019Sdesread_config_file(const char *filename, const char *host, Options *options,
977137019Sdes    int checkperm)
97857429Smarkm{
97957429Smarkm	FILE *f;
98057429Smarkm	char line[1024];
98157429Smarkm	int active, linenum;
98257429Smarkm	int bad_options = 0;
98357429Smarkm
984137019Sdes	if ((f = fopen(filename, "r")) == NULL)
98592559Sdes		return 0;
98657429Smarkm
987137019Sdes	if (checkperm) {
988137019Sdes		struct stat sb;
989137019Sdes
990137019Sdes		if (fstat(fileno(f), &sb) == -1)
991137019Sdes			fatal("fstat %s: %s", filename, strerror(errno));
992137019Sdes		if (((sb.st_uid != 0 && sb.st_uid != getuid()) ||
993137019Sdes		    (sb.st_mode & 022) != 0))
994137019Sdes			fatal("Bad owner or permissions on %s", filename);
995137019Sdes	}
996137019Sdes
99757429Smarkm	debug("Reading configuration data %.200s", filename);
99857429Smarkm
99957429Smarkm	/*
100057429Smarkm	 * Mark that we are now processing the options.  This flag is turned
100157429Smarkm	 * on/off by Host specifications.
100257429Smarkm	 */
100357429Smarkm	active = 1;
100457429Smarkm	linenum = 0;
100557429Smarkm	while (fgets(line, sizeof(line), f)) {
100657429Smarkm		/* Update line number counter. */
100757429Smarkm		linenum++;
100857429Smarkm		if (process_config_line(options, host, line, filename, linenum, &active) != 0)
100957429Smarkm			bad_options++;
101057429Smarkm	}
101157429Smarkm	fclose(f);
101257429Smarkm	if (bad_options > 0)
101376262Sgreen		fatal("%s: terminating, %d bad configuration options",
101492559Sdes		    filename, bad_options);
101592559Sdes	return 1;
101657429Smarkm}
101757429Smarkm
101857429Smarkm/*
101957429Smarkm * Initializes options to special values that indicate that they have not yet
102057429Smarkm * been set.  Read_config_file will only set options with this value. Options
102157429Smarkm * are processed in the following order: command line, user config file,
102257429Smarkm * system config file.  Last, fill_default_options is called.
102357429Smarkm */
102457429Smarkm
102560576Skrisvoid
102657429Smarkminitialize_options(Options * options)
102757429Smarkm{
102857429Smarkm	memset(options, 'X', sizeof(*options));
102957429Smarkm	options->forward_agent = -1;
103057429Smarkm	options->forward_x11 = -1;
1031126277Sdes	options->forward_x11_trusted = -1;
1032162856Sdes	options->exit_on_forward_failure = -1;
103365674Skris	options->xauth_location = NULL;
103457429Smarkm	options->gateway_ports = -1;
103557429Smarkm	options->use_privileged_port = -1;
103657429Smarkm	options->rsa_authentication = -1;
103776262Sgreen	options->pubkey_authentication = -1;
103892559Sdes	options->challenge_response_authentication = -1;
1039124211Sdes	options->gss_authentication = -1;
1040124211Sdes	options->gss_deleg_creds = -1;
104157429Smarkm	options->password_authentication = -1;
104269591Sgreen	options->kbd_interactive_authentication = -1;
104369591Sgreen	options->kbd_interactive_devices = NULL;
104457429Smarkm	options->rhosts_rsa_authentication = -1;
104576262Sgreen	options->hostbased_authentication = -1;
104657429Smarkm	options->batch_mode = -1;
104757429Smarkm	options->check_host_ip = -1;
104857429Smarkm	options->strict_host_key_checking = -1;
104957429Smarkm	options->compression = -1;
1050126277Sdes	options->tcp_keep_alive = -1;
105157429Smarkm	options->compression_level = -1;
105257429Smarkm	options->port = -1;
1053124211Sdes	options->address_family = -1;
105457429Smarkm	options->connection_attempts = -1;
1055124211Sdes	options->connection_timeout = -1;
105657429Smarkm	options->number_of_password_prompts = -1;
105757429Smarkm	options->cipher = -1;
105860576Skris	options->ciphers = NULL;
105976262Sgreen	options->macs = NULL;
106076262Sgreen	options->hostkeyalgorithms = NULL;
106160576Skris	options->protocol = SSH_PROTO_UNKNOWN;
106257429Smarkm	options->num_identity_files = 0;
106357429Smarkm	options->hostname = NULL;
106476262Sgreen	options->host_key_alias = NULL;
106557429Smarkm	options->proxy_command = NULL;
106657429Smarkm	options->user = NULL;
106757429Smarkm	options->escape_char = -1;
106857429Smarkm	options->system_hostfile = NULL;
106957429Smarkm	options->user_hostfile = NULL;
107060576Skris	options->system_hostfile2 = NULL;
107160576Skris	options->user_hostfile2 = NULL;
107257429Smarkm	options->num_local_forwards = 0;
107357429Smarkm	options->num_remote_forwards = 0;
107492559Sdes	options->clear_forwardings = -1;
107592559Sdes	options->log_level = SYSLOG_LEVEL_NOT_SET;
107676262Sgreen	options->preferred_authentications = NULL;
107792559Sdes	options->bind_address = NULL;
107892559Sdes	options->smartcard_device = NULL;
1079113911Sdes	options->enable_ssh_keysign = - 1;
108092559Sdes	options->no_host_authentication_for_localhost = - 1;
1081128460Sdes	options->identities_only = - 1;
1082124211Sdes	options->rekey_limit = - 1;
1083124211Sdes	options->verify_host_key_dns = -1;
1084126277Sdes	options->server_alive_interval = -1;
1085126277Sdes	options->server_alive_count_max = -1;
1086137019Sdes	options->num_send_env = 0;
1087137019Sdes	options->control_path = NULL;
1088137019Sdes	options->control_master = -1;
1089147005Sdes	options->hash_known_hosts = -1;
1090157019Sdes	options->tun_open = -1;
1091157019Sdes	options->tun_local = -1;
1092157019Sdes	options->tun_remote = -1;
1093157019Sdes	options->local_command = NULL;
1094157019Sdes	options->permit_local_command = -1;
1095197679Sdes	options->use_roaming = -1;
1096181111Sdes	options->visual_host_key = -1;
1097192595Sdes	options->zero_knowledge_password_authentication = -1;
109857429Smarkm}
109957429Smarkm
110057429Smarkm/*
110157429Smarkm * Called after processing other sources of option data, this fills those
110257429Smarkm * options for which no value has been specified with their default values.
110357429Smarkm */
110457429Smarkm
110560576Skrisvoid
110657429Smarkmfill_default_options(Options * options)
110757429Smarkm{
110876262Sgreen	int len;
110976262Sgreen
111057429Smarkm	if (options->forward_agent == -1)
111161203Skris		options->forward_agent = 0;
111257429Smarkm	if (options->forward_x11 == -1)
111357708Sgreen		options->forward_x11 = 0;
1114126277Sdes	if (options->forward_x11_trusted == -1)
1115126277Sdes		options->forward_x11_trusted = 0;
1116162856Sdes	if (options->exit_on_forward_failure == -1)
1117162856Sdes		options->exit_on_forward_failure = 0;
111865674Skris	if (options->xauth_location == NULL)
111992559Sdes		options->xauth_location = _PATH_XAUTH;
112057429Smarkm	if (options->gateway_ports == -1)
112157429Smarkm		options->gateway_ports = 0;
112257429Smarkm	if (options->use_privileged_port == -1)
112376262Sgreen		options->use_privileged_port = 0;
112457429Smarkm	if (options->rsa_authentication == -1)
112557429Smarkm		options->rsa_authentication = 1;
112676262Sgreen	if (options->pubkey_authentication == -1)
112776262Sgreen		options->pubkey_authentication = 1;
112892559Sdes	if (options->challenge_response_authentication == -1)
112992559Sdes		options->challenge_response_authentication = 1;
1130124211Sdes	if (options->gss_authentication == -1)
1131126277Sdes		options->gss_authentication = 0;
1132124211Sdes	if (options->gss_deleg_creds == -1)
1133124211Sdes		options->gss_deleg_creds = 0;
113457429Smarkm	if (options->password_authentication == -1)
113557429Smarkm		options->password_authentication = 1;
113669591Sgreen	if (options->kbd_interactive_authentication == -1)
113776262Sgreen		options->kbd_interactive_authentication = 1;
113857429Smarkm	if (options->rhosts_rsa_authentication == -1)
113998684Sdes		options->rhosts_rsa_authentication = 0;
114076262Sgreen	if (options->hostbased_authentication == -1)
114176262Sgreen		options->hostbased_authentication = 0;
114257429Smarkm	if (options->batch_mode == -1)
114357429Smarkm		options->batch_mode = 0;
114457429Smarkm	if (options->check_host_ip == -1)
114599048Sdes		options->check_host_ip = 0;
114657429Smarkm	if (options->strict_host_key_checking == -1)
114757429Smarkm		options->strict_host_key_checking = 2;	/* 2 is default */
114857429Smarkm	if (options->compression == -1)
114957429Smarkm		options->compression = 0;
1150126277Sdes	if (options->tcp_keep_alive == -1)
1151126277Sdes		options->tcp_keep_alive = 1;
115257429Smarkm	if (options->compression_level == -1)
115357429Smarkm		options->compression_level = 6;
115457429Smarkm	if (options->port == -1)
115557429Smarkm		options->port = 0;	/* Filled in ssh_connect. */
1156124211Sdes	if (options->address_family == -1)
1157124211Sdes		options->address_family = AF_UNSPEC;
115857429Smarkm	if (options->connection_attempts == -1)
115992559Sdes		options->connection_attempts = 1;
116057429Smarkm	if (options->number_of_password_prompts == -1)
116157429Smarkm		options->number_of_password_prompts = 3;
116257429Smarkm	/* Selected in ssh_login(). */
116357429Smarkm	if (options->cipher == -1)
116457429Smarkm		options->cipher = SSH_CIPHER_NOT_SET;
116560576Skris	/* options->ciphers, default set in myproposals.h */
116676262Sgreen	/* options->macs, default set in myproposals.h */
116776262Sgreen	/* options->hostkeyalgorithms, default set in myproposals.h */
116860576Skris	if (options->protocol == SSH_PROTO_UNKNOWN)
116976262Sgreen		options->protocol = SSH_PROTO_1|SSH_PROTO_2;
117057429Smarkm	if (options->num_identity_files == 0) {
117176262Sgreen		if (options->protocol & SSH_PROTO_1) {
117276262Sgreen			len = 2 + strlen(_PATH_SSH_CLIENT_IDENTITY) + 1;
117376262Sgreen			options->identity_files[options->num_identity_files] =
117476262Sgreen			    xmalloc(len);
117576262Sgreen			snprintf(options->identity_files[options->num_identity_files++],
117676262Sgreen			    len, "~/%.100s", _PATH_SSH_CLIENT_IDENTITY);
117776262Sgreen		}
117876262Sgreen		if (options->protocol & SSH_PROTO_2) {
117976262Sgreen			len = 2 + strlen(_PATH_SSH_CLIENT_ID_RSA) + 1;
118076262Sgreen			options->identity_files[options->num_identity_files] =
118176262Sgreen			    xmalloc(len);
118276262Sgreen			snprintf(options->identity_files[options->num_identity_files++],
118376262Sgreen			    len, "~/%.100s", _PATH_SSH_CLIENT_ID_RSA);
118476262Sgreen
118576262Sgreen			len = 2 + strlen(_PATH_SSH_CLIENT_ID_DSA) + 1;
118676262Sgreen			options->identity_files[options->num_identity_files] =
118776262Sgreen			    xmalloc(len);
118876262Sgreen			snprintf(options->identity_files[options->num_identity_files++],
118976262Sgreen			    len, "~/%.100s", _PATH_SSH_CLIENT_ID_DSA);
119076262Sgreen		}
119157429Smarkm	}
119257429Smarkm	if (options->escape_char == -1)
119357429Smarkm		options->escape_char = '~';
119457429Smarkm	if (options->system_hostfile == NULL)
119576262Sgreen		options->system_hostfile = _PATH_SSH_SYSTEM_HOSTFILE;
119657429Smarkm	if (options->user_hostfile == NULL)
119776262Sgreen		options->user_hostfile = _PATH_SSH_USER_HOSTFILE;
119860576Skris	if (options->system_hostfile2 == NULL)
119976262Sgreen		options->system_hostfile2 = _PATH_SSH_SYSTEM_HOSTFILE2;
120060576Skris	if (options->user_hostfile2 == NULL)
120176262Sgreen		options->user_hostfile2 = _PATH_SSH_USER_HOSTFILE2;
120292559Sdes	if (options->log_level == SYSLOG_LEVEL_NOT_SET)
120357429Smarkm		options->log_level = SYSLOG_LEVEL_INFO;
120492559Sdes	if (options->clear_forwardings == 1)
120592559Sdes		clear_forwardings(options);
120692559Sdes	if (options->no_host_authentication_for_localhost == - 1)
120792559Sdes		options->no_host_authentication_for_localhost = 0;
1208128460Sdes	if (options->identities_only == -1)
1209128460Sdes		options->identities_only = 0;
1210113911Sdes	if (options->enable_ssh_keysign == -1)
1211113911Sdes		options->enable_ssh_keysign = 0;
1212124211Sdes	if (options->rekey_limit == -1)
1213124211Sdes		options->rekey_limit = 0;
1214124211Sdes	if (options->verify_host_key_dns == -1)
1215124211Sdes		options->verify_host_key_dns = 0;
1216126277Sdes	if (options->server_alive_interval == -1)
1217126277Sdes		options->server_alive_interval = 0;
1218126277Sdes	if (options->server_alive_count_max == -1)
1219126277Sdes		options->server_alive_count_max = 3;
1220137019Sdes	if (options->control_master == -1)
1221137019Sdes		options->control_master = 0;
1222147005Sdes	if (options->hash_known_hosts == -1)
1223147005Sdes		options->hash_known_hosts = 0;
1224157019Sdes	if (options->tun_open == -1)
1225157019Sdes		options->tun_open = SSH_TUNMODE_NO;
1226157019Sdes	if (options->tun_local == -1)
1227157019Sdes		options->tun_local = SSH_TUNID_ANY;
1228157019Sdes	if (options->tun_remote == -1)
1229157019Sdes		options->tun_remote = SSH_TUNID_ANY;
1230157019Sdes	if (options->permit_local_command == -1)
1231157019Sdes		options->permit_local_command = 0;
1232197679Sdes	if (options->use_roaming == -1)
1233197679Sdes		options->use_roaming = 1;
1234181111Sdes	if (options->visual_host_key == -1)
1235181111Sdes		options->visual_host_key = 0;
1236192595Sdes	if (options->zero_knowledge_password_authentication == -1)
1237192595Sdes		options->zero_knowledge_password_authentication = 0;
1238157019Sdes	/* options->local_command should not be set by default */
123957429Smarkm	/* options->proxy_command should not be set by default */
124057429Smarkm	/* options->user will be set in the main program if appropriate */
124157429Smarkm	/* options->hostname will be set in the main program if appropriate */
124276262Sgreen	/* options->host_key_alias should not be set by default */
124376262Sgreen	/* options->preferred_authentications will be set in ssh */
124457429Smarkm}
1245147005Sdes
1246147005Sdes/*
1247147005Sdes * parse_forward
1248147005Sdes * parses a string containing a port forwarding specification of the form:
1249192595Sdes *   dynamicfwd == 0
1250147005Sdes *	[listenhost:]listenport:connecthost:connectport
1251192595Sdes *   dynamicfwd == 1
1252192595Sdes *	[listenhost:]listenport
1253147005Sdes * returns number of arguments parsed or zero on error
1254147005Sdes */
1255147005Sdesint
1256192595Sdesparse_forward(Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
1257147005Sdes{
1258147005Sdes	int i;
1259147005Sdes	char *p, *cp, *fwdarg[4];
1260147005Sdes
1261147005Sdes	memset(fwd, '\0', sizeof(*fwd));
1262147005Sdes
1263147005Sdes	cp = p = xstrdup(fwdspec);
1264147005Sdes
1265147005Sdes	/* skip leading spaces */
1266181111Sdes	while (isspace(*cp))
1267147005Sdes		cp++;
1268147005Sdes
1269147005Sdes	for (i = 0; i < 4; ++i)
1270147005Sdes		if ((fwdarg[i] = hpdelim(&cp)) == NULL)
1271147005Sdes			break;
1272147005Sdes
1273192595Sdes	/* Check for trailing garbage */
1274147005Sdes	if (cp != NULL)
1275147005Sdes		i = 0;	/* failure */
1276147005Sdes
1277147005Sdes	switch (i) {
1278192595Sdes	case 1:
1279192595Sdes		fwd->listen_host = NULL;
1280192595Sdes		fwd->listen_port = a2port(fwdarg[0]);
1281192595Sdes		fwd->connect_host = xstrdup("socks");
1282192595Sdes		break;
1283192595Sdes
1284192595Sdes	case 2:
1285192595Sdes		fwd->listen_host = xstrdup(cleanhostname(fwdarg[0]));
1286192595Sdes		fwd->listen_port = a2port(fwdarg[1]);
1287192595Sdes		fwd->connect_host = xstrdup("socks");
1288192595Sdes		break;
1289192595Sdes
1290147005Sdes	case 3:
1291147005Sdes		fwd->listen_host = NULL;
1292147005Sdes		fwd->listen_port = a2port(fwdarg[0]);
1293147005Sdes		fwd->connect_host = xstrdup(cleanhostname(fwdarg[1]));
1294147005Sdes		fwd->connect_port = a2port(fwdarg[2]);
1295147005Sdes		break;
1296147005Sdes
1297147005Sdes	case 4:
1298147005Sdes		fwd->listen_host = xstrdup(cleanhostname(fwdarg[0]));
1299147005Sdes		fwd->listen_port = a2port(fwdarg[1]);
1300147005Sdes		fwd->connect_host = xstrdup(cleanhostname(fwdarg[2]));
1301147005Sdes		fwd->connect_port = a2port(fwdarg[3]);
1302147005Sdes		break;
1303147005Sdes	default:
1304147005Sdes		i = 0; /* failure */
1305147005Sdes	}
1306147005Sdes
1307147005Sdes	xfree(p);
1308147005Sdes
1309192595Sdes	if (dynamicfwd) {
1310192595Sdes		if (!(i == 1 || i == 2))
1311192595Sdes			goto fail_free;
1312192595Sdes	} else {
1313192595Sdes		if (!(i == 3 || i == 4))
1314192595Sdes			goto fail_free;
1315192595Sdes		if (fwd->connect_port <= 0)
1316192595Sdes			goto fail_free;
1317192595Sdes	}
1318192595Sdes
1319192595Sdes	if (fwd->listen_port < 0 || (!remotefwd && fwd->listen_port == 0))
1320147005Sdes		goto fail_free;
1321147005Sdes
1322147005Sdes	if (fwd->connect_host != NULL &&
1323147005Sdes	    strlen(fwd->connect_host) >= NI_MAXHOST)
1324147005Sdes		goto fail_free;
1325192595Sdes	if (fwd->listen_host != NULL &&
1326192595Sdes	    strlen(fwd->listen_host) >= NI_MAXHOST)
1327192595Sdes		goto fail_free;
1328147005Sdes
1329192595Sdes
1330147005Sdes	return (i);
1331147005Sdes
1332147005Sdes fail_free:
1333192595Sdes	if (fwd->connect_host != NULL) {
1334147005Sdes		xfree(fwd->connect_host);
1335192595Sdes		fwd->connect_host = NULL;
1336192595Sdes	}
1337192595Sdes	if (fwd->listen_host != NULL) {
1338147005Sdes		xfree(fwd->listen_host);
1339192595Sdes		fwd->listen_host = NULL;
1340192595Sdes	}
1341147005Sdes	return (0);
1342147005Sdes}
1343