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