1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * Author: Tatu Ylonen <ylo@cs.hut.fi>
3*0Sstevel@tonic-gate  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4*0Sstevel@tonic-gate  *                    All rights reserved
5*0Sstevel@tonic-gate  * Functions for reading the configuration files.
6*0Sstevel@tonic-gate  *
7*0Sstevel@tonic-gate  * As far as I am concerned, the code I have written for this software
8*0Sstevel@tonic-gate  * can be used freely for any purpose.  Any derived versions of this
9*0Sstevel@tonic-gate  * software must be clearly marked as such, and if the derived work is
10*0Sstevel@tonic-gate  * incompatible with the protocol description in the RFC file, it must be
11*0Sstevel@tonic-gate  * called by a name other than "ssh" or "Secure Shell".
12*0Sstevel@tonic-gate  */
13*0Sstevel@tonic-gate /*
14*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
15*0Sstevel@tonic-gate  * Use is subject to license terms.
16*0Sstevel@tonic-gate  */
17*0Sstevel@tonic-gate 
18*0Sstevel@tonic-gate #include "includes.h"
19*0Sstevel@tonic-gate RCSID("$OpenBSD: readconf.c,v 1.100 2002/06/19 00:27:55 deraadt Exp $");
20*0Sstevel@tonic-gate 
21*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
22*0Sstevel@tonic-gate 
23*0Sstevel@tonic-gate #include "ssh.h"
24*0Sstevel@tonic-gate #include "xmalloc.h"
25*0Sstevel@tonic-gate #include "compat.h"
26*0Sstevel@tonic-gate #include "cipher.h"
27*0Sstevel@tonic-gate #include "pathnames.h"
28*0Sstevel@tonic-gate #include "log.h"
29*0Sstevel@tonic-gate #include "readconf.h"
30*0Sstevel@tonic-gate #include "match.h"
31*0Sstevel@tonic-gate #include "misc.h"
32*0Sstevel@tonic-gate #include "kex.h"
33*0Sstevel@tonic-gate #include "mac.h"
34*0Sstevel@tonic-gate 
35*0Sstevel@tonic-gate /* Format of the configuration file:
36*0Sstevel@tonic-gate 
37*0Sstevel@tonic-gate    # Configuration data is parsed as follows:
38*0Sstevel@tonic-gate    #  1. command line options
39*0Sstevel@tonic-gate    #  2. user-specific file
40*0Sstevel@tonic-gate    #  3. system-wide file
41*0Sstevel@tonic-gate    # Any configuration value is only changed the first time it is set.
42*0Sstevel@tonic-gate    # Thus, host-specific definitions should be at the beginning of the
43*0Sstevel@tonic-gate    # configuration file, and defaults at the end.
44*0Sstevel@tonic-gate 
45*0Sstevel@tonic-gate    # Host-specific declarations.  These may override anything above.  A single
46*0Sstevel@tonic-gate    # host may match multiple declarations; these are processed in the order
47*0Sstevel@tonic-gate    # that they are given in.
48*0Sstevel@tonic-gate 
49*0Sstevel@tonic-gate    Host *.ngs.fi ngs.fi
50*0Sstevel@tonic-gate      User foo
51*0Sstevel@tonic-gate 
52*0Sstevel@tonic-gate    Host fake.com
53*0Sstevel@tonic-gate      HostName another.host.name.real.org
54*0Sstevel@tonic-gate      User blaah
55*0Sstevel@tonic-gate      Port 34289
56*0Sstevel@tonic-gate      ForwardX11 no
57*0Sstevel@tonic-gate      ForwardAgent no
58*0Sstevel@tonic-gate 
59*0Sstevel@tonic-gate    Host books.com
60*0Sstevel@tonic-gate      RemoteForward 9999 shadows.cs.hut.fi:9999
61*0Sstevel@tonic-gate      Cipher 3des
62*0Sstevel@tonic-gate 
63*0Sstevel@tonic-gate    Host fascist.blob.com
64*0Sstevel@tonic-gate      Port 23123
65*0Sstevel@tonic-gate      User tylonen
66*0Sstevel@tonic-gate      RhostsAuthentication no
67*0Sstevel@tonic-gate      PasswordAuthentication no
68*0Sstevel@tonic-gate 
69*0Sstevel@tonic-gate    Host puukko.hut.fi
70*0Sstevel@tonic-gate      User t35124p
71*0Sstevel@tonic-gate      ProxyCommand ssh-proxy %h %p
72*0Sstevel@tonic-gate 
73*0Sstevel@tonic-gate    Host *.fr
74*0Sstevel@tonic-gate      PublicKeyAuthentication no
75*0Sstevel@tonic-gate 
76*0Sstevel@tonic-gate    Host *.su
77*0Sstevel@tonic-gate      Cipher none
78*0Sstevel@tonic-gate      PasswordAuthentication no
79*0Sstevel@tonic-gate 
80*0Sstevel@tonic-gate    # Defaults for various options
81*0Sstevel@tonic-gate    Host *
82*0Sstevel@tonic-gate      ForwardAgent no
83*0Sstevel@tonic-gate      ForwardX11 no
84*0Sstevel@tonic-gate      RhostsAuthentication yes
85*0Sstevel@tonic-gate      PasswordAuthentication yes
86*0Sstevel@tonic-gate      RSAAuthentication yes
87*0Sstevel@tonic-gate      RhostsRSAAuthentication yes
88*0Sstevel@tonic-gate      StrictHostKeyChecking yes
89*0Sstevel@tonic-gate      KeepAlives no
90*0Sstevel@tonic-gate      IdentityFile ~/.ssh/identity
91*0Sstevel@tonic-gate      Port 22
92*0Sstevel@tonic-gate      EscapeChar ~
93*0Sstevel@tonic-gate 
94*0Sstevel@tonic-gate */
95*0Sstevel@tonic-gate 
96*0Sstevel@tonic-gate /* Keyword tokens. */
97*0Sstevel@tonic-gate 
98*0Sstevel@tonic-gate typedef enum {
99*0Sstevel@tonic-gate 	oBadOption,
100*0Sstevel@tonic-gate 	oForwardAgent, oForwardX11, oGatewayPorts, oRhostsAuthentication,
101*0Sstevel@tonic-gate 	oPasswordAuthentication, oRSAAuthentication,
102*0Sstevel@tonic-gate 	oChallengeResponseAuthentication, oXAuthLocation,
103*0Sstevel@tonic-gate #if defined(KRB4) || defined(KRB5)
104*0Sstevel@tonic-gate 	oKerberosAuthentication,
105*0Sstevel@tonic-gate #endif
106*0Sstevel@tonic-gate #ifdef GSSAPI
107*0Sstevel@tonic-gate 	oGssKeyEx, oGssAuthentication, oGssDelegateCreds,
108*0Sstevel@tonic-gate #ifdef GSI
109*0Sstevel@tonic-gate 	oGssGlobusDelegateLimitedCreds,
110*0Sstevel@tonic-gate #endif /* GSI */
111*0Sstevel@tonic-gate #endif /* GSSAPI */
112*0Sstevel@tonic-gate #if defined(AFS) || defined(KRB5)
113*0Sstevel@tonic-gate 	oKerberosTgtPassing,
114*0Sstevel@tonic-gate #endif
115*0Sstevel@tonic-gate #ifdef AFS
116*0Sstevel@tonic-gate 	oAFSTokenPassing,
117*0Sstevel@tonic-gate #endif
118*0Sstevel@tonic-gate 	oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward,
119*0Sstevel@tonic-gate 	oUser, oHost, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
120*0Sstevel@tonic-gate 	oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
121*0Sstevel@tonic-gate 	oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
122*0Sstevel@tonic-gate 	oCompressionLevel, oKeepAlives, oNumberOfPasswordPrompts,
123*0Sstevel@tonic-gate 	oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oMacs,
124*0Sstevel@tonic-gate 	oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication,
125*0Sstevel@tonic-gate 	oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
126*0Sstevel@tonic-gate 	oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
127*0Sstevel@tonic-gate 	oHostKeyAlgorithms, oBindAddress, oSmartcardDevice,
128*0Sstevel@tonic-gate 	oClearAllForwardings, oNoHostAuthenticationForLocalhost,
129*0Sstevel@tonic-gate 	oFallBackToRsh, oUseRsh,
130*0Sstevel@tonic-gate 	oDeprecated
131*0Sstevel@tonic-gate } OpCodes;
132*0Sstevel@tonic-gate 
133*0Sstevel@tonic-gate /* Textual representations of the tokens. */
134*0Sstevel@tonic-gate 
135*0Sstevel@tonic-gate static struct {
136*0Sstevel@tonic-gate 	const char *name;
137*0Sstevel@tonic-gate 	OpCodes opcode;
138*0Sstevel@tonic-gate } keywords[] = {
139*0Sstevel@tonic-gate 	{ "forwardagent", oForwardAgent },
140*0Sstevel@tonic-gate 	{ "forwardx11", oForwardX11 },
141*0Sstevel@tonic-gate 	{ "xauthlocation", oXAuthLocation },
142*0Sstevel@tonic-gate 	{ "gatewayports", oGatewayPorts },
143*0Sstevel@tonic-gate 	{ "useprivilegedport", oUsePrivilegedPort },
144*0Sstevel@tonic-gate 	{ "rhostsauthentication", oRhostsAuthentication },
145*0Sstevel@tonic-gate 	{ "passwordauthentication", oPasswordAuthentication },
146*0Sstevel@tonic-gate 	{ "kbdinteractiveauthentication", oKbdInteractiveAuthentication },
147*0Sstevel@tonic-gate 	{ "kbdinteractivedevices", oKbdInteractiveDevices },
148*0Sstevel@tonic-gate 	{ "rsaauthentication", oRSAAuthentication },
149*0Sstevel@tonic-gate 	{ "pubkeyauthentication", oPubkeyAuthentication },
150*0Sstevel@tonic-gate 	{ "dsaauthentication", oPubkeyAuthentication },		    /* alias */
151*0Sstevel@tonic-gate 	{ "rhostsrsaauthentication", oRhostsRSAAuthentication },
152*0Sstevel@tonic-gate 	{ "hostbasedauthentication", oHostbasedAuthentication },
153*0Sstevel@tonic-gate 	{ "challengeresponseauthentication", oChallengeResponseAuthentication },
154*0Sstevel@tonic-gate 	{ "skeyauthentication", oChallengeResponseAuthentication }, /* alias */
155*0Sstevel@tonic-gate 	{ "tisauthentication", oChallengeResponseAuthentication },  /* alias */
156*0Sstevel@tonic-gate #if defined(KRB4) || defined(KRB5)
157*0Sstevel@tonic-gate 	{ "kerberosauthentication", oKerberosAuthentication },
158*0Sstevel@tonic-gate #endif
159*0Sstevel@tonic-gate #ifdef GSSAPI
160*0Sstevel@tonic-gate 	{ "gssapikeyexchange", oGssKeyEx },
161*0Sstevel@tonic-gate 	{ "gssapiauthentication", oGssAuthentication },
162*0Sstevel@tonic-gate 	{ "gssapidelegatecredentials", oGssDelegateCreds },
163*0Sstevel@tonic-gate 	{ "gsskeyex", oGssKeyEx },				/* alias */
164*0Sstevel@tonic-gate 	{ "gssauthentication", oGssAuthentication },		/* alias */
165*0Sstevel@tonic-gate 	{ "gssdelegatecreds", oGssDelegateCreds },		/* alias */
166*0Sstevel@tonic-gate #ifdef GSI
167*0Sstevel@tonic-gate 	/* For backwards compatability with old 1.2.27 client code */
168*0Sstevel@tonic-gate 	{ "forwardgssapiglobusproxy", oGssDelegateCreds }, /* alias */
169*0Sstevel@tonic-gate 	{ "forwardgssapiglobuslimitedproxy", oGssGlobusDelegateLimitedCreds },
170*0Sstevel@tonic-gate #endif /* GSI */
171*0Sstevel@tonic-gate #endif /* GSSAPI */
172*0Sstevel@tonic-gate #if defined(AFS) || defined(KRB5)
173*0Sstevel@tonic-gate 	{ "kerberostgtpassing", oKerberosTgtPassing },
174*0Sstevel@tonic-gate #endif
175*0Sstevel@tonic-gate #ifdef AFS
176*0Sstevel@tonic-gate 	{ "afstokenpassing", oAFSTokenPassing },
177*0Sstevel@tonic-gate #endif
178*0Sstevel@tonic-gate 	{ "fallbacktorsh", oFallBackToRsh },
179*0Sstevel@tonic-gate 	{ "usersh", oUseRsh },
180*0Sstevel@tonic-gate 	{ "identityfile", oIdentityFile },
181*0Sstevel@tonic-gate 	{ "identityfile2", oIdentityFile },			/* alias */
182*0Sstevel@tonic-gate 	{ "hostname", oHostName },
183*0Sstevel@tonic-gate 	{ "hostkeyalias", oHostKeyAlias },
184*0Sstevel@tonic-gate 	{ "proxycommand", oProxyCommand },
185*0Sstevel@tonic-gate 	{ "port", oPort },
186*0Sstevel@tonic-gate 	{ "cipher", oCipher },
187*0Sstevel@tonic-gate 	{ "ciphers", oCiphers },
188*0Sstevel@tonic-gate 	{ "macs", oMacs },
189*0Sstevel@tonic-gate 	{ "protocol", oProtocol },
190*0Sstevel@tonic-gate 	{ "remoteforward", oRemoteForward },
191*0Sstevel@tonic-gate 	{ "localforward", oLocalForward },
192*0Sstevel@tonic-gate 	{ "user", oUser },
193*0Sstevel@tonic-gate 	{ "host", oHost },
194*0Sstevel@tonic-gate 	{ "escapechar", oEscapeChar },
195*0Sstevel@tonic-gate 	{ "globalknownhostsfile", oGlobalKnownHostsFile },
196*0Sstevel@tonic-gate 	{ "userknownhostsfile", oUserKnownHostsFile },		/* obsolete */
197*0Sstevel@tonic-gate 	{ "globalknownhostsfile2", oGlobalKnownHostsFile2 },
198*0Sstevel@tonic-gate 	{ "userknownhostsfile2", oUserKnownHostsFile2 },	/* obsolete */
199*0Sstevel@tonic-gate 	{ "connectionattempts", oConnectionAttempts },
200*0Sstevel@tonic-gate 	{ "batchmode", oBatchMode },
201*0Sstevel@tonic-gate 	{ "checkhostip", oCheckHostIP },
202*0Sstevel@tonic-gate 	{ "stricthostkeychecking", oStrictHostKeyChecking },
203*0Sstevel@tonic-gate 	{ "compression", oCompression },
204*0Sstevel@tonic-gate 	{ "compressionlevel", oCompressionLevel },
205*0Sstevel@tonic-gate 	{ "keepalive", oKeepAlives },
206*0Sstevel@tonic-gate 	{ "numberofpasswordprompts", oNumberOfPasswordPrompts },
207*0Sstevel@tonic-gate 	{ "loglevel", oLogLevel },
208*0Sstevel@tonic-gate 	{ "dynamicforward", oDynamicForward },
209*0Sstevel@tonic-gate 	{ "preferredauthentications", oPreferredAuthentications },
210*0Sstevel@tonic-gate 	{ "hostkeyalgorithms", oHostKeyAlgorithms },
211*0Sstevel@tonic-gate 	{ "bindaddress", oBindAddress },
212*0Sstevel@tonic-gate 	{ "smartcarddevice", oSmartcardDevice },
213*0Sstevel@tonic-gate 	{ "clearallforwardings", oClearAllForwardings },
214*0Sstevel@tonic-gate 	{ "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
215*0Sstevel@tonic-gate 	{ NULL, oBadOption }
216*0Sstevel@tonic-gate };
217*0Sstevel@tonic-gate 
218*0Sstevel@tonic-gate /*
219*0Sstevel@tonic-gate  * Adds a local TCP/IP port forward to options.  Never returns if there is an
220*0Sstevel@tonic-gate  * error.
221*0Sstevel@tonic-gate  */
222*0Sstevel@tonic-gate 
223*0Sstevel@tonic-gate void
224*0Sstevel@tonic-gate add_local_forward(Options *options, u_short port, const char *host,
225*0Sstevel@tonic-gate 		  u_short host_port)
226*0Sstevel@tonic-gate {
227*0Sstevel@tonic-gate 	Forward *fwd;
228*0Sstevel@tonic-gate #ifndef NO_IPPORT_RESERVED_CONCEPT
229*0Sstevel@tonic-gate 	extern uid_t original_real_uid;
230*0Sstevel@tonic-gate 	if (port < IPPORT_RESERVED && original_real_uid != 0)
231*0Sstevel@tonic-gate 		fatal("Privileged ports can only be forwarded by root.");
232*0Sstevel@tonic-gate #endif
233*0Sstevel@tonic-gate 	if (options->num_local_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
234*0Sstevel@tonic-gate 		fatal("Too many local forwards (max %d).", SSH_MAX_FORWARDS_PER_DIRECTION);
235*0Sstevel@tonic-gate 	fwd = &options->local_forwards[options->num_local_forwards++];
236*0Sstevel@tonic-gate 	fwd->port = port;
237*0Sstevel@tonic-gate 	fwd->host = xstrdup(host);
238*0Sstevel@tonic-gate 	fwd->host_port = host_port;
239*0Sstevel@tonic-gate }
240*0Sstevel@tonic-gate 
241*0Sstevel@tonic-gate /*
242*0Sstevel@tonic-gate  * Adds a remote TCP/IP port forward to options.  Never returns if there is
243*0Sstevel@tonic-gate  * an error.
244*0Sstevel@tonic-gate  */
245*0Sstevel@tonic-gate 
246*0Sstevel@tonic-gate void
247*0Sstevel@tonic-gate add_remote_forward(Options *options, u_short port, const char *host,
248*0Sstevel@tonic-gate 		   u_short host_port)
249*0Sstevel@tonic-gate {
250*0Sstevel@tonic-gate 	Forward *fwd;
251*0Sstevel@tonic-gate 	if (options->num_remote_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
252*0Sstevel@tonic-gate 		fatal("Too many remote forwards (max %d).",
253*0Sstevel@tonic-gate 		    SSH_MAX_FORWARDS_PER_DIRECTION);
254*0Sstevel@tonic-gate 	fwd = &options->remote_forwards[options->num_remote_forwards++];
255*0Sstevel@tonic-gate 	fwd->port = port;
256*0Sstevel@tonic-gate 	fwd->host = xstrdup(host);
257*0Sstevel@tonic-gate 	fwd->host_port = host_port;
258*0Sstevel@tonic-gate }
259*0Sstevel@tonic-gate 
260*0Sstevel@tonic-gate static void
261*0Sstevel@tonic-gate clear_forwardings(Options *options)
262*0Sstevel@tonic-gate {
263*0Sstevel@tonic-gate 	int i;
264*0Sstevel@tonic-gate 
265*0Sstevel@tonic-gate 	for (i = 0; i < options->num_local_forwards; i++)
266*0Sstevel@tonic-gate 		xfree(options->local_forwards[i].host);
267*0Sstevel@tonic-gate 	options->num_local_forwards = 0;
268*0Sstevel@tonic-gate 	for (i = 0; i < options->num_remote_forwards; i++)
269*0Sstevel@tonic-gate 		xfree(options->remote_forwards[i].host);
270*0Sstevel@tonic-gate 	options->num_remote_forwards = 0;
271*0Sstevel@tonic-gate }
272*0Sstevel@tonic-gate 
273*0Sstevel@tonic-gate /*
274*0Sstevel@tonic-gate  * Returns the number of the token pointed to by cp or oBadOption.
275*0Sstevel@tonic-gate  */
276*0Sstevel@tonic-gate 
277*0Sstevel@tonic-gate static OpCodes
278*0Sstevel@tonic-gate parse_token(const char *cp, const char *filename, int linenum)
279*0Sstevel@tonic-gate {
280*0Sstevel@tonic-gate 	u_int i;
281*0Sstevel@tonic-gate 
282*0Sstevel@tonic-gate 	for (i = 0; keywords[i].name; i++)
283*0Sstevel@tonic-gate 		if (strcasecmp(cp, keywords[i].name) == 0)
284*0Sstevel@tonic-gate 			return keywords[i].opcode;
285*0Sstevel@tonic-gate 
286*0Sstevel@tonic-gate 	error("%s: line %d: Bad configuration option: %s",
287*0Sstevel@tonic-gate 	    filename, linenum, cp);
288*0Sstevel@tonic-gate 	return oBadOption;
289*0Sstevel@tonic-gate }
290*0Sstevel@tonic-gate 
291*0Sstevel@tonic-gate /*
292*0Sstevel@tonic-gate  * Processes a single option line as used in the configuration files. This
293*0Sstevel@tonic-gate  * only sets those values that have not already been set.
294*0Sstevel@tonic-gate  */
295*0Sstevel@tonic-gate 
296*0Sstevel@tonic-gate int
297*0Sstevel@tonic-gate process_config_line(Options *options, const char *host,
298*0Sstevel@tonic-gate 		    char *line, const char *filename, int linenum,
299*0Sstevel@tonic-gate 		    int *activep)
300*0Sstevel@tonic-gate {
301*0Sstevel@tonic-gate 	char buf[256], *s, *string, **charptr, *endofnumber, *keyword, *arg;
302*0Sstevel@tonic-gate 	int opcode, *intptr, value;
303*0Sstevel@tonic-gate 	u_short fwd_port, fwd_host_port;
304*0Sstevel@tonic-gate 	char sfwd_host_port[6];
305*0Sstevel@tonic-gate 
306*0Sstevel@tonic-gate 	s = line;
307*0Sstevel@tonic-gate 	/* Get the keyword. (Each line is supposed to begin with a keyword). */
308*0Sstevel@tonic-gate 	keyword = strdelim(&s);
309*0Sstevel@tonic-gate 	/* Ignore leading whitespace. */
310*0Sstevel@tonic-gate 	if (*keyword == '\0')
311*0Sstevel@tonic-gate 		keyword = strdelim(&s);
312*0Sstevel@tonic-gate 	if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#')
313*0Sstevel@tonic-gate 		return 0;
314*0Sstevel@tonic-gate 
315*0Sstevel@tonic-gate 	opcode = parse_token(keyword, filename, linenum);
316*0Sstevel@tonic-gate 
317*0Sstevel@tonic-gate 	switch (opcode) {
318*0Sstevel@tonic-gate 	case oBadOption:
319*0Sstevel@tonic-gate 		/* don't panic, but count bad options */
320*0Sstevel@tonic-gate 		return -1;
321*0Sstevel@tonic-gate 		/* NOTREACHED */
322*0Sstevel@tonic-gate 	case oForwardAgent:
323*0Sstevel@tonic-gate 		intptr = &options->forward_agent;
324*0Sstevel@tonic-gate parse_flag:
325*0Sstevel@tonic-gate 		arg = strdelim(&s);
326*0Sstevel@tonic-gate 		if (!arg || *arg == '\0')
327*0Sstevel@tonic-gate 			fatal("%.200s line %d: Missing yes/no argument.", filename, linenum);
328*0Sstevel@tonic-gate 		value = 0;	/* To avoid compiler warning... */
329*0Sstevel@tonic-gate 		if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
330*0Sstevel@tonic-gate 			value = 1;
331*0Sstevel@tonic-gate 		else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
332*0Sstevel@tonic-gate 			value = 0;
333*0Sstevel@tonic-gate 		else
334*0Sstevel@tonic-gate 			fatal("%.200s line %d: Bad yes/no argument.", filename, linenum);
335*0Sstevel@tonic-gate 		if (*activep && *intptr == -1)
336*0Sstevel@tonic-gate 			*intptr = value;
337*0Sstevel@tonic-gate 		break;
338*0Sstevel@tonic-gate 
339*0Sstevel@tonic-gate 	case oForwardX11:
340*0Sstevel@tonic-gate 		intptr = &options->forward_x11;
341*0Sstevel@tonic-gate 		goto parse_flag;
342*0Sstevel@tonic-gate 
343*0Sstevel@tonic-gate 	case oGatewayPorts:
344*0Sstevel@tonic-gate 		intptr = &options->gateway_ports;
345*0Sstevel@tonic-gate 		goto parse_flag;
346*0Sstevel@tonic-gate 
347*0Sstevel@tonic-gate 	case oUsePrivilegedPort:
348*0Sstevel@tonic-gate 		intptr = &options->use_privileged_port;
349*0Sstevel@tonic-gate 		goto parse_flag;
350*0Sstevel@tonic-gate 
351*0Sstevel@tonic-gate 	case oRhostsAuthentication:
352*0Sstevel@tonic-gate 		intptr = &options->rhosts_authentication;
353*0Sstevel@tonic-gate 		goto parse_flag;
354*0Sstevel@tonic-gate 
355*0Sstevel@tonic-gate 	case oPasswordAuthentication:
356*0Sstevel@tonic-gate 		intptr = &options->password_authentication;
357*0Sstevel@tonic-gate 		goto parse_flag;
358*0Sstevel@tonic-gate 
359*0Sstevel@tonic-gate 	case oKbdInteractiveAuthentication:
360*0Sstevel@tonic-gate 		intptr = &options->kbd_interactive_authentication;
361*0Sstevel@tonic-gate 		goto parse_flag;
362*0Sstevel@tonic-gate 
363*0Sstevel@tonic-gate 	case oKbdInteractiveDevices:
364*0Sstevel@tonic-gate 		charptr = &options->kbd_interactive_devices;
365*0Sstevel@tonic-gate 		goto parse_string;
366*0Sstevel@tonic-gate 
367*0Sstevel@tonic-gate 	case oPubkeyAuthentication:
368*0Sstevel@tonic-gate 		intptr = &options->pubkey_authentication;
369*0Sstevel@tonic-gate 		goto parse_flag;
370*0Sstevel@tonic-gate 
371*0Sstevel@tonic-gate 	case oRSAAuthentication:
372*0Sstevel@tonic-gate 		intptr = &options->rsa_authentication;
373*0Sstevel@tonic-gate 		goto parse_flag;
374*0Sstevel@tonic-gate 
375*0Sstevel@tonic-gate 	case oRhostsRSAAuthentication:
376*0Sstevel@tonic-gate 		intptr = &options->rhosts_rsa_authentication;
377*0Sstevel@tonic-gate 		goto parse_flag;
378*0Sstevel@tonic-gate 
379*0Sstevel@tonic-gate 	case oHostbasedAuthentication:
380*0Sstevel@tonic-gate 		intptr = &options->hostbased_authentication;
381*0Sstevel@tonic-gate 		goto parse_flag;
382*0Sstevel@tonic-gate 
383*0Sstevel@tonic-gate 	case oChallengeResponseAuthentication:
384*0Sstevel@tonic-gate 		intptr = &options->challenge_response_authentication;
385*0Sstevel@tonic-gate 		goto parse_flag;
386*0Sstevel@tonic-gate #if defined(KRB4) || defined(KRB5)
387*0Sstevel@tonic-gate 	case oKerberosAuthentication:
388*0Sstevel@tonic-gate 		intptr = &options->kerberos_authentication;
389*0Sstevel@tonic-gate 		goto parse_flag;
390*0Sstevel@tonic-gate #endif
391*0Sstevel@tonic-gate #ifdef GSSAPI
392*0Sstevel@tonic-gate 	case oGssKeyEx:
393*0Sstevel@tonic-gate 		intptr = &options->gss_keyex;
394*0Sstevel@tonic-gate 		goto parse_flag;
395*0Sstevel@tonic-gate 
396*0Sstevel@tonic-gate 	case oGssAuthentication:
397*0Sstevel@tonic-gate 		intptr = &options->gss_authentication;
398*0Sstevel@tonic-gate 		goto parse_flag;
399*0Sstevel@tonic-gate 
400*0Sstevel@tonic-gate 	case oGssDelegateCreds:
401*0Sstevel@tonic-gate 		intptr = &options->gss_deleg_creds;
402*0Sstevel@tonic-gate 		goto parse_flag;
403*0Sstevel@tonic-gate 
404*0Sstevel@tonic-gate #ifdef GSI
405*0Sstevel@tonic-gate 	case oGssGlobusDelegateLimitedCreds:
406*0Sstevel@tonic-gate 		intptr = &options->gss_globus_deleg_limited_proxy;
407*0Sstevel@tonic-gate 		goto parse_flag;
408*0Sstevel@tonic-gate #endif /* GSI */
409*0Sstevel@tonic-gate 
410*0Sstevel@tonic-gate #endif /* GSSAPI */
411*0Sstevel@tonic-gate 
412*0Sstevel@tonic-gate #if defined(AFS) || defined(KRB5)
413*0Sstevel@tonic-gate 	case oKerberosTgtPassing:
414*0Sstevel@tonic-gate 		intptr = &options->kerberos_tgt_passing;
415*0Sstevel@tonic-gate 		goto parse_flag;
416*0Sstevel@tonic-gate #endif
417*0Sstevel@tonic-gate #ifdef AFS
418*0Sstevel@tonic-gate 	case oAFSTokenPassing:
419*0Sstevel@tonic-gate 		intptr = &options->afs_token_passing;
420*0Sstevel@tonic-gate 		goto parse_flag;
421*0Sstevel@tonic-gate #endif
422*0Sstevel@tonic-gate 	case oFallBackToRsh:
423*0Sstevel@tonic-gate 		intptr = &options->fallback_to_rsh;
424*0Sstevel@tonic-gate 		goto parse_flag;
425*0Sstevel@tonic-gate 
426*0Sstevel@tonic-gate 	case oUseRsh:
427*0Sstevel@tonic-gate 		intptr = &options->use_rsh;
428*0Sstevel@tonic-gate 		goto parse_flag;
429*0Sstevel@tonic-gate 
430*0Sstevel@tonic-gate 	case oBatchMode:
431*0Sstevel@tonic-gate 		intptr = &options->batch_mode;
432*0Sstevel@tonic-gate 		goto parse_flag;
433*0Sstevel@tonic-gate 
434*0Sstevel@tonic-gate 	case oCheckHostIP:
435*0Sstevel@tonic-gate 		intptr = &options->check_host_ip;
436*0Sstevel@tonic-gate 		goto parse_flag;
437*0Sstevel@tonic-gate 
438*0Sstevel@tonic-gate 	case oStrictHostKeyChecking:
439*0Sstevel@tonic-gate 		intptr = &options->strict_host_key_checking;
440*0Sstevel@tonic-gate 		arg = strdelim(&s);
441*0Sstevel@tonic-gate 		if (!arg || *arg == '\0')
442*0Sstevel@tonic-gate 			fatal("%.200s line %d: Missing yes/no/ask argument.",
443*0Sstevel@tonic-gate 			    filename, linenum);
444*0Sstevel@tonic-gate 		value = 0;	/* To avoid compiler warning... */
445*0Sstevel@tonic-gate 		if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
446*0Sstevel@tonic-gate 			value = 1;
447*0Sstevel@tonic-gate 		else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
448*0Sstevel@tonic-gate 			value = 0;
449*0Sstevel@tonic-gate 		else if (strcmp(arg, "ask") == 0)
450*0Sstevel@tonic-gate 			value = 2;
451*0Sstevel@tonic-gate 		else
452*0Sstevel@tonic-gate 			fatal("%.200s line %d: Bad yes/no/ask argument.", filename, linenum);
453*0Sstevel@tonic-gate 		if (*activep && *intptr == -1)
454*0Sstevel@tonic-gate 			*intptr = value;
455*0Sstevel@tonic-gate 		break;
456*0Sstevel@tonic-gate 
457*0Sstevel@tonic-gate 	case oCompression:
458*0Sstevel@tonic-gate 		intptr = &options->compression;
459*0Sstevel@tonic-gate 		goto parse_flag;
460*0Sstevel@tonic-gate 
461*0Sstevel@tonic-gate 	case oKeepAlives:
462*0Sstevel@tonic-gate 		intptr = &options->keepalives;
463*0Sstevel@tonic-gate 		goto parse_flag;
464*0Sstevel@tonic-gate 
465*0Sstevel@tonic-gate 	case oNoHostAuthenticationForLocalhost:
466*0Sstevel@tonic-gate 		intptr = &options->no_host_authentication_for_localhost;
467*0Sstevel@tonic-gate 		goto parse_flag;
468*0Sstevel@tonic-gate 
469*0Sstevel@tonic-gate 	case oNumberOfPasswordPrompts:
470*0Sstevel@tonic-gate 		intptr = &options->number_of_password_prompts;
471*0Sstevel@tonic-gate 		goto parse_int;
472*0Sstevel@tonic-gate 
473*0Sstevel@tonic-gate 	case oCompressionLevel:
474*0Sstevel@tonic-gate 		intptr = &options->compression_level;
475*0Sstevel@tonic-gate 		goto parse_int;
476*0Sstevel@tonic-gate 
477*0Sstevel@tonic-gate 	case oIdentityFile:
478*0Sstevel@tonic-gate 		arg = strdelim(&s);
479*0Sstevel@tonic-gate 		if (!arg || *arg == '\0')
480*0Sstevel@tonic-gate 			fatal("%.200s line %d: Missing argument.", filename, linenum);
481*0Sstevel@tonic-gate 		if (*activep) {
482*0Sstevel@tonic-gate 			intptr = &options->num_identity_files;
483*0Sstevel@tonic-gate 			if (*intptr >= SSH_MAX_IDENTITY_FILES)
484*0Sstevel@tonic-gate 				fatal("%.200s line %d: Too many identity files specified (max %d).",
485*0Sstevel@tonic-gate 				    filename, linenum, SSH_MAX_IDENTITY_FILES);
486*0Sstevel@tonic-gate 			charptr =  &options->identity_files[*intptr];
487*0Sstevel@tonic-gate 			*charptr = xstrdup(arg);
488*0Sstevel@tonic-gate 			*intptr = *intptr + 1;
489*0Sstevel@tonic-gate 		}
490*0Sstevel@tonic-gate 		break;
491*0Sstevel@tonic-gate 
492*0Sstevel@tonic-gate 	case oXAuthLocation:
493*0Sstevel@tonic-gate 		charptr=&options->xauth_location;
494*0Sstevel@tonic-gate 		goto parse_string;
495*0Sstevel@tonic-gate 
496*0Sstevel@tonic-gate 	case oUser:
497*0Sstevel@tonic-gate 		charptr = &options->user;
498*0Sstevel@tonic-gate parse_string:
499*0Sstevel@tonic-gate 		arg = strdelim(&s);
500*0Sstevel@tonic-gate 		if (!arg || *arg == '\0')
501*0Sstevel@tonic-gate 			fatal("%.200s line %d: Missing argument.", filename, linenum);
502*0Sstevel@tonic-gate 		if (*activep && *charptr == NULL)
503*0Sstevel@tonic-gate 			*charptr = xstrdup(arg);
504*0Sstevel@tonic-gate 		break;
505*0Sstevel@tonic-gate 
506*0Sstevel@tonic-gate 	case oGlobalKnownHostsFile:
507*0Sstevel@tonic-gate 		charptr = &options->system_hostfile;
508*0Sstevel@tonic-gate 		goto parse_string;
509*0Sstevel@tonic-gate 
510*0Sstevel@tonic-gate 	case oUserKnownHostsFile:
511*0Sstevel@tonic-gate 		charptr = &options->user_hostfile;
512*0Sstevel@tonic-gate 		goto parse_string;
513*0Sstevel@tonic-gate 
514*0Sstevel@tonic-gate 	case oGlobalKnownHostsFile2:
515*0Sstevel@tonic-gate 		charptr = &options->system_hostfile2;
516*0Sstevel@tonic-gate 		goto parse_string;
517*0Sstevel@tonic-gate 
518*0Sstevel@tonic-gate 	case oUserKnownHostsFile2:
519*0Sstevel@tonic-gate 		charptr = &options->user_hostfile2;
520*0Sstevel@tonic-gate 		goto parse_string;
521*0Sstevel@tonic-gate 
522*0Sstevel@tonic-gate 	case oHostName:
523*0Sstevel@tonic-gate 		charptr = &options->hostname;
524*0Sstevel@tonic-gate 		goto parse_string;
525*0Sstevel@tonic-gate 
526*0Sstevel@tonic-gate 	case oHostKeyAlias:
527*0Sstevel@tonic-gate 		charptr = &options->host_key_alias;
528*0Sstevel@tonic-gate 		goto parse_string;
529*0Sstevel@tonic-gate 
530*0Sstevel@tonic-gate 	case oPreferredAuthentications:
531*0Sstevel@tonic-gate 		charptr = &options->preferred_authentications;
532*0Sstevel@tonic-gate 		goto parse_string;
533*0Sstevel@tonic-gate 
534*0Sstevel@tonic-gate 	case oBindAddress:
535*0Sstevel@tonic-gate 		charptr = &options->bind_address;
536*0Sstevel@tonic-gate 		goto parse_string;
537*0Sstevel@tonic-gate 
538*0Sstevel@tonic-gate 	case oSmartcardDevice:
539*0Sstevel@tonic-gate 		charptr = &options->smartcard_device;
540*0Sstevel@tonic-gate 		goto parse_string;
541*0Sstevel@tonic-gate 
542*0Sstevel@tonic-gate 	case oProxyCommand:
543*0Sstevel@tonic-gate 		charptr = &options->proxy_command;
544*0Sstevel@tonic-gate 		string = xstrdup("");
545*0Sstevel@tonic-gate 		while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
546*0Sstevel@tonic-gate 			string = xrealloc(string, strlen(string) + strlen(arg) + 2);
547*0Sstevel@tonic-gate 			strcat(string, " ");
548*0Sstevel@tonic-gate 			strcat(string, arg);
549*0Sstevel@tonic-gate 		}
550*0Sstevel@tonic-gate 		if (*activep && *charptr == NULL)
551*0Sstevel@tonic-gate 			*charptr = string;
552*0Sstevel@tonic-gate 		else
553*0Sstevel@tonic-gate 			xfree(string);
554*0Sstevel@tonic-gate 		return 0;
555*0Sstevel@tonic-gate 
556*0Sstevel@tonic-gate 	case oPort:
557*0Sstevel@tonic-gate 		intptr = &options->port;
558*0Sstevel@tonic-gate parse_int:
559*0Sstevel@tonic-gate 		arg = strdelim(&s);
560*0Sstevel@tonic-gate 		if (!arg || *arg == '\0')
561*0Sstevel@tonic-gate 			fatal("%.200s line %d: Missing argument.", filename, linenum);
562*0Sstevel@tonic-gate 		if (arg[0] < '0' || arg[0] > '9')
563*0Sstevel@tonic-gate 			fatal("%.200s line %d: Bad number.", filename, linenum);
564*0Sstevel@tonic-gate 
565*0Sstevel@tonic-gate 		/* Octal, decimal, or hex format? */
566*0Sstevel@tonic-gate 		value = strtol(arg, &endofnumber, 0);
567*0Sstevel@tonic-gate 		if (arg == endofnumber)
568*0Sstevel@tonic-gate 			fatal("%.200s line %d: Bad number.", filename, linenum);
569*0Sstevel@tonic-gate 		if (*activep && *intptr == -1)
570*0Sstevel@tonic-gate 			*intptr = value;
571*0Sstevel@tonic-gate 		break;
572*0Sstevel@tonic-gate 
573*0Sstevel@tonic-gate 	case oConnectionAttempts:
574*0Sstevel@tonic-gate 		intptr = &options->connection_attempts;
575*0Sstevel@tonic-gate 		goto parse_int;
576*0Sstevel@tonic-gate 
577*0Sstevel@tonic-gate 	case oCipher:
578*0Sstevel@tonic-gate 		intptr = &options->cipher;
579*0Sstevel@tonic-gate 		arg = strdelim(&s);
580*0Sstevel@tonic-gate 		if (!arg || *arg == '\0')
581*0Sstevel@tonic-gate 			fatal("%.200s line %d: Missing argument.", filename, linenum);
582*0Sstevel@tonic-gate 		value = cipher_number(arg);
583*0Sstevel@tonic-gate 		if (value == -1)
584*0Sstevel@tonic-gate 			fatal("%.200s line %d: Bad cipher '%s'.",
585*0Sstevel@tonic-gate 			    filename, linenum, arg ? arg : "<NONE>");
586*0Sstevel@tonic-gate 		if (*activep && *intptr == -1)
587*0Sstevel@tonic-gate 			*intptr = value;
588*0Sstevel@tonic-gate 		break;
589*0Sstevel@tonic-gate 
590*0Sstevel@tonic-gate 	case oCiphers:
591*0Sstevel@tonic-gate 		arg = strdelim(&s);
592*0Sstevel@tonic-gate 		if (!arg || *arg == '\0')
593*0Sstevel@tonic-gate 			fatal("%.200s line %d: Missing argument.", filename, linenum);
594*0Sstevel@tonic-gate 		if (!ciphers_valid(arg))
595*0Sstevel@tonic-gate 			fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.",
596*0Sstevel@tonic-gate 			    filename, linenum, arg ? arg : "<NONE>");
597*0Sstevel@tonic-gate 		if (*activep && options->ciphers == NULL)
598*0Sstevel@tonic-gate 			options->ciphers = xstrdup(arg);
599*0Sstevel@tonic-gate 		break;
600*0Sstevel@tonic-gate 
601*0Sstevel@tonic-gate 	case oMacs:
602*0Sstevel@tonic-gate 		arg = strdelim(&s);
603*0Sstevel@tonic-gate 		if (!arg || *arg == '\0')
604*0Sstevel@tonic-gate 			fatal("%.200s line %d: Missing argument.", filename, linenum);
605*0Sstevel@tonic-gate 		if (!mac_valid(arg))
606*0Sstevel@tonic-gate 			fatal("%.200s line %d: Bad SSH2 Mac spec '%s'.",
607*0Sstevel@tonic-gate 			    filename, linenum, arg ? arg : "<NONE>");
608*0Sstevel@tonic-gate 		if (*activep && options->macs == NULL)
609*0Sstevel@tonic-gate 			options->macs = xstrdup(arg);
610*0Sstevel@tonic-gate 		break;
611*0Sstevel@tonic-gate 
612*0Sstevel@tonic-gate 	case oHostKeyAlgorithms:
613*0Sstevel@tonic-gate 		arg = strdelim(&s);
614*0Sstevel@tonic-gate 		if (!arg || *arg == '\0')
615*0Sstevel@tonic-gate 			fatal("%.200s line %d: Missing argument.", filename, linenum);
616*0Sstevel@tonic-gate 		if (!key_names_valid2(arg))
617*0Sstevel@tonic-gate 			fatal("%.200s line %d: Bad protocol 2 host key algorithms '%s'.",
618*0Sstevel@tonic-gate 			    filename, linenum, arg ? arg : "<NONE>");
619*0Sstevel@tonic-gate 		if (*activep && options->hostkeyalgorithms == NULL)
620*0Sstevel@tonic-gate 			options->hostkeyalgorithms = xstrdup(arg);
621*0Sstevel@tonic-gate 		break;
622*0Sstevel@tonic-gate 
623*0Sstevel@tonic-gate 	case oProtocol:
624*0Sstevel@tonic-gate 		intptr = &options->protocol;
625*0Sstevel@tonic-gate 		arg = strdelim(&s);
626*0Sstevel@tonic-gate 		if (!arg || *arg == '\0')
627*0Sstevel@tonic-gate 			fatal("%.200s line %d: Missing argument.", filename, linenum);
628*0Sstevel@tonic-gate 		value = proto_spec(arg);
629*0Sstevel@tonic-gate 		if (value == SSH_PROTO_UNKNOWN)
630*0Sstevel@tonic-gate 			fatal("%.200s line %d: Bad protocol spec '%s'.",
631*0Sstevel@tonic-gate 			    filename, linenum, arg ? arg : "<NONE>");
632*0Sstevel@tonic-gate 		if (*activep && *intptr == SSH_PROTO_UNKNOWN)
633*0Sstevel@tonic-gate 			*intptr = value;
634*0Sstevel@tonic-gate 		break;
635*0Sstevel@tonic-gate 
636*0Sstevel@tonic-gate 	case oLogLevel:
637*0Sstevel@tonic-gate 		intptr = (int *) &options->log_level;
638*0Sstevel@tonic-gate 		arg = strdelim(&s);
639*0Sstevel@tonic-gate 		value = log_level_number(arg);
640*0Sstevel@tonic-gate 		if (value == SYSLOG_LEVEL_NOT_SET)
641*0Sstevel@tonic-gate 			fatal("%.200s line %d: unsupported log level '%s'",
642*0Sstevel@tonic-gate 			    filename, linenum, arg ? arg : "<NONE>");
643*0Sstevel@tonic-gate 		if (*activep && (LogLevel) *intptr == SYSLOG_LEVEL_NOT_SET)
644*0Sstevel@tonic-gate 			*intptr = (LogLevel) value;
645*0Sstevel@tonic-gate 		break;
646*0Sstevel@tonic-gate 
647*0Sstevel@tonic-gate 	case oLocalForward:
648*0Sstevel@tonic-gate 	case oRemoteForward:
649*0Sstevel@tonic-gate 		arg = strdelim(&s);
650*0Sstevel@tonic-gate 		if (!arg || *arg == '\0')
651*0Sstevel@tonic-gate 			fatal("%.200s line %d: Missing port argument.",
652*0Sstevel@tonic-gate 			    filename, linenum);
653*0Sstevel@tonic-gate 		if ((fwd_port = a2port(arg)) == 0)
654*0Sstevel@tonic-gate 			fatal("%.200s line %d: Bad listen port.",
655*0Sstevel@tonic-gate 			    filename, linenum);
656*0Sstevel@tonic-gate 		arg = strdelim(&s);
657*0Sstevel@tonic-gate 		if (!arg || *arg == '\0')
658*0Sstevel@tonic-gate 			fatal("%.200s line %d: Missing second argument.",
659*0Sstevel@tonic-gate 			    filename, linenum);
660*0Sstevel@tonic-gate 		if (sscanf(arg, "%255[^:]:%5[0-9]", buf, sfwd_host_port) != 2 &&
661*0Sstevel@tonic-gate 		    sscanf(arg, "%255[^/]/%5[0-9]", buf, sfwd_host_port) != 2)
662*0Sstevel@tonic-gate 			fatal("%.200s line %d: Bad forwarding specification.",
663*0Sstevel@tonic-gate 			    filename, linenum);
664*0Sstevel@tonic-gate 		if ((fwd_host_port = a2port(sfwd_host_port)) == 0)
665*0Sstevel@tonic-gate 			fatal("%.200s line %d: Bad forwarding port.",
666*0Sstevel@tonic-gate 			    filename, linenum);
667*0Sstevel@tonic-gate 		if (*activep) {
668*0Sstevel@tonic-gate 			if (opcode == oLocalForward)
669*0Sstevel@tonic-gate 				add_local_forward(options, fwd_port, buf,
670*0Sstevel@tonic-gate 				    fwd_host_port);
671*0Sstevel@tonic-gate 			else if (opcode == oRemoteForward)
672*0Sstevel@tonic-gate 				add_remote_forward(options, fwd_port, buf,
673*0Sstevel@tonic-gate 				    fwd_host_port);
674*0Sstevel@tonic-gate 		}
675*0Sstevel@tonic-gate 		break;
676*0Sstevel@tonic-gate 
677*0Sstevel@tonic-gate 	case oDynamicForward:
678*0Sstevel@tonic-gate 		arg = strdelim(&s);
679*0Sstevel@tonic-gate 		if (!arg || *arg == '\0')
680*0Sstevel@tonic-gate 			fatal("%.200s line %d: Missing port argument.",
681*0Sstevel@tonic-gate 			    filename, linenum);
682*0Sstevel@tonic-gate 		fwd_port = a2port(arg);
683*0Sstevel@tonic-gate 		if (fwd_port == 0)
684*0Sstevel@tonic-gate 			fatal("%.200s line %d: Badly formatted port number.",
685*0Sstevel@tonic-gate 			    filename, linenum);
686*0Sstevel@tonic-gate 		if (*activep)
687*0Sstevel@tonic-gate 			add_local_forward(options, fwd_port, "socks4", 0);
688*0Sstevel@tonic-gate 		break;
689*0Sstevel@tonic-gate 
690*0Sstevel@tonic-gate 	case oClearAllForwardings:
691*0Sstevel@tonic-gate 		intptr = &options->clear_forwardings;
692*0Sstevel@tonic-gate 		goto parse_flag;
693*0Sstevel@tonic-gate 
694*0Sstevel@tonic-gate 	case oHost:
695*0Sstevel@tonic-gate 		*activep = 0;
696*0Sstevel@tonic-gate 		while ((arg = strdelim(&s)) != NULL && *arg != '\0')
697*0Sstevel@tonic-gate 			if (match_pattern(host, arg)) {
698*0Sstevel@tonic-gate 				debug("Applying options for %.100s", arg);
699*0Sstevel@tonic-gate 				*activep = 1;
700*0Sstevel@tonic-gate 				break;
701*0Sstevel@tonic-gate 			}
702*0Sstevel@tonic-gate 		/* Avoid garbage check below, as strdelim is done. */
703*0Sstevel@tonic-gate 		return 0;
704*0Sstevel@tonic-gate 
705*0Sstevel@tonic-gate 	case oEscapeChar:
706*0Sstevel@tonic-gate 		intptr = &options->escape_char;
707*0Sstevel@tonic-gate 		arg = strdelim(&s);
708*0Sstevel@tonic-gate 		if (!arg || *arg == '\0')
709*0Sstevel@tonic-gate 			fatal("%.200s line %d: Missing argument.", filename, linenum);
710*0Sstevel@tonic-gate 		if (arg[0] == '^' && arg[2] == 0 &&
711*0Sstevel@tonic-gate 		    (u_char) arg[1] >= 64 && (u_char) arg[1] < 128)
712*0Sstevel@tonic-gate 			value = (u_char) arg[1] & 31;
713*0Sstevel@tonic-gate 		else if (strlen(arg) == 1)
714*0Sstevel@tonic-gate 			value = (u_char) arg[0];
715*0Sstevel@tonic-gate 		else if (strcmp(arg, "none") == 0)
716*0Sstevel@tonic-gate 			value = SSH_ESCAPECHAR_NONE;
717*0Sstevel@tonic-gate 		else {
718*0Sstevel@tonic-gate 			fatal("%.200s line %d: Bad escape character.",
719*0Sstevel@tonic-gate 			    filename, linenum);
720*0Sstevel@tonic-gate 			/* NOTREACHED */
721*0Sstevel@tonic-gate 			value = 0;	/* Avoid compiler warning. */
722*0Sstevel@tonic-gate 		}
723*0Sstevel@tonic-gate 		if (*activep && *intptr == -1)
724*0Sstevel@tonic-gate 			*intptr = value;
725*0Sstevel@tonic-gate 		break;
726*0Sstevel@tonic-gate 
727*0Sstevel@tonic-gate 	case oDeprecated:
728*0Sstevel@tonic-gate 		debug("%s line %d: Deprecated option \"%s\"",
729*0Sstevel@tonic-gate 		    filename, linenum, keyword);
730*0Sstevel@tonic-gate 		return 0;
731*0Sstevel@tonic-gate 
732*0Sstevel@tonic-gate 	default:
733*0Sstevel@tonic-gate 		fatal("process_config_line: Unimplemented opcode %d", opcode);
734*0Sstevel@tonic-gate 	}
735*0Sstevel@tonic-gate 
736*0Sstevel@tonic-gate 	/* Check that there is no garbage at end of line. */
737*0Sstevel@tonic-gate 	if ((arg = strdelim(&s)) != NULL && *arg != '\0') {
738*0Sstevel@tonic-gate 		fatal("%.200s line %d: garbage at end of line; \"%.200s\".",
739*0Sstevel@tonic-gate 		     filename, linenum, arg);
740*0Sstevel@tonic-gate 	}
741*0Sstevel@tonic-gate 	return 0;
742*0Sstevel@tonic-gate }
743*0Sstevel@tonic-gate 
744*0Sstevel@tonic-gate 
745*0Sstevel@tonic-gate /*
746*0Sstevel@tonic-gate  * Reads the config file and modifies the options accordingly.  Options
747*0Sstevel@tonic-gate  * should already be initialized before this call.  This never returns if
748*0Sstevel@tonic-gate  * there is an error.  If the file does not exist, this returns 0.
749*0Sstevel@tonic-gate  */
750*0Sstevel@tonic-gate 
751*0Sstevel@tonic-gate int
752*0Sstevel@tonic-gate read_config_file(const char *filename, const char *host, Options *options)
753*0Sstevel@tonic-gate {
754*0Sstevel@tonic-gate 	FILE *f;
755*0Sstevel@tonic-gate 	char line[1024];
756*0Sstevel@tonic-gate 	int active, linenum;
757*0Sstevel@tonic-gate 	int bad_options = 0;
758*0Sstevel@tonic-gate 
759*0Sstevel@tonic-gate 	/* Open the file. */
760*0Sstevel@tonic-gate 	f = fopen(filename, "r");
761*0Sstevel@tonic-gate 	if (!f)
762*0Sstevel@tonic-gate 		return 0;
763*0Sstevel@tonic-gate 
764*0Sstevel@tonic-gate 	debug("Reading configuration data %.200s", filename);
765*0Sstevel@tonic-gate 
766*0Sstevel@tonic-gate 	/*
767*0Sstevel@tonic-gate 	 * Mark that we are now processing the options.  This flag is turned
768*0Sstevel@tonic-gate 	 * on/off by Host specifications.
769*0Sstevel@tonic-gate 	 */
770*0Sstevel@tonic-gate 	active = 1;
771*0Sstevel@tonic-gate 	linenum = 0;
772*0Sstevel@tonic-gate 	while (fgets(line, sizeof(line), f)) {
773*0Sstevel@tonic-gate 		/* Update line number counter. */
774*0Sstevel@tonic-gate 		linenum++;
775*0Sstevel@tonic-gate 		if (process_config_line(options, host, line, filename, linenum, &active) != 0)
776*0Sstevel@tonic-gate 			bad_options++;
777*0Sstevel@tonic-gate 	}
778*0Sstevel@tonic-gate 	fclose(f);
779*0Sstevel@tonic-gate 	if (bad_options > 0)
780*0Sstevel@tonic-gate 		fatal("%s: terminating, %d bad configuration options",
781*0Sstevel@tonic-gate 		    filename, bad_options);
782*0Sstevel@tonic-gate 	return 1;
783*0Sstevel@tonic-gate }
784*0Sstevel@tonic-gate 
785*0Sstevel@tonic-gate /*
786*0Sstevel@tonic-gate  * Initializes options to special values that indicate that they have not yet
787*0Sstevel@tonic-gate  * been set.  Read_config_file will only set options with this value. Options
788*0Sstevel@tonic-gate  * are processed in the following order: command line, user config file,
789*0Sstevel@tonic-gate  * system config file.  Last, fill_default_options is called.
790*0Sstevel@tonic-gate  */
791*0Sstevel@tonic-gate 
792*0Sstevel@tonic-gate void
793*0Sstevel@tonic-gate initialize_options(Options * options)
794*0Sstevel@tonic-gate {
795*0Sstevel@tonic-gate 	memset(options, 'X', sizeof(*options));
796*0Sstevel@tonic-gate 	options->forward_agent = -1;
797*0Sstevel@tonic-gate 	options->forward_x11 = -1;
798*0Sstevel@tonic-gate 	options->xauth_location = NULL;
799*0Sstevel@tonic-gate 	options->gateway_ports = -1;
800*0Sstevel@tonic-gate 	options->use_privileged_port = -1;
801*0Sstevel@tonic-gate 	options->rhosts_authentication = -1;
802*0Sstevel@tonic-gate 	options->rsa_authentication = -1;
803*0Sstevel@tonic-gate 	options->pubkey_authentication = -1;
804*0Sstevel@tonic-gate 	options->challenge_response_authentication = -1;
805*0Sstevel@tonic-gate #ifdef GSSAPI
806*0Sstevel@tonic-gate         options->gss_keyex = -1;
807*0Sstevel@tonic-gate         options->gss_authentication = -1;
808*0Sstevel@tonic-gate         options->gss_deleg_creds = -1;
809*0Sstevel@tonic-gate #ifdef GSI
810*0Sstevel@tonic-gate         options->gss_globus_deleg_limited_proxy = -1;
811*0Sstevel@tonic-gate #endif /* GSI */
812*0Sstevel@tonic-gate #endif /* GSSAPI */
813*0Sstevel@tonic-gate 
814*0Sstevel@tonic-gate #if defined(KRB4) || defined(KRB5)
815*0Sstevel@tonic-gate 	options->kerberos_authentication = -1;
816*0Sstevel@tonic-gate #endif
817*0Sstevel@tonic-gate #if defined(AFS) || defined(KRB5)
818*0Sstevel@tonic-gate 	options->kerberos_tgt_passing = -1;
819*0Sstevel@tonic-gate #endif
820*0Sstevel@tonic-gate #ifdef AFS
821*0Sstevel@tonic-gate 	options->afs_token_passing = -1;
822*0Sstevel@tonic-gate #endif
823*0Sstevel@tonic-gate 	options->password_authentication = -1;
824*0Sstevel@tonic-gate 	options->kbd_interactive_authentication = -1;
825*0Sstevel@tonic-gate 	options->kbd_interactive_devices = NULL;
826*0Sstevel@tonic-gate 	options->rhosts_rsa_authentication = -1;
827*0Sstevel@tonic-gate 	options->hostbased_authentication = -1;
828*0Sstevel@tonic-gate 	options->batch_mode = -1;
829*0Sstevel@tonic-gate 	options->check_host_ip = -1;
830*0Sstevel@tonic-gate 	options->strict_host_key_checking = -1;
831*0Sstevel@tonic-gate 	options->compression = -1;
832*0Sstevel@tonic-gate 	options->keepalives = -1;
833*0Sstevel@tonic-gate 	options->compression_level = -1;
834*0Sstevel@tonic-gate 	options->port = -1;
835*0Sstevel@tonic-gate 	options->connection_attempts = -1;
836*0Sstevel@tonic-gate 	options->number_of_password_prompts = -1;
837*0Sstevel@tonic-gate 	options->cipher = -1;
838*0Sstevel@tonic-gate 	options->ciphers = NULL;
839*0Sstevel@tonic-gate 	options->macs = NULL;
840*0Sstevel@tonic-gate 	options->hostkeyalgorithms = NULL;
841*0Sstevel@tonic-gate 	options->protocol = SSH_PROTO_UNKNOWN;
842*0Sstevel@tonic-gate 	options->num_identity_files = 0;
843*0Sstevel@tonic-gate 	options->hostname = NULL;
844*0Sstevel@tonic-gate 	options->host_key_alias = NULL;
845*0Sstevel@tonic-gate 	options->proxy_command = NULL;
846*0Sstevel@tonic-gate 	options->user = NULL;
847*0Sstevel@tonic-gate 	options->escape_char = -1;
848*0Sstevel@tonic-gate 	options->system_hostfile = NULL;
849*0Sstevel@tonic-gate 	options->user_hostfile = NULL;
850*0Sstevel@tonic-gate 	options->system_hostfile2 = NULL;
851*0Sstevel@tonic-gate 	options->user_hostfile2 = NULL;
852*0Sstevel@tonic-gate 	options->num_local_forwards = 0;
853*0Sstevel@tonic-gate 	options->num_remote_forwards = 0;
854*0Sstevel@tonic-gate 	options->clear_forwardings = -1;
855*0Sstevel@tonic-gate 	options->log_level = SYSLOG_LEVEL_NOT_SET;
856*0Sstevel@tonic-gate 	options->preferred_authentications = NULL;
857*0Sstevel@tonic-gate 	options->bind_address = NULL;
858*0Sstevel@tonic-gate 	options->smartcard_device = NULL;
859*0Sstevel@tonic-gate 	options->no_host_authentication_for_localhost = - 1;
860*0Sstevel@tonic-gate 	options->fallback_to_rsh = -1;
861*0Sstevel@tonic-gate 	options->use_rsh = -1;
862*0Sstevel@tonic-gate }
863*0Sstevel@tonic-gate 
864*0Sstevel@tonic-gate /*
865*0Sstevel@tonic-gate  * Called after processing other sources of option data, this fills those
866*0Sstevel@tonic-gate  * options for which no value has been specified with their default values.
867*0Sstevel@tonic-gate  */
868*0Sstevel@tonic-gate 
869*0Sstevel@tonic-gate void
870*0Sstevel@tonic-gate fill_default_options(Options * options)
871*0Sstevel@tonic-gate {
872*0Sstevel@tonic-gate 	int len;
873*0Sstevel@tonic-gate 
874*0Sstevel@tonic-gate 	if (options->forward_agent == -1)
875*0Sstevel@tonic-gate 		options->forward_agent = 0;
876*0Sstevel@tonic-gate 	if (options->forward_x11 == -1)
877*0Sstevel@tonic-gate 		options->forward_x11 = 0;
878*0Sstevel@tonic-gate 	if (options->xauth_location == NULL)
879*0Sstevel@tonic-gate 		options->xauth_location = _PATH_XAUTH;
880*0Sstevel@tonic-gate 	if (options->gateway_ports == -1)
881*0Sstevel@tonic-gate 		options->gateway_ports = 0;
882*0Sstevel@tonic-gate 	if (options->use_privileged_port == -1)
883*0Sstevel@tonic-gate 		options->use_privileged_port = 0;
884*0Sstevel@tonic-gate 	if (options->rhosts_authentication == -1)
885*0Sstevel@tonic-gate 		options->rhosts_authentication = 0;
886*0Sstevel@tonic-gate 	if (options->rsa_authentication == -1)
887*0Sstevel@tonic-gate 		options->rsa_authentication = 1;
888*0Sstevel@tonic-gate 	if (options->pubkey_authentication == -1)
889*0Sstevel@tonic-gate 		options->pubkey_authentication = 1;
890*0Sstevel@tonic-gate 	if (options->challenge_response_authentication == -1)
891*0Sstevel@tonic-gate 		options->challenge_response_authentication = 1;
892*0Sstevel@tonic-gate #ifdef GSSAPI
893*0Sstevel@tonic-gate 	if (options->gss_keyex == -1)
894*0Sstevel@tonic-gate 		options->gss_keyex = 1;
895*0Sstevel@tonic-gate 	if (options->gss_authentication == -1)
896*0Sstevel@tonic-gate 		options->gss_authentication = 1;
897*0Sstevel@tonic-gate 	if (options->gss_deleg_creds == -1)
898*0Sstevel@tonic-gate 		options->gss_deleg_creds = 0;
899*0Sstevel@tonic-gate #ifdef GSI
900*0Sstevel@tonic-gate 	if (options->gss_globus_deleg_limited_proxy == -1)
901*0Sstevel@tonic-gate 		options->gss_globus_deleg_limited_proxy = 0;
902*0Sstevel@tonic-gate #endif /* GSI */
903*0Sstevel@tonic-gate #endif /* GSSAPI */
904*0Sstevel@tonic-gate #if defined(KRB4) || defined(KRB5)
905*0Sstevel@tonic-gate 	if (options->kerberos_authentication == -1)
906*0Sstevel@tonic-gate 		options->kerberos_authentication = 1;
907*0Sstevel@tonic-gate #endif
908*0Sstevel@tonic-gate #if defined(AFS) || defined(KRB5)
909*0Sstevel@tonic-gate 	if (options->kerberos_tgt_passing == -1)
910*0Sstevel@tonic-gate 		options->kerberos_tgt_passing = 1;
911*0Sstevel@tonic-gate #endif
912*0Sstevel@tonic-gate #ifdef AFS
913*0Sstevel@tonic-gate 	if (options->afs_token_passing == -1)
914*0Sstevel@tonic-gate 		options->afs_token_passing = 1;
915*0Sstevel@tonic-gate #endif
916*0Sstevel@tonic-gate 	if (options->password_authentication == -1)
917*0Sstevel@tonic-gate 		options->password_authentication = 1;
918*0Sstevel@tonic-gate 	if (options->kbd_interactive_authentication == -1)
919*0Sstevel@tonic-gate 		options->kbd_interactive_authentication = 1;
920*0Sstevel@tonic-gate 	if (options->rhosts_rsa_authentication == -1)
921*0Sstevel@tonic-gate 		options->rhosts_rsa_authentication = 0;
922*0Sstevel@tonic-gate 	if (options->hostbased_authentication == -1)
923*0Sstevel@tonic-gate 		options->hostbased_authentication = 0;
924*0Sstevel@tonic-gate 	if (options->batch_mode == -1)
925*0Sstevel@tonic-gate 		options->batch_mode = 0;
926*0Sstevel@tonic-gate 	if (options->check_host_ip == -1)
927*0Sstevel@tonic-gate 		options->check_host_ip = 1;
928*0Sstevel@tonic-gate 	if (options->strict_host_key_checking == -1)
929*0Sstevel@tonic-gate 		options->strict_host_key_checking = 2;	/* 2 is default */
930*0Sstevel@tonic-gate 	if (options->compression == -1)
931*0Sstevel@tonic-gate 		options->compression = 0;
932*0Sstevel@tonic-gate 	if (options->keepalives == -1)
933*0Sstevel@tonic-gate 		options->keepalives = 1;
934*0Sstevel@tonic-gate 	if (options->compression_level == -1)
935*0Sstevel@tonic-gate 		options->compression_level = 6;
936*0Sstevel@tonic-gate 	if (options->port == -1)
937*0Sstevel@tonic-gate 		options->port = 0;	/* Filled in ssh_connect. */
938*0Sstevel@tonic-gate 	if (options->connection_attempts == -1)
939*0Sstevel@tonic-gate 		options->connection_attempts = 1;
940*0Sstevel@tonic-gate 	if (options->number_of_password_prompts == -1)
941*0Sstevel@tonic-gate 		options->number_of_password_prompts = 3;
942*0Sstevel@tonic-gate 	/* Selected in ssh_login(). */
943*0Sstevel@tonic-gate 	if (options->cipher == -1)
944*0Sstevel@tonic-gate 		options->cipher = SSH_CIPHER_NOT_SET;
945*0Sstevel@tonic-gate 	/* options->ciphers, default set in myproposals.h */
946*0Sstevel@tonic-gate 	/* options->macs, default set in myproposals.h */
947*0Sstevel@tonic-gate 	/* options->hostkeyalgorithms, default set in myproposals.h */
948*0Sstevel@tonic-gate 	if (options->protocol == SSH_PROTO_UNKNOWN)
949*0Sstevel@tonic-gate 		options->protocol = SSH_PROTO_1|SSH_PROTO_2;
950*0Sstevel@tonic-gate 	if (options->num_identity_files == 0) {
951*0Sstevel@tonic-gate 		if (options->protocol & SSH_PROTO_1) {
952*0Sstevel@tonic-gate 			len = 2 + strlen(_PATH_SSH_CLIENT_IDENTITY) + 1;
953*0Sstevel@tonic-gate 			options->identity_files[options->num_identity_files] =
954*0Sstevel@tonic-gate 			    xmalloc(len);
955*0Sstevel@tonic-gate 			snprintf(options->identity_files[options->num_identity_files++],
956*0Sstevel@tonic-gate 			    len, "~/%.100s", _PATH_SSH_CLIENT_IDENTITY);
957*0Sstevel@tonic-gate 		}
958*0Sstevel@tonic-gate 		if (options->protocol & SSH_PROTO_2) {
959*0Sstevel@tonic-gate 			len = 2 + strlen(_PATH_SSH_CLIENT_ID_RSA) + 1;
960*0Sstevel@tonic-gate 			options->identity_files[options->num_identity_files] =
961*0Sstevel@tonic-gate 			    xmalloc(len);
962*0Sstevel@tonic-gate 			snprintf(options->identity_files[options->num_identity_files++],
963*0Sstevel@tonic-gate 			    len, "~/%.100s", _PATH_SSH_CLIENT_ID_RSA);
964*0Sstevel@tonic-gate 
965*0Sstevel@tonic-gate 			len = 2 + strlen(_PATH_SSH_CLIENT_ID_DSA) + 1;
966*0Sstevel@tonic-gate 			options->identity_files[options->num_identity_files] =
967*0Sstevel@tonic-gate 			    xmalloc(len);
968*0Sstevel@tonic-gate 			snprintf(options->identity_files[options->num_identity_files++],
969*0Sstevel@tonic-gate 			    len, "~/%.100s", _PATH_SSH_CLIENT_ID_DSA);
970*0Sstevel@tonic-gate 		}
971*0Sstevel@tonic-gate 	}
972*0Sstevel@tonic-gate 	if (options->escape_char == -1)
973*0Sstevel@tonic-gate 		options->escape_char = '~';
974*0Sstevel@tonic-gate 	if (options->system_hostfile == NULL)
975*0Sstevel@tonic-gate 		options->system_hostfile = _PATH_SSH_SYSTEM_HOSTFILE;
976*0Sstevel@tonic-gate 	if (options->user_hostfile == NULL)
977*0Sstevel@tonic-gate 		options->user_hostfile = _PATH_SSH_USER_HOSTFILE;
978*0Sstevel@tonic-gate 	if (options->system_hostfile2 == NULL)
979*0Sstevel@tonic-gate 		options->system_hostfile2 = _PATH_SSH_SYSTEM_HOSTFILE2;
980*0Sstevel@tonic-gate 	if (options->user_hostfile2 == NULL)
981*0Sstevel@tonic-gate 		options->user_hostfile2 = _PATH_SSH_USER_HOSTFILE2;
982*0Sstevel@tonic-gate 	if (options->log_level == SYSLOG_LEVEL_NOT_SET)
983*0Sstevel@tonic-gate 		options->log_level = SYSLOG_LEVEL_INFO;
984*0Sstevel@tonic-gate 	if (options->clear_forwardings == 1)
985*0Sstevel@tonic-gate 		clear_forwardings(options);
986*0Sstevel@tonic-gate 	if (options->no_host_authentication_for_localhost == - 1)
987*0Sstevel@tonic-gate 		options->no_host_authentication_for_localhost = 0;
988*0Sstevel@tonic-gate 	if (options->fallback_to_rsh == - 1)
989*0Sstevel@tonic-gate 		options->fallback_to_rsh = 0;
990*0Sstevel@tonic-gate 	if (options->use_rsh == - 1)
991*0Sstevel@tonic-gate 		options->use_rsh = 0;
992*0Sstevel@tonic-gate 	/* options->proxy_command should not be set by default */
993*0Sstevel@tonic-gate 	/* options->user will be set in the main program if appropriate */
994*0Sstevel@tonic-gate 	/* options->hostname will be set in the main program if appropriate */
995*0Sstevel@tonic-gate 	/* options->host_key_alias should not be set by default */
996*0Sstevel@tonic-gate 	/* options->preferred_authentications will be set in ssh */
997*0Sstevel@tonic-gate }
998