readconf.c revision 57430
162587Sitojun/*
295023Ssuz *
362587Sitojun * readconf.c
453541Sshin *
553541Sshin * Author: Tatu Ylonen <ylo@cs.hut.fi>
653541Sshin *
753541Sshin * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
853541Sshin *                    All rights reserved
953541Sshin *
1053541Sshin * Created: Sat Apr 22 00:03:10 1995 ylo
1153541Sshin *
1253541Sshin * Functions for reading the configuration files.
1353541Sshin *
1453541Sshin */
1553541Sshin
1653541Sshin#include "includes.h"
1753541SshinRCSID("$Id: readconf.c,v 1.22 1999/12/01 13:59:15 markus Exp $");
1853541Sshin
1953541Sshin#include "ssh.h"
2053541Sshin#include "cipher.h"
2153541Sshin#include "readconf.h"
2253541Sshin#include "xmalloc.h"
2353541Sshin
2453541Sshin/* Format of the configuration file:
2553541Sshin
2653541Sshin   # Configuration data is parsed as follows:
2753541Sshin   #  1. command line options
2853541Sshin   #  2. user-specific file
2953541Sshin   #  3. system-wide file
3053541Sshin   # Any configuration value is only changed the first time it is set.
3153541Sshin   # Thus, host-specific definitions should be at the beginning of the
3253541Sshin   # configuration file, and defaults at the end.
3353541Sshin
3453541Sshin   # Host-specific declarations.  These may override anything above.  A single
3553541Sshin   # host may match multiple declarations; these are processed in the order
3653541Sshin   # that they are given in.
3753541Sshin
3853541Sshin   Host *.ngs.fi ngs.fi
3953541Sshin     FallBackToRsh no
4053541Sshin
4153541Sshin   Host fake.com
4253541Sshin     HostName another.host.name.real.org
4353541Sshin     User blaah
4453541Sshin     Port 34289
4553541Sshin     ForwardX11 no
4653541Sshin     ForwardAgent no
4753541Sshin
4853541Sshin   Host books.com
4953541Sshin     RemoteForward 9999 shadows.cs.hut.fi:9999
5053541Sshin     Cipher 3des
5153541Sshin
5253541Sshin   Host fascist.blob.com
5353541Sshin     Port 23123
5453541Sshin     User tylonen
5553541Sshin     RhostsAuthentication no
5653541Sshin     PasswordAuthentication no
5753541Sshin
5853541Sshin   Host puukko.hut.fi
5953541Sshin     User t35124p
6053541Sshin     ProxyCommand ssh-proxy %h %p
6153541Sshin
6253541Sshin   Host *.fr
6353541Sshin     UseRsh yes
6453541Sshin
6553541Sshin   Host *.su
6653541Sshin     Cipher none
6753541Sshin     PasswordAuthentication no
6862587Sitojun
6962587Sitojun   # Defaults for various options
7062587Sitojun   Host *
7153541Sshin     ForwardAgent no
7253541Sshin     ForwardX11 yes
7353541Sshin     RhostsAuthentication yes
7453541Sshin     PasswordAuthentication yes
7553541Sshin     RSAAuthentication yes
7653541Sshin     RhostsRSAAuthentication yes
7753541Sshin     FallBackToRsh no
7853541Sshin     UseRsh no
7953541Sshin     StrictHostKeyChecking yes
8053541Sshin     KeepAlives no
8153541Sshin     IdentityFile ~/.ssh/identity
8253541Sshin     Port 22
8353541Sshin     EscapeChar ~
8453541Sshin
8553541Sshin*/
8653541Sshin
8753541Sshin/* Keyword tokens. */
8853541Sshin
8953541Sshintypedef enum {
9053541Sshin	oBadOption,
9178064Sume	oForwardAgent, oForwardX11, oGatewayPorts, oRhostsAuthentication,
9278064Sume	oPasswordAuthentication, oRSAAuthentication, oFallBackToRsh, oUseRsh,
9378064Sume	oSkeyAuthentication,
9453541Sshin#ifdef KRB4
9562587Sitojun	oKerberosAuthentication,
9653541Sshin#endif /* KRB4 */
9795023Ssuz#ifdef AFS
9853541Sshin	oKerberosTgtPassing, oAFSTokenPassing,
9962587Sitojun#endif
10053541Sshin	oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward,
10162587Sitojun	oUser, oHost, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
10278064Sume	oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
10362587Sitojun	oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
10453541Sshin	oCompressionLevel, oKeepAlives, oNumberOfPasswordPrompts, oTISAuthentication,
10553541Sshin	oUsePrivilegedPort, oLogLevel
10653541Sshin} OpCodes;
10753541Sshin
10853541Sshin/* Textual representations of the tokens. */
10953541Sshin
11053541Sshinstatic struct {
11162587Sitojun	const char *name;
11262587Sitojun	OpCodes opcode;
11362587Sitojun} keywords[] = {
11453541Sshin	{ "forwardagent", oForwardAgent },
11562587Sitojun	{ "forwardx11", oForwardX11 },
11653541Sshin	{ "gatewayports", oGatewayPorts },
11762587Sitojun	{ "useprivilegedport", oUsePrivilegedPort },
11853541Sshin	{ "rhostsauthentication", oRhostsAuthentication },
11953541Sshin	{ "passwordauthentication", oPasswordAuthentication },
12062587Sitojun	{ "rsaauthentication", oRSAAuthentication },
12162587Sitojun	{ "skeyauthentication", oSkeyAuthentication },
12262587Sitojun#ifdef KRB4
12362587Sitojun	{ "kerberosauthentication", oKerberosAuthentication },
12462587Sitojun#endif /* KRB4 */
12553541Sshin#ifdef AFS
12678064Sume	{ "kerberostgtpassing", oKerberosTgtPassing },
12778064Sume	{ "afstokenpassing", oAFSTokenPassing },
12878064Sume#endif
12962587Sitojun	{ "fallbacktorsh", oFallBackToRsh },
13083366Sjulian	{ "usersh", oUseRsh },
13178064Sume	{ "identityfile", oIdentityFile },
132120891Sume	{ "hostname", oHostName },
13378064Sume	{ "proxycommand", oProxyCommand },
13453541Sshin	{ "port", oPort },
13562587Sitojun	{ "cipher", oCipher },
13683934Sbrooks	{ "remoteforward", oRemoteForward },
13783934Sbrooks	{ "localforward", oLocalForward },
13853541Sshin	{ "user", oUser },
13953541Sshin	{ "host", oHost },
14053541Sshin	{ "escapechar", oEscapeChar },
14153541Sshin	{ "rhostsrsaauthentication", oRhostsRSAAuthentication },
14253541Sshin	{ "globalknownhostsfile", oGlobalKnownHostsFile },
14353541Sshin	{ "userknownhostsfile", oUserKnownHostsFile },
14453541Sshin	{ "connectionattempts", oConnectionAttempts },
14553541Sshin	{ "batchmode", oBatchMode },
14678064Sume	{ "checkhostip", oCheckHostIP },
14778064Sume	{ "stricthostkeychecking", oStrictHostKeyChecking },
148120891Sume	{ "compression", oCompression },
14953541Sshin	{ "compressionlevel", oCompressionLevel },
15078064Sume	{ "keepalive", oKeepAlives },
15178064Sume	{ "numberofpasswordprompts", oNumberOfPasswordPrompts },
15253541Sshin	{ "tisauthentication", oTISAuthentication },
15378064Sume	{ "loglevel", oLogLevel },
15462587Sitojun	{ NULL, 0 }
15578064Sume};
15678064Sume
15778064Sume/* Characters considered whitespace in strtok calls. */
15878064Sume#define WHITESPACE " \t\r\n"
15978064Sume
16078064Sume
16162587Sitojun/*
16278064Sume * Adds a local TCP/IP port forward to options.  Never returns if there is an
163120891Sume * error.
16478064Sume */
165120891Sume
16678064Sumevoid
16778064Sumeadd_local_forward(Options *options, u_short port, const char *host,
16878064Sume		  u_short host_port)
16978064Sume{
17078064Sume	Forward *fwd;
17178064Sume	extern uid_t original_real_uid;
17253541Sshin	if (port < IPPORT_RESERVED && original_real_uid != 0)
173120727Ssam		fatal("Privileged ports can only be forwarded by root.\n");
174120727Ssam	if (options->num_local_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
175120727Ssam		fatal("Too many local forwards (max %d).", SSH_MAX_FORWARDS_PER_DIRECTION);
176120727Ssam	fwd = &options->local_forwards[options->num_local_forwards++];
177120727Ssam	fwd->port = port;
178120727Ssam	fwd->host = xstrdup(host);
179120727Ssam	fwd->host_port = host_port;
180120727Ssam}
181120727Ssam
182120727Ssam/*
183120727Ssam * Adds a remote TCP/IP port forward to options.  Never returns if there is
184120727Ssam * an error.
185120727Ssam */
18678064Sume
187120727Ssamvoid
188120727Ssamadd_remote_forward(Options *options, u_short port, const char *host,
189120727Ssam		   u_short host_port)
190120727Ssam{
191120727Ssam	Forward *fwd;
192120727Ssam	if (options->num_remote_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
193120727Ssam		fatal("Too many remote forwards (max %d).",
194120727Ssam		      SSH_MAX_FORWARDS_PER_DIRECTION);
19578064Sume	fwd = &options->remote_forwards[options->num_remote_forwards++];
19678064Sume	fwd->port = port;
197120727Ssam	fwd->host = xstrdup(host);
19878064Sume	fwd->host_port = host_port;
19978064Sume}
200122334Ssam
201120727Ssam/*
20278064Sume * Returns the number of the token pointed to by cp of length len. Never
20378064Sume * returns if the token is not known.
20453541Sshin */
20553541Sshin
20653541Sshinstatic OpCodes
20778064Sumeparse_token(const char *cp, const char *filename, int linenum)
20878064Sume{
20978064Sume	unsigned int i;
21078064Sume
21178064Sume	for (i = 0; keywords[i].name; i++)
21253541Sshin		if (strcasecmp(cp, keywords[i].name) == 0)
21353541Sshin			return keywords[i].opcode;
21453541Sshin
21553541Sshin	fprintf(stderr, "%s: line %d: Bad configuration option: %s\n",
21678064Sume		filename, linenum, cp);
217121716Ssam	return oBadOption;
21853541Sshin}
21978064Sume
22078064Sume/*
221121716Ssam * Processes a single option line as used in the configuration files. This
222121716Ssam * only sets those values that have not already been set.
22378064Sume */
224120727Ssam
225121716Ssamint
226121716Ssamprocess_config_line(Options *options, const char *host,
22753541Sshin		    char *line, const char *filename, int linenum,
22853541Sshin		    int *activep)
22953541Sshin{
23053541Sshin	char buf[256], *cp, *string, **charptr, *cp2;
23153541Sshin	int opcode, *intptr, value;
23253541Sshin	u_short fwd_port, fwd_host_port;
23353541Sshin
23453541Sshin	/* Skip leading whitespace. */
23553541Sshin	cp = line + strspn(line, WHITESPACE);
23662587Sitojun	if (!*cp || *cp == '\n' || *cp == '#')
23778064Sume		return 0;
23862587Sitojun
23953541Sshin	/* Get the keyword. (Each line is supposed to begin with a keyword). */
24062587Sitojun	cp = strtok(cp, WHITESPACE);
24178064Sume	opcode = parse_token(cp, filename, linenum);
24262587Sitojun
24378064Sume	switch (opcode) {
24478064Sume	case oBadOption:
24578064Sume		/* don't panic, but count bad options */
24678064Sume		return -1;
24762587Sitojun		/* NOTREACHED */
24862587Sitojun	case oForwardAgent:
24978064Sume		intptr = &options->forward_agent;
25078064Sumeparse_flag:
25195023Ssuz		cp = strtok(NULL, WHITESPACE);
25278064Sume		if (!cp)
25378064Sume			fatal("%.200s line %d: Missing yes/no argument.", filename, linenum);
25478064Sume		value = 0;	/* To avoid compiler warning... */
25578064Sume		if (strcmp(cp, "yes") == 0 || strcmp(cp, "true") == 0)
25678064Sume			value = 1;
25778064Sume		else if (strcmp(cp, "no") == 0 || strcmp(cp, "false") == 0)
25878064Sume			value = 0;
25978064Sume		else
26078064Sume			fatal("%.200s line %d: Bad yes/no argument.", filename, linenum);
26153541Sshin		if (*activep && *intptr == -1)
26278064Sume			*intptr = value;
26378064Sume		break;
26478064Sume
26578064Sume	case oForwardX11:
26678064Sume		intptr = &options->forward_x11;
26795023Ssuz		goto parse_flag;
26878064Sume
269120891Sume	case oGatewayPorts:
27078064Sume		intptr = &options->gateway_ports;
27178064Sume		goto parse_flag;
27278064Sume
27378064Sume	case oUsePrivilegedPort:
274120727Ssam		intptr = &options->use_privileged_port;
275120727Ssam		goto parse_flag;
276120727Ssam
277120727Ssam	case oRhostsAuthentication:
278120727Ssam		intptr = &options->rhosts_authentication;
279120727Ssam		goto parse_flag;
280120727Ssam
28178064Sume	case oPasswordAuthentication:
28253541Sshin		intptr = &options->password_authentication;
28353541Sshin		goto parse_flag;
28453541Sshin
28553541Sshin	case oRSAAuthentication:
28678064Sume		intptr = &options->rsa_authentication;
28753541Sshin		goto parse_flag;
28878064Sume
28953541Sshin	case oRhostsRSAAuthentication:
29078064Sume		intptr = &options->rhosts_rsa_authentication;
29178064Sume		goto parse_flag;
29253541Sshin
293120891Sume	case oTISAuthentication:
294120891Sume		/* fallthrough, there is no difference on the client side */
29578064Sume	case oSkeyAuthentication:
29678064Sume		intptr = &options->skey_authentication;
29778064Sume		goto parse_flag;
29853541Sshin
29953541Sshin#ifdef KRB4
30053541Sshin	case oKerberosAuthentication:
30178064Sume		intptr = &options->kerberos_authentication;
30253541Sshin		goto parse_flag;
30378064Sume#endif /* KRB4 */
30453541Sshin
30553541Sshin#ifdef AFS
30653541Sshin	case oKerberosTgtPassing:
30778064Sume		intptr = &options->kerberos_tgt_passing;
30878064Sume		goto parse_flag;
30978064Sume
31078064Sume	case oAFSTokenPassing:
31178064Sume		intptr = &options->afs_token_passing;
31278064Sume		goto parse_flag;
31378064Sume#endif
314120856Sume
31578064Sume	case oFallBackToRsh:
31678064Sume		intptr = &options->fallback_to_rsh;
317120856Sume		goto parse_flag;
31878064Sume
319120891Sume	case oUseRsh:
32053541Sshin		intptr = &options->use_rsh;
32153541Sshin		goto parse_flag;
32253541Sshin
32353541Sshin	case oBatchMode:
32462587Sitojun		intptr = &options->batch_mode;
32553541Sshin		goto parse_flag;
32653541Sshin
32783366Sjulian	case oCheckHostIP:
32853541Sshin		intptr = &options->check_host_ip;
32953541Sshin		goto parse_flag;
33053541Sshin
33153541Sshin	case oStrictHostKeyChecking:
33283366Sjulian		intptr = &options->strict_host_key_checking;
33353541Sshin		cp = strtok(NULL, WHITESPACE);
33453541Sshin		if (!cp)
33578064Sume			fatal("%.200s line %d: Missing yes/no argument.",
33653541Sshin			      filename, linenum);
33753541Sshin		value = 0;	/* To avoid compiler warning... */
33853541Sshin		if (strcmp(cp, "yes") == 0 || strcmp(cp, "true") == 0)
33953541Sshin			value = 1;
34093593Sjhb		else if (strcmp(cp, "no") == 0 || strcmp(cp, "false") == 0)
34153541Sshin			value = 0;
34253541Sshin		else if (strcmp(cp, "ask") == 0)
34362587Sitojun			value = 2;
34462587Sitojun		else
34562587Sitojun			fatal("%.200s line %d: Bad yes/no/ask argument.", filename, linenum);
34662587Sitojun		if (*activep && *intptr == -1)
34762587Sitojun			*intptr = value;
34853541Sshin		break;
349121742Sume
350121742Sume	case oCompression:
351121742Sume		intptr = &options->compression;
352121742Sume		goto parse_flag;
353121742Sume
354121742Sume	case oKeepAlives:
355121742Sume		intptr = &options->keepalives;
356121742Sume		goto parse_flag;
35762587Sitojun
358120856Sume	case oNumberOfPasswordPrompts:
35953541Sshin		intptr = &options->number_of_password_prompts;
36053541Sshin		goto parse_int;
36153541Sshin
36253541Sshin	case oCompressionLevel:
36353541Sshin		intptr = &options->compression_level;
36462587Sitojun		goto parse_int;
36562587Sitojun
36653541Sshin	case oIdentityFile:
367120856Sume		cp = strtok(NULL, WHITESPACE);
368120891Sume		if (!cp)
36978064Sume			fatal("%.200s line %d: Missing argument.", filename, linenum);
37053541Sshin		if (*activep) {
37153541Sshin			if (options->num_identity_files >= SSH_MAX_IDENTITY_FILES)
37253541Sshin				fatal("%.200s line %d: Too many identity files specified (max %d).",
37353541Sshin				      filename, linenum, SSH_MAX_IDENTITY_FILES);
37462587Sitojun			options->identity_files[options->num_identity_files++] = xstrdup(cp);
375120856Sume		}
37653541Sshin		break;
37753541Sshin
37853541Sshin	case oUser:
37953541Sshin		charptr = &options->user;
38053541Sshinparse_string:
38153541Sshin		cp = strtok(NULL, WHITESPACE);
38253541Sshin		if (!cp)
38353541Sshin			fatal("%.200s line %d: Missing argument.", filename, linenum);
38453541Sshin		if (*activep && *charptr == NULL)
38578064Sume			*charptr = xstrdup(cp);
38678064Sume		break;
38778064Sume
388120856Sume	case oGlobalKnownHostsFile:
38953541Sshin		charptr = &options->system_hostfile;
39053541Sshin		goto parse_string;
39195023Ssuz
39262587Sitojun	case oUserKnownHostsFile:
39362587Sitojun		charptr = &options->user_hostfile;
394120856Sume		goto parse_string;
395121161Sume
396121161Sume	case oHostName:
39762587Sitojun		charptr = &options->hostname;
398121161Sume		goto parse_string;
399121161Sume
40062587Sitojun	case oProxyCommand:
401121161Sume		charptr = &options->proxy_command;
402121161Sume		string = xstrdup("");
40362587Sitojun		while ((cp = strtok(NULL, WHITESPACE)) != NULL) {
40462587Sitojun			string = xrealloc(string, strlen(string) + strlen(cp) + 2);
40553541Sshin			strcat(string, " ");
40653541Sshin			strcat(string, cp);
40753541Sshin		}
40853541Sshin		if (*activep && *charptr == NULL)
409120856Sume			*charptr = string;
410120891Sume		else
41153541Sshin			xfree(string);
41283366Sjulian		return 0;
41353541Sshin
41453541Sshin	case oPort:
41553541Sshin		intptr = &options->port;
41653541Sshinparse_int:
41753541Sshin		cp = strtok(NULL, WHITESPACE);
41862587Sitojun		if (!cp)
41953541Sshin			fatal("%.200s line %d: Missing argument.", filename, linenum);
42053541Sshin		if (cp[0] < '0' || cp[0] > '9')
42153541Sshin			fatal("%.200s line %d: Bad number.", filename, linenum);
42253541Sshin
42353541Sshin		/* Octal, decimal, or hex format? */
42478064Sume		value = strtol(cp, &cp2, 0);
42553541Sshin		if (cp == cp2)
426120891Sume			fatal("%.200s line %d: Bad number.", filename, linenum);
42762587Sitojun		if (*activep && *intptr == -1)
428120891Sume			*intptr = value;
429120856Sume		break;
43062587Sitojun
43153541Sshin	case oConnectionAttempts:
43253541Sshin		intptr = &options->connection_attempts;
43353541Sshin		goto parse_int;
434120856Sume
43553541Sshin	case oCipher:
43653541Sshin		intptr = &options->cipher;
43753541Sshin		cp = strtok(NULL, WHITESPACE);
43862587Sitojun		value = cipher_number(cp);
43953541Sshin		if (value == -1)
44053541Sshin			fatal("%.200s line %d: Bad cipher '%s'.",
44153541Sshin			      filename, linenum, cp ? cp : "<NONE>");
44278064Sume		if (*activep && *intptr == -1)
44378064Sume			*intptr = value;
44478064Sume		break;
44578064Sume
44678064Sume	case oLogLevel:
44778064Sume		intptr = (int *) &options->log_level;
44878064Sume		cp = strtok(NULL, WHITESPACE);
44978064Sume		value = log_level_number(cp);
45078064Sume		if (value == (LogLevel) - 1)
451120856Sume			fatal("%.200s line %d: unsupported log level '%s'\n",
45253541Sshin			      filename, linenum, cp ? cp : "<NONE>");
45353541Sshin		if (*activep && (LogLevel) * intptr == -1)
45462587Sitojun			*intptr = (LogLevel) value;
45578064Sume		break;
45662587Sitojun
45762587Sitojun	case oRemoteForward:
45862587Sitojun		cp = strtok(NULL, WHITESPACE);
45978064Sume		if (!cp)
46062587Sitojun			fatal("%.200s line %d: Missing argument.", filename, linenum);
46162587Sitojun		if (cp[0] < '0' || cp[0] > '9')
462120856Sume			fatal("%.200s line %d: Badly formatted port number.",
46353541Sshin			      filename, linenum);
46453541Sshin		fwd_port = atoi(cp);
46562587Sitojun		cp = strtok(NULL, WHITESPACE);
46678064Sume		if (!cp)
46778064Sume			fatal("%.200s line %d: Missing second argument.",
46862587Sitojun			      filename, linenum);
46978064Sume		if (sscanf(cp, "%255[^:]:%hu", buf, &fwd_host_port) != 2)
47078064Sume			fatal("%.200s line %d: Badly formatted host:port.",
471120856Sume			      filename, linenum);
47253541Sshin		if (*activep)
473120856Sume			add_remote_forward(options, fwd_port, buf, fwd_host_port);
47453541Sshin		break;
47553541Sshin
47653541Sshin	case oLocalForward:
47753541Sshin		cp = strtok(NULL, WHITESPACE);
47853541Sshin		if (!cp)
479120891Sume			fatal("%.200s line %d: Missing argument.", filename, linenum);
48053541Sshin		if (cp[0] < '0' || cp[0] > '9')
48153541Sshin			fatal("%.200s line %d: Badly formatted port number.",
48253541Sshin			      filename, linenum);
48353541Sshin		fwd_port = atoi(cp);
48453541Sshin		cp = strtok(NULL, WHITESPACE);
48562587Sitojun		if (!cp)
486120856Sume			fatal("%.200s line %d: Missing second argument.",
48753541Sshin			      filename, linenum);
48853541Sshin		if (sscanf(cp, "%255[^:]:%hu", buf, &fwd_host_port) != 2)
48953541Sshin			fatal("%.200s line %d: Badly formatted host:port.",
49053541Sshin			      filename, linenum);
49153541Sshin		if (*activep)
49253541Sshin			add_local_forward(options, fwd_port, buf, fwd_host_port);
493120856Sume		break;
49462587Sitojun
495120856Sume	case oHost:
49653541Sshin		*activep = 0;
49753541Sshin		while ((cp = strtok(NULL, WHITESPACE)) != NULL)
49853541Sshin			if (match_pattern(host, cp)) {
49953541Sshin				debug("Applying options for %.100s", cp);
50053541Sshin				*activep = 1;
50153541Sshin				break;
50253541Sshin			}
50353541Sshin		/* Avoid garbage check below, as strtok already returned NULL. */
50453541Sshin		return 0;
50553541Sshin
50653541Sshin	case oEscapeChar:
50753541Sshin		intptr = &options->escape_char;
50853541Sshin		cp = strtok(NULL, WHITESPACE);
50953541Sshin		if (!cp)
51053541Sshin			fatal("%.200s line %d: Missing argument.", filename, linenum);
51153541Sshin		if (cp[0] == '^' && cp[2] == 0 &&
51253541Sshin		    (unsigned char) cp[1] >= 64 && (unsigned char) cp[1] < 128)
51353541Sshin			value = (unsigned char) cp[1] & 31;
51453541Sshin		else if (strlen(cp) == 1)
51553541Sshin			value = (unsigned char) cp[0];
51653541Sshin		else if (strcmp(cp, "none") == 0)
51753541Sshin			value = -2;
518120856Sume		else {
51962587Sitojun			fatal("%.200s line %d: Bad escape character.",
52062587Sitojun			      filename, linenum);
52162587Sitojun			/* NOTREACHED */
52262587Sitojun			value = 0;	/* Avoid compiler warning. */
52353541Sshin		}
52453541Sshin		if (*activep && *intptr == -1)
52553541Sshin			*intptr = value;
52653541Sshin		break;
52753541Sshin
52853541Sshin	default:
52953541Sshin		fatal("process_config_line: Unimplemented opcode %d", opcode);
53053541Sshin	}
53153541Sshin
53253541Sshin	/* Check that there is no garbage at end of line. */
53353541Sshin	if (strtok(NULL, WHITESPACE) != NULL)
53453541Sshin		fatal("%.200s line %d: garbage at end of line.",
535121167Sume		      filename, linenum);
536121167Sume	return 0;
537121161Sume}
538121161Sume
539121161Sume
540121161Sume/*
54153541Sshin * Reads the config file and modifies the options accordingly.  Options
54253541Sshin * should already be initialized before this call.  This never returns if
54353541Sshin * there is an error.  If the file does not exist, this returns immediately.
54453541Sshin */
54553541Sshin
546121161Sumevoid
547121161Sumeread_config_file(const char *filename, const char *host, Options *options)
548121161Sume{
549121161Sume	FILE *f;
55053541Sshin	char line[1024];
55153541Sshin	int active, linenum;
55253541Sshin	int bad_options = 0;
55353541Sshin
55453541Sshin	/* Open the file. */
55553541Sshin	f = fopen(filename, "r");
55653541Sshin	if (!f)
55753541Sshin		return;
55853541Sshin
55953541Sshin	debug("Reading configuration data %.200s", filename);
56053541Sshin
56153541Sshin	/*
56253541Sshin	 * Mark that we are now processing the options.  This flag is turned
56353541Sshin	 * on/off by Host specifications.
56453541Sshin	 */
56553541Sshin	active = 1;
56653541Sshin	linenum = 0;
56753541Sshin	while (fgets(line, sizeof(line), f)) {
56853541Sshin		/* Update line number counter. */
56953541Sshin		linenum++;
57053541Sshin		if (process_config_line(options, host, line, filename, linenum, &active) != 0)
57178064Sume			bad_options++;
57278064Sume	}
57378064Sume	fclose(f);
57478064Sume	if (bad_options > 0)
57578064Sume		fatal("%s: terminating, %d bad configuration options\n",
57662587Sitojun		      filename, bad_options);
57778064Sume}
57878064Sume
57962587Sitojun/*
58078064Sume * Initializes options to special values that indicate that they have not yet
581120856Sume * been set.  Read_config_file will only set options with this value. Options
58253541Sshin * are processed in the following order: command line, user config file,
58378064Sume * system config file.  Last, fill_default_options is called.
58478064Sume */
58578064Sume
58678064Sumevoid
58778064Sumeinitialize_options(Options * options)
58878064Sume{
58978064Sume	memset(options, 'X', sizeof(*options));
59078064Sume	options->forward_agent = -1;
59178064Sume	options->forward_x11 = -1;
59278064Sume	options->gateway_ports = -1;
59378064Sume	options->use_privileged_port = -1;
59478064Sume	options->rhosts_authentication = -1;
59578064Sume	options->rsa_authentication = -1;
59678064Sume	options->skey_authentication = -1;
597120891Sume#ifdef KRB4
598120891Sume	options->kerberos_authentication = -1;
59978064Sume#endif
600120891Sume#ifdef AFS
60178064Sume	options->kerberos_tgt_passing = -1;
60278064Sume	options->afs_token_passing = -1;
60378064Sume#endif
60478064Sume	options->password_authentication = -1;
60578064Sume	options->rhosts_rsa_authentication = -1;
606120891Sume	options->fallback_to_rsh = -1;
60778064Sume	options->use_rsh = -1;
60878064Sume	options->batch_mode = -1;
60995023Ssuz	options->check_host_ip = -1;
61095023Ssuz	options->strict_host_key_checking = -1;
61195023Ssuz	options->compression = -1;
61295023Ssuz	options->keepalives = -1;
61395023Ssuz	options->compression_level = -1;
61478064Sume	options->port = -1;
61578064Sume	options->connection_attempts = -1;
61678064Sume	options->number_of_password_prompts = -1;
617120891Sume	options->cipher = -1;
61878064Sume	options->num_identity_files = 0;
61978064Sume	options->hostname = NULL;
62078064Sume	options->proxy_command = NULL;
621120891Sume	options->user = NULL;
62278064Sume	options->escape_char = -1;
62378064Sume	options->system_hostfile = NULL;
62478064Sume	options->user_hostfile = NULL;
62578064Sume	options->num_local_forwards = 0;
62678064Sume	options->num_remote_forwards = 0;
62778064Sume	options->log_level = (LogLevel) - 1;
628120856Sume}
62978064Sume
630120891Sume/*
63178064Sume * Called after processing other sources of option data, this fills those
632120856Sume * options for which no value has been specified with their default values.
63378064Sume */
63478064Sume
63578064Sumevoid
63678064Sumefill_default_options(Options * options)
63778064Sume{
63878064Sume	if (options->forward_agent == -1)
63978064Sume		options->forward_agent = 1;
64078064Sume	if (options->forward_x11 == -1)
64178064Sume		options->forward_x11 = 1;
64278064Sume	if (options->gateway_ports == -1)
64378064Sume		options->gateway_ports = 0;
64478064Sume	if (options->use_privileged_port == -1)
64578064Sume		options->use_privileged_port = 1;
64678064Sume	if (options->rhosts_authentication == -1)
64778064Sume		options->rhosts_authentication = 1;
64878064Sume	if (options->rsa_authentication == -1)
64978064Sume		options->rsa_authentication = 1;
65078064Sume	if (options->skey_authentication == -1)
65178064Sume		options->skey_authentication = 0;
65278064Sume#ifdef KRB4
65378064Sume	if (options->kerberos_authentication == -1)
65478064Sume		options->kerberos_authentication = 1;
65578064Sume#endif /* KRB4 */
65678064Sume#ifdef AFS
65778064Sume	if (options->kerberos_tgt_passing == -1)
658122059Sume		options->kerberos_tgt_passing = 1;
65978064Sume	if (options->afs_token_passing == -1)
66062587Sitojun		options->afs_token_passing = 1;
66162587Sitojun#endif /* AFS */
66278064Sume	if (options->password_authentication == -1)
66378064Sume		options->password_authentication = 1;
66478064Sume	if (options->rhosts_rsa_authentication == -1)
66578064Sume		options->rhosts_rsa_authentication = 1;
66678064Sume	if (options->fallback_to_rsh == -1)
66778064Sume		options->fallback_to_rsh = 1;
66878064Sume	if (options->use_rsh == -1)
66962587Sitojun		options->use_rsh = 0;
67078064Sume	if (options->batch_mode == -1)
67178064Sume		options->batch_mode = 0;
67262587Sitojun	if (options->check_host_ip == -1)
67378064Sume		options->check_host_ip = 1;
67478064Sume	if (options->strict_host_key_checking == -1)
67578064Sume		options->strict_host_key_checking = 2;	/* 2 is default */
67678064Sume	if (options->compression == -1)
67778064Sume		options->compression = 0;
67878064Sume	if (options->keepalives == -1)
67978064Sume		options->keepalives = 1;
68078064Sume	if (options->compression_level == -1)
681120891Sume		options->compression_level = 6;
68278064Sume	if (options->port == -1)
68378064Sume		options->port = 0;	/* Filled in ssh_connect. */
68478064Sume	if (options->connection_attempts == -1)
68578064Sume		options->connection_attempts = 4;
68678064Sume	if (options->number_of_password_prompts == -1)
68778064Sume		options->number_of_password_prompts = 3;
68878064Sume	/* Selected in ssh_login(). */
68978064Sume	if (options->cipher == -1)
69078064Sume		options->cipher = SSH_CIPHER_NOT_SET;
69178064Sume	if (options->num_identity_files == 0) {
69278064Sume		options->identity_files[0] =
69378064Sume			xmalloc(2 + strlen(SSH_CLIENT_IDENTITY) + 1);
69478064Sume		sprintf(options->identity_files[0], "~/%.100s", SSH_CLIENT_IDENTITY);
69578064Sume		options->num_identity_files = 1;
69678064Sume	}
69778064Sume	if (options->escape_char == -1)
69878064Sume		options->escape_char = '~';
69978064Sume	if (options->system_hostfile == NULL)
70078064Sume		options->system_hostfile = SSH_SYSTEM_HOSTFILE;
70178064Sume	if (options->user_hostfile == NULL)
70278064Sume		options->user_hostfile = SSH_USER_HOSTFILE;
70378064Sume	if (options->log_level == (LogLevel) - 1)
70478064Sume		options->log_level = SYSLOG_LEVEL_INFO;
70578064Sume	/* options->proxy_command should not be set by default */
70678064Sume	/* options->user will be set in the main program if appropriate */
70778064Sume	/* options->hostname will be set in the main program if appropriate */
70878064Sume}
70978064Sume