readconf.c revision 181111
1181111Sdes/* $OpenBSD: readconf.c,v 1.167 2008/06/26 11:46:31 grunk 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 181111 2008-08-01 02:48:36Z 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,
134181111Sdes	oVisualHostKey,
13599048Sdes	oVersionAddendum,
136124211Sdes	oDeprecated, oUnsupported
13757429Smarkm} OpCodes;
13857429Smarkm
13957429Smarkm/* Textual representations of the tokens. */
14057429Smarkm
14157429Smarkmstatic struct {
14257429Smarkm	const char *name;
14357429Smarkm	OpCodes opcode;
14457429Smarkm} keywords[] = {
14557429Smarkm	{ "forwardagent", oForwardAgent },
14657429Smarkm	{ "forwardx11", oForwardX11 },
147126277Sdes	{ "forwardx11trusted", oForwardX11Trusted },
148162856Sdes	{ "exitonforwardfailure", oExitOnForwardFailure },
14965674Skris	{ "xauthlocation", oXAuthLocation },
15057429Smarkm	{ "gatewayports", oGatewayPorts },
15157429Smarkm	{ "useprivilegedport", oUsePrivilegedPort },
152124211Sdes	{ "rhostsauthentication", oDeprecated },
15357429Smarkm	{ "passwordauthentication", oPasswordAuthentication },
15469591Sgreen	{ "kbdinteractiveauthentication", oKbdInteractiveAuthentication },
15569591Sgreen	{ "kbdinteractivedevices", oKbdInteractiveDevices },
15657429Smarkm	{ "rsaauthentication", oRSAAuthentication },
15776262Sgreen	{ "pubkeyauthentication", oPubkeyAuthentication },
15876262Sgreen	{ "dsaauthentication", oPubkeyAuthentication },		    /* alias */
15976262Sgreen	{ "rhostsrsaauthentication", oRhostsRSAAuthentication },
16076262Sgreen	{ "hostbasedauthentication", oHostbasedAuthentication },
16176262Sgreen	{ "challengeresponseauthentication", oChallengeResponseAuthentication },
16276262Sgreen	{ "skeyauthentication", oChallengeResponseAuthentication }, /* alias */
16376262Sgreen	{ "tisauthentication", oChallengeResponseAuthentication },  /* alias */
164124211Sdes	{ "kerberosauthentication", oUnsupported },
165124211Sdes	{ "kerberostgtpassing", oUnsupported },
166124211Sdes	{ "afstokenpassing", oUnsupported },
167124211Sdes#if defined(GSSAPI)
168124211Sdes	{ "gssapiauthentication", oGssAuthentication },
169124211Sdes	{ "gssapidelegatecredentials", oGssDelegateCreds },
170124211Sdes#else
171124211Sdes	{ "gssapiauthentication", oUnsupported },
172124211Sdes	{ "gssapidelegatecredentials", oUnsupported },
17392559Sdes#endif
17498684Sdes	{ "fallbacktorsh", oDeprecated },
17598684Sdes	{ "usersh", oDeprecated },
17657429Smarkm	{ "identityfile", oIdentityFile },
17776262Sgreen	{ "identityfile2", oIdentityFile },			/* alias */
178128460Sdes	{ "identitiesonly", oIdentitiesOnly },
17957429Smarkm	{ "hostname", oHostName },
18076262Sgreen	{ "hostkeyalias", oHostKeyAlias },
18157429Smarkm	{ "proxycommand", oProxyCommand },
18257429Smarkm	{ "port", oPort },
18357429Smarkm	{ "cipher", oCipher },
18460576Skris	{ "ciphers", oCiphers },
18576262Sgreen	{ "macs", oMacs },
18660576Skris	{ "protocol", oProtocol },
18757429Smarkm	{ "remoteforward", oRemoteForward },
18857429Smarkm	{ "localforward", oLocalForward },
18957429Smarkm	{ "user", oUser },
19057429Smarkm	{ "host", oHost },
19157429Smarkm	{ "escapechar", oEscapeChar },
19257429Smarkm	{ "globalknownhostsfile", oGlobalKnownHostsFile },
19392559Sdes	{ "userknownhostsfile", oUserKnownHostsFile },		/* obsolete */
19460576Skris	{ "globalknownhostsfile2", oGlobalKnownHostsFile2 },
19592559Sdes	{ "userknownhostsfile2", oUserKnownHostsFile2 },	/* obsolete */
19657429Smarkm	{ "connectionattempts", oConnectionAttempts },
19757429Smarkm	{ "batchmode", oBatchMode },
19857429Smarkm	{ "checkhostip", oCheckHostIP },
19957429Smarkm	{ "stricthostkeychecking", oStrictHostKeyChecking },
20057429Smarkm	{ "compression", oCompression },
20157429Smarkm	{ "compressionlevel", oCompressionLevel },
202126277Sdes	{ "tcpkeepalive", oTCPKeepAlive },
203126277Sdes	{ "keepalive", oTCPKeepAlive },				/* obsolete */
20457429Smarkm	{ "numberofpasswordprompts", oNumberOfPasswordPrompts },
20557429Smarkm	{ "loglevel", oLogLevel },
20676262Sgreen	{ "dynamicforward", oDynamicForward },
20776262Sgreen	{ "preferredauthentications", oPreferredAuthentications },
20876262Sgreen	{ "hostkeyalgorithms", oHostKeyAlgorithms },
20992559Sdes	{ "bindaddress", oBindAddress },
210124211Sdes#ifdef SMARTCARD
21192559Sdes	{ "smartcarddevice", oSmartcardDevice },
212124211Sdes#else
213124211Sdes	{ "smartcarddevice", oUnsupported },
214124211Sdes#endif
21592559Sdes	{ "clearallforwardings", oClearAllForwardings },
216113911Sdes	{ "enablesshkeysign", oEnableSSHKeysign },
217124211Sdes	{ "verifyhostkeydns", oVerifyHostKeyDNS },
21892559Sdes	{ "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
219124211Sdes	{ "rekeylimit", oRekeyLimit },
220124211Sdes	{ "connecttimeout", oConnectTimeout },
221124211Sdes	{ "addressfamily", oAddressFamily },
222126277Sdes	{ "serveraliveinterval", oServerAliveInterval },
223126277Sdes	{ "serveralivecountmax", oServerAliveCountMax },
224137019Sdes	{ "sendenv", oSendEnv },
225137019Sdes	{ "controlpath", oControlPath },
226137019Sdes	{ "controlmaster", oControlMaster },
227147005Sdes	{ "hashknownhosts", oHashKnownHosts },
228157019Sdes	{ "tunnel", oTunnel },
229157019Sdes	{ "tunneldevice", oTunnelDevice },
230157019Sdes	{ "localcommand", oLocalCommand },
231157019Sdes	{ "permitlocalcommand", oPermitLocalCommand },
232181111Sdes	{ "visualhostkey", oVisualHostKey },
23399048Sdes	{ "versionaddendum", oVersionAddendum },
23492559Sdes	{ NULL, oBadOption }
23557429Smarkm};
23657429Smarkm
23757429Smarkm/*
23857429Smarkm * Adds a local TCP/IP port forward to options.  Never returns if there is an
23957429Smarkm * error.
24057429Smarkm */
24157429Smarkm
24260576Skrisvoid
243147005Sdesadd_local_forward(Options *options, const Forward *newfwd)
24457429Smarkm{
24557429Smarkm	Forward *fwd;
246106130Sdes#ifndef NO_IPPORT_RESERVED_CONCEPT
24757429Smarkm	extern uid_t original_real_uid;
248147005Sdes	if (newfwd->listen_port < IPPORT_RESERVED && original_real_uid != 0)
24976262Sgreen		fatal("Privileged ports can only be forwarded by root.");
25098941Sdes#endif
25157429Smarkm	if (options->num_local_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
25257429Smarkm		fatal("Too many local forwards (max %d).", SSH_MAX_FORWARDS_PER_DIRECTION);
25357429Smarkm	fwd = &options->local_forwards[options->num_local_forwards++];
254147005Sdes
255147005Sdes	fwd->listen_host = (newfwd->listen_host == NULL) ?
256147005Sdes	    NULL : xstrdup(newfwd->listen_host);
257147005Sdes	fwd->listen_port = newfwd->listen_port;
258147005Sdes	fwd->connect_host = xstrdup(newfwd->connect_host);
259147005Sdes	fwd->connect_port = newfwd->connect_port;
26057429Smarkm}
26157429Smarkm
26257429Smarkm/*
26357429Smarkm * Adds a remote TCP/IP port forward to options.  Never returns if there is
26457429Smarkm * an error.
26557429Smarkm */
26657429Smarkm
26760576Skrisvoid
268147005Sdesadd_remote_forward(Options *options, const Forward *newfwd)
26957429Smarkm{
27057429Smarkm	Forward *fwd;
27157429Smarkm	if (options->num_remote_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
27257429Smarkm		fatal("Too many remote forwards (max %d).",
27392559Sdes		    SSH_MAX_FORWARDS_PER_DIRECTION);
27457429Smarkm	fwd = &options->remote_forwards[options->num_remote_forwards++];
275147005Sdes
276147005Sdes	fwd->listen_host = (newfwd->listen_host == NULL) ?
277147005Sdes	    NULL : xstrdup(newfwd->listen_host);
278147005Sdes	fwd->listen_port = newfwd->listen_port;
279147005Sdes	fwd->connect_host = xstrdup(newfwd->connect_host);
280147005Sdes	fwd->connect_port = newfwd->connect_port;
28157429Smarkm}
28257429Smarkm
28392559Sdesstatic void
28492559Sdesclear_forwardings(Options *options)
28592559Sdes{
28692559Sdes	int i;
28792559Sdes
288147005Sdes	for (i = 0; i < options->num_local_forwards; i++) {
289147005Sdes		if (options->local_forwards[i].listen_host != NULL)
290147005Sdes			xfree(options->local_forwards[i].listen_host);
291147005Sdes		xfree(options->local_forwards[i].connect_host);
292147005Sdes	}
29392559Sdes	options->num_local_forwards = 0;
294147005Sdes	for (i = 0; i < options->num_remote_forwards; i++) {
295147005Sdes		if (options->remote_forwards[i].listen_host != NULL)
296147005Sdes			xfree(options->remote_forwards[i].listen_host);
297147005Sdes		xfree(options->remote_forwards[i].connect_host);
298147005Sdes	}
29992559Sdes	options->num_remote_forwards = 0;
300157019Sdes	options->tun_open = SSH_TUNMODE_NO;
30192559Sdes}
30292559Sdes
30357429Smarkm/*
30476262Sgreen * Returns the number of the token pointed to by cp or oBadOption.
30557429Smarkm */
30657429Smarkm
30760576Skrisstatic OpCodes
30857429Smarkmparse_token(const char *cp, const char *filename, int linenum)
30957429Smarkm{
31076262Sgreen	u_int i;
31157429Smarkm
31257429Smarkm	for (i = 0; keywords[i].name; i++)
31357429Smarkm		if (strcasecmp(cp, keywords[i].name) == 0)
31457429Smarkm			return keywords[i].opcode;
31557429Smarkm
31676262Sgreen	error("%s: line %d: Bad configuration option: %s",
31776262Sgreen	    filename, linenum, cp);
31857429Smarkm	return oBadOption;
31957429Smarkm}
32057429Smarkm
32157429Smarkm/*
32257429Smarkm * Processes a single option line as used in the configuration files. This
32357429Smarkm * only sets those values that have not already been set.
32457429Smarkm */
325113911Sdes#define WHITESPACE " \t\r\n"
32657429Smarkm
32757429Smarkmint
32857429Smarkmprocess_config_line(Options *options, const char *host,
32957429Smarkm		    char *line, const char *filename, int linenum,
33057429Smarkm		    int *activep)
33157429Smarkm{
332147005Sdes	char *s, **charptr, *endofnumber, *keyword, *arg, *arg2, fwdarg[256];
333162856Sdes	int opcode, *intptr, value, value2, scale;
334181111Sdes	LogLevel *log_level_ptr;
335162856Sdes	long long orig, val64;
336113911Sdes	size_t len;
337147005Sdes	Forward fwd;
33857429Smarkm
339124211Sdes	/* Strip trailing whitespace */
340147005Sdes	for (len = strlen(line) - 1; len > 0; len--) {
341124211Sdes		if (strchr(WHITESPACE, line[len]) == NULL)
342124211Sdes			break;
343124211Sdes		line[len] = '\0';
344124211Sdes	}
345124211Sdes
34665674Skris	s = line;
34765674Skris	/* Get the keyword. (Each line is supposed to begin with a keyword). */
348162856Sdes	if ((keyword = strdelim(&s)) == NULL)
349162856Sdes		return 0;
35065674Skris	/* Ignore leading whitespace. */
35165674Skris	if (*keyword == '\0')
35265674Skris		keyword = strdelim(&s);
35376262Sgreen	if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#')
35457429Smarkm		return 0;
35557429Smarkm
35665674Skris	opcode = parse_token(keyword, filename, linenum);
35757429Smarkm
35857429Smarkm	switch (opcode) {
35957429Smarkm	case oBadOption:
36057429Smarkm		/* don't panic, but count bad options */
36157429Smarkm		return -1;
36257429Smarkm		/* NOTREACHED */
363124211Sdes	case oConnectTimeout:
364124211Sdes		intptr = &options->connection_timeout;
365126277Sdesparse_time:
366124211Sdes		arg = strdelim(&s);
367124211Sdes		if (!arg || *arg == '\0')
368124211Sdes			fatal("%s line %d: missing time value.",
369124211Sdes			    filename, linenum);
370124211Sdes		if ((value = convtime(arg)) == -1)
371124211Sdes			fatal("%s line %d: invalid time value.",
372124211Sdes			    filename, linenum);
373181111Sdes		if (*activep && *intptr == -1)
374124211Sdes			*intptr = value;
375124211Sdes		break;
376124211Sdes
37757429Smarkm	case oForwardAgent:
37857429Smarkm		intptr = &options->forward_agent;
37957429Smarkmparse_flag:
38065674Skris		arg = strdelim(&s);
38165674Skris		if (!arg || *arg == '\0')
38257429Smarkm			fatal("%.200s line %d: Missing yes/no argument.", filename, linenum);
38357429Smarkm		value = 0;	/* To avoid compiler warning... */
38465674Skris		if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
38557429Smarkm			value = 1;
38665674Skris		else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
38757429Smarkm			value = 0;
38857429Smarkm		else
38957429Smarkm			fatal("%.200s line %d: Bad yes/no argument.", filename, linenum);
39057429Smarkm		if (*activep && *intptr == -1)
39157429Smarkm			*intptr = value;
39257429Smarkm		break;
39357429Smarkm
39457429Smarkm	case oForwardX11:
39557429Smarkm		intptr = &options->forward_x11;
39657429Smarkm		goto parse_flag;
39757429Smarkm
398126277Sdes	case oForwardX11Trusted:
399126277Sdes		intptr = &options->forward_x11_trusted;
400126277Sdes		goto parse_flag;
401126277Sdes
40257429Smarkm	case oGatewayPorts:
40357429Smarkm		intptr = &options->gateway_ports;
40457429Smarkm		goto parse_flag;
40557429Smarkm
406162856Sdes	case oExitOnForwardFailure:
407162856Sdes		intptr = &options->exit_on_forward_failure;
408162856Sdes		goto parse_flag;
409162856Sdes
41057429Smarkm	case oUsePrivilegedPort:
41157429Smarkm		intptr = &options->use_privileged_port;
41257429Smarkm		goto parse_flag;
41357429Smarkm
41457429Smarkm	case oPasswordAuthentication:
41557429Smarkm		intptr = &options->password_authentication;
41657429Smarkm		goto parse_flag;
41757429Smarkm
41869591Sgreen	case oKbdInteractiveAuthentication:
41969591Sgreen		intptr = &options->kbd_interactive_authentication;
42069591Sgreen		goto parse_flag;
42169591Sgreen
42269591Sgreen	case oKbdInteractiveDevices:
42369591Sgreen		charptr = &options->kbd_interactive_devices;
42469591Sgreen		goto parse_string;
42569591Sgreen
42676262Sgreen	case oPubkeyAuthentication:
42776262Sgreen		intptr = &options->pubkey_authentication;
42860576Skris		goto parse_flag;
42960576Skris
43057429Smarkm	case oRSAAuthentication:
43157429Smarkm		intptr = &options->rsa_authentication;
43257429Smarkm		goto parse_flag;
43357429Smarkm
43457429Smarkm	case oRhostsRSAAuthentication:
43557429Smarkm		intptr = &options->rhosts_rsa_authentication;
43657429Smarkm		goto parse_flag;
43757429Smarkm
43876262Sgreen	case oHostbasedAuthentication:
43976262Sgreen		intptr = &options->hostbased_authentication;
44057429Smarkm		goto parse_flag;
44157429Smarkm
44292559Sdes	case oChallengeResponseAuthentication:
44392559Sdes		intptr = &options->challenge_response_authentication;
44492559Sdes		goto parse_flag;
445124211Sdes
446124211Sdes	case oGssAuthentication:
447124211Sdes		intptr = &options->gss_authentication;
44857429Smarkm		goto parse_flag;
449124211Sdes
450124211Sdes	case oGssDelegateCreds:
451124211Sdes		intptr = &options->gss_deleg_creds;
45276262Sgreen		goto parse_flag;
453124211Sdes
45457429Smarkm	case oBatchMode:
45557429Smarkm		intptr = &options->batch_mode;
45657429Smarkm		goto parse_flag;
45757429Smarkm
45857429Smarkm	case oCheckHostIP:
45957429Smarkm		intptr = &options->check_host_ip;
46057429Smarkm		goto parse_flag;
46157429Smarkm
462124211Sdes	case oVerifyHostKeyDNS:
463124211Sdes		intptr = &options->verify_host_key_dns;
464126277Sdes		goto parse_yesnoask;
465124211Sdes
46657429Smarkm	case oStrictHostKeyChecking:
46757429Smarkm		intptr = &options->strict_host_key_checking;
468126277Sdesparse_yesnoask:
46965674Skris		arg = strdelim(&s);
47065674Skris		if (!arg || *arg == '\0')
47176262Sgreen			fatal("%.200s line %d: Missing yes/no/ask argument.",
47292559Sdes			    filename, linenum);
47357429Smarkm		value = 0;	/* To avoid compiler warning... */
47465674Skris		if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
47557429Smarkm			value = 1;
47665674Skris		else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
47757429Smarkm			value = 0;
47865674Skris		else if (strcmp(arg, "ask") == 0)
47957429Smarkm			value = 2;
48057429Smarkm		else
48157429Smarkm			fatal("%.200s line %d: Bad yes/no/ask argument.", filename, linenum);
48257429Smarkm		if (*activep && *intptr == -1)
48357429Smarkm			*intptr = value;
48457429Smarkm		break;
48557429Smarkm
48657429Smarkm	case oCompression:
48757429Smarkm		intptr = &options->compression;
48857429Smarkm		goto parse_flag;
48957429Smarkm
490126277Sdes	case oTCPKeepAlive:
491126277Sdes		intptr = &options->tcp_keep_alive;
49257429Smarkm		goto parse_flag;
49357429Smarkm
49492559Sdes	case oNoHostAuthenticationForLocalhost:
49592559Sdes		intptr = &options->no_host_authentication_for_localhost;
49692559Sdes		goto parse_flag;
49792559Sdes
49857429Smarkm	case oNumberOfPasswordPrompts:
49957429Smarkm		intptr = &options->number_of_password_prompts;
50057429Smarkm		goto parse_int;
50157429Smarkm
50257429Smarkm	case oCompressionLevel:
50357429Smarkm		intptr = &options->compression_level;
50457429Smarkm		goto parse_int;
50557429Smarkm
506124211Sdes	case oRekeyLimit:
507124211Sdes		arg = strdelim(&s);
508124211Sdes		if (!arg || *arg == '\0')
509124211Sdes			fatal("%.200s line %d: Missing argument.", filename, linenum);
510124211Sdes		if (arg[0] < '0' || arg[0] > '9')
511124211Sdes			fatal("%.200s line %d: Bad number.", filename, linenum);
512162856Sdes		orig = val64 = strtoll(arg, &endofnumber, 10);
513124211Sdes		if (arg == endofnumber)
514124211Sdes			fatal("%.200s line %d: Bad number.", filename, linenum);
515124211Sdes		switch (toupper(*endofnumber)) {
516162856Sdes		case '\0':
517162856Sdes			scale = 1;
518162856Sdes			break;
519124211Sdes		case 'K':
520162856Sdes			scale = 1<<10;
521124211Sdes			break;
522124211Sdes		case 'M':
523162856Sdes			scale = 1<<20;
524124211Sdes			break;
525124211Sdes		case 'G':
526162856Sdes			scale = 1<<30;
527124211Sdes			break;
528162856Sdes		default:
529162856Sdes			fatal("%.200s line %d: Invalid RekeyLimit suffix",
530162856Sdes			    filename, linenum);
531124211Sdes		}
532162856Sdes		val64 *= scale;
533162856Sdes		/* detect integer wrap and too-large limits */
534181111Sdes		if ((val64 / scale) != orig || val64 > UINT_MAX)
535162856Sdes			fatal("%.200s line %d: RekeyLimit too large",
536162856Sdes			    filename, linenum);
537162856Sdes		if (val64 < 16)
538162856Sdes			fatal("%.200s line %d: RekeyLimit too small",
539162856Sdes			    filename, linenum);
540181111Sdes		if (*activep && options->rekey_limit == -1)
541181111Sdes			options->rekey_limit = (u_int32_t)val64;
542124211Sdes		break;
543124211Sdes
54457429Smarkm	case oIdentityFile:
54565674Skris		arg = strdelim(&s);
54665674Skris		if (!arg || *arg == '\0')
54757429Smarkm			fatal("%.200s line %d: Missing argument.", filename, linenum);
54857429Smarkm		if (*activep) {
54976262Sgreen			intptr = &options->num_identity_files;
55060576Skris			if (*intptr >= SSH_MAX_IDENTITY_FILES)
55157429Smarkm				fatal("%.200s line %d: Too many identity files specified (max %d).",
55292559Sdes				    filename, linenum, SSH_MAX_IDENTITY_FILES);
553181111Sdes			charptr = &options->identity_files[*intptr];
55465674Skris			*charptr = xstrdup(arg);
55560576Skris			*intptr = *intptr + 1;
55657429Smarkm		}
55757429Smarkm		break;
55857429Smarkm
55965674Skris	case oXAuthLocation:
56065674Skris		charptr=&options->xauth_location;
56165674Skris		goto parse_string;
56265674Skris
56357429Smarkm	case oUser:
56457429Smarkm		charptr = &options->user;
56557429Smarkmparse_string:
56665674Skris		arg = strdelim(&s);
56765674Skris		if (!arg || *arg == '\0')
56857429Smarkm			fatal("%.200s line %d: Missing argument.", filename, linenum);
56957429Smarkm		if (*activep && *charptr == NULL)
57065674Skris			*charptr = xstrdup(arg);
57157429Smarkm		break;
57257429Smarkm
57357429Smarkm	case oGlobalKnownHostsFile:
57457429Smarkm		charptr = &options->system_hostfile;
57557429Smarkm		goto parse_string;
57657429Smarkm
57757429Smarkm	case oUserKnownHostsFile:
57857429Smarkm		charptr = &options->user_hostfile;
57957429Smarkm		goto parse_string;
58057429Smarkm
58160576Skris	case oGlobalKnownHostsFile2:
58260576Skris		charptr = &options->system_hostfile2;
58360576Skris		goto parse_string;
58460576Skris
58560576Skris	case oUserKnownHostsFile2:
58660576Skris		charptr = &options->user_hostfile2;
58760576Skris		goto parse_string;
58860576Skris
58957429Smarkm	case oHostName:
59057429Smarkm		charptr = &options->hostname;
59157429Smarkm		goto parse_string;
59257429Smarkm
59376262Sgreen	case oHostKeyAlias:
59476262Sgreen		charptr = &options->host_key_alias;
59576262Sgreen		goto parse_string;
59676262Sgreen
59776262Sgreen	case oPreferredAuthentications:
59876262Sgreen		charptr = &options->preferred_authentications;
59976262Sgreen		goto parse_string;
60076262Sgreen
60192559Sdes	case oBindAddress:
60292559Sdes		charptr = &options->bind_address;
60392559Sdes		goto parse_string;
60492559Sdes
60592559Sdes	case oSmartcardDevice:
60692559Sdes		charptr = &options->smartcard_device;
60792559Sdes		goto parse_string;
60892559Sdes
60957429Smarkm	case oProxyCommand:
610157019Sdes		charptr = &options->proxy_command;
611157019Sdesparse_command:
612124211Sdes		if (s == NULL)
613124211Sdes			fatal("%.200s line %d: Missing argument.", filename, linenum);
614113911Sdes		len = strspn(s, WHITESPACE "=");
61557429Smarkm		if (*activep && *charptr == NULL)
616113911Sdes			*charptr = xstrdup(s + len);
61757429Smarkm		return 0;
61857429Smarkm
61957429Smarkm	case oPort:
62057429Smarkm		intptr = &options->port;
62157429Smarkmparse_int:
62265674Skris		arg = strdelim(&s);
62365674Skris		if (!arg || *arg == '\0')
62457429Smarkm			fatal("%.200s line %d: Missing argument.", filename, linenum);
62565674Skris		if (arg[0] < '0' || arg[0] > '9')
62657429Smarkm			fatal("%.200s line %d: Bad number.", filename, linenum);
62757429Smarkm
62857429Smarkm		/* Octal, decimal, or hex format? */
62965674Skris		value = strtol(arg, &endofnumber, 0);
63065674Skris		if (arg == endofnumber)
63157429Smarkm			fatal("%.200s line %d: Bad number.", filename, linenum);
63257429Smarkm		if (*activep && *intptr == -1)
63357429Smarkm			*intptr = value;
63457429Smarkm		break;
63557429Smarkm
63657429Smarkm	case oConnectionAttempts:
63757429Smarkm		intptr = &options->connection_attempts;
63857429Smarkm		goto parse_int;
63957429Smarkm
64057429Smarkm	case oCipher:
64157429Smarkm		intptr = &options->cipher;
64265674Skris		arg = strdelim(&s);
64365674Skris		if (!arg || *arg == '\0')
64461203Skris			fatal("%.200s line %d: Missing argument.", filename, linenum);
64565674Skris		value = cipher_number(arg);
64657429Smarkm		if (value == -1)
64757429Smarkm			fatal("%.200s line %d: Bad cipher '%s'.",
64892559Sdes			    filename, linenum, arg ? arg : "<NONE>");
64957429Smarkm		if (*activep && *intptr == -1)
65057429Smarkm			*intptr = value;
65157429Smarkm		break;
65257429Smarkm
65360576Skris	case oCiphers:
65465674Skris		arg = strdelim(&s);
65565674Skris		if (!arg || *arg == '\0')
65661203Skris			fatal("%.200s line %d: Missing argument.", filename, linenum);
65765674Skris		if (!ciphers_valid(arg))
65860576Skris			fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.",
65992559Sdes			    filename, linenum, arg ? arg : "<NONE>");
66060576Skris		if (*activep && options->ciphers == NULL)
66165674Skris			options->ciphers = xstrdup(arg);
66260576Skris		break;
66360576Skris
66476262Sgreen	case oMacs:
66576262Sgreen		arg = strdelim(&s);
66676262Sgreen		if (!arg || *arg == '\0')
66776262Sgreen			fatal("%.200s line %d: Missing argument.", filename, linenum);
66876262Sgreen		if (!mac_valid(arg))
66976262Sgreen			fatal("%.200s line %d: Bad SSH2 Mac spec '%s'.",
67092559Sdes			    filename, linenum, arg ? arg : "<NONE>");
67176262Sgreen		if (*activep && options->macs == NULL)
67276262Sgreen			options->macs = xstrdup(arg);
67376262Sgreen		break;
67476262Sgreen
67576262Sgreen	case oHostKeyAlgorithms:
67676262Sgreen		arg = strdelim(&s);
67776262Sgreen		if (!arg || *arg == '\0')
67876262Sgreen			fatal("%.200s line %d: Missing argument.", filename, linenum);
67976262Sgreen		if (!key_names_valid2(arg))
68076262Sgreen			fatal("%.200s line %d: Bad protocol 2 host key algorithms '%s'.",
68192559Sdes			    filename, linenum, arg ? arg : "<NONE>");
68276262Sgreen		if (*activep && options->hostkeyalgorithms == NULL)
68376262Sgreen			options->hostkeyalgorithms = xstrdup(arg);
68476262Sgreen		break;
68576262Sgreen
68660576Skris	case oProtocol:
68760576Skris		intptr = &options->protocol;
68865674Skris		arg = strdelim(&s);
68965674Skris		if (!arg || *arg == '\0')
69061203Skris			fatal("%.200s line %d: Missing argument.", filename, linenum);
69165674Skris		value = proto_spec(arg);
69260576Skris		if (value == SSH_PROTO_UNKNOWN)
69360576Skris			fatal("%.200s line %d: Bad protocol spec '%s'.",
69492559Sdes			    filename, linenum, arg ? arg : "<NONE>");
69560576Skris		if (*activep && *intptr == SSH_PROTO_UNKNOWN)
69660576Skris			*intptr = value;
69760576Skris		break;
69860576Skris
69957429Smarkm	case oLogLevel:
700181111Sdes		log_level_ptr = &options->log_level;
70165674Skris		arg = strdelim(&s);
70265674Skris		value = log_level_number(arg);
70392559Sdes		if (value == SYSLOG_LEVEL_NOT_SET)
70476262Sgreen			fatal("%.200s line %d: unsupported log level '%s'",
70592559Sdes			    filename, linenum, arg ? arg : "<NONE>");
706181111Sdes		if (*activep && *log_level_ptr == SYSLOG_LEVEL_NOT_SET)
707181111Sdes			*log_level_ptr = (LogLevel) value;
70857429Smarkm		break;
70957429Smarkm
71092559Sdes	case oLocalForward:
71157429Smarkm	case oRemoteForward:
71265674Skris		arg = strdelim(&s);
713147005Sdes		if (arg == NULL || *arg == '\0')
71492559Sdes			fatal("%.200s line %d: Missing port argument.",
71592559Sdes			    filename, linenum);
716147005Sdes		arg2 = strdelim(&s);
717147005Sdes		if (arg2 == NULL || *arg2 == '\0')
718147005Sdes			fatal("%.200s line %d: Missing target argument.",
71992559Sdes			    filename, linenum);
720147005Sdes
721147005Sdes		/* construct a string for parse_forward */
722147005Sdes		snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg, arg2);
723147005Sdes
724147005Sdes		if (parse_forward(&fwd, fwdarg) == 0)
72592559Sdes			fatal("%.200s line %d: Bad forwarding specification.",
72692559Sdes			    filename, linenum);
727147005Sdes
72892559Sdes		if (*activep) {
72992559Sdes			if (opcode == oLocalForward)
730147005Sdes				add_local_forward(options, &fwd);
73192559Sdes			else if (opcode == oRemoteForward)
732147005Sdes				add_remote_forward(options, &fwd);
73392559Sdes		}
73457429Smarkm		break;
73557429Smarkm
73676262Sgreen	case oDynamicForward:
73776262Sgreen		arg = strdelim(&s);
73876262Sgreen		if (!arg || *arg == '\0')
73976262Sgreen			fatal("%.200s line %d: Missing port argument.",
74076262Sgreen			    filename, linenum);
741147005Sdes		memset(&fwd, '\0', sizeof(fwd));
742147005Sdes		fwd.connect_host = "socks";
743147005Sdes		fwd.listen_host = hpdelim(&arg);
744147005Sdes		if (fwd.listen_host == NULL ||
745147005Sdes		    strlen(fwd.listen_host) >= NI_MAXHOST)
746147005Sdes			fatal("%.200s line %d: Bad forwarding specification.",
747147005Sdes			    filename, linenum);
748147005Sdes		if (arg) {
749147005Sdes			fwd.listen_port = a2port(arg);
750147005Sdes			fwd.listen_host = cleanhostname(fwd.listen_host);
751147005Sdes		} else {
752147005Sdes			fwd.listen_port = a2port(fwd.listen_host);
753149753Sdes			fwd.listen_host = NULL;
754147005Sdes		}
755147005Sdes		if (fwd.listen_port == 0)
75676262Sgreen			fatal("%.200s line %d: Badly formatted port number.",
75776262Sgreen			    filename, linenum);
75892559Sdes		if (*activep)
759147005Sdes			add_local_forward(options, &fwd);
76076262Sgreen		break;
76176262Sgreen
76292559Sdes	case oClearAllForwardings:
76392559Sdes		intptr = &options->clear_forwardings;
76492559Sdes		goto parse_flag;
76592559Sdes
76657429Smarkm	case oHost:
76757429Smarkm		*activep = 0;
76865674Skris		while ((arg = strdelim(&s)) != NULL && *arg != '\0')
76965674Skris			if (match_pattern(host, arg)) {
77065674Skris				debug("Applying options for %.100s", arg);
77157429Smarkm				*activep = 1;
77257429Smarkm				break;
77357429Smarkm			}
77465674Skris		/* Avoid garbage check below, as strdelim is done. */
77557429Smarkm		return 0;
77657429Smarkm
77757429Smarkm	case oEscapeChar:
77857429Smarkm		intptr = &options->escape_char;
77965674Skris		arg = strdelim(&s);
78065674Skris		if (!arg || *arg == '\0')
78157429Smarkm			fatal("%.200s line %d: Missing argument.", filename, linenum);
78265674Skris		if (arg[0] == '^' && arg[2] == 0 &&
78376262Sgreen		    (u_char) arg[1] >= 64 && (u_char) arg[1] < 128)
78476262Sgreen			value = (u_char) arg[1] & 31;
78565674Skris		else if (strlen(arg) == 1)
78676262Sgreen			value = (u_char) arg[0];
78765674Skris		else if (strcmp(arg, "none") == 0)
78892559Sdes			value = SSH_ESCAPECHAR_NONE;
78957429Smarkm		else {
79057429Smarkm			fatal("%.200s line %d: Bad escape character.",
79192559Sdes			    filename, linenum);
79257429Smarkm			/* NOTREACHED */
79357429Smarkm			value = 0;	/* Avoid compiler warning. */
79457429Smarkm		}
79557429Smarkm		if (*activep && *intptr == -1)
79657429Smarkm			*intptr = value;
79757429Smarkm		break;
79857429Smarkm
799124211Sdes	case oAddressFamily:
800124211Sdes		arg = strdelim(&s);
801149753Sdes		if (!arg || *arg == '\0')
802149753Sdes			fatal("%s line %d: missing address family.",
803149753Sdes			    filename, linenum);
804124211Sdes		intptr = &options->address_family;
805124211Sdes		if (strcasecmp(arg, "inet") == 0)
806124211Sdes			value = AF_INET;
807124211Sdes		else if (strcasecmp(arg, "inet6") == 0)
808124211Sdes			value = AF_INET6;
809124211Sdes		else if (strcasecmp(arg, "any") == 0)
810124211Sdes			value = AF_UNSPEC;
811124211Sdes		else
812124211Sdes			fatal("Unsupported AddressFamily \"%s\"", arg);
813124211Sdes		if (*activep && *intptr == -1)
814124211Sdes			*intptr = value;
815124211Sdes		break;
816124211Sdes
817113911Sdes	case oEnableSSHKeysign:
818113911Sdes		intptr = &options->enable_ssh_keysign;
819113911Sdes		goto parse_flag;
820113911Sdes
821128460Sdes	case oIdentitiesOnly:
822128460Sdes		intptr = &options->identities_only;
823128460Sdes		goto parse_flag;
824128460Sdes
825126277Sdes	case oServerAliveInterval:
826126277Sdes		intptr = &options->server_alive_interval;
827126277Sdes		goto parse_time;
828126277Sdes
829126277Sdes	case oServerAliveCountMax:
830126277Sdes		intptr = &options->server_alive_count_max;
831126277Sdes		goto parse_int;
832126277Sdes
833137019Sdes	case oSendEnv:
834137019Sdes		while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
835137019Sdes			if (strchr(arg, '=') != NULL)
836137019Sdes				fatal("%s line %d: Invalid environment name.",
837137019Sdes				    filename, linenum);
838147005Sdes			if (!*activep)
839147005Sdes				continue;
840137019Sdes			if (options->num_send_env >= MAX_SEND_ENV)
841137019Sdes				fatal("%s line %d: too many send env.",
842137019Sdes				    filename, linenum);
843137019Sdes			options->send_env[options->num_send_env++] =
844137019Sdes			    xstrdup(arg);
845137019Sdes		}
846137019Sdes		break;
847137019Sdes
848137019Sdes	case oControlPath:
849137019Sdes		charptr = &options->control_path;
850137019Sdes		goto parse_string;
851137019Sdes
852137019Sdes	case oControlMaster:
853137019Sdes		intptr = &options->control_master;
854149753Sdes		arg = strdelim(&s);
855149753Sdes		if (!arg || *arg == '\0')
856149753Sdes			fatal("%.200s line %d: Missing ControlMaster argument.",
857149753Sdes			    filename, linenum);
858149753Sdes		value = 0;	/* To avoid compiler warning... */
859149753Sdes		if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
860149753Sdes			value = SSHCTL_MASTER_YES;
861149753Sdes		else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
862149753Sdes			value = SSHCTL_MASTER_NO;
863149753Sdes		else if (strcmp(arg, "auto") == 0)
864149753Sdes			value = SSHCTL_MASTER_AUTO;
865149753Sdes		else if (strcmp(arg, "ask") == 0)
866149753Sdes			value = SSHCTL_MASTER_ASK;
867149753Sdes		else if (strcmp(arg, "autoask") == 0)
868149753Sdes			value = SSHCTL_MASTER_AUTO_ASK;
869149753Sdes		else
870149753Sdes			fatal("%.200s line %d: Bad ControlMaster argument.",
871149753Sdes			    filename, linenum);
872149753Sdes		if (*activep && *intptr == -1)
873149753Sdes			*intptr = value;
874149753Sdes		break;
875137019Sdes
876147005Sdes	case oHashKnownHosts:
877147005Sdes		intptr = &options->hash_known_hosts;
878147005Sdes		goto parse_flag;
879147005Sdes
880157019Sdes	case oTunnel:
881157019Sdes		intptr = &options->tun_open;
882157019Sdes		arg = strdelim(&s);
883157019Sdes		if (!arg || *arg == '\0')
884157019Sdes			fatal("%s line %d: Missing yes/point-to-point/"
885157019Sdes			    "ethernet/no argument.", filename, linenum);
886157019Sdes		value = 0;	/* silence compiler */
887157019Sdes		if (strcasecmp(arg, "ethernet") == 0)
888157019Sdes			value = SSH_TUNMODE_ETHERNET;
889157019Sdes		else if (strcasecmp(arg, "point-to-point") == 0)
890157019Sdes			value = SSH_TUNMODE_POINTOPOINT;
891157019Sdes		else if (strcasecmp(arg, "yes") == 0)
892157019Sdes			value = SSH_TUNMODE_DEFAULT;
893157019Sdes		else if (strcasecmp(arg, "no") == 0)
894157019Sdes			value = SSH_TUNMODE_NO;
895157019Sdes		else
896157019Sdes			fatal("%s line %d: Bad yes/point-to-point/ethernet/"
897157019Sdes			    "no argument: %s", filename, linenum, arg);
898157019Sdes		if (*activep)
899157019Sdes			*intptr = value;
900157019Sdes		break;
901157019Sdes
902157019Sdes	case oTunnelDevice:
903157019Sdes		arg = strdelim(&s);
904157019Sdes		if (!arg || *arg == '\0')
905157019Sdes			fatal("%.200s line %d: Missing argument.", filename, linenum);
906157019Sdes		value = a2tun(arg, &value2);
907157019Sdes		if (value == SSH_TUNID_ERR)
908157019Sdes			fatal("%.200s line %d: Bad tun device.", filename, linenum);
909157019Sdes		if (*activep) {
910157019Sdes			options->tun_local = value;
911157019Sdes			options->tun_remote = value2;
912157019Sdes		}
913157019Sdes		break;
914157019Sdes
915157019Sdes	case oLocalCommand:
916157019Sdes		charptr = &options->local_command;
917157019Sdes		goto parse_command;
918157019Sdes
919157019Sdes	case oPermitLocalCommand:
920157019Sdes		intptr = &options->permit_local_command;
921157019Sdes		goto parse_flag;
922157019Sdes
923181111Sdes	case oVisualHostKey:
924181111Sdes		intptr = &options->visual_host_key;
925181111Sdes		goto parse_flag;
926181111Sdes
92799048Sdes	case oVersionAddendum:
92899048Sdes		ssh_version_set_addendum(strtok(s, "\n"));
92999048Sdes		do {
93099048Sdes			arg = strdelim(&s);
93199048Sdes		} while (arg != NULL && *arg != '\0');
93299048Sdes		break;
93399048Sdes
93498684Sdes	case oDeprecated:
93598684Sdes		debug("%s line %d: Deprecated option \"%s\"",
93698684Sdes		    filename, linenum, keyword);
93798684Sdes		return 0;
93898684Sdes
939124211Sdes	case oUnsupported:
940124211Sdes		error("%s line %d: Unsupported option \"%s\"",
941124211Sdes		    filename, linenum, keyword);
942124211Sdes		return 0;
943124211Sdes
94457429Smarkm	default:
94557429Smarkm		fatal("process_config_line: Unimplemented opcode %d", opcode);
94657429Smarkm	}
94757429Smarkm
94857429Smarkm	/* Check that there is no garbage at end of line. */
94976262Sgreen	if ((arg = strdelim(&s)) != NULL && *arg != '\0') {
95065674Skris		fatal("%.200s line %d: garbage at end of line; \"%.200s\".",
951149753Sdes		    filename, linenum, arg);
95265674Skris	}
95357429Smarkm	return 0;
95457429Smarkm}
95557429Smarkm
95657429Smarkm
95757429Smarkm/*
95857429Smarkm * Reads the config file and modifies the options accordingly.  Options
95957429Smarkm * should already be initialized before this call.  This never returns if
96092559Sdes * there is an error.  If the file does not exist, this returns 0.
96157429Smarkm */
96257429Smarkm
96392559Sdesint
964137019Sdesread_config_file(const char *filename, const char *host, Options *options,
965137019Sdes    int checkperm)
96657429Smarkm{
96757429Smarkm	FILE *f;
96857429Smarkm	char line[1024];
96957429Smarkm	int active, linenum;
97057429Smarkm	int bad_options = 0;
97157429Smarkm
97257429Smarkm	/* Open the file. */
973137019Sdes	if ((f = fopen(filename, "r")) == NULL)
97492559Sdes		return 0;
97557429Smarkm
976137019Sdes	if (checkperm) {
977137019Sdes		struct stat sb;
978137019Sdes
979137019Sdes		if (fstat(fileno(f), &sb) == -1)
980137019Sdes			fatal("fstat %s: %s", filename, strerror(errno));
981137019Sdes		if (((sb.st_uid != 0 && sb.st_uid != getuid()) ||
982137019Sdes		    (sb.st_mode & 022) != 0))
983137019Sdes			fatal("Bad owner or permissions on %s", filename);
984137019Sdes	}
985137019Sdes
98657429Smarkm	debug("Reading configuration data %.200s", filename);
98757429Smarkm
98857429Smarkm	/*
98957429Smarkm	 * Mark that we are now processing the options.  This flag is turned
99057429Smarkm	 * on/off by Host specifications.
99157429Smarkm	 */
99257429Smarkm	active = 1;
99357429Smarkm	linenum = 0;
99457429Smarkm	while (fgets(line, sizeof(line), f)) {
99557429Smarkm		/* Update line number counter. */
99657429Smarkm		linenum++;
99757429Smarkm		if (process_config_line(options, host, line, filename, linenum, &active) != 0)
99857429Smarkm			bad_options++;
99957429Smarkm	}
100057429Smarkm	fclose(f);
100157429Smarkm	if (bad_options > 0)
100276262Sgreen		fatal("%s: terminating, %d bad configuration options",
100392559Sdes		    filename, bad_options);
100492559Sdes	return 1;
100557429Smarkm}
100657429Smarkm
100757429Smarkm/*
100857429Smarkm * Initializes options to special values that indicate that they have not yet
100957429Smarkm * been set.  Read_config_file will only set options with this value. Options
101057429Smarkm * are processed in the following order: command line, user config file,
101157429Smarkm * system config file.  Last, fill_default_options is called.
101257429Smarkm */
101357429Smarkm
101460576Skrisvoid
101557429Smarkminitialize_options(Options * options)
101657429Smarkm{
101757429Smarkm	memset(options, 'X', sizeof(*options));
101857429Smarkm	options->forward_agent = -1;
101957429Smarkm	options->forward_x11 = -1;
1020126277Sdes	options->forward_x11_trusted = -1;
1021162856Sdes	options->exit_on_forward_failure = -1;
102265674Skris	options->xauth_location = NULL;
102357429Smarkm	options->gateway_ports = -1;
102457429Smarkm	options->use_privileged_port = -1;
102557429Smarkm	options->rsa_authentication = -1;
102676262Sgreen	options->pubkey_authentication = -1;
102792559Sdes	options->challenge_response_authentication = -1;
1028124211Sdes	options->gss_authentication = -1;
1029124211Sdes	options->gss_deleg_creds = -1;
103057429Smarkm	options->password_authentication = -1;
103169591Sgreen	options->kbd_interactive_authentication = -1;
103269591Sgreen	options->kbd_interactive_devices = NULL;
103357429Smarkm	options->rhosts_rsa_authentication = -1;
103476262Sgreen	options->hostbased_authentication = -1;
103557429Smarkm	options->batch_mode = -1;
103657429Smarkm	options->check_host_ip = -1;
103757429Smarkm	options->strict_host_key_checking = -1;
103857429Smarkm	options->compression = -1;
1039126277Sdes	options->tcp_keep_alive = -1;
104057429Smarkm	options->compression_level = -1;
104157429Smarkm	options->port = -1;
1042124211Sdes	options->address_family = -1;
104357429Smarkm	options->connection_attempts = -1;
1044124211Sdes	options->connection_timeout = -1;
104557429Smarkm	options->number_of_password_prompts = -1;
104657429Smarkm	options->cipher = -1;
104760576Skris	options->ciphers = NULL;
104876262Sgreen	options->macs = NULL;
104976262Sgreen	options->hostkeyalgorithms = NULL;
105060576Skris	options->protocol = SSH_PROTO_UNKNOWN;
105157429Smarkm	options->num_identity_files = 0;
105257429Smarkm	options->hostname = NULL;
105376262Sgreen	options->host_key_alias = NULL;
105457429Smarkm	options->proxy_command = NULL;
105557429Smarkm	options->user = NULL;
105657429Smarkm	options->escape_char = -1;
105757429Smarkm	options->system_hostfile = NULL;
105857429Smarkm	options->user_hostfile = NULL;
105960576Skris	options->system_hostfile2 = NULL;
106060576Skris	options->user_hostfile2 = NULL;
106157429Smarkm	options->num_local_forwards = 0;
106257429Smarkm	options->num_remote_forwards = 0;
106392559Sdes	options->clear_forwardings = -1;
106492559Sdes	options->log_level = SYSLOG_LEVEL_NOT_SET;
106576262Sgreen	options->preferred_authentications = NULL;
106692559Sdes	options->bind_address = NULL;
106792559Sdes	options->smartcard_device = NULL;
1068113911Sdes	options->enable_ssh_keysign = - 1;
106992559Sdes	options->no_host_authentication_for_localhost = - 1;
1070128460Sdes	options->identities_only = - 1;
1071124211Sdes	options->rekey_limit = - 1;
1072124211Sdes	options->verify_host_key_dns = -1;
1073126277Sdes	options->server_alive_interval = -1;
1074126277Sdes	options->server_alive_count_max = -1;
1075137019Sdes	options->num_send_env = 0;
1076137019Sdes	options->control_path = NULL;
1077137019Sdes	options->control_master = -1;
1078147005Sdes	options->hash_known_hosts = -1;
1079157019Sdes	options->tun_open = -1;
1080157019Sdes	options->tun_local = -1;
1081157019Sdes	options->tun_remote = -1;
1082157019Sdes	options->local_command = NULL;
1083157019Sdes	options->permit_local_command = -1;
1084181111Sdes	options->visual_host_key = -1;
108557429Smarkm}
108657429Smarkm
108757429Smarkm/*
108857429Smarkm * Called after processing other sources of option data, this fills those
108957429Smarkm * options for which no value has been specified with their default values.
109057429Smarkm */
109157429Smarkm
109260576Skrisvoid
109357429Smarkmfill_default_options(Options * options)
109457429Smarkm{
109576262Sgreen	int len;
109676262Sgreen
109757429Smarkm	if (options->forward_agent == -1)
109861203Skris		options->forward_agent = 0;
109957429Smarkm	if (options->forward_x11 == -1)
110057708Sgreen		options->forward_x11 = 0;
1101126277Sdes	if (options->forward_x11_trusted == -1)
1102126277Sdes		options->forward_x11_trusted = 0;
1103162856Sdes	if (options->exit_on_forward_failure == -1)
1104162856Sdes		options->exit_on_forward_failure = 0;
110565674Skris	if (options->xauth_location == NULL)
110692559Sdes		options->xauth_location = _PATH_XAUTH;
110757429Smarkm	if (options->gateway_ports == -1)
110857429Smarkm		options->gateway_ports = 0;
110957429Smarkm	if (options->use_privileged_port == -1)
111076262Sgreen		options->use_privileged_port = 0;
111157429Smarkm	if (options->rsa_authentication == -1)
111257429Smarkm		options->rsa_authentication = 1;
111376262Sgreen	if (options->pubkey_authentication == -1)
111476262Sgreen		options->pubkey_authentication = 1;
111592559Sdes	if (options->challenge_response_authentication == -1)
111692559Sdes		options->challenge_response_authentication = 1;
1117124211Sdes	if (options->gss_authentication == -1)
1118126277Sdes		options->gss_authentication = 0;
1119124211Sdes	if (options->gss_deleg_creds == -1)
1120124211Sdes		options->gss_deleg_creds = 0;
112157429Smarkm	if (options->password_authentication == -1)
112257429Smarkm		options->password_authentication = 1;
112369591Sgreen	if (options->kbd_interactive_authentication == -1)
112476262Sgreen		options->kbd_interactive_authentication = 1;
112557429Smarkm	if (options->rhosts_rsa_authentication == -1)
112698684Sdes		options->rhosts_rsa_authentication = 0;
112776262Sgreen	if (options->hostbased_authentication == -1)
112876262Sgreen		options->hostbased_authentication = 0;
112957429Smarkm	if (options->batch_mode == -1)
113057429Smarkm		options->batch_mode = 0;
113157429Smarkm	if (options->check_host_ip == -1)
113299048Sdes		options->check_host_ip = 0;
113357429Smarkm	if (options->strict_host_key_checking == -1)
113457429Smarkm		options->strict_host_key_checking = 2;	/* 2 is default */
113557429Smarkm	if (options->compression == -1)
113657429Smarkm		options->compression = 0;
1137126277Sdes	if (options->tcp_keep_alive == -1)
1138126277Sdes		options->tcp_keep_alive = 1;
113957429Smarkm	if (options->compression_level == -1)
114057429Smarkm		options->compression_level = 6;
114157429Smarkm	if (options->port == -1)
114257429Smarkm		options->port = 0;	/* Filled in ssh_connect. */
1143124211Sdes	if (options->address_family == -1)
1144124211Sdes		options->address_family = AF_UNSPEC;
114557429Smarkm	if (options->connection_attempts == -1)
114692559Sdes		options->connection_attempts = 1;
114757429Smarkm	if (options->number_of_password_prompts == -1)
114857429Smarkm		options->number_of_password_prompts = 3;
114957429Smarkm	/* Selected in ssh_login(). */
115057429Smarkm	if (options->cipher == -1)
115157429Smarkm		options->cipher = SSH_CIPHER_NOT_SET;
115260576Skris	/* options->ciphers, default set in myproposals.h */
115376262Sgreen	/* options->macs, default set in myproposals.h */
115476262Sgreen	/* options->hostkeyalgorithms, default set in myproposals.h */
115560576Skris	if (options->protocol == SSH_PROTO_UNKNOWN)
115676262Sgreen		options->protocol = SSH_PROTO_1|SSH_PROTO_2;
115757429Smarkm	if (options->num_identity_files == 0) {
115876262Sgreen		if (options->protocol & SSH_PROTO_1) {
115976262Sgreen			len = 2 + strlen(_PATH_SSH_CLIENT_IDENTITY) + 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_IDENTITY);
116476262Sgreen		}
116576262Sgreen		if (options->protocol & SSH_PROTO_2) {
116676262Sgreen			len = 2 + strlen(_PATH_SSH_CLIENT_ID_RSA) + 1;
116776262Sgreen			options->identity_files[options->num_identity_files] =
116876262Sgreen			    xmalloc(len);
116976262Sgreen			snprintf(options->identity_files[options->num_identity_files++],
117076262Sgreen			    len, "~/%.100s", _PATH_SSH_CLIENT_ID_RSA);
117176262Sgreen
117276262Sgreen			len = 2 + strlen(_PATH_SSH_CLIENT_ID_DSA) + 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_ID_DSA);
117776262Sgreen		}
117857429Smarkm	}
117957429Smarkm	if (options->escape_char == -1)
118057429Smarkm		options->escape_char = '~';
118157429Smarkm	if (options->system_hostfile == NULL)
118276262Sgreen		options->system_hostfile = _PATH_SSH_SYSTEM_HOSTFILE;
118357429Smarkm	if (options->user_hostfile == NULL)
118476262Sgreen		options->user_hostfile = _PATH_SSH_USER_HOSTFILE;
118560576Skris	if (options->system_hostfile2 == NULL)
118676262Sgreen		options->system_hostfile2 = _PATH_SSH_SYSTEM_HOSTFILE2;
118760576Skris	if (options->user_hostfile2 == NULL)
118876262Sgreen		options->user_hostfile2 = _PATH_SSH_USER_HOSTFILE2;
118992559Sdes	if (options->log_level == SYSLOG_LEVEL_NOT_SET)
119057429Smarkm		options->log_level = SYSLOG_LEVEL_INFO;
119192559Sdes	if (options->clear_forwardings == 1)
119292559Sdes		clear_forwardings(options);
119392559Sdes	if (options->no_host_authentication_for_localhost == - 1)
119492559Sdes		options->no_host_authentication_for_localhost = 0;
1195128460Sdes	if (options->identities_only == -1)
1196128460Sdes		options->identities_only = 0;
1197113911Sdes	if (options->enable_ssh_keysign == -1)
1198113911Sdes		options->enable_ssh_keysign = 0;
1199124211Sdes	if (options->rekey_limit == -1)
1200124211Sdes		options->rekey_limit = 0;
1201124211Sdes	if (options->verify_host_key_dns == -1)
1202124211Sdes		options->verify_host_key_dns = 0;
1203126277Sdes	if (options->server_alive_interval == -1)
1204126277Sdes		options->server_alive_interval = 0;
1205126277Sdes	if (options->server_alive_count_max == -1)
1206126277Sdes		options->server_alive_count_max = 3;
1207137019Sdes	if (options->control_master == -1)
1208137019Sdes		options->control_master = 0;
1209147005Sdes	if (options->hash_known_hosts == -1)
1210147005Sdes		options->hash_known_hosts = 0;
1211157019Sdes	if (options->tun_open == -1)
1212157019Sdes		options->tun_open = SSH_TUNMODE_NO;
1213157019Sdes	if (options->tun_local == -1)
1214157019Sdes		options->tun_local = SSH_TUNID_ANY;
1215157019Sdes	if (options->tun_remote == -1)
1216157019Sdes		options->tun_remote = SSH_TUNID_ANY;
1217157019Sdes	if (options->permit_local_command == -1)
1218157019Sdes		options->permit_local_command = 0;
1219181111Sdes	if (options->visual_host_key == -1)
1220181111Sdes		options->visual_host_key = 0;
1221157019Sdes	/* options->local_command should not be set by default */
122257429Smarkm	/* options->proxy_command should not be set by default */
122357429Smarkm	/* options->user will be set in the main program if appropriate */
122457429Smarkm	/* options->hostname will be set in the main program if appropriate */
122576262Sgreen	/* options->host_key_alias should not be set by default */
122676262Sgreen	/* options->preferred_authentications will be set in ssh */
122757429Smarkm}
1228147005Sdes
1229147005Sdes/*
1230147005Sdes * parse_forward
1231147005Sdes * parses a string containing a port forwarding specification of the form:
1232147005Sdes *	[listenhost:]listenport:connecthost:connectport
1233147005Sdes * returns number of arguments parsed or zero on error
1234147005Sdes */
1235147005Sdesint
1236147005Sdesparse_forward(Forward *fwd, const char *fwdspec)
1237147005Sdes{
1238147005Sdes	int i;
1239147005Sdes	char *p, *cp, *fwdarg[4];
1240147005Sdes
1241147005Sdes	memset(fwd, '\0', sizeof(*fwd));
1242147005Sdes
1243147005Sdes	cp = p = xstrdup(fwdspec);
1244147005Sdes
1245147005Sdes	/* skip leading spaces */
1246181111Sdes	while (isspace(*cp))
1247147005Sdes		cp++;
1248147005Sdes
1249147005Sdes	for (i = 0; i < 4; ++i)
1250147005Sdes		if ((fwdarg[i] = hpdelim(&cp)) == NULL)
1251147005Sdes			break;
1252147005Sdes
1253147005Sdes	/* Check for trailing garbage in 4-arg case*/
1254147005Sdes	if (cp != NULL)
1255147005Sdes		i = 0;	/* failure */
1256147005Sdes
1257147005Sdes	switch (i) {
1258147005Sdes	case 3:
1259147005Sdes		fwd->listen_host = NULL;
1260147005Sdes		fwd->listen_port = a2port(fwdarg[0]);
1261147005Sdes		fwd->connect_host = xstrdup(cleanhostname(fwdarg[1]));
1262147005Sdes		fwd->connect_port = a2port(fwdarg[2]);
1263147005Sdes		break;
1264147005Sdes
1265147005Sdes	case 4:
1266147005Sdes		fwd->listen_host = xstrdup(cleanhostname(fwdarg[0]));
1267147005Sdes		fwd->listen_port = a2port(fwdarg[1]);
1268147005Sdes		fwd->connect_host = xstrdup(cleanhostname(fwdarg[2]));
1269147005Sdes		fwd->connect_port = a2port(fwdarg[3]);
1270147005Sdes		break;
1271147005Sdes	default:
1272147005Sdes		i = 0; /* failure */
1273147005Sdes	}
1274147005Sdes
1275147005Sdes	xfree(p);
1276147005Sdes
1277181111Sdes	if (fwd->listen_port == 0 || fwd->connect_port == 0)
1278147005Sdes		goto fail_free;
1279147005Sdes
1280147005Sdes	if (fwd->connect_host != NULL &&
1281147005Sdes	    strlen(fwd->connect_host) >= NI_MAXHOST)
1282147005Sdes		goto fail_free;
1283147005Sdes
1284147005Sdes	return (i);
1285147005Sdes
1286147005Sdes fail_free:
1287147005Sdes	if (fwd->connect_host != NULL)
1288147005Sdes		xfree(fwd->connect_host);
1289147005Sdes	if (fwd->listen_host != NULL)
1290147005Sdes		xfree(fwd->listen_host);
1291147005Sdes	return (0);
1292147005Sdes}
1293