readconf.c revision 99048
157429Smarkm/*
257429Smarkm * Author: Tatu Ylonen <ylo@cs.hut.fi>
357429Smarkm * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
457429Smarkm *                    All rights reserved
557429Smarkm * Functions for reading the configuration files.
660576Skris *
765674Skris * As far as I am concerned, the code I have written for this software
865674Skris * can be used freely for any purpose.  Any derived versions of this
965674Skris * software must be clearly marked as such, and if the derived work is
1065674Skris * incompatible with the protocol description in the RFC file, it must be
1165674Skris * called by a name other than "ssh" or "Secure Shell".
1257429Smarkm */
1357429Smarkm
1457429Smarkm#include "includes.h"
1598684SdesRCSID("$OpenBSD: readconf.c,v 1.100 2002/06/19 00:27:55 deraadt Exp $");
1699048SdesRCSID("$FreeBSD: head/crypto/openssh/readconf.c 99048 2002-06-29 10:51:56Z des $");
1757429Smarkm
1857429Smarkm#include "ssh.h"
1976262Sgreen#include "xmalloc.h"
2076262Sgreen#include "compat.h"
2176262Sgreen#include "cipher.h"
2276262Sgreen#include "pathnames.h"
2376262Sgreen#include "log.h"
2457429Smarkm#include "readconf.h"
2560576Skris#include "match.h"
2676262Sgreen#include "misc.h"
2776262Sgreen#include "kex.h"
2876262Sgreen#include "mac.h"
2957429Smarkm
3057429Smarkm/* Format of the configuration file:
3157429Smarkm
3257429Smarkm   # Configuration data is parsed as follows:
3357429Smarkm   #  1. command line options
3457429Smarkm   #  2. user-specific file
3557429Smarkm   #  3. system-wide file
3657429Smarkm   # Any configuration value is only changed the first time it is set.
3757429Smarkm   # Thus, host-specific definitions should be at the beginning of the
3857429Smarkm   # configuration file, and defaults at the end.
3957429Smarkm
4057429Smarkm   # Host-specific declarations.  These may override anything above.  A single
4157429Smarkm   # host may match multiple declarations; these are processed in the order
4257429Smarkm   # that they are given in.
4357429Smarkm
4457429Smarkm   Host *.ngs.fi ngs.fi
4598684Sdes     User foo
4657429Smarkm
4757429Smarkm   Host fake.com
4857429Smarkm     HostName another.host.name.real.org
4957429Smarkm     User blaah
5057429Smarkm     Port 34289
5157429Smarkm     ForwardX11 no
5257429Smarkm     ForwardAgent no
5357429Smarkm
5457429Smarkm   Host books.com
5557429Smarkm     RemoteForward 9999 shadows.cs.hut.fi:9999
5657429Smarkm     Cipher 3des
5757429Smarkm
5857429Smarkm   Host fascist.blob.com
5957429Smarkm     Port 23123
6057429Smarkm     User tylonen
6157429Smarkm     RhostsAuthentication no
6257429Smarkm     PasswordAuthentication no
6357429Smarkm
6457429Smarkm   Host puukko.hut.fi
6557429Smarkm     User t35124p
6657429Smarkm     ProxyCommand ssh-proxy %h %p
6757429Smarkm
6857429Smarkm   Host *.fr
6998684Sdes     PublicKeyAuthentication no
7057429Smarkm
7157429Smarkm   Host *.su
7257429Smarkm     Cipher none
7357429Smarkm     PasswordAuthentication no
7457429Smarkm
7557429Smarkm   # Defaults for various options
7657429Smarkm   Host *
7757429Smarkm     ForwardAgent no
7876262Sgreen     ForwardX11 no
7957429Smarkm     RhostsAuthentication yes
8057429Smarkm     PasswordAuthentication yes
8157429Smarkm     RSAAuthentication yes
8257429Smarkm     RhostsRSAAuthentication yes
8357429Smarkm     StrictHostKeyChecking yes
8457429Smarkm     KeepAlives no
8557429Smarkm     IdentityFile ~/.ssh/identity
8657429Smarkm     Port 22
8757429Smarkm     EscapeChar ~
8857429Smarkm
8957429Smarkm*/
9057429Smarkm
9157429Smarkm/* Keyword tokens. */
9257429Smarkm
9357429Smarkmtypedef enum {
9457429Smarkm	oBadOption,
9557429Smarkm	oForwardAgent, oForwardX11, oGatewayPorts, oRhostsAuthentication,
9698684Sdes	oPasswordAuthentication, oRSAAuthentication,
9776262Sgreen	oChallengeResponseAuthentication, oXAuthLocation,
9873400Sassar#if defined(KRB4) || defined(KRB5)
9973400Sassar	oKerberosAuthentication,
10092559Sdes#endif
10192559Sdes#if defined(AFS) || defined(KRB5)
10292559Sdes	oKerberosTgtPassing,
10392559Sdes#endif
10457429Smarkm#ifdef AFS
10592559Sdes	oAFSTokenPassing,
10657429Smarkm#endif
10757429Smarkm	oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward,
10857429Smarkm	oUser, oHost, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
10957429Smarkm	oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
11057429Smarkm	oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
11176262Sgreen	oCompressionLevel, oKeepAlives, oNumberOfPasswordPrompts,
11276262Sgreen	oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oMacs,
11376262Sgreen	oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication,
11476262Sgreen	oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
11576262Sgreen	oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
11692559Sdes	oHostKeyAlgorithms, oBindAddress, oSmartcardDevice,
11793698Sdes	oClearAllForwardings, oNoHostAuthenticationForLocalhost,
11899048Sdes	oVersionAddendum,
11998684Sdes	oDeprecated
12057429Smarkm} OpCodes;
12157429Smarkm
12257429Smarkm/* Textual representations of the tokens. */
12357429Smarkm
12457429Smarkmstatic struct {
12557429Smarkm	const char *name;
12657429Smarkm	OpCodes opcode;
12757429Smarkm} keywords[] = {
12857429Smarkm	{ "forwardagent", oForwardAgent },
12957429Smarkm	{ "forwardx11", oForwardX11 },
13065674Skris	{ "xauthlocation", oXAuthLocation },
13157429Smarkm	{ "gatewayports", oGatewayPorts },
13257429Smarkm	{ "useprivilegedport", oUsePrivilegedPort },
13357429Smarkm	{ "rhostsauthentication", oRhostsAuthentication },
13457429Smarkm	{ "passwordauthentication", oPasswordAuthentication },
13569591Sgreen	{ "kbdinteractiveauthentication", oKbdInteractiveAuthentication },
13669591Sgreen	{ "kbdinteractivedevices", oKbdInteractiveDevices },
13757429Smarkm	{ "rsaauthentication", oRSAAuthentication },
13876262Sgreen	{ "pubkeyauthentication", oPubkeyAuthentication },
13976262Sgreen	{ "dsaauthentication", oPubkeyAuthentication },		    /* alias */
14076262Sgreen	{ "rhostsrsaauthentication", oRhostsRSAAuthentication },
14176262Sgreen	{ "hostbasedauthentication", oHostbasedAuthentication },
14276262Sgreen	{ "challengeresponseauthentication", oChallengeResponseAuthentication },
14376262Sgreen	{ "skeyauthentication", oChallengeResponseAuthentication }, /* alias */
14476262Sgreen	{ "tisauthentication", oChallengeResponseAuthentication },  /* alias */
14573400Sassar#if defined(KRB4) || defined(KRB5)
14673400Sassar	{ "kerberosauthentication", oKerberosAuthentication },
14792559Sdes#endif
14892559Sdes#if defined(AFS) || defined(KRB5)
14992559Sdes	{ "kerberostgtpassing", oKerberosTgtPassing },
15092559Sdes#endif
15157429Smarkm#ifdef AFS
15257429Smarkm	{ "afstokenpassing", oAFSTokenPassing },
15357429Smarkm#endif
15498684Sdes	{ "fallbacktorsh", oDeprecated },
15598684Sdes	{ "usersh", oDeprecated },
15657429Smarkm	{ "identityfile", oIdentityFile },
15776262Sgreen	{ "identityfile2", oIdentityFile },			/* alias */
15857429Smarkm	{ "hostname", oHostName },
15976262Sgreen	{ "hostkeyalias", oHostKeyAlias },
16057429Smarkm	{ "proxycommand", oProxyCommand },
16157429Smarkm	{ "port", oPort },
16257429Smarkm	{ "cipher", oCipher },
16360576Skris	{ "ciphers", oCiphers },
16476262Sgreen	{ "macs", oMacs },
16560576Skris	{ "protocol", oProtocol },
16657429Smarkm	{ "remoteforward", oRemoteForward },
16757429Smarkm	{ "localforward", oLocalForward },
16857429Smarkm	{ "user", oUser },
16957429Smarkm	{ "host", oHost },
17057429Smarkm	{ "escapechar", oEscapeChar },
17157429Smarkm	{ "globalknownhostsfile", oGlobalKnownHostsFile },
17292559Sdes	{ "userknownhostsfile", oUserKnownHostsFile },		/* obsolete */
17360576Skris	{ "globalknownhostsfile2", oGlobalKnownHostsFile2 },
17492559Sdes	{ "userknownhostsfile2", oUserKnownHostsFile2 },	/* obsolete */
17557429Smarkm	{ "connectionattempts", oConnectionAttempts },
17657429Smarkm	{ "batchmode", oBatchMode },
17757429Smarkm	{ "checkhostip", oCheckHostIP },
17857429Smarkm	{ "stricthostkeychecking", oStrictHostKeyChecking },
17957429Smarkm	{ "compression", oCompression },
18057429Smarkm	{ "compressionlevel", oCompressionLevel },
18157429Smarkm	{ "keepalive", oKeepAlives },
18257429Smarkm	{ "numberofpasswordprompts", oNumberOfPasswordPrompts },
18357429Smarkm	{ "loglevel", oLogLevel },
18476262Sgreen	{ "dynamicforward", oDynamicForward },
18576262Sgreen	{ "preferredauthentications", oPreferredAuthentications },
18676262Sgreen	{ "hostkeyalgorithms", oHostKeyAlgorithms },
18792559Sdes	{ "bindaddress", oBindAddress },
18892559Sdes	{ "smartcarddevice", oSmartcardDevice },
18992559Sdes	{ "clearallforwardings", oClearAllForwardings },
19092559Sdes	{ "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
19199048Sdes	{ "versionaddendum", oVersionAddendum },
19292559Sdes	{ NULL, oBadOption }
19357429Smarkm};
19457429Smarkm
19557429Smarkm/*
19657429Smarkm * Adds a local TCP/IP port forward to options.  Never returns if there is an
19757429Smarkm * error.
19857429Smarkm */
19957429Smarkm
20060576Skrisvoid
20157429Smarkmadd_local_forward(Options *options, u_short port, const char *host,
20257429Smarkm		  u_short host_port)
20357429Smarkm{
20457429Smarkm	Forward *fwd;
20598941Sdes#ifndef HAVE_CYGWIN
20657429Smarkm	extern uid_t original_real_uid;
20757429Smarkm	if (port < IPPORT_RESERVED && original_real_uid != 0)
20876262Sgreen		fatal("Privileged ports can only be forwarded by root.");
20998941Sdes#endif
21057429Smarkm	if (options->num_local_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
21157429Smarkm		fatal("Too many local forwards (max %d).", SSH_MAX_FORWARDS_PER_DIRECTION);
21257429Smarkm	fwd = &options->local_forwards[options->num_local_forwards++];
21357429Smarkm	fwd->port = port;
21457429Smarkm	fwd->host = xstrdup(host);
21557429Smarkm	fwd->host_port = host_port;
21657429Smarkm}
21757429Smarkm
21857429Smarkm/*
21957429Smarkm * Adds a remote TCP/IP port forward to options.  Never returns if there is
22057429Smarkm * an error.
22157429Smarkm */
22257429Smarkm
22360576Skrisvoid
22457429Smarkmadd_remote_forward(Options *options, u_short port, const char *host,
22557429Smarkm		   u_short host_port)
22657429Smarkm{
22757429Smarkm	Forward *fwd;
22857429Smarkm	if (options->num_remote_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
22957429Smarkm		fatal("Too many remote forwards (max %d).",
23092559Sdes		    SSH_MAX_FORWARDS_PER_DIRECTION);
23157429Smarkm	fwd = &options->remote_forwards[options->num_remote_forwards++];
23257429Smarkm	fwd->port = port;
23357429Smarkm	fwd->host = xstrdup(host);
23457429Smarkm	fwd->host_port = host_port;
23557429Smarkm}
23657429Smarkm
23792559Sdesstatic void
23892559Sdesclear_forwardings(Options *options)
23992559Sdes{
24092559Sdes	int i;
24192559Sdes
24292559Sdes	for (i = 0; i < options->num_local_forwards; i++)
24392559Sdes		xfree(options->local_forwards[i].host);
24492559Sdes	options->num_local_forwards = 0;
24592559Sdes	for (i = 0; i < options->num_remote_forwards; i++)
24692559Sdes		xfree(options->remote_forwards[i].host);
24792559Sdes	options->num_remote_forwards = 0;
24892559Sdes}
24992559Sdes
25057429Smarkm/*
25176262Sgreen * Returns the number of the token pointed to by cp or oBadOption.
25257429Smarkm */
25357429Smarkm
25460576Skrisstatic OpCodes
25557429Smarkmparse_token(const char *cp, const char *filename, int linenum)
25657429Smarkm{
25776262Sgreen	u_int i;
25857429Smarkm
25957429Smarkm	for (i = 0; keywords[i].name; i++)
26057429Smarkm		if (strcasecmp(cp, keywords[i].name) == 0)
26157429Smarkm			return keywords[i].opcode;
26257429Smarkm
26376262Sgreen	error("%s: line %d: Bad configuration option: %s",
26476262Sgreen	    filename, linenum, cp);
26557429Smarkm	return oBadOption;
26657429Smarkm}
26757429Smarkm
26857429Smarkm/*
26957429Smarkm * Processes a single option line as used in the configuration files. This
27057429Smarkm * only sets those values that have not already been set.
27157429Smarkm */
27257429Smarkm
27357429Smarkmint
27457429Smarkmprocess_config_line(Options *options, const char *host,
27557429Smarkm		    char *line, const char *filename, int linenum,
27657429Smarkm		    int *activep)
27757429Smarkm{
27865674Skris	char buf[256], *s, *string, **charptr, *endofnumber, *keyword, *arg;
27957429Smarkm	int opcode, *intptr, value;
28057429Smarkm	u_short fwd_port, fwd_host_port;
28192559Sdes	char sfwd_host_port[6];
28257429Smarkm
28365674Skris	s = line;
28465674Skris	/* Get the keyword. (Each line is supposed to begin with a keyword). */
28565674Skris	keyword = strdelim(&s);
28665674Skris	/* Ignore leading whitespace. */
28765674Skris	if (*keyword == '\0')
28865674Skris		keyword = strdelim(&s);
28976262Sgreen	if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#')
29057429Smarkm		return 0;
29157429Smarkm
29265674Skris	opcode = parse_token(keyword, filename, linenum);
29357429Smarkm
29457429Smarkm	switch (opcode) {
29557429Smarkm	case oBadOption:
29657429Smarkm		/* don't panic, but count bad options */
29757429Smarkm		return -1;
29857429Smarkm		/* NOTREACHED */
29957429Smarkm	case oForwardAgent:
30057429Smarkm		intptr = &options->forward_agent;
30157429Smarkmparse_flag:
30265674Skris		arg = strdelim(&s);
30365674Skris		if (!arg || *arg == '\0')
30457429Smarkm			fatal("%.200s line %d: Missing yes/no argument.", filename, linenum);
30557429Smarkm		value = 0;	/* To avoid compiler warning... */
30665674Skris		if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
30757429Smarkm			value = 1;
30865674Skris		else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
30957429Smarkm			value = 0;
31057429Smarkm		else
31157429Smarkm			fatal("%.200s line %d: Bad yes/no argument.", filename, linenum);
31257429Smarkm		if (*activep && *intptr == -1)
31357429Smarkm			*intptr = value;
31457429Smarkm		break;
31557429Smarkm
31657429Smarkm	case oForwardX11:
31757429Smarkm		intptr = &options->forward_x11;
31857429Smarkm		goto parse_flag;
31957429Smarkm
32057429Smarkm	case oGatewayPorts:
32157429Smarkm		intptr = &options->gateway_ports;
32257429Smarkm		goto parse_flag;
32357429Smarkm
32457429Smarkm	case oUsePrivilegedPort:
32557429Smarkm		intptr = &options->use_privileged_port;
32657429Smarkm		goto parse_flag;
32757429Smarkm
32857429Smarkm	case oRhostsAuthentication:
32957429Smarkm		intptr = &options->rhosts_authentication;
33057429Smarkm		goto parse_flag;
33157429Smarkm
33257429Smarkm	case oPasswordAuthentication:
33357429Smarkm		intptr = &options->password_authentication;
33457429Smarkm		goto parse_flag;
33557429Smarkm
33669591Sgreen	case oKbdInteractiveAuthentication:
33769591Sgreen		intptr = &options->kbd_interactive_authentication;
33869591Sgreen		goto parse_flag;
33969591Sgreen
34069591Sgreen	case oKbdInteractiveDevices:
34169591Sgreen		charptr = &options->kbd_interactive_devices;
34269591Sgreen		goto parse_string;
34369591Sgreen
34476262Sgreen	case oPubkeyAuthentication:
34576262Sgreen		intptr = &options->pubkey_authentication;
34660576Skris		goto parse_flag;
34760576Skris
34857429Smarkm	case oRSAAuthentication:
34957429Smarkm		intptr = &options->rsa_authentication;
35057429Smarkm		goto parse_flag;
35157429Smarkm
35257429Smarkm	case oRhostsRSAAuthentication:
35357429Smarkm		intptr = &options->rhosts_rsa_authentication;
35457429Smarkm		goto parse_flag;
35557429Smarkm
35676262Sgreen	case oHostbasedAuthentication:
35776262Sgreen		intptr = &options->hostbased_authentication;
35857429Smarkm		goto parse_flag;
35957429Smarkm
36092559Sdes	case oChallengeResponseAuthentication:
36192559Sdes		intptr = &options->challenge_response_authentication;
36292559Sdes		goto parse_flag;
36373400Sassar#if defined(KRB4) || defined(KRB5)
36473400Sassar	case oKerberosAuthentication:
36573400Sassar		intptr = &options->kerberos_authentication;
36657429Smarkm		goto parse_flag;
36792559Sdes#endif
36892559Sdes#if defined(AFS) || defined(KRB5)
36992559Sdes	case oKerberosTgtPassing:
37092559Sdes		intptr = &options->kerberos_tgt_passing;
37176262Sgreen		goto parse_flag;
37292559Sdes#endif
37357429Smarkm#ifdef AFS
37457429Smarkm	case oAFSTokenPassing:
37557429Smarkm		intptr = &options->afs_token_passing;
37657429Smarkm		goto parse_flag;
37757429Smarkm#endif
37857429Smarkm	case oBatchMode:
37957429Smarkm		intptr = &options->batch_mode;
38057429Smarkm		goto parse_flag;
38157429Smarkm
38257429Smarkm	case oCheckHostIP:
38357429Smarkm		intptr = &options->check_host_ip;
38457429Smarkm		goto parse_flag;
38557429Smarkm
38657429Smarkm	case oStrictHostKeyChecking:
38757429Smarkm		intptr = &options->strict_host_key_checking;
38865674Skris		arg = strdelim(&s);
38965674Skris		if (!arg || *arg == '\0')
39076262Sgreen			fatal("%.200s line %d: Missing yes/no/ask argument.",
39192559Sdes			    filename, linenum);
39257429Smarkm		value = 0;	/* To avoid compiler warning... */
39365674Skris		if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
39457429Smarkm			value = 1;
39565674Skris		else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
39657429Smarkm			value = 0;
39765674Skris		else if (strcmp(arg, "ask") == 0)
39857429Smarkm			value = 2;
39957429Smarkm		else
40057429Smarkm			fatal("%.200s line %d: Bad yes/no/ask argument.", filename, linenum);
40157429Smarkm		if (*activep && *intptr == -1)
40257429Smarkm			*intptr = value;
40357429Smarkm		break;
40457429Smarkm
40557429Smarkm	case oCompression:
40657429Smarkm		intptr = &options->compression;
40757429Smarkm		goto parse_flag;
40857429Smarkm
40957429Smarkm	case oKeepAlives:
41057429Smarkm		intptr = &options->keepalives;
41157429Smarkm		goto parse_flag;
41257429Smarkm
41392559Sdes	case oNoHostAuthenticationForLocalhost:
41492559Sdes		intptr = &options->no_host_authentication_for_localhost;
41592559Sdes		goto parse_flag;
41692559Sdes
41757429Smarkm	case oNumberOfPasswordPrompts:
41857429Smarkm		intptr = &options->number_of_password_prompts;
41957429Smarkm		goto parse_int;
42057429Smarkm
42157429Smarkm	case oCompressionLevel:
42257429Smarkm		intptr = &options->compression_level;
42357429Smarkm		goto parse_int;
42457429Smarkm
42557429Smarkm	case oIdentityFile:
42665674Skris		arg = strdelim(&s);
42765674Skris		if (!arg || *arg == '\0')
42857429Smarkm			fatal("%.200s line %d: Missing argument.", filename, linenum);
42957429Smarkm		if (*activep) {
43076262Sgreen			intptr = &options->num_identity_files;
43160576Skris			if (*intptr >= SSH_MAX_IDENTITY_FILES)
43257429Smarkm				fatal("%.200s line %d: Too many identity files specified (max %d).",
43392559Sdes				    filename, linenum, SSH_MAX_IDENTITY_FILES);
43476262Sgreen			charptr =  &options->identity_files[*intptr];
43565674Skris			*charptr = xstrdup(arg);
43660576Skris			*intptr = *intptr + 1;
43757429Smarkm		}
43857429Smarkm		break;
43957429Smarkm
44065674Skris	case oXAuthLocation:
44165674Skris		charptr=&options->xauth_location;
44265674Skris		goto parse_string;
44365674Skris
44457429Smarkm	case oUser:
44557429Smarkm		charptr = &options->user;
44657429Smarkmparse_string:
44765674Skris		arg = strdelim(&s);
44865674Skris		if (!arg || *arg == '\0')
44957429Smarkm			fatal("%.200s line %d: Missing argument.", filename, linenum);
45057429Smarkm		if (*activep && *charptr == NULL)
45165674Skris			*charptr = xstrdup(arg);
45257429Smarkm		break;
45357429Smarkm
45457429Smarkm	case oGlobalKnownHostsFile:
45557429Smarkm		charptr = &options->system_hostfile;
45657429Smarkm		goto parse_string;
45757429Smarkm
45857429Smarkm	case oUserKnownHostsFile:
45957429Smarkm		charptr = &options->user_hostfile;
46057429Smarkm		goto parse_string;
46157429Smarkm
46260576Skris	case oGlobalKnownHostsFile2:
46360576Skris		charptr = &options->system_hostfile2;
46460576Skris		goto parse_string;
46560576Skris
46660576Skris	case oUserKnownHostsFile2:
46760576Skris		charptr = &options->user_hostfile2;
46860576Skris		goto parse_string;
46960576Skris
47057429Smarkm	case oHostName:
47157429Smarkm		charptr = &options->hostname;
47257429Smarkm		goto parse_string;
47357429Smarkm
47476262Sgreen	case oHostKeyAlias:
47576262Sgreen		charptr = &options->host_key_alias;
47676262Sgreen		goto parse_string;
47776262Sgreen
47876262Sgreen	case oPreferredAuthentications:
47976262Sgreen		charptr = &options->preferred_authentications;
48076262Sgreen		goto parse_string;
48176262Sgreen
48292559Sdes	case oBindAddress:
48392559Sdes		charptr = &options->bind_address;
48492559Sdes		goto parse_string;
48592559Sdes
48692559Sdes	case oSmartcardDevice:
48792559Sdes		charptr = &options->smartcard_device;
48892559Sdes		goto parse_string;
48992559Sdes
49057429Smarkm	case oProxyCommand:
49157429Smarkm		charptr = &options->proxy_command;
49257429Smarkm		string = xstrdup("");
49365674Skris		while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
49465674Skris			string = xrealloc(string, strlen(string) + strlen(arg) + 2);
49557429Smarkm			strcat(string, " ");
49665674Skris			strcat(string, arg);
49757429Smarkm		}
49857429Smarkm		if (*activep && *charptr == NULL)
49957429Smarkm			*charptr = string;
50057429Smarkm		else
50157429Smarkm			xfree(string);
50257429Smarkm		return 0;
50357429Smarkm
50457429Smarkm	case oPort:
50557429Smarkm		intptr = &options->port;
50657429Smarkmparse_int:
50765674Skris		arg = strdelim(&s);
50865674Skris		if (!arg || *arg == '\0')
50957429Smarkm			fatal("%.200s line %d: Missing argument.", filename, linenum);
51065674Skris		if (arg[0] < '0' || arg[0] > '9')
51157429Smarkm			fatal("%.200s line %d: Bad number.", filename, linenum);
51257429Smarkm
51357429Smarkm		/* Octal, decimal, or hex format? */
51465674Skris		value = strtol(arg, &endofnumber, 0);
51565674Skris		if (arg == endofnumber)
51657429Smarkm			fatal("%.200s line %d: Bad number.", filename, linenum);
51757429Smarkm		if (*activep && *intptr == -1)
51857429Smarkm			*intptr = value;
51957429Smarkm		break;
52057429Smarkm
52157429Smarkm	case oConnectionAttempts:
52257429Smarkm		intptr = &options->connection_attempts;
52357429Smarkm		goto parse_int;
52457429Smarkm
52557429Smarkm	case oCipher:
52657429Smarkm		intptr = &options->cipher;
52765674Skris		arg = strdelim(&s);
52865674Skris		if (!arg || *arg == '\0')
52961203Skris			fatal("%.200s line %d: Missing argument.", filename, linenum);
53065674Skris		value = cipher_number(arg);
53157429Smarkm		if (value == -1)
53257429Smarkm			fatal("%.200s line %d: Bad cipher '%s'.",
53392559Sdes			    filename, linenum, arg ? arg : "<NONE>");
53457429Smarkm		if (*activep && *intptr == -1)
53557429Smarkm			*intptr = value;
53657429Smarkm		break;
53757429Smarkm
53860576Skris	case oCiphers:
53965674Skris		arg = strdelim(&s);
54065674Skris		if (!arg || *arg == '\0')
54161203Skris			fatal("%.200s line %d: Missing argument.", filename, linenum);
54265674Skris		if (!ciphers_valid(arg))
54360576Skris			fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.",
54492559Sdes			    filename, linenum, arg ? arg : "<NONE>");
54560576Skris		if (*activep && options->ciphers == NULL)
54665674Skris			options->ciphers = xstrdup(arg);
54760576Skris		break;
54860576Skris
54976262Sgreen	case oMacs:
55076262Sgreen		arg = strdelim(&s);
55176262Sgreen		if (!arg || *arg == '\0')
55276262Sgreen			fatal("%.200s line %d: Missing argument.", filename, linenum);
55376262Sgreen		if (!mac_valid(arg))
55476262Sgreen			fatal("%.200s line %d: Bad SSH2 Mac spec '%s'.",
55592559Sdes			    filename, linenum, arg ? arg : "<NONE>");
55676262Sgreen		if (*activep && options->macs == NULL)
55776262Sgreen			options->macs = xstrdup(arg);
55876262Sgreen		break;
55976262Sgreen
56076262Sgreen	case oHostKeyAlgorithms:
56176262Sgreen		arg = strdelim(&s);
56276262Sgreen		if (!arg || *arg == '\0')
56376262Sgreen			fatal("%.200s line %d: Missing argument.", filename, linenum);
56476262Sgreen		if (!key_names_valid2(arg))
56576262Sgreen			fatal("%.200s line %d: Bad protocol 2 host key algorithms '%s'.",
56692559Sdes			    filename, linenum, arg ? arg : "<NONE>");
56776262Sgreen		if (*activep && options->hostkeyalgorithms == NULL)
56876262Sgreen			options->hostkeyalgorithms = xstrdup(arg);
56976262Sgreen		break;
57076262Sgreen
57160576Skris	case oProtocol:
57260576Skris		intptr = &options->protocol;
57365674Skris		arg = strdelim(&s);
57465674Skris		if (!arg || *arg == '\0')
57561203Skris			fatal("%.200s line %d: Missing argument.", filename, linenum);
57665674Skris		value = proto_spec(arg);
57760576Skris		if (value == SSH_PROTO_UNKNOWN)
57860576Skris			fatal("%.200s line %d: Bad protocol spec '%s'.",
57992559Sdes			    filename, linenum, arg ? arg : "<NONE>");
58060576Skris		if (*activep && *intptr == SSH_PROTO_UNKNOWN)
58160576Skris			*intptr = value;
58260576Skris		break;
58360576Skris
58457429Smarkm	case oLogLevel:
58557429Smarkm		intptr = (int *) &options->log_level;
58665674Skris		arg = strdelim(&s);
58765674Skris		value = log_level_number(arg);
58892559Sdes		if (value == SYSLOG_LEVEL_NOT_SET)
58976262Sgreen			fatal("%.200s line %d: unsupported log level '%s'",
59092559Sdes			    filename, linenum, arg ? arg : "<NONE>");
59192559Sdes		if (*activep && (LogLevel) *intptr == SYSLOG_LEVEL_NOT_SET)
59257429Smarkm			*intptr = (LogLevel) value;
59357429Smarkm		break;
59457429Smarkm
59592559Sdes	case oLocalForward:
59657429Smarkm	case oRemoteForward:
59765674Skris		arg = strdelim(&s);
59865674Skris		if (!arg || *arg == '\0')
59992559Sdes			fatal("%.200s line %d: Missing port argument.",
60092559Sdes			    filename, linenum);
60192559Sdes		if ((fwd_port = a2port(arg)) == 0)
60292559Sdes			fatal("%.200s line %d: Bad listen port.",
60392559Sdes			    filename, linenum);
60465674Skris		arg = strdelim(&s);
60565674Skris		if (!arg || *arg == '\0')
60657429Smarkm			fatal("%.200s line %d: Missing second argument.",
60792559Sdes			    filename, linenum);
60892559Sdes		if (sscanf(arg, "%255[^:]:%5[0-9]", buf, sfwd_host_port) != 2 &&
60992559Sdes		    sscanf(arg, "%255[^/]/%5[0-9]", buf, sfwd_host_port) != 2)
61092559Sdes			fatal("%.200s line %d: Bad forwarding specification.",
61192559Sdes			    filename, linenum);
61292559Sdes		if ((fwd_host_port = a2port(sfwd_host_port)) == 0)
61392559Sdes			fatal("%.200s line %d: Bad forwarding port.",
61492559Sdes			    filename, linenum);
61592559Sdes		if (*activep) {
61692559Sdes			if (opcode == oLocalForward)
61792559Sdes				add_local_forward(options, fwd_port, buf,
61892559Sdes				    fwd_host_port);
61992559Sdes			else if (opcode == oRemoteForward)
62092559Sdes				add_remote_forward(options, fwd_port, buf,
62192559Sdes				    fwd_host_port);
62292559Sdes		}
62357429Smarkm		break;
62457429Smarkm
62576262Sgreen	case oDynamicForward:
62676262Sgreen		arg = strdelim(&s);
62776262Sgreen		if (!arg || *arg == '\0')
62876262Sgreen			fatal("%.200s line %d: Missing port argument.",
62976262Sgreen			    filename, linenum);
63076262Sgreen		fwd_port = a2port(arg);
63176262Sgreen		if (fwd_port == 0)
63276262Sgreen			fatal("%.200s line %d: Badly formatted port number.",
63376262Sgreen			    filename, linenum);
63492559Sdes		if (*activep)
63592559Sdes			add_local_forward(options, fwd_port, "socks4", 0);
63676262Sgreen		break;
63776262Sgreen
63892559Sdes	case oClearAllForwardings:
63992559Sdes		intptr = &options->clear_forwardings;
64092559Sdes		goto parse_flag;
64192559Sdes
64257429Smarkm	case oHost:
64357429Smarkm		*activep = 0;
64465674Skris		while ((arg = strdelim(&s)) != NULL && *arg != '\0')
64565674Skris			if (match_pattern(host, arg)) {
64665674Skris				debug("Applying options for %.100s", arg);
64757429Smarkm				*activep = 1;
64857429Smarkm				break;
64957429Smarkm			}
65065674Skris		/* Avoid garbage check below, as strdelim is done. */
65157429Smarkm		return 0;
65257429Smarkm
65357429Smarkm	case oEscapeChar:
65457429Smarkm		intptr = &options->escape_char;
65565674Skris		arg = strdelim(&s);
65665674Skris		if (!arg || *arg == '\0')
65757429Smarkm			fatal("%.200s line %d: Missing argument.", filename, linenum);
65865674Skris		if (arg[0] == '^' && arg[2] == 0 &&
65976262Sgreen		    (u_char) arg[1] >= 64 && (u_char) arg[1] < 128)
66076262Sgreen			value = (u_char) arg[1] & 31;
66165674Skris		else if (strlen(arg) == 1)
66276262Sgreen			value = (u_char) arg[0];
66365674Skris		else if (strcmp(arg, "none") == 0)
66492559Sdes			value = SSH_ESCAPECHAR_NONE;
66557429Smarkm		else {
66657429Smarkm			fatal("%.200s line %d: Bad escape character.",
66792559Sdes			    filename, linenum);
66857429Smarkm			/* NOTREACHED */
66957429Smarkm			value = 0;	/* Avoid compiler warning. */
67057429Smarkm		}
67157429Smarkm		if (*activep && *intptr == -1)
67257429Smarkm			*intptr = value;
67357429Smarkm		break;
67457429Smarkm
67599048Sdes	case oVersionAddendum:
67699048Sdes		ssh_version_set_addendum(strtok(s, "\n"));
67799048Sdes		do {
67899048Sdes			arg = strdelim(&s);
67999048Sdes		} while (arg != NULL && *arg != '\0');
68099048Sdes		break;
68199048Sdes
68298684Sdes	case oDeprecated:
68398684Sdes		debug("%s line %d: Deprecated option \"%s\"",
68498684Sdes		    filename, linenum, keyword);
68598684Sdes		return 0;
68698684Sdes
68757429Smarkm	default:
68857429Smarkm		fatal("process_config_line: Unimplemented opcode %d", opcode);
68957429Smarkm	}
69057429Smarkm
69157429Smarkm	/* Check that there is no garbage at end of line. */
69276262Sgreen	if ((arg = strdelim(&s)) != NULL && *arg != '\0') {
69365674Skris		fatal("%.200s line %d: garbage at end of line; \"%.200s\".",
69492559Sdes		     filename, linenum, arg);
69565674Skris	}
69657429Smarkm	return 0;
69757429Smarkm}
69857429Smarkm
69957429Smarkm
70057429Smarkm/*
70157429Smarkm * Reads the config file and modifies the options accordingly.  Options
70257429Smarkm * should already be initialized before this call.  This never returns if
70392559Sdes * there is an error.  If the file does not exist, this returns 0.
70457429Smarkm */
70557429Smarkm
70692559Sdesint
70757429Smarkmread_config_file(const char *filename, const char *host, Options *options)
70857429Smarkm{
70957429Smarkm	FILE *f;
71057429Smarkm	char line[1024];
71157429Smarkm	int active, linenum;
71257429Smarkm	int bad_options = 0;
71357429Smarkm
71457429Smarkm	/* Open the file. */
71557429Smarkm	f = fopen(filename, "r");
71657429Smarkm	if (!f)
71792559Sdes		return 0;
71857429Smarkm
71957429Smarkm	debug("Reading configuration data %.200s", filename);
72057429Smarkm
72157429Smarkm	/*
72257429Smarkm	 * Mark that we are now processing the options.  This flag is turned
72357429Smarkm	 * on/off by Host specifications.
72457429Smarkm	 */
72557429Smarkm	active = 1;
72657429Smarkm	linenum = 0;
72757429Smarkm	while (fgets(line, sizeof(line), f)) {
72857429Smarkm		/* Update line number counter. */
72957429Smarkm		linenum++;
73057429Smarkm		if (process_config_line(options, host, line, filename, linenum, &active) != 0)
73157429Smarkm			bad_options++;
73257429Smarkm	}
73357429Smarkm	fclose(f);
73457429Smarkm	if (bad_options > 0)
73576262Sgreen		fatal("%s: terminating, %d bad configuration options",
73692559Sdes		    filename, bad_options);
73792559Sdes	return 1;
73857429Smarkm}
73957429Smarkm
74057429Smarkm/*
74157429Smarkm * Initializes options to special values that indicate that they have not yet
74257429Smarkm * been set.  Read_config_file will only set options with this value. Options
74357429Smarkm * are processed in the following order: command line, user config file,
74457429Smarkm * system config file.  Last, fill_default_options is called.
74557429Smarkm */
74657429Smarkm
74760576Skrisvoid
74857429Smarkminitialize_options(Options * options)
74957429Smarkm{
75057429Smarkm	memset(options, 'X', sizeof(*options));
75157429Smarkm	options->forward_agent = -1;
75257429Smarkm	options->forward_x11 = -1;
75365674Skris	options->xauth_location = NULL;
75457429Smarkm	options->gateway_ports = -1;
75557429Smarkm	options->use_privileged_port = -1;
75657429Smarkm	options->rhosts_authentication = -1;
75757429Smarkm	options->rsa_authentication = -1;
75876262Sgreen	options->pubkey_authentication = -1;
75992559Sdes	options->challenge_response_authentication = -1;
76073400Sassar#if defined(KRB4) || defined(KRB5)
76173400Sassar	options->kerberos_authentication = -1;
76257429Smarkm#endif
76392559Sdes#if defined(AFS) || defined(KRB5)
76492559Sdes	options->kerberos_tgt_passing = -1;
76592559Sdes#endif
76657429Smarkm#ifdef AFS
76757429Smarkm	options->afs_token_passing = -1;
76857429Smarkm#endif
76957429Smarkm	options->password_authentication = -1;
77069591Sgreen	options->kbd_interactive_authentication = -1;
77169591Sgreen	options->kbd_interactive_devices = NULL;
77257429Smarkm	options->rhosts_rsa_authentication = -1;
77376262Sgreen	options->hostbased_authentication = -1;
77457429Smarkm	options->batch_mode = -1;
77557429Smarkm	options->check_host_ip = -1;
77657429Smarkm	options->strict_host_key_checking = -1;
77757429Smarkm	options->compression = -1;
77857429Smarkm	options->keepalives = -1;
77957429Smarkm	options->compression_level = -1;
78057429Smarkm	options->port = -1;
78157429Smarkm	options->connection_attempts = -1;
78257429Smarkm	options->number_of_password_prompts = -1;
78357429Smarkm	options->cipher = -1;
78460576Skris	options->ciphers = NULL;
78576262Sgreen	options->macs = NULL;
78676262Sgreen	options->hostkeyalgorithms = NULL;
78760576Skris	options->protocol = SSH_PROTO_UNKNOWN;
78857429Smarkm	options->num_identity_files = 0;
78957429Smarkm	options->hostname = NULL;
79076262Sgreen	options->host_key_alias = NULL;
79157429Smarkm	options->proxy_command = NULL;
79257429Smarkm	options->user = NULL;
79357429Smarkm	options->escape_char = -1;
79457429Smarkm	options->system_hostfile = NULL;
79557429Smarkm	options->user_hostfile = NULL;
79660576Skris	options->system_hostfile2 = NULL;
79760576Skris	options->user_hostfile2 = NULL;
79857429Smarkm	options->num_local_forwards = 0;
79957429Smarkm	options->num_remote_forwards = 0;
80092559Sdes	options->clear_forwardings = -1;
80192559Sdes	options->log_level = SYSLOG_LEVEL_NOT_SET;
80276262Sgreen	options->preferred_authentications = NULL;
80392559Sdes	options->bind_address = NULL;
80492559Sdes	options->smartcard_device = NULL;
80592559Sdes	options->no_host_authentication_for_localhost = - 1;
80657429Smarkm}
80757429Smarkm
80857429Smarkm/*
80957429Smarkm * Called after processing other sources of option data, this fills those
81057429Smarkm * options for which no value has been specified with their default values.
81157429Smarkm */
81257429Smarkm
81360576Skrisvoid
81457429Smarkmfill_default_options(Options * options)
81557429Smarkm{
81676262Sgreen	int len;
81776262Sgreen
81857429Smarkm	if (options->forward_agent == -1)
81961203Skris		options->forward_agent = 0;
82057429Smarkm	if (options->forward_x11 == -1)
82157708Sgreen		options->forward_x11 = 0;
82265674Skris	if (options->xauth_location == NULL)
82392559Sdes		options->xauth_location = _PATH_XAUTH;
82457429Smarkm	if (options->gateway_ports == -1)
82557429Smarkm		options->gateway_ports = 0;
82657429Smarkm	if (options->use_privileged_port == -1)
82776262Sgreen		options->use_privileged_port = 0;
82857429Smarkm	if (options->rhosts_authentication == -1)
82998684Sdes		options->rhosts_authentication = 0;
83057429Smarkm	if (options->rsa_authentication == -1)
83157429Smarkm		options->rsa_authentication = 1;
83276262Sgreen	if (options->pubkey_authentication == -1)
83376262Sgreen		options->pubkey_authentication = 1;
83492559Sdes	if (options->challenge_response_authentication == -1)
83592559Sdes		options->challenge_response_authentication = 1;
83673400Sassar#if defined(KRB4) || defined(KRB5)
83773400Sassar	if (options->kerberos_authentication == -1)
83873400Sassar		options->kerberos_authentication = 1;
83992559Sdes#endif
84092559Sdes#if defined(AFS) || defined(KRB5)
84192559Sdes	if (options->kerberos_tgt_passing == -1)
84292559Sdes		options->kerberos_tgt_passing = 1;
84392559Sdes#endif
84457429Smarkm#ifdef AFS
84557429Smarkm	if (options->afs_token_passing == -1)
84657429Smarkm		options->afs_token_passing = 1;
84792559Sdes#endif
84857429Smarkm	if (options->password_authentication == -1)
84957429Smarkm		options->password_authentication = 1;
85069591Sgreen	if (options->kbd_interactive_authentication == -1)
85176262Sgreen		options->kbd_interactive_authentication = 1;
85257429Smarkm	if (options->rhosts_rsa_authentication == -1)
85398684Sdes		options->rhosts_rsa_authentication = 0;
85476262Sgreen	if (options->hostbased_authentication == -1)
85576262Sgreen		options->hostbased_authentication = 0;
85657429Smarkm	if (options->batch_mode == -1)
85757429Smarkm		options->batch_mode = 0;
85857429Smarkm	if (options->check_host_ip == -1)
85999048Sdes		options->check_host_ip = 0;
86057429Smarkm	if (options->strict_host_key_checking == -1)
86157429Smarkm		options->strict_host_key_checking = 2;	/* 2 is default */
86257429Smarkm	if (options->compression == -1)
86357429Smarkm		options->compression = 0;
86457429Smarkm	if (options->keepalives == -1)
86557429Smarkm		options->keepalives = 1;
86657429Smarkm	if (options->compression_level == -1)
86757429Smarkm		options->compression_level = 6;
86857429Smarkm	if (options->port == -1)
86957429Smarkm		options->port = 0;	/* Filled in ssh_connect. */
87057429Smarkm	if (options->connection_attempts == -1)
87192559Sdes		options->connection_attempts = 1;
87257429Smarkm	if (options->number_of_password_prompts == -1)
87357429Smarkm		options->number_of_password_prompts = 3;
87457429Smarkm	/* Selected in ssh_login(). */
87557429Smarkm	if (options->cipher == -1)
87657429Smarkm		options->cipher = SSH_CIPHER_NOT_SET;
87760576Skris	/* options->ciphers, default set in myproposals.h */
87876262Sgreen	/* options->macs, default set in myproposals.h */
87976262Sgreen	/* options->hostkeyalgorithms, default set in myproposals.h */
88060576Skris	if (options->protocol == SSH_PROTO_UNKNOWN)
88176262Sgreen		options->protocol = SSH_PROTO_1|SSH_PROTO_2;
88257429Smarkm	if (options->num_identity_files == 0) {
88376262Sgreen		if (options->protocol & SSH_PROTO_1) {
88476262Sgreen			len = 2 + strlen(_PATH_SSH_CLIENT_IDENTITY) + 1;
88576262Sgreen			options->identity_files[options->num_identity_files] =
88676262Sgreen			    xmalloc(len);
88776262Sgreen			snprintf(options->identity_files[options->num_identity_files++],
88876262Sgreen			    len, "~/%.100s", _PATH_SSH_CLIENT_IDENTITY);
88976262Sgreen		}
89076262Sgreen		if (options->protocol & SSH_PROTO_2) {
89176262Sgreen			len = 2 + strlen(_PATH_SSH_CLIENT_ID_RSA) + 1;
89276262Sgreen			options->identity_files[options->num_identity_files] =
89376262Sgreen			    xmalloc(len);
89476262Sgreen			snprintf(options->identity_files[options->num_identity_files++],
89576262Sgreen			    len, "~/%.100s", _PATH_SSH_CLIENT_ID_RSA);
89676262Sgreen
89776262Sgreen			len = 2 + strlen(_PATH_SSH_CLIENT_ID_DSA) + 1;
89876262Sgreen			options->identity_files[options->num_identity_files] =
89976262Sgreen			    xmalloc(len);
90076262Sgreen			snprintf(options->identity_files[options->num_identity_files++],
90176262Sgreen			    len, "~/%.100s", _PATH_SSH_CLIENT_ID_DSA);
90276262Sgreen		}
90357429Smarkm	}
90457429Smarkm	if (options->escape_char == -1)
90557429Smarkm		options->escape_char = '~';
90657429Smarkm	if (options->system_hostfile == NULL)
90776262Sgreen		options->system_hostfile = _PATH_SSH_SYSTEM_HOSTFILE;
90857429Smarkm	if (options->user_hostfile == NULL)
90976262Sgreen		options->user_hostfile = _PATH_SSH_USER_HOSTFILE;
91060576Skris	if (options->system_hostfile2 == NULL)
91176262Sgreen		options->system_hostfile2 = _PATH_SSH_SYSTEM_HOSTFILE2;
91260576Skris	if (options->user_hostfile2 == NULL)
91376262Sgreen		options->user_hostfile2 = _PATH_SSH_USER_HOSTFILE2;
91492559Sdes	if (options->log_level == SYSLOG_LEVEL_NOT_SET)
91557429Smarkm		options->log_level = SYSLOG_LEVEL_INFO;
91692559Sdes	if (options->clear_forwardings == 1)
91792559Sdes		clear_forwardings(options);
91892559Sdes	if (options->no_host_authentication_for_localhost == - 1)
91992559Sdes		options->no_host_authentication_for_localhost = 0;
92057429Smarkm	/* options->proxy_command should not be set by default */
92157429Smarkm	/* options->user will be set in the main program if appropriate */
92257429Smarkm	/* options->hostname will be set in the main program if appropriate */
92376262Sgreen	/* options->host_key_alias should not be set by default */
92476262Sgreen	/* options->preferred_authentications will be set in ssh */
92557429Smarkm}
926