xref: /freebsd/crypto/openssh/readconf.c (revision 511b41d2a18c00a5f0db1a67a87ef8d831b19f2a)
1511b41d2SMark Murray /*
2511b41d2SMark Murray  *
3511b41d2SMark Murray  * readconf.c
4511b41d2SMark Murray  *
5511b41d2SMark Murray  * Author: Tatu Ylonen <ylo@cs.hut.fi>
6511b41d2SMark Murray  *
7511b41d2SMark Murray  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8511b41d2SMark Murray  *                    All rights reserved
9511b41d2SMark Murray  *
10511b41d2SMark Murray  * Created: Sat Apr 22 00:03:10 1995 ylo
11511b41d2SMark Murray  *
12511b41d2SMark Murray  * Functions for reading the configuration files.
13511b41d2SMark Murray  *
14511b41d2SMark Murray  */
15511b41d2SMark Murray 
16511b41d2SMark Murray #include "includes.h"
17511b41d2SMark Murray RCSID("$Id: readconf.c,v 1.22 1999/12/01 13:59:15 markus Exp $");
18511b41d2SMark Murray 
19511b41d2SMark Murray #include "ssh.h"
20511b41d2SMark Murray #include "cipher.h"
21511b41d2SMark Murray #include "readconf.h"
22511b41d2SMark Murray #include "xmalloc.h"
23511b41d2SMark Murray 
24511b41d2SMark Murray /* Format of the configuration file:
25511b41d2SMark Murray 
26511b41d2SMark Murray    # Configuration data is parsed as follows:
27511b41d2SMark Murray    #  1. command line options
28511b41d2SMark Murray    #  2. user-specific file
29511b41d2SMark Murray    #  3. system-wide file
30511b41d2SMark Murray    # Any configuration value is only changed the first time it is set.
31511b41d2SMark Murray    # Thus, host-specific definitions should be at the beginning of the
32511b41d2SMark Murray    # configuration file, and defaults at the end.
33511b41d2SMark Murray 
34511b41d2SMark Murray    # Host-specific declarations.  These may override anything above.  A single
35511b41d2SMark Murray    # host may match multiple declarations; these are processed in the order
36511b41d2SMark Murray    # that they are given in.
37511b41d2SMark Murray 
38511b41d2SMark Murray    Host *.ngs.fi ngs.fi
39511b41d2SMark Murray      FallBackToRsh no
40511b41d2SMark Murray 
41511b41d2SMark Murray    Host fake.com
42511b41d2SMark Murray      HostName another.host.name.real.org
43511b41d2SMark Murray      User blaah
44511b41d2SMark Murray      Port 34289
45511b41d2SMark Murray      ForwardX11 no
46511b41d2SMark Murray      ForwardAgent no
47511b41d2SMark Murray 
48511b41d2SMark Murray    Host books.com
49511b41d2SMark Murray      RemoteForward 9999 shadows.cs.hut.fi:9999
50511b41d2SMark Murray      Cipher 3des
51511b41d2SMark Murray 
52511b41d2SMark Murray    Host fascist.blob.com
53511b41d2SMark Murray      Port 23123
54511b41d2SMark Murray      User tylonen
55511b41d2SMark Murray      RhostsAuthentication no
56511b41d2SMark Murray      PasswordAuthentication no
57511b41d2SMark Murray 
58511b41d2SMark Murray    Host puukko.hut.fi
59511b41d2SMark Murray      User t35124p
60511b41d2SMark Murray      ProxyCommand ssh-proxy %h %p
61511b41d2SMark Murray 
62511b41d2SMark Murray    Host *.fr
63511b41d2SMark Murray      UseRsh yes
64511b41d2SMark Murray 
65511b41d2SMark Murray    Host *.su
66511b41d2SMark Murray      Cipher none
67511b41d2SMark Murray      PasswordAuthentication no
68511b41d2SMark Murray 
69511b41d2SMark Murray    # Defaults for various options
70511b41d2SMark Murray    Host *
71511b41d2SMark Murray      ForwardAgent no
72511b41d2SMark Murray      ForwardX11 yes
73511b41d2SMark Murray      RhostsAuthentication yes
74511b41d2SMark Murray      PasswordAuthentication yes
75511b41d2SMark Murray      RSAAuthentication yes
76511b41d2SMark Murray      RhostsRSAAuthentication yes
77511b41d2SMark Murray      FallBackToRsh no
78511b41d2SMark Murray      UseRsh no
79511b41d2SMark Murray      StrictHostKeyChecking yes
80511b41d2SMark Murray      KeepAlives no
81511b41d2SMark Murray      IdentityFile ~/.ssh/identity
82511b41d2SMark Murray      Port 22
83511b41d2SMark Murray      EscapeChar ~
84511b41d2SMark Murray 
85511b41d2SMark Murray */
86511b41d2SMark Murray 
87511b41d2SMark Murray /* Keyword tokens. */
88511b41d2SMark Murray 
89511b41d2SMark Murray typedef enum {
90511b41d2SMark Murray 	oBadOption,
91511b41d2SMark Murray 	oForwardAgent, oForwardX11, oGatewayPorts, oRhostsAuthentication,
92511b41d2SMark Murray 	oPasswordAuthentication, oRSAAuthentication, oFallBackToRsh, oUseRsh,
93511b41d2SMark Murray 	oSkeyAuthentication,
94511b41d2SMark Murray #ifdef KRB4
95511b41d2SMark Murray 	oKerberosAuthentication,
96511b41d2SMark Murray #endif /* KRB4 */
97511b41d2SMark Murray #ifdef AFS
98511b41d2SMark Murray 	oKerberosTgtPassing, oAFSTokenPassing,
99511b41d2SMark Murray #endif
100511b41d2SMark Murray 	oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward,
101511b41d2SMark Murray 	oUser, oHost, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
102511b41d2SMark Murray 	oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
103511b41d2SMark Murray 	oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
104511b41d2SMark Murray 	oCompressionLevel, oKeepAlives, oNumberOfPasswordPrompts, oTISAuthentication,
105511b41d2SMark Murray 	oUsePrivilegedPort, oLogLevel
106511b41d2SMark Murray } OpCodes;
107511b41d2SMark Murray 
108511b41d2SMark Murray /* Textual representations of the tokens. */
109511b41d2SMark Murray 
110511b41d2SMark Murray static struct {
111511b41d2SMark Murray 	const char *name;
112511b41d2SMark Murray 	OpCodes opcode;
113511b41d2SMark Murray } keywords[] = {
114511b41d2SMark Murray 	{ "forwardagent", oForwardAgent },
115511b41d2SMark Murray 	{ "forwardx11", oForwardX11 },
116511b41d2SMark Murray 	{ "gatewayports", oGatewayPorts },
117511b41d2SMark Murray 	{ "useprivilegedport", oUsePrivilegedPort },
118511b41d2SMark Murray 	{ "rhostsauthentication", oRhostsAuthentication },
119511b41d2SMark Murray 	{ "passwordauthentication", oPasswordAuthentication },
120511b41d2SMark Murray 	{ "rsaauthentication", oRSAAuthentication },
121511b41d2SMark Murray 	{ "skeyauthentication", oSkeyAuthentication },
122511b41d2SMark Murray #ifdef KRB4
123511b41d2SMark Murray 	{ "kerberosauthentication", oKerberosAuthentication },
124511b41d2SMark Murray #endif /* KRB4 */
125511b41d2SMark Murray #ifdef AFS
126511b41d2SMark Murray 	{ "kerberostgtpassing", oKerberosTgtPassing },
127511b41d2SMark Murray 	{ "afstokenpassing", oAFSTokenPassing },
128511b41d2SMark Murray #endif
129511b41d2SMark Murray 	{ "fallbacktorsh", oFallBackToRsh },
130511b41d2SMark Murray 	{ "usersh", oUseRsh },
131511b41d2SMark Murray 	{ "identityfile", oIdentityFile },
132511b41d2SMark Murray 	{ "hostname", oHostName },
133511b41d2SMark Murray 	{ "proxycommand", oProxyCommand },
134511b41d2SMark Murray 	{ "port", oPort },
135511b41d2SMark Murray 	{ "cipher", oCipher },
136511b41d2SMark Murray 	{ "remoteforward", oRemoteForward },
137511b41d2SMark Murray 	{ "localforward", oLocalForward },
138511b41d2SMark Murray 	{ "user", oUser },
139511b41d2SMark Murray 	{ "host", oHost },
140511b41d2SMark Murray 	{ "escapechar", oEscapeChar },
141511b41d2SMark Murray 	{ "rhostsrsaauthentication", oRhostsRSAAuthentication },
142511b41d2SMark Murray 	{ "globalknownhostsfile", oGlobalKnownHostsFile },
143511b41d2SMark Murray 	{ "userknownhostsfile", oUserKnownHostsFile },
144511b41d2SMark Murray 	{ "connectionattempts", oConnectionAttempts },
145511b41d2SMark Murray 	{ "batchmode", oBatchMode },
146511b41d2SMark Murray 	{ "checkhostip", oCheckHostIP },
147511b41d2SMark Murray 	{ "stricthostkeychecking", oStrictHostKeyChecking },
148511b41d2SMark Murray 	{ "compression", oCompression },
149511b41d2SMark Murray 	{ "compressionlevel", oCompressionLevel },
150511b41d2SMark Murray 	{ "keepalive", oKeepAlives },
151511b41d2SMark Murray 	{ "numberofpasswordprompts", oNumberOfPasswordPrompts },
152511b41d2SMark Murray 	{ "tisauthentication", oTISAuthentication },
153511b41d2SMark Murray 	{ "loglevel", oLogLevel },
154511b41d2SMark Murray 	{ NULL, 0 }
155511b41d2SMark Murray };
156511b41d2SMark Murray 
157511b41d2SMark Murray /* Characters considered whitespace in strtok calls. */
158511b41d2SMark Murray #define WHITESPACE " \t\r\n"
159511b41d2SMark Murray 
160511b41d2SMark Murray 
161511b41d2SMark Murray /*
162511b41d2SMark Murray  * Adds a local TCP/IP port forward to options.  Never returns if there is an
163511b41d2SMark Murray  * error.
164511b41d2SMark Murray  */
165511b41d2SMark Murray 
166511b41d2SMark Murray void
167511b41d2SMark Murray add_local_forward(Options *options, u_short port, const char *host,
168511b41d2SMark Murray 		  u_short host_port)
169511b41d2SMark Murray {
170511b41d2SMark Murray 	Forward *fwd;
171511b41d2SMark Murray 	extern uid_t original_real_uid;
172511b41d2SMark Murray 	if (port < IPPORT_RESERVED && original_real_uid != 0)
173511b41d2SMark Murray 		fatal("Privileged ports can only be forwarded by root.\n");
174511b41d2SMark Murray 	if (options->num_local_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
175511b41d2SMark Murray 		fatal("Too many local forwards (max %d).", SSH_MAX_FORWARDS_PER_DIRECTION);
176511b41d2SMark Murray 	fwd = &options->local_forwards[options->num_local_forwards++];
177511b41d2SMark Murray 	fwd->port = port;
178511b41d2SMark Murray 	fwd->host = xstrdup(host);
179511b41d2SMark Murray 	fwd->host_port = host_port;
180511b41d2SMark Murray }
181511b41d2SMark Murray 
182511b41d2SMark Murray /*
183511b41d2SMark Murray  * Adds a remote TCP/IP port forward to options.  Never returns if there is
184511b41d2SMark Murray  * an error.
185511b41d2SMark Murray  */
186511b41d2SMark Murray 
187511b41d2SMark Murray void
188511b41d2SMark Murray add_remote_forward(Options *options, u_short port, const char *host,
189511b41d2SMark Murray 		   u_short host_port)
190511b41d2SMark Murray {
191511b41d2SMark Murray 	Forward *fwd;
192511b41d2SMark Murray 	if (options->num_remote_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
193511b41d2SMark Murray 		fatal("Too many remote forwards (max %d).",
194511b41d2SMark Murray 		      SSH_MAX_FORWARDS_PER_DIRECTION);
195511b41d2SMark Murray 	fwd = &options->remote_forwards[options->num_remote_forwards++];
196511b41d2SMark Murray 	fwd->port = port;
197511b41d2SMark Murray 	fwd->host = xstrdup(host);
198511b41d2SMark Murray 	fwd->host_port = host_port;
199511b41d2SMark Murray }
200511b41d2SMark Murray 
201511b41d2SMark Murray /*
202511b41d2SMark Murray  * Returns the number of the token pointed to by cp of length len. Never
203511b41d2SMark Murray  * returns if the token is not known.
204511b41d2SMark Murray  */
205511b41d2SMark Murray 
206511b41d2SMark Murray static OpCodes
207511b41d2SMark Murray parse_token(const char *cp, const char *filename, int linenum)
208511b41d2SMark Murray {
209511b41d2SMark Murray 	unsigned int i;
210511b41d2SMark Murray 
211511b41d2SMark Murray 	for (i = 0; keywords[i].name; i++)
212511b41d2SMark Murray 		if (strcasecmp(cp, keywords[i].name) == 0)
213511b41d2SMark Murray 			return keywords[i].opcode;
214511b41d2SMark Murray 
215511b41d2SMark Murray 	fprintf(stderr, "%s: line %d: Bad configuration option: %s\n",
216511b41d2SMark Murray 		filename, linenum, cp);
217511b41d2SMark Murray 	return oBadOption;
218511b41d2SMark Murray }
219511b41d2SMark Murray 
220511b41d2SMark Murray /*
221511b41d2SMark Murray  * Processes a single option line as used in the configuration files. This
222511b41d2SMark Murray  * only sets those values that have not already been set.
223511b41d2SMark Murray  */
224511b41d2SMark Murray 
225511b41d2SMark Murray int
226511b41d2SMark Murray process_config_line(Options *options, const char *host,
227511b41d2SMark Murray 		    char *line, const char *filename, int linenum,
228511b41d2SMark Murray 		    int *activep)
229511b41d2SMark Murray {
230511b41d2SMark Murray 	char buf[256], *cp, *string, **charptr, *cp2;
231511b41d2SMark Murray 	int opcode, *intptr, value;
232511b41d2SMark Murray 	u_short fwd_port, fwd_host_port;
233511b41d2SMark Murray 
234511b41d2SMark Murray 	/* Skip leading whitespace. */
235511b41d2SMark Murray 	cp = line + strspn(line, WHITESPACE);
236511b41d2SMark Murray 	if (!*cp || *cp == '\n' || *cp == '#')
237511b41d2SMark Murray 		return 0;
238511b41d2SMark Murray 
239511b41d2SMark Murray 	/* Get the keyword. (Each line is supposed to begin with a keyword). */
240511b41d2SMark Murray 	cp = strtok(cp, WHITESPACE);
241511b41d2SMark Murray 	opcode = parse_token(cp, filename, linenum);
242511b41d2SMark Murray 
243511b41d2SMark Murray 	switch (opcode) {
244511b41d2SMark Murray 	case oBadOption:
245511b41d2SMark Murray 		/* don't panic, but count bad options */
246511b41d2SMark Murray 		return -1;
247511b41d2SMark Murray 		/* NOTREACHED */
248511b41d2SMark Murray 	case oForwardAgent:
249511b41d2SMark Murray 		intptr = &options->forward_agent;
250511b41d2SMark Murray parse_flag:
251511b41d2SMark Murray 		cp = strtok(NULL, WHITESPACE);
252511b41d2SMark Murray 		if (!cp)
253511b41d2SMark Murray 			fatal("%.200s line %d: Missing yes/no argument.", filename, linenum);
254511b41d2SMark Murray 		value = 0;	/* To avoid compiler warning... */
255511b41d2SMark Murray 		if (strcmp(cp, "yes") == 0 || strcmp(cp, "true") == 0)
256511b41d2SMark Murray 			value = 1;
257511b41d2SMark Murray 		else if (strcmp(cp, "no") == 0 || strcmp(cp, "false") == 0)
258511b41d2SMark Murray 			value = 0;
259511b41d2SMark Murray 		else
260511b41d2SMark Murray 			fatal("%.200s line %d: Bad yes/no argument.", filename, linenum);
261511b41d2SMark Murray 		if (*activep && *intptr == -1)
262511b41d2SMark Murray 			*intptr = value;
263511b41d2SMark Murray 		break;
264511b41d2SMark Murray 
265511b41d2SMark Murray 	case oForwardX11:
266511b41d2SMark Murray 		intptr = &options->forward_x11;
267511b41d2SMark Murray 		goto parse_flag;
268511b41d2SMark Murray 
269511b41d2SMark Murray 	case oGatewayPorts:
270511b41d2SMark Murray 		intptr = &options->gateway_ports;
271511b41d2SMark Murray 		goto parse_flag;
272511b41d2SMark Murray 
273511b41d2SMark Murray 	case oUsePrivilegedPort:
274511b41d2SMark Murray 		intptr = &options->use_privileged_port;
275511b41d2SMark Murray 		goto parse_flag;
276511b41d2SMark Murray 
277511b41d2SMark Murray 	case oRhostsAuthentication:
278511b41d2SMark Murray 		intptr = &options->rhosts_authentication;
279511b41d2SMark Murray 		goto parse_flag;
280511b41d2SMark Murray 
281511b41d2SMark Murray 	case oPasswordAuthentication:
282511b41d2SMark Murray 		intptr = &options->password_authentication;
283511b41d2SMark Murray 		goto parse_flag;
284511b41d2SMark Murray 
285511b41d2SMark Murray 	case oRSAAuthentication:
286511b41d2SMark Murray 		intptr = &options->rsa_authentication;
287511b41d2SMark Murray 		goto parse_flag;
288511b41d2SMark Murray 
289511b41d2SMark Murray 	case oRhostsRSAAuthentication:
290511b41d2SMark Murray 		intptr = &options->rhosts_rsa_authentication;
291511b41d2SMark Murray 		goto parse_flag;
292511b41d2SMark Murray 
293511b41d2SMark Murray 	case oTISAuthentication:
294511b41d2SMark Murray 		/* fallthrough, there is no difference on the client side */
295511b41d2SMark Murray 	case oSkeyAuthentication:
296511b41d2SMark Murray 		intptr = &options->skey_authentication;
297511b41d2SMark Murray 		goto parse_flag;
298511b41d2SMark Murray 
299511b41d2SMark Murray #ifdef KRB4
300511b41d2SMark Murray 	case oKerberosAuthentication:
301511b41d2SMark Murray 		intptr = &options->kerberos_authentication;
302511b41d2SMark Murray 		goto parse_flag;
303511b41d2SMark Murray #endif /* KRB4 */
304511b41d2SMark Murray 
305511b41d2SMark Murray #ifdef AFS
306511b41d2SMark Murray 	case oKerberosTgtPassing:
307511b41d2SMark Murray 		intptr = &options->kerberos_tgt_passing;
308511b41d2SMark Murray 		goto parse_flag;
309511b41d2SMark Murray 
310511b41d2SMark Murray 	case oAFSTokenPassing:
311511b41d2SMark Murray 		intptr = &options->afs_token_passing;
312511b41d2SMark Murray 		goto parse_flag;
313511b41d2SMark Murray #endif
314511b41d2SMark Murray 
315511b41d2SMark Murray 	case oFallBackToRsh:
316511b41d2SMark Murray 		intptr = &options->fallback_to_rsh;
317511b41d2SMark Murray 		goto parse_flag;
318511b41d2SMark Murray 
319511b41d2SMark Murray 	case oUseRsh:
320511b41d2SMark Murray 		intptr = &options->use_rsh;
321511b41d2SMark Murray 		goto parse_flag;
322511b41d2SMark Murray 
323511b41d2SMark Murray 	case oBatchMode:
324511b41d2SMark Murray 		intptr = &options->batch_mode;
325511b41d2SMark Murray 		goto parse_flag;
326511b41d2SMark Murray 
327511b41d2SMark Murray 	case oCheckHostIP:
328511b41d2SMark Murray 		intptr = &options->check_host_ip;
329511b41d2SMark Murray 		goto parse_flag;
330511b41d2SMark Murray 
331511b41d2SMark Murray 	case oStrictHostKeyChecking:
332511b41d2SMark Murray 		intptr = &options->strict_host_key_checking;
333511b41d2SMark Murray 		cp = strtok(NULL, WHITESPACE);
334511b41d2SMark Murray 		if (!cp)
335511b41d2SMark Murray 			fatal("%.200s line %d: Missing yes/no argument.",
336511b41d2SMark Murray 			      filename, linenum);
337511b41d2SMark Murray 		value = 0;	/* To avoid compiler warning... */
338511b41d2SMark Murray 		if (strcmp(cp, "yes") == 0 || strcmp(cp, "true") == 0)
339511b41d2SMark Murray 			value = 1;
340511b41d2SMark Murray 		else if (strcmp(cp, "no") == 0 || strcmp(cp, "false") == 0)
341511b41d2SMark Murray 			value = 0;
342511b41d2SMark Murray 		else if (strcmp(cp, "ask") == 0)
343511b41d2SMark Murray 			value = 2;
344511b41d2SMark Murray 		else
345511b41d2SMark Murray 			fatal("%.200s line %d: Bad yes/no/ask argument.", filename, linenum);
346511b41d2SMark Murray 		if (*activep && *intptr == -1)
347511b41d2SMark Murray 			*intptr = value;
348511b41d2SMark Murray 		break;
349511b41d2SMark Murray 
350511b41d2SMark Murray 	case oCompression:
351511b41d2SMark Murray 		intptr = &options->compression;
352511b41d2SMark Murray 		goto parse_flag;
353511b41d2SMark Murray 
354511b41d2SMark Murray 	case oKeepAlives:
355511b41d2SMark Murray 		intptr = &options->keepalives;
356511b41d2SMark Murray 		goto parse_flag;
357511b41d2SMark Murray 
358511b41d2SMark Murray 	case oNumberOfPasswordPrompts:
359511b41d2SMark Murray 		intptr = &options->number_of_password_prompts;
360511b41d2SMark Murray 		goto parse_int;
361511b41d2SMark Murray 
362511b41d2SMark Murray 	case oCompressionLevel:
363511b41d2SMark Murray 		intptr = &options->compression_level;
364511b41d2SMark Murray 		goto parse_int;
365511b41d2SMark Murray 
366511b41d2SMark Murray 	case oIdentityFile:
367511b41d2SMark Murray 		cp = strtok(NULL, WHITESPACE);
368511b41d2SMark Murray 		if (!cp)
369511b41d2SMark Murray 			fatal("%.200s line %d: Missing argument.", filename, linenum);
370511b41d2SMark Murray 		if (*activep) {
371511b41d2SMark Murray 			if (options->num_identity_files >= SSH_MAX_IDENTITY_FILES)
372511b41d2SMark Murray 				fatal("%.200s line %d: Too many identity files specified (max %d).",
373511b41d2SMark Murray 				      filename, linenum, SSH_MAX_IDENTITY_FILES);
374511b41d2SMark Murray 			options->identity_files[options->num_identity_files++] = xstrdup(cp);
375511b41d2SMark Murray 		}
376511b41d2SMark Murray 		break;
377511b41d2SMark Murray 
378511b41d2SMark Murray 	case oUser:
379511b41d2SMark Murray 		charptr = &options->user;
380511b41d2SMark Murray parse_string:
381511b41d2SMark Murray 		cp = strtok(NULL, WHITESPACE);
382511b41d2SMark Murray 		if (!cp)
383511b41d2SMark Murray 			fatal("%.200s line %d: Missing argument.", filename, linenum);
384511b41d2SMark Murray 		if (*activep && *charptr == NULL)
385511b41d2SMark Murray 			*charptr = xstrdup(cp);
386511b41d2SMark Murray 		break;
387511b41d2SMark Murray 
388511b41d2SMark Murray 	case oGlobalKnownHostsFile:
389511b41d2SMark Murray 		charptr = &options->system_hostfile;
390511b41d2SMark Murray 		goto parse_string;
391511b41d2SMark Murray 
392511b41d2SMark Murray 	case oUserKnownHostsFile:
393511b41d2SMark Murray 		charptr = &options->user_hostfile;
394511b41d2SMark Murray 		goto parse_string;
395511b41d2SMark Murray 
396511b41d2SMark Murray 	case oHostName:
397511b41d2SMark Murray 		charptr = &options->hostname;
398511b41d2SMark Murray 		goto parse_string;
399511b41d2SMark Murray 
400511b41d2SMark Murray 	case oProxyCommand:
401511b41d2SMark Murray 		charptr = &options->proxy_command;
402511b41d2SMark Murray 		string = xstrdup("");
403511b41d2SMark Murray 		while ((cp = strtok(NULL, WHITESPACE)) != NULL) {
404511b41d2SMark Murray 			string = xrealloc(string, strlen(string) + strlen(cp) + 2);
405511b41d2SMark Murray 			strcat(string, " ");
406511b41d2SMark Murray 			strcat(string, cp);
407511b41d2SMark Murray 		}
408511b41d2SMark Murray 		if (*activep && *charptr == NULL)
409511b41d2SMark Murray 			*charptr = string;
410511b41d2SMark Murray 		else
411511b41d2SMark Murray 			xfree(string);
412511b41d2SMark Murray 		return 0;
413511b41d2SMark Murray 
414511b41d2SMark Murray 	case oPort:
415511b41d2SMark Murray 		intptr = &options->port;
416511b41d2SMark Murray parse_int:
417511b41d2SMark Murray 		cp = strtok(NULL, WHITESPACE);
418511b41d2SMark Murray 		if (!cp)
419511b41d2SMark Murray 			fatal("%.200s line %d: Missing argument.", filename, linenum);
420511b41d2SMark Murray 		if (cp[0] < '0' || cp[0] > '9')
421511b41d2SMark Murray 			fatal("%.200s line %d: Bad number.", filename, linenum);
422511b41d2SMark Murray 
423511b41d2SMark Murray 		/* Octal, decimal, or hex format? */
424511b41d2SMark Murray 		value = strtol(cp, &cp2, 0);
425511b41d2SMark Murray 		if (cp == cp2)
426511b41d2SMark Murray 			fatal("%.200s line %d: Bad number.", filename, linenum);
427511b41d2SMark Murray 		if (*activep && *intptr == -1)
428511b41d2SMark Murray 			*intptr = value;
429511b41d2SMark Murray 		break;
430511b41d2SMark Murray 
431511b41d2SMark Murray 	case oConnectionAttempts:
432511b41d2SMark Murray 		intptr = &options->connection_attempts;
433511b41d2SMark Murray 		goto parse_int;
434511b41d2SMark Murray 
435511b41d2SMark Murray 	case oCipher:
436511b41d2SMark Murray 		intptr = &options->cipher;
437511b41d2SMark Murray 		cp = strtok(NULL, WHITESPACE);
438511b41d2SMark Murray 		value = cipher_number(cp);
439511b41d2SMark Murray 		if (value == -1)
440511b41d2SMark Murray 			fatal("%.200s line %d: Bad cipher '%s'.",
441511b41d2SMark Murray 			      filename, linenum, cp ? cp : "<NONE>");
442511b41d2SMark Murray 		if (*activep && *intptr == -1)
443511b41d2SMark Murray 			*intptr = value;
444511b41d2SMark Murray 		break;
445511b41d2SMark Murray 
446511b41d2SMark Murray 	case oLogLevel:
447511b41d2SMark Murray 		intptr = (int *) &options->log_level;
448511b41d2SMark Murray 		cp = strtok(NULL, WHITESPACE);
449511b41d2SMark Murray 		value = log_level_number(cp);
450511b41d2SMark Murray 		if (value == (LogLevel) - 1)
451511b41d2SMark Murray 			fatal("%.200s line %d: unsupported log level '%s'\n",
452511b41d2SMark Murray 			      filename, linenum, cp ? cp : "<NONE>");
453511b41d2SMark Murray 		if (*activep && (LogLevel) * intptr == -1)
454511b41d2SMark Murray 			*intptr = (LogLevel) value;
455511b41d2SMark Murray 		break;
456511b41d2SMark Murray 
457511b41d2SMark Murray 	case oRemoteForward:
458511b41d2SMark Murray 		cp = strtok(NULL, WHITESPACE);
459511b41d2SMark Murray 		if (!cp)
460511b41d2SMark Murray 			fatal("%.200s line %d: Missing argument.", filename, linenum);
461511b41d2SMark Murray 		if (cp[0] < '0' || cp[0] > '9')
462511b41d2SMark Murray 			fatal("%.200s line %d: Badly formatted port number.",
463511b41d2SMark Murray 			      filename, linenum);
464511b41d2SMark Murray 		fwd_port = atoi(cp);
465511b41d2SMark Murray 		cp = strtok(NULL, WHITESPACE);
466511b41d2SMark Murray 		if (!cp)
467511b41d2SMark Murray 			fatal("%.200s line %d: Missing second argument.",
468511b41d2SMark Murray 			      filename, linenum);
469511b41d2SMark Murray 		if (sscanf(cp, "%255[^:]:%hu", buf, &fwd_host_port) != 2)
470511b41d2SMark Murray 			fatal("%.200s line %d: Badly formatted host:port.",
471511b41d2SMark Murray 			      filename, linenum);
472511b41d2SMark Murray 		if (*activep)
473511b41d2SMark Murray 			add_remote_forward(options, fwd_port, buf, fwd_host_port);
474511b41d2SMark Murray 		break;
475511b41d2SMark Murray 
476511b41d2SMark Murray 	case oLocalForward:
477511b41d2SMark Murray 		cp = strtok(NULL, WHITESPACE);
478511b41d2SMark Murray 		if (!cp)
479511b41d2SMark Murray 			fatal("%.200s line %d: Missing argument.", filename, linenum);
480511b41d2SMark Murray 		if (cp[0] < '0' || cp[0] > '9')
481511b41d2SMark Murray 			fatal("%.200s line %d: Badly formatted port number.",
482511b41d2SMark Murray 			      filename, linenum);
483511b41d2SMark Murray 		fwd_port = atoi(cp);
484511b41d2SMark Murray 		cp = strtok(NULL, WHITESPACE);
485511b41d2SMark Murray 		if (!cp)
486511b41d2SMark Murray 			fatal("%.200s line %d: Missing second argument.",
487511b41d2SMark Murray 			      filename, linenum);
488511b41d2SMark Murray 		if (sscanf(cp, "%255[^:]:%hu", buf, &fwd_host_port) != 2)
489511b41d2SMark Murray 			fatal("%.200s line %d: Badly formatted host:port.",
490511b41d2SMark Murray 			      filename, linenum);
491511b41d2SMark Murray 		if (*activep)
492511b41d2SMark Murray 			add_local_forward(options, fwd_port, buf, fwd_host_port);
493511b41d2SMark Murray 		break;
494511b41d2SMark Murray 
495511b41d2SMark Murray 	case oHost:
496511b41d2SMark Murray 		*activep = 0;
497511b41d2SMark Murray 		while ((cp = strtok(NULL, WHITESPACE)) != NULL)
498511b41d2SMark Murray 			if (match_pattern(host, cp)) {
499511b41d2SMark Murray 				debug("Applying options for %.100s", cp);
500511b41d2SMark Murray 				*activep = 1;
501511b41d2SMark Murray 				break;
502511b41d2SMark Murray 			}
503511b41d2SMark Murray 		/* Avoid garbage check below, as strtok already returned NULL. */
504511b41d2SMark Murray 		return 0;
505511b41d2SMark Murray 
506511b41d2SMark Murray 	case oEscapeChar:
507511b41d2SMark Murray 		intptr = &options->escape_char;
508511b41d2SMark Murray 		cp = strtok(NULL, WHITESPACE);
509511b41d2SMark Murray 		if (!cp)
510511b41d2SMark Murray 			fatal("%.200s line %d: Missing argument.", filename, linenum);
511511b41d2SMark Murray 		if (cp[0] == '^' && cp[2] == 0 &&
512511b41d2SMark Murray 		    (unsigned char) cp[1] >= 64 && (unsigned char) cp[1] < 128)
513511b41d2SMark Murray 			value = (unsigned char) cp[1] & 31;
514511b41d2SMark Murray 		else if (strlen(cp) == 1)
515511b41d2SMark Murray 			value = (unsigned char) cp[0];
516511b41d2SMark Murray 		else if (strcmp(cp, "none") == 0)
517511b41d2SMark Murray 			value = -2;
518511b41d2SMark Murray 		else {
519511b41d2SMark Murray 			fatal("%.200s line %d: Bad escape character.",
520511b41d2SMark Murray 			      filename, linenum);
521511b41d2SMark Murray 			/* NOTREACHED */
522511b41d2SMark Murray 			value = 0;	/* Avoid compiler warning. */
523511b41d2SMark Murray 		}
524511b41d2SMark Murray 		if (*activep && *intptr == -1)
525511b41d2SMark Murray 			*intptr = value;
526511b41d2SMark Murray 		break;
527511b41d2SMark Murray 
528511b41d2SMark Murray 	default:
529511b41d2SMark Murray 		fatal("process_config_line: Unimplemented opcode %d", opcode);
530511b41d2SMark Murray 	}
531511b41d2SMark Murray 
532511b41d2SMark Murray 	/* Check that there is no garbage at end of line. */
533511b41d2SMark Murray 	if (strtok(NULL, WHITESPACE) != NULL)
534511b41d2SMark Murray 		fatal("%.200s line %d: garbage at end of line.",
535511b41d2SMark Murray 		      filename, linenum);
536511b41d2SMark Murray 	return 0;
537511b41d2SMark Murray }
538511b41d2SMark Murray 
539511b41d2SMark Murray 
540511b41d2SMark Murray /*
541511b41d2SMark Murray  * Reads the config file and modifies the options accordingly.  Options
542511b41d2SMark Murray  * should already be initialized before this call.  This never returns if
543511b41d2SMark Murray  * there is an error.  If the file does not exist, this returns immediately.
544511b41d2SMark Murray  */
545511b41d2SMark Murray 
546511b41d2SMark Murray void
547511b41d2SMark Murray read_config_file(const char *filename, const char *host, Options *options)
548511b41d2SMark Murray {
549511b41d2SMark Murray 	FILE *f;
550511b41d2SMark Murray 	char line[1024];
551511b41d2SMark Murray 	int active, linenum;
552511b41d2SMark Murray 	int bad_options = 0;
553511b41d2SMark Murray 
554511b41d2SMark Murray 	/* Open the file. */
555511b41d2SMark Murray 	f = fopen(filename, "r");
556511b41d2SMark Murray 	if (!f)
557511b41d2SMark Murray 		return;
558511b41d2SMark Murray 
559511b41d2SMark Murray 	debug("Reading configuration data %.200s", filename);
560511b41d2SMark Murray 
561511b41d2SMark Murray 	/*
562511b41d2SMark Murray 	 * Mark that we are now processing the options.  This flag is turned
563511b41d2SMark Murray 	 * on/off by Host specifications.
564511b41d2SMark Murray 	 */
565511b41d2SMark Murray 	active = 1;
566511b41d2SMark Murray 	linenum = 0;
567511b41d2SMark Murray 	while (fgets(line, sizeof(line), f)) {
568511b41d2SMark Murray 		/* Update line number counter. */
569511b41d2SMark Murray 		linenum++;
570511b41d2SMark Murray 		if (process_config_line(options, host, line, filename, linenum, &active) != 0)
571511b41d2SMark Murray 			bad_options++;
572511b41d2SMark Murray 	}
573511b41d2SMark Murray 	fclose(f);
574511b41d2SMark Murray 	if (bad_options > 0)
575511b41d2SMark Murray 		fatal("%s: terminating, %d bad configuration options\n",
576511b41d2SMark Murray 		      filename, bad_options);
577511b41d2SMark Murray }
578511b41d2SMark Murray 
579511b41d2SMark Murray /*
580511b41d2SMark Murray  * Initializes options to special values that indicate that they have not yet
581511b41d2SMark Murray  * been set.  Read_config_file will only set options with this value. Options
582511b41d2SMark Murray  * are processed in the following order: command line, user config file,
583511b41d2SMark Murray  * system config file.  Last, fill_default_options is called.
584511b41d2SMark Murray  */
585511b41d2SMark Murray 
586511b41d2SMark Murray void
587511b41d2SMark Murray initialize_options(Options * options)
588511b41d2SMark Murray {
589511b41d2SMark Murray 	memset(options, 'X', sizeof(*options));
590511b41d2SMark Murray 	options->forward_agent = -1;
591511b41d2SMark Murray 	options->forward_x11 = -1;
592511b41d2SMark Murray 	options->gateway_ports = -1;
593511b41d2SMark Murray 	options->use_privileged_port = -1;
594511b41d2SMark Murray 	options->rhosts_authentication = -1;
595511b41d2SMark Murray 	options->rsa_authentication = -1;
596511b41d2SMark Murray 	options->skey_authentication = -1;
597511b41d2SMark Murray #ifdef KRB4
598511b41d2SMark Murray 	options->kerberos_authentication = -1;
599511b41d2SMark Murray #endif
600511b41d2SMark Murray #ifdef AFS
601511b41d2SMark Murray 	options->kerberos_tgt_passing = -1;
602511b41d2SMark Murray 	options->afs_token_passing = -1;
603511b41d2SMark Murray #endif
604511b41d2SMark Murray 	options->password_authentication = -1;
605511b41d2SMark Murray 	options->rhosts_rsa_authentication = -1;
606511b41d2SMark Murray 	options->fallback_to_rsh = -1;
607511b41d2SMark Murray 	options->use_rsh = -1;
608511b41d2SMark Murray 	options->batch_mode = -1;
609511b41d2SMark Murray 	options->check_host_ip = -1;
610511b41d2SMark Murray 	options->strict_host_key_checking = -1;
611511b41d2SMark Murray 	options->compression = -1;
612511b41d2SMark Murray 	options->keepalives = -1;
613511b41d2SMark Murray 	options->compression_level = -1;
614511b41d2SMark Murray 	options->port = -1;
615511b41d2SMark Murray 	options->connection_attempts = -1;
616511b41d2SMark Murray 	options->number_of_password_prompts = -1;
617511b41d2SMark Murray 	options->cipher = -1;
618511b41d2SMark Murray 	options->num_identity_files = 0;
619511b41d2SMark Murray 	options->hostname = NULL;
620511b41d2SMark Murray 	options->proxy_command = NULL;
621511b41d2SMark Murray 	options->user = NULL;
622511b41d2SMark Murray 	options->escape_char = -1;
623511b41d2SMark Murray 	options->system_hostfile = NULL;
624511b41d2SMark Murray 	options->user_hostfile = NULL;
625511b41d2SMark Murray 	options->num_local_forwards = 0;
626511b41d2SMark Murray 	options->num_remote_forwards = 0;
627511b41d2SMark Murray 	options->log_level = (LogLevel) - 1;
628511b41d2SMark Murray }
629511b41d2SMark Murray 
630511b41d2SMark Murray /*
631511b41d2SMark Murray  * Called after processing other sources of option data, this fills those
632511b41d2SMark Murray  * options for which no value has been specified with their default values.
633511b41d2SMark Murray  */
634511b41d2SMark Murray 
635511b41d2SMark Murray void
636511b41d2SMark Murray fill_default_options(Options * options)
637511b41d2SMark Murray {
638511b41d2SMark Murray 	if (options->forward_agent == -1)
639511b41d2SMark Murray 		options->forward_agent = 1;
640511b41d2SMark Murray 	if (options->forward_x11 == -1)
641511b41d2SMark Murray 		options->forward_x11 = 1;
642511b41d2SMark Murray 	if (options->gateway_ports == -1)
643511b41d2SMark Murray 		options->gateway_ports = 0;
644511b41d2SMark Murray 	if (options->use_privileged_port == -1)
645511b41d2SMark Murray 		options->use_privileged_port = 1;
646511b41d2SMark Murray 	if (options->rhosts_authentication == -1)
647511b41d2SMark Murray 		options->rhosts_authentication = 1;
648511b41d2SMark Murray 	if (options->rsa_authentication == -1)
649511b41d2SMark Murray 		options->rsa_authentication = 1;
650511b41d2SMark Murray 	if (options->skey_authentication == -1)
651511b41d2SMark Murray 		options->skey_authentication = 0;
652511b41d2SMark Murray #ifdef KRB4
653511b41d2SMark Murray 	if (options->kerberos_authentication == -1)
654511b41d2SMark Murray 		options->kerberos_authentication = 1;
655511b41d2SMark Murray #endif /* KRB4 */
656511b41d2SMark Murray #ifdef AFS
657511b41d2SMark Murray 	if (options->kerberos_tgt_passing == -1)
658511b41d2SMark Murray 		options->kerberos_tgt_passing = 1;
659511b41d2SMark Murray 	if (options->afs_token_passing == -1)
660511b41d2SMark Murray 		options->afs_token_passing = 1;
661511b41d2SMark Murray #endif /* AFS */
662511b41d2SMark Murray 	if (options->password_authentication == -1)
663511b41d2SMark Murray 		options->password_authentication = 1;
664511b41d2SMark Murray 	if (options->rhosts_rsa_authentication == -1)
665511b41d2SMark Murray 		options->rhosts_rsa_authentication = 1;
666511b41d2SMark Murray 	if (options->fallback_to_rsh == -1)
667511b41d2SMark Murray 		options->fallback_to_rsh = 1;
668511b41d2SMark Murray 	if (options->use_rsh == -1)
669511b41d2SMark Murray 		options->use_rsh = 0;
670511b41d2SMark Murray 	if (options->batch_mode == -1)
671511b41d2SMark Murray 		options->batch_mode = 0;
672511b41d2SMark Murray 	if (options->check_host_ip == -1)
673511b41d2SMark Murray 		options->check_host_ip = 1;
674511b41d2SMark Murray 	if (options->strict_host_key_checking == -1)
675511b41d2SMark Murray 		options->strict_host_key_checking = 2;	/* 2 is default */
676511b41d2SMark Murray 	if (options->compression == -1)
677511b41d2SMark Murray 		options->compression = 0;
678511b41d2SMark Murray 	if (options->keepalives == -1)
679511b41d2SMark Murray 		options->keepalives = 1;
680511b41d2SMark Murray 	if (options->compression_level == -1)
681511b41d2SMark Murray 		options->compression_level = 6;
682511b41d2SMark Murray 	if (options->port == -1)
683511b41d2SMark Murray 		options->port = 0;	/* Filled in ssh_connect. */
684511b41d2SMark Murray 	if (options->connection_attempts == -1)
685511b41d2SMark Murray 		options->connection_attempts = 4;
686511b41d2SMark Murray 	if (options->number_of_password_prompts == -1)
687511b41d2SMark Murray 		options->number_of_password_prompts = 3;
688511b41d2SMark Murray 	/* Selected in ssh_login(). */
689511b41d2SMark Murray 	if (options->cipher == -1)
690511b41d2SMark Murray 		options->cipher = SSH_CIPHER_NOT_SET;
691511b41d2SMark Murray 	if (options->num_identity_files == 0) {
692511b41d2SMark Murray 		options->identity_files[0] =
693511b41d2SMark Murray 			xmalloc(2 + strlen(SSH_CLIENT_IDENTITY) + 1);
694511b41d2SMark Murray 		sprintf(options->identity_files[0], "~/%.100s", SSH_CLIENT_IDENTITY);
695511b41d2SMark Murray 		options->num_identity_files = 1;
696511b41d2SMark Murray 	}
697511b41d2SMark Murray 	if (options->escape_char == -1)
698511b41d2SMark Murray 		options->escape_char = '~';
699511b41d2SMark Murray 	if (options->system_hostfile == NULL)
700511b41d2SMark Murray 		options->system_hostfile = SSH_SYSTEM_HOSTFILE;
701511b41d2SMark Murray 	if (options->user_hostfile == NULL)
702511b41d2SMark Murray 		options->user_hostfile = SSH_USER_HOSTFILE;
703511b41d2SMark Murray 	if (options->log_level == (LogLevel) - 1)
704511b41d2SMark Murray 		options->log_level = SYSLOG_LEVEL_INFO;
705511b41d2SMark Murray 	/* options->proxy_command should not be set by default */
706511b41d2SMark Murray 	/* options->user will be set in the main program if appropriate */
707511b41d2SMark Murray 	/* options->hostname will be set in the main program if appropriate */
708511b41d2SMark Murray }
709