xref: /titanic_44/usr/src/cmd/ssh/libssh/common/readconf.c (revision 33c41f2b7f5e60517664bd7f392221865f833526)
1 /*
2  * Author: Tatu Ylonen <ylo@cs.hut.fi>
3  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4  *                    All rights reserved
5  * Functions for reading the configuration files.
6  *
7  * As far as I am concerned, the code I have written for this software
8  * can be used freely for any purpose.  Any derived versions of this
9  * software must be clearly marked as such, and if the derived work is
10  * incompatible with the protocol description in the RFC file, it must be
11  * called by a name other than "ssh" or "Secure Shell".
12  */
13 /*
14  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
15  * Use is subject to license terms.
16  * Copyright 2013 Joyent, Inc.  All rights reserved.
17  */
18 
19 #include "includes.h"
20 RCSID("$OpenBSD: readconf.c,v 1.100 2002/06/19 00:27:55 deraadt Exp $");
21 
22 #include "ssh.h"
23 #include "xmalloc.h"
24 #include "compat.h"
25 #include "cipher.h"
26 #include "pathnames.h"
27 #include "log.h"
28 #include "readconf.h"
29 #include "match.h"
30 #include "misc.h"
31 #include "kex.h"
32 #include "mac.h"
33 
34 /* Format of the configuration file:
35 
36    # Configuration data is parsed as follows:
37    #  1. command line options
38    #  2. user-specific file
39    #  3. system-wide file
40    # Any configuration value is only changed the first time it is set.
41    # Thus, host-specific definitions should be at the beginning of the
42    # configuration file, and defaults at the end.
43 
44    # Host-specific declarations.  These may override anything above.  A single
45    # host may match multiple declarations; these are processed in the order
46    # that they are given in.
47 
48    Host *.ngs.fi ngs.fi
49      User foo
50 
51    Host fake.com
52      HostName another.host.name.real.org
53      User blaah
54      Port 34289
55      ForwardX11 no
56      ForwardAgent no
57 
58    Host books.com
59      RemoteForward 9999 shadows.cs.hut.fi:9999
60      Cipher 3des
61 
62    Host fascist.blob.com
63      Port 23123
64      User tylonen
65      RhostsAuthentication no
66      PasswordAuthentication no
67 
68    Host puukko.hut.fi
69      User t35124p
70      ProxyCommand ssh-proxy %h %p
71 
72    Host *.fr
73      PublicKeyAuthentication no
74 
75    Host *.su
76      Cipher none
77      PasswordAuthentication no
78 
79    # Defaults for various options
80    Host *
81      ForwardAgent no
82      ForwardX11 no
83      RhostsAuthentication yes
84      PasswordAuthentication yes
85      RSAAuthentication yes
86      RhostsRSAAuthentication yes
87      StrictHostKeyChecking yes
88      KeepAlives no
89      IdentityFile ~/.ssh/identity
90      Port 22
91      EscapeChar ~
92 
93 */
94 
95 /* Keyword tokens. */
96 
97 typedef enum {
98 	oBadOption,
99 	oForwardAgent, oForwardX11, oForwardX11Trusted, oGatewayPorts,
100 	oRhostsAuthentication,
101 	oPasswordAuthentication, oRSAAuthentication,
102 	oChallengeResponseAuthentication, oXAuthLocation,
103 #if defined(KRB4) || defined(KRB5)
104 	oKerberosAuthentication,
105 #endif
106 #ifdef GSSAPI
107 	oGssKeyEx, oGssAuthentication, oGssDelegateCreds,
108 #ifdef GSI
109 	oGssGlobusDelegateLimitedCreds,
110 #endif /* GSI */
111 #endif /* GSSAPI */
112 #if defined(AFS) || defined(KRB5)
113 	oKerberosTgtPassing,
114 #endif
115 #ifdef AFS
116 	oAFSTokenPassing,
117 #endif
118 	oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward,
119 	oUser, oHost, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
120 	oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
121 	oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
122 	oCompressionLevel, oKeepAlives, oNumberOfPasswordPrompts,
123 	oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oMacs,
124 	oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication,
125 	oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
126 	oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
127 	oHostKeyAlgorithms, oBindAddress, oSmartcardDevice,
128 	oClearAllForwardings, oNoHostAuthenticationForLocalhost,
129 	oFallBackToRsh, oUseRsh, oConnectTimeout, oHashKnownHosts,
130 	oServerAliveInterval, oServerAliveCountMax, oDisableBanner,
131 	oIgnoreIfUnknown, oRekeyLimit, oUseOpenSSLEngine,
132 	oDeprecated
133 } OpCodes;
134 
135 /* Textual representations of the tokens. */
136 
137 static struct {
138 	const char *name;
139 	OpCodes opcode;
140 } keywords[] = {
141 	{ "forwardagent", oForwardAgent },
142 	{ "forwardx11", oForwardX11 },
143 	{ "forwardx11trusted", oForwardX11Trusted },
144 	{ "xauthlocation", oXAuthLocation },
145 	{ "gatewayports", oGatewayPorts },
146 	{ "useprivilegedport", oUsePrivilegedPort },
147 	{ "rhostsauthentication", oRhostsAuthentication },
148 	{ "passwordauthentication", oPasswordAuthentication },
149 	{ "kbdinteractiveauthentication", oKbdInteractiveAuthentication },
150 	{ "kbdinteractivedevices", oKbdInteractiveDevices },
151 	{ "rsaauthentication", oRSAAuthentication },
152 	{ "pubkeyauthentication", oPubkeyAuthentication },
153 	{ "dsaauthentication", oPubkeyAuthentication },		    /* alias */
154 	{ "rhostsrsaauthentication", oRhostsRSAAuthentication },
155 	{ "hostbasedauthentication", oHostbasedAuthentication },
156 	{ "challengeresponseauthentication", oChallengeResponseAuthentication },
157 	{ "skeyauthentication", oChallengeResponseAuthentication }, /* alias */
158 	{ "tisauthentication", oChallengeResponseAuthentication },  /* alias */
159 #if defined(KRB4) || defined(KRB5)
160 	{ "kerberosauthentication", oKerberosAuthentication },
161 #endif
162 #ifdef GSSAPI
163 	{ "gssapikeyexchange", oGssKeyEx },
164 	{ "gssapiauthentication", oGssAuthentication },
165 	{ "gssapidelegatecredentials", oGssDelegateCreds },
166 	{ "gsskeyex", oGssKeyEx },				/* alias */
167 	{ "gssauthentication", oGssAuthentication },		/* alias */
168 	{ "gssdelegatecreds", oGssDelegateCreds },		/* alias */
169 #ifdef GSI
170 	/* For backwards compatability with old 1.2.27 client code */
171 	{ "forwardgssapiglobusproxy", oGssDelegateCreds }, /* alias */
172 	{ "forwardgssapiglobuslimitedproxy", oGssGlobusDelegateLimitedCreds },
173 #endif /* GSI */
174 #endif /* GSSAPI */
175 #if defined(AFS) || defined(KRB5)
176 	{ "kerberostgtpassing", oKerberosTgtPassing },
177 #endif
178 #ifdef AFS
179 	{ "afstokenpassing", oAFSTokenPassing },
180 #endif
181 	{ "fallbacktorsh", oFallBackToRsh },
182 	{ "usersh", oUseRsh },
183 	{ "identityfile", oIdentityFile },
184 	{ "identityfile2", oIdentityFile },			/* alias */
185 	{ "hostname", oHostName },
186 	{ "hostkeyalias", oHostKeyAlias },
187 	{ "proxycommand", oProxyCommand },
188 	{ "port", oPort },
189 	{ "cipher", oCipher },
190 	{ "ciphers", oCiphers },
191 	{ "macs", oMacs },
192 	{ "protocol", oProtocol },
193 	{ "remoteforward", oRemoteForward },
194 	{ "localforward", oLocalForward },
195 	{ "user", oUser },
196 	{ "host", oHost },
197 	{ "escapechar", oEscapeChar },
198 	{ "globalknownhostsfile", oGlobalKnownHostsFile },
199 	{ "userknownhostsfile", oUserKnownHostsFile },		/* obsolete */
200 	{ "globalknownhostsfile2", oGlobalKnownHostsFile2 },
201 	{ "userknownhostsfile2", oUserKnownHostsFile2 },	/* obsolete */
202 	{ "connectionattempts", oConnectionAttempts },
203 	{ "batchmode", oBatchMode },
204 	{ "checkhostip", oCheckHostIP },
205 	{ "stricthostkeychecking", oStrictHostKeyChecking },
206 	{ "compression", oCompression },
207 	{ "compressionlevel", oCompressionLevel },
208 	{ "tcpkeepalive", oKeepAlives },
209 	{ "keepalive", oKeepAlives },				/* obsolete */
210 	{ "numberofpasswordprompts", oNumberOfPasswordPrompts },
211 	{ "loglevel", oLogLevel },
212 	{ "dynamicforward", oDynamicForward },
213 	{ "preferredauthentications", oPreferredAuthentications },
214 	{ "hostkeyalgorithms", oHostKeyAlgorithms },
215 	{ "bindaddress", oBindAddress },
216 	{ "smartcarddevice", oSmartcardDevice },
217 	{ "clearallforwardings", oClearAllForwardings },
218 	{ "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
219 	{ "rekeylimit", oRekeyLimit },
220 	{ "connecttimeout", oConnectTimeout },
221 	{ "serveraliveinterval", oServerAliveInterval },
222 	{ "serveralivecountmax", oServerAliveCountMax },
223 	{ "disablebanner", oDisableBanner },
224 	{ "hashknownhosts", oHashKnownHosts },
225 	{ "ignoreifunknown", oIgnoreIfUnknown },
226 	{ "useopensslengine", oUseOpenSSLEngine },
227 	{ NULL, oBadOption }
228 };
229 
230 /*
231  * Adds a local TCP/IP port forward to options.  Never returns if there is an
232  * error.
233  */
234 
235 void
add_local_forward(Options * options,const Forward * newfwd)236 add_local_forward(Options *options, const Forward *newfwd)
237 {
238 	Forward *fwd;
239 #ifndef NO_IPPORT_RESERVED_CONCEPT
240 	extern uid_t original_real_uid;
241 	if (newfwd->listen_port < IPPORT_RESERVED && original_real_uid != 0)
242 		fatal("Privileged ports can only be forwarded by root.");
243 #endif
244 	if (options->num_local_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
245 		fatal("Too many local forwards (max %d).", SSH_MAX_FORWARDS_PER_DIRECTION);
246 	fwd = &options->local_forwards[options->num_local_forwards++];
247 
248 	fwd->listen_host = (newfwd->listen_host == NULL) ?
249 	    NULL : xstrdup(newfwd->listen_host);
250 	fwd->listen_port = newfwd->listen_port;
251 	fwd->connect_host = xstrdup(newfwd->connect_host);
252 	fwd->connect_port = newfwd->connect_port;
253 }
254 
255 /*
256  * Adds a remote TCP/IP port forward to options.  Never returns if there is
257  * an error.
258  */
259 
260 void
add_remote_forward(Options * options,const Forward * newfwd)261 add_remote_forward(Options *options, const Forward *newfwd)
262 {
263 	Forward *fwd;
264 	if (options->num_remote_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
265 		fatal("Too many remote forwards (max %d).",
266 		    SSH_MAX_FORWARDS_PER_DIRECTION);
267 	fwd = &options->remote_forwards[options->num_remote_forwards++];
268 
269 	fwd->listen_host = (newfwd->listen_host == NULL) ?
270 	    NULL : xstrdup(newfwd->listen_host);
271 	fwd->listen_port = newfwd->listen_port;
272 	fwd->connect_host = xstrdup(newfwd->connect_host);
273 	fwd->connect_port = newfwd->connect_port;
274 }
275 
276 static void
clear_forwardings(Options * options)277 clear_forwardings(Options *options)
278 {
279 	int i;
280 
281 	for (i = 0; i < options->num_local_forwards; i++) {
282 		if (options->local_forwards[i].listen_host != NULL)
283 			xfree(options->local_forwards[i].listen_host);
284 		xfree(options->local_forwards[i].connect_host);
285 	}
286 	options->num_local_forwards = 0;
287 	for (i = 0; i < options->num_remote_forwards; i++) {
288 		if (options->remote_forwards[i].listen_host != NULL)
289 			xfree(options->remote_forwards[i].listen_host);
290 		xfree(options->remote_forwards[i].connect_host);
291 	}
292 	options->num_remote_forwards = 0;
293 }
294 
295 /*
296  * Returns the number of the token pointed to by cp or oBadOption.
297  */
298 
299 static OpCodes
parse_token(const char * cp,const char * filename,int linenum)300 parse_token(const char *cp, const char *filename, int linenum)
301 {
302 	u_int i;
303 
304 	for (i = 0; keywords[i].name; i++)
305 		if (strcasecmp(cp, keywords[i].name) == 0)
306 			return keywords[i].opcode;
307 
308 	debug("%s: line %d: unknown configuration option: %s",
309 	    filename, linenum, cp);
310 	return oBadOption;
311 }
312 
313 /*
314  * Processes a single option line as used in the configuration files. This
315  * only sets those values that have not already been set.
316  */
317 
318 int
process_config_line(Options * options,const char * host,char * line,const char * filename,int linenum,int * activep)319 process_config_line(Options *options, const char *host,
320 		    char *line, const char *filename, int linenum,
321 		    int *activep)
322 {
323 	char *s, *string, **charptr, *endofnumber, *keyword, *arg, *arg2, fwdarg[256];
324 	int opcode, *intptr, value, scale, i;
325 	long long orig, val64;
326 	StoredOption *so;
327 	Forward fwd;
328 
329 	s = line;
330 	/* Get the keyword. (Each line is supposed to begin with a keyword). */
331 	keyword = strdelim(&s);
332 	/* Ignore leading whitespace. */
333 	if (*keyword == '\0')
334 		keyword = strdelim(&s);
335 	if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#')
336 		return 0;
337 
338 	opcode = parse_token(keyword, filename, linenum);
339 
340 	switch (opcode) {
341 	case oBadOption:
342 		if (options->unknown_opts_num == MAX_UNKNOWN_OPTIONS) {
343 			error("we can't have more than %d unknown options:",
344 			    MAX_UNKNOWN_OPTIONS);
345 			for (i = 0; i < MAX_UNKNOWN_OPTIONS; ++i) {
346 				so = &options->unknown_opts[i];
347 				error("%s:%d:%s",
348 				    so->filename, so->linenum, so->keyword);
349 				xfree(so->keyword);
350 				xfree(so->filename);
351 			}
352 			fatal("too many unknown options found, can't continue");
353 		}
354 
355 		/* unknown options will be processed later */
356 		so = &options->unknown_opts[options->unknown_opts_num];
357 		so->keyword = xstrdup(keyword);
358 		so->filename = xstrdup(filename);
359 		so->linenum = linenum;
360 		options->unknown_opts_num++;
361 		return (0);
362 
363 		/* NOTREACHED */
364 	case oConnectTimeout:
365 		intptr = &options->connection_timeout;
366 parse_time:
367 		arg = strdelim(&s);
368 		if (!arg || *arg == '\0')
369 			fatal("%s line %d: missing time value.",
370 			    filename, linenum);
371 		if ((value = convtime(arg)) == -1)
372 			fatal("%s line %d: invalid time value.",
373 			    filename, linenum);
374 		if (*activep && *intptr == -1)
375 			*intptr = value;
376 		break;
377 
378 	case oForwardAgent:
379 		intptr = &options->forward_agent;
380 parse_flag:
381 		arg = strdelim(&s);
382 		if (!arg || *arg == '\0')
383 			fatal("%.200s line %d: Missing yes/no argument.", filename, linenum);
384 		value = 0;	/* To avoid compiler warning... */
385 		if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
386 			value = 1;
387 		else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
388 			value = 0;
389 		else
390 			fatal("%.200s line %d: Bad yes/no argument.", filename, linenum);
391 		if (*activep && *intptr == -1)
392 			*intptr = value;
393 		break;
394 
395 	case oForwardX11:
396 		intptr = &options->forward_x11;
397 		goto parse_flag;
398 
399 	case oForwardX11Trusted:
400 		intptr = &options->forward_x11_trusted;
401 		goto parse_flag;
402 
403 	case oGatewayPorts:
404 		intptr = &options->gateway_ports;
405 		goto parse_flag;
406 
407 	case oUsePrivilegedPort:
408 		intptr = &options->use_privileged_port;
409 		goto parse_flag;
410 
411 	case oRhostsAuthentication:
412 		intptr = &options->rhosts_authentication;
413 		goto parse_flag;
414 
415 	case oPasswordAuthentication:
416 		intptr = &options->password_authentication;
417 		goto parse_flag;
418 
419 	case oKbdInteractiveAuthentication:
420 		intptr = &options->kbd_interactive_authentication;
421 		goto parse_flag;
422 
423 	case oKbdInteractiveDevices:
424 		charptr = &options->kbd_interactive_devices;
425 		goto parse_string;
426 
427 	case oPubkeyAuthentication:
428 		intptr = &options->pubkey_authentication;
429 		goto parse_flag;
430 
431 	case oRSAAuthentication:
432 		intptr = &options->rsa_authentication;
433 		goto parse_flag;
434 
435 	case oRhostsRSAAuthentication:
436 		intptr = &options->rhosts_rsa_authentication;
437 		goto parse_flag;
438 
439 	case oHostbasedAuthentication:
440 		intptr = &options->hostbased_authentication;
441 		goto parse_flag;
442 
443 	case oChallengeResponseAuthentication:
444 		intptr = &options->challenge_response_authentication;
445 		goto parse_flag;
446 #if defined(KRB4) || defined(KRB5)
447 	case oKerberosAuthentication:
448 		intptr = &options->kerberos_authentication;
449 		goto parse_flag;
450 #endif
451 #ifdef GSSAPI
452 	case oGssKeyEx:
453 		intptr = &options->gss_keyex;
454 		goto parse_flag;
455 
456 	case oGssAuthentication:
457 		intptr = &options->gss_authentication;
458 		goto parse_flag;
459 
460 	case oGssDelegateCreds:
461 		intptr = &options->gss_deleg_creds;
462 		goto parse_flag;
463 
464 #ifdef GSI
465 	case oGssGlobusDelegateLimitedCreds:
466 		intptr = &options->gss_globus_deleg_limited_proxy;
467 		goto parse_flag;
468 #endif /* GSI */
469 
470 #endif /* GSSAPI */
471 
472 #if defined(AFS) || defined(KRB5)
473 	case oKerberosTgtPassing:
474 		intptr = &options->kerberos_tgt_passing;
475 		goto parse_flag;
476 #endif
477 #ifdef AFS
478 	case oAFSTokenPassing:
479 		intptr = &options->afs_token_passing;
480 		goto parse_flag;
481 #endif
482 	case oFallBackToRsh:
483 		intptr = &options->fallback_to_rsh;
484 		goto parse_flag;
485 
486 	case oUseRsh:
487 		intptr = &options->use_rsh;
488 		goto parse_flag;
489 
490 	case oBatchMode:
491 		intptr = &options->batch_mode;
492 		goto parse_flag;
493 
494 	case oCheckHostIP:
495 		intptr = &options->check_host_ip;
496 		goto parse_flag;
497 
498 	case oStrictHostKeyChecking:
499 		intptr = &options->strict_host_key_checking;
500 		arg = strdelim(&s);
501 		if (!arg || *arg == '\0')
502 			fatal("%.200s line %d: Missing yes/no/ask argument.",
503 			    filename, linenum);
504 		value = 0;	/* To avoid compiler warning... */
505 		if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
506 			value = 1;
507 		else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
508 			value = 0;
509 		else if (strcmp(arg, "ask") == 0)
510 			value = 2;
511 		else
512 			fatal("%.200s line %d: Bad yes/no/ask argument.", filename, linenum);
513 		if (*activep && *intptr == -1)
514 			*intptr = value;
515 		break;
516 
517 	case oCompression:
518 		intptr = &options->compression;
519 		goto parse_flag;
520 
521 	case oKeepAlives:
522 		intptr = &options->keepalives;
523 		goto parse_flag;
524 
525 	case oNoHostAuthenticationForLocalhost:
526 		intptr = &options->no_host_authentication_for_localhost;
527 		goto parse_flag;
528 
529 	case oNumberOfPasswordPrompts:
530 		intptr = &options->number_of_password_prompts;
531 		goto parse_int;
532 
533 	case oCompressionLevel:
534 		intptr = &options->compression_level;
535 		goto parse_int;
536 
537 	case oRekeyLimit:
538 		arg = strdelim(&s);
539 		if (!arg || *arg == '\0')
540 			fatal("%.200s line %d: Missing argument.", filename, linenum);
541 		if (arg[0] < '0' || arg[0] > '9')
542 			fatal("%.200s line %d: Bad number.", filename, linenum);
543 		orig = val64 = strtoll(arg, &endofnumber, 10);
544 		if (arg == endofnumber)
545 			fatal("%.200s line %d: Bad number.", filename, linenum);
546 		switch (toupper(*endofnumber)) {
547 		case '\0':
548 			scale = 1;
549 			break;
550 		case 'K':
551 			scale = 1<<10;
552 			break;
553 		case 'M':
554 			scale = 1<<20;
555 			break;
556 		case 'G':
557 			scale = 1<<30;
558 			break;
559 		default:
560 			fatal("%.200s line %d: Invalid RekeyLimit suffix",
561 			    filename, linenum);
562 		}
563 		val64 *= scale;
564 		/* detect integer wrap and too-large limits */
565 		if ((val64 / scale) != orig || val64 > UINT_MAX)
566 			fatal("%.200s line %d: RekeyLimit too large",
567 			    filename, linenum);
568 		if (val64 < 16)
569 			fatal("%.200s line %d: RekeyLimit too small",
570 			    filename, linenum);
571 		if (*activep && options->rekey_limit == -1)
572 			options->rekey_limit = (u_int32_t)val64;
573 		break;
574 
575 	case oIdentityFile:
576 		arg = strdelim(&s);
577 		if (!arg || *arg == '\0')
578 			fatal("%.200s line %d: Missing argument.", filename, linenum);
579 		if (*activep) {
580 			intptr = &options->num_identity_files;
581 			if (*intptr >= SSH_MAX_IDENTITY_FILES)
582 				fatal("%.200s line %d: Too many identity files specified (max %d).",
583 				    filename, linenum, SSH_MAX_IDENTITY_FILES);
584 			charptr =  &options->identity_files[*intptr];
585 			*charptr = xstrdup(arg);
586 			*intptr = *intptr + 1;
587 		}
588 		break;
589 
590 	case oXAuthLocation:
591 		charptr=&options->xauth_location;
592 		goto parse_string;
593 
594 	case oUser:
595 		charptr = &options->user;
596 parse_string:
597 		arg = strdelim(&s);
598 		if (!arg || *arg == '\0')
599 			fatal("%.200s line %d: Missing argument.", filename, linenum);
600 		if (*activep && *charptr == NULL)
601 			*charptr = xstrdup(arg);
602 		break;
603 
604 	case oGlobalKnownHostsFile:
605 		charptr = &options->system_hostfile;
606 		goto parse_string;
607 
608 	case oUserKnownHostsFile:
609 		charptr = &options->user_hostfile;
610 		goto parse_string;
611 
612 	case oGlobalKnownHostsFile2:
613 		charptr = &options->system_hostfile2;
614 		goto parse_string;
615 
616 	case oUserKnownHostsFile2:
617 		charptr = &options->user_hostfile2;
618 		goto parse_string;
619 
620 	case oHostName:
621 		charptr = &options->hostname;
622 		goto parse_string;
623 
624 	case oHostKeyAlias:
625 		charptr = &options->host_key_alias;
626 		goto parse_string;
627 
628 	case oPreferredAuthentications:
629 		charptr = &options->preferred_authentications;
630 		goto parse_string;
631 
632 	case oBindAddress:
633 		charptr = &options->bind_address;
634 		goto parse_string;
635 
636 	case oSmartcardDevice:
637 		charptr = &options->smartcard_device;
638 		goto parse_string;
639 
640 	case oProxyCommand:
641 		charptr = &options->proxy_command;
642 		string = xstrdup("");
643 		while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
644 			string = xrealloc(string, strlen(string) + strlen(arg) + 2);
645 			strcat(string, " ");
646 			strcat(string, arg);
647 		}
648 		if (*activep && *charptr == NULL)
649 			*charptr = string;
650 		else
651 			xfree(string);
652 		return 0;
653 
654 	case oPort:
655 		intptr = &options->port;
656 parse_int:
657 		arg = strdelim(&s);
658 		if (!arg || *arg == '\0')
659 			fatal("%.200s line %d: Missing argument.", filename, linenum);
660 		if (arg[0] < '0' || arg[0] > '9')
661 			fatal("%.200s line %d: Bad number.", filename, linenum);
662 
663 		/* Octal, decimal, or hex format? */
664 		value = strtol(arg, &endofnumber, 0);
665 		if (arg == endofnumber)
666 			fatal("%.200s line %d: Bad number.", filename, linenum);
667 		if (*activep && *intptr == -1)
668 			*intptr = value;
669 		break;
670 
671 	case oConnectionAttempts:
672 		intptr = &options->connection_attempts;
673 		goto parse_int;
674 
675 	case oCipher:
676 		intptr = &options->cipher;
677 		arg = strdelim(&s);
678 		if (!arg || *arg == '\0')
679 			fatal("%.200s line %d: Missing argument.", filename, linenum);
680 		value = cipher_number(arg);
681 		if (value == -1)
682 			fatal("%.200s line %d: Bad cipher '%s'.",
683 			    filename, linenum, arg ? arg : "<NONE>");
684 		if (*activep && *intptr == -1)
685 			*intptr = value;
686 		break;
687 
688 	case oCiphers:
689 		arg = strdelim(&s);
690 		if (!arg || *arg == '\0')
691 			fatal("%.200s line %d: Missing argument.", filename, linenum);
692 		if (!ciphers_valid(arg))
693 			fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.",
694 			    filename, linenum, arg ? arg : "<NONE>");
695 		if (*activep && options->ciphers == NULL)
696 			options->ciphers = xstrdup(arg);
697 		break;
698 
699 	case oMacs:
700 		arg = strdelim(&s);
701 		if (!arg || *arg == '\0')
702 			fatal("%.200s line %d: Missing argument.", filename, linenum);
703 		if (!mac_valid(arg))
704 			fatal("%.200s line %d: Bad SSH2 Mac spec '%s'.",
705 			    filename, linenum, arg ? arg : "<NONE>");
706 		if (*activep && options->macs == NULL)
707 			options->macs = xstrdup(arg);
708 		break;
709 
710 	case oHostKeyAlgorithms:
711 		arg = strdelim(&s);
712 		if (!arg || *arg == '\0')
713 			fatal("%.200s line %d: Missing argument.", filename, linenum);
714 		if (!key_names_valid2(arg))
715 			fatal("%.200s line %d: Bad protocol 2 host key algorithms '%s'.",
716 			    filename, linenum, arg ? arg : "<NONE>");
717 		if (*activep && options->hostkeyalgorithms == NULL)
718 			options->hostkeyalgorithms = xstrdup(arg);
719 		break;
720 
721 	case oProtocol:
722 		intptr = &options->protocol;
723 		arg = strdelim(&s);
724 		if (!arg || *arg == '\0')
725 			fatal("%.200s line %d: Missing argument.", filename, linenum);
726 		value = proto_spec(arg);
727 		if (value == SSH_PROTO_UNKNOWN)
728 			fatal("%.200s line %d: Bad protocol spec '%s'.",
729 			    filename, linenum, arg ? arg : "<NONE>");
730 		if (*activep && *intptr == SSH_PROTO_UNKNOWN)
731 			*intptr = value;
732 		break;
733 
734 	case oLogLevel:
735 		intptr = (int *) &options->log_level;
736 		arg = strdelim(&s);
737 		value = log_level_number(arg);
738 		if (value == SYSLOG_LEVEL_NOT_SET)
739 			fatal("%.200s line %d: unsupported log level '%s'",
740 			    filename, linenum, arg ? arg : "<NONE>");
741 		if (*activep && (LogLevel) *intptr == SYSLOG_LEVEL_NOT_SET)
742 			*intptr = (LogLevel) value;
743 		break;
744 
745 	case oLocalForward:
746 	case oRemoteForward:
747 		arg = strdelim(&s);
748 		if (arg == NULL || *arg == '\0')
749 			fatal("%.200s line %d: Missing port argument.",
750 			    filename, linenum);
751 		arg2 = strdelim(&s);
752 		if (arg2 == NULL || *arg2 == '\0')
753 			fatal("%.200s line %d: Missing target argument.",
754 			    filename, linenum);
755 
756 		/* construct a string for parse_forward */
757 		snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg, arg2);
758 
759 		if (parse_forward(1, &fwd, fwdarg) == 0)
760 			fatal("%.200s line %d: Bad forwarding specification.",
761 			    filename, linenum);
762 
763 		if (*activep) {
764 			if (opcode == oLocalForward)
765 				add_local_forward(options, &fwd);
766 			else if (opcode == oRemoteForward)
767 				add_remote_forward(options, &fwd);
768 		}
769 		break;
770 
771 	case oDynamicForward:
772 		arg = strdelim(&s);
773 		if (!arg || *arg == '\0')
774 			fatal("%.200s line %d: Missing port argument.",
775 			    filename, linenum);
776 
777 		if (parse_forward(0, &fwd, arg) == 0) {
778 			fatal("%.200s line %d: Bad dynamic forwarding specification.",
779 			    filename, linenum);
780 		}
781 
782 		if (*activep) {
783 			fwd.connect_host = "socks";
784 			add_local_forward(options, &fwd);
785 		}
786 		break;
787 
788 	case oClearAllForwardings:
789 		intptr = &options->clear_forwardings;
790 		goto parse_flag;
791 
792 	case oHost:
793 		*activep = 0;
794 		while ((arg = strdelim(&s)) != NULL && *arg != '\0')
795 			if (match_pattern(host, arg)) {
796 				debug("Applying options for %.100s", arg);
797 				*activep = 1;
798 				break;
799 			}
800 		/* Avoid garbage check below, as strdelim is done. */
801 		return 0;
802 
803 	case oEscapeChar:
804 		intptr = &options->escape_char;
805 		arg = strdelim(&s);
806 		if (!arg || *arg == '\0')
807 			fatal("%.200s line %d: Missing argument.", filename, linenum);
808 		if (arg[0] == '^' && arg[2] == 0 &&
809 		    (u_char) arg[1] >= 64 && (u_char) arg[1] < 128)
810 			value = (u_char) arg[1] & 31;
811 		else if (strlen(arg) == 1)
812 			value = (u_char) arg[0];
813 		else if (strcmp(arg, "none") == 0)
814 			value = SSH_ESCAPECHAR_NONE;
815 		else {
816 			fatal("%.200s line %d: Bad escape character.",
817 			    filename, linenum);
818 			/* NOTREACHED */
819 			value = 0;	/* Avoid compiler warning. */
820 		}
821 		if (*activep && *intptr == -1)
822 			*intptr = value;
823 		break;
824 
825 	case oServerAliveInterval:
826 		intptr = &options->server_alive_interval;
827 		goto parse_time;
828 
829 	case oServerAliveCountMax:
830 		intptr = &options->server_alive_count_max;
831 		goto parse_int;
832 
833 	case oHashKnownHosts:
834 		intptr = &options->hash_known_hosts;
835 		goto parse_flag;
836 
837 	case oDisableBanner:
838 		arg = strdelim(&s);
839 		if (get_yes_no_flag(&options->disable_banner, arg, filename,
840 		    linenum, *activep) == 1)
841 			break;
842 
843 		if (strcmp(arg, "in-exec-mode") == 0)
844 			options->disable_banner = SSH_NO_BANNER_IN_EXEC_MODE;
845 		else
846 			fatal("%.200s line %d: Bad yes/no/in-exec-mode "
847 			    "argument.", filename, linenum);
848 		break;
849 
850 	case oIgnoreIfUnknown:
851 		charptr = &options->ignore_if_unknown;
852 		goto parse_string;
853 
854 	case oUseOpenSSLEngine:
855 		intptr = &options->use_openssl_engine;
856 		goto parse_flag;
857 
858 	case oDeprecated:
859 		debug("%s line %d: Deprecated option \"%s\"",
860 		    filename, linenum, keyword);
861 		return 0;
862 
863 	default:
864 		fatal("process_config_line: Unimplemented opcode %d", opcode);
865 	}
866 
867 	/* Check that there is no garbage at end of line. */
868 	if ((arg = strdelim(&s)) != NULL && *arg != '\0') {
869 		fatal("%.200s line %d: garbage at end of line; \"%.200s\".",
870 		     filename, linenum, arg);
871 	}
872 	return 0;
873 }
874 
875 
876 /*
877  * Reads the config file and modifies the options accordingly.  Options
878  * should already be initialized before this call.  This never returns if
879  * there is an error.  If the file does not exist, this returns 0.
880  */
881 
882 int
read_config_file(const char * filename,const char * host,Options * options)883 read_config_file(const char *filename, const char *host, Options *options)
884 {
885 	FILE *f;
886 	char line[1024];
887 	int active, linenum;
888 
889 	/* Open the file. */
890 	f = fopen(filename, "r");
891 	if (!f)
892 		return 0;
893 
894 	debug("Reading configuration data %.200s", filename);
895 
896 	/*
897 	 * Mark that we are now processing the options.  This flag is turned
898 	 * on/off by Host specifications.
899 	 */
900 	active = 1;
901 	linenum = 0;
902 	while (fgets(line, sizeof(line), f)) {
903 		/* Update line number counter. */
904 		linenum++;
905 		process_config_line(options, host, line, filename, linenum, &active);
906 	}
907 	fclose(f);
908 	return 1;
909 }
910 
911 /*
912  * Initializes options to special values that indicate that they have not yet
913  * been set.  Read_config_file will only set options with this value. Options
914  * are processed in the following order: command line, user config file,
915  * system config file.  Last, fill_default_options is called.
916  */
917 
918 void
initialize_options(Options * options)919 initialize_options(Options * options)
920 {
921 	memset(options, 'X', sizeof(*options));
922 	options->forward_agent = -1;
923 	options->forward_x11 = -1;
924 	options->forward_x11_trusted = -1;
925 	options->xauth_location = NULL;
926 	options->gateway_ports = -1;
927 	options->use_privileged_port = -1;
928 	options->rhosts_authentication = -1;
929 	options->rsa_authentication = -1;
930 	options->pubkey_authentication = -1;
931 	options->challenge_response_authentication = -1;
932 #ifdef GSSAPI
933         options->gss_keyex = -1;
934         options->gss_authentication = -1;
935         options->gss_deleg_creds = -1;
936 #ifdef GSI
937         options->gss_globus_deleg_limited_proxy = -1;
938 #endif /* GSI */
939 #endif /* GSSAPI */
940 
941 #if defined(KRB4) || defined(KRB5)
942 	options->kerberos_authentication = -1;
943 #endif
944 #if defined(AFS) || defined(KRB5)
945 	options->kerberos_tgt_passing = -1;
946 #endif
947 #ifdef AFS
948 	options->afs_token_passing = -1;
949 #endif
950 	options->password_authentication = -1;
951 	options->kbd_interactive_authentication = -1;
952 	options->kbd_interactive_devices = NULL;
953 	options->rhosts_rsa_authentication = -1;
954 	options->hostbased_authentication = -1;
955 	options->batch_mode = -1;
956 	options->check_host_ip = -1;
957 	options->strict_host_key_checking = -1;
958 	options->compression = -1;
959 	options->keepalives = -1;
960 	options->compression_level = -1;
961 	options->port = -1;
962 	options->connection_attempts = -1;
963 	options->connection_timeout = -1;
964 	options->number_of_password_prompts = -1;
965 	options->cipher = -1;
966 	options->ciphers = NULL;
967 	options->macs = NULL;
968 	options->hostkeyalgorithms = NULL;
969 	options->protocol = SSH_PROTO_UNKNOWN;
970 	options->num_identity_files = 0;
971 	options->hostname = NULL;
972 	options->host_key_alias = NULL;
973 	options->proxy_command = NULL;
974 	options->user = NULL;
975 	options->escape_char = -1;
976 	options->system_hostfile = NULL;
977 	options->user_hostfile = NULL;
978 	options->system_hostfile2 = NULL;
979 	options->user_hostfile2 = NULL;
980 	options->num_local_forwards = 0;
981 	options->num_remote_forwards = 0;
982 	options->clear_forwardings = -1;
983 	options->log_level = SYSLOG_LEVEL_NOT_SET;
984 	options->preferred_authentications = NULL;
985 	options->bind_address = NULL;
986 	options->smartcard_device = NULL;
987 	options->no_host_authentication_for_localhost = -1;
988 	options->rekey_limit = -1;
989 	options->fallback_to_rsh = -1;
990 	options->use_rsh = -1;
991 	options->server_alive_interval = -1;
992 	options->server_alive_count_max = -1;
993 	options->hash_known_hosts = -1;
994 	options->ignore_if_unknown = NULL;
995 	options->unknown_opts_num = 0;
996 	options->disable_banner = -1;
997 	options->use_openssl_engine = -1;
998 }
999 
1000 /*
1001  * Called after processing other sources of option data, this fills those
1002  * options for which no value has been specified with their default values.
1003  */
1004 
1005 void
fill_default_options(Options * options)1006 fill_default_options(Options * options)
1007 {
1008 	int len;
1009 
1010 	if (options->forward_agent == -1)
1011 		options->forward_agent = 0;
1012 	if (options->forward_x11 == -1)
1013 		options->forward_x11 = 0;
1014 	/*
1015 	 * Unlike OpenSSH, we keep backward compatibility for '-X' option
1016 	 * which means that X11 forwarding is trusted by default.
1017 	 */
1018 	if (options->forward_x11_trusted == -1)
1019 		options->forward_x11_trusted = 1;
1020 	if (options->xauth_location == NULL)
1021 		options->xauth_location = _PATH_XAUTH;
1022 	if (options->gateway_ports == -1)
1023 		options->gateway_ports = 0;
1024 	if (options->use_privileged_port == -1)
1025 		options->use_privileged_port = 0;
1026 	if (options->rhosts_authentication == -1)
1027 		options->rhosts_authentication = 0;
1028 	if (options->rsa_authentication == -1)
1029 		options->rsa_authentication = 1;
1030 	if (options->pubkey_authentication == -1)
1031 		options->pubkey_authentication = 1;
1032 	if (options->challenge_response_authentication == -1)
1033 		options->challenge_response_authentication = 1;
1034 #ifdef GSSAPI
1035 	if (options->gss_keyex == -1)
1036 		options->gss_keyex = 1;
1037 	if (options->gss_authentication == -1)
1038 		options->gss_authentication = 1;
1039 	if (options->gss_deleg_creds == -1)
1040 		options->gss_deleg_creds = 0;
1041 #ifdef GSI
1042 	if (options->gss_globus_deleg_limited_proxy == -1)
1043 		options->gss_globus_deleg_limited_proxy = 0;
1044 #endif /* GSI */
1045 #endif /* GSSAPI */
1046 #if defined(KRB4) || defined(KRB5)
1047 	if (options->kerberos_authentication == -1)
1048 		options->kerberos_authentication = 1;
1049 #endif
1050 #if defined(AFS) || defined(KRB5)
1051 	if (options->kerberos_tgt_passing == -1)
1052 		options->kerberos_tgt_passing = 1;
1053 #endif
1054 #ifdef AFS
1055 	if (options->afs_token_passing == -1)
1056 		options->afs_token_passing = 1;
1057 #endif
1058 	if (options->password_authentication == -1)
1059 		options->password_authentication = 1;
1060 	if (options->kbd_interactive_authentication == -1)
1061 		options->kbd_interactive_authentication = 1;
1062 	if (options->rhosts_rsa_authentication == -1)
1063 		options->rhosts_rsa_authentication = 0;
1064 	if (options->hostbased_authentication == -1)
1065 		options->hostbased_authentication = 0;
1066 	if (options->batch_mode == -1)
1067 		options->batch_mode = 0;
1068 	if (options->check_host_ip == -1)
1069 		options->check_host_ip = 1;
1070 	if (options->strict_host_key_checking == -1)
1071 		options->strict_host_key_checking = 2;	/* 2 is default */
1072 	if (options->compression == -1)
1073 		options->compression = 0;
1074 	if (options->keepalives == -1)
1075 		options->keepalives = 1;
1076 	if (options->compression_level == -1)
1077 		options->compression_level = 6;
1078 	if (options->port == -1)
1079 		options->port = 0;	/* Filled in ssh_connect. */
1080 	if (options->connection_attempts == -1)
1081 		options->connection_attempts = 1;
1082 	if (options->number_of_password_prompts == -1)
1083 		options->number_of_password_prompts = 3;
1084 	/* Selected in ssh_login(). */
1085 	if (options->cipher == -1)
1086 		options->cipher = SSH_CIPHER_NOT_SET;
1087 	/* options->ciphers, default set in myproposals.h */
1088 	/* options->macs, default set in myproposals.h */
1089 	/* options->hostkeyalgorithms, default set in myproposals.h */
1090 	if (options->protocol == SSH_PROTO_UNKNOWN)
1091 		options->protocol = SSH_PROTO_1|SSH_PROTO_2;
1092 	if (options->num_identity_files == 0) {
1093 		if (options->protocol & SSH_PROTO_1) {
1094 			len = 2 + strlen(_PATH_SSH_CLIENT_IDENTITY) + 1;
1095 			options->identity_files[options->num_identity_files] =
1096 			    xmalloc(len);
1097 			snprintf(options->identity_files[options->num_identity_files++],
1098 			    len, "~/%.100s", _PATH_SSH_CLIENT_IDENTITY);
1099 		}
1100 		if (options->protocol & SSH_PROTO_2) {
1101 			len = 2 + strlen(_PATH_SSH_CLIENT_ID_RSA) + 1;
1102 			options->identity_files[options->num_identity_files] =
1103 			    xmalloc(len);
1104 			snprintf(options->identity_files[options->num_identity_files++],
1105 			    len, "~/%.100s", _PATH_SSH_CLIENT_ID_RSA);
1106 
1107 			len = 2 + strlen(_PATH_SSH_CLIENT_ID_DSA) + 1;
1108 			options->identity_files[options->num_identity_files] =
1109 			    xmalloc(len);
1110 			snprintf(options->identity_files[options->num_identity_files++],
1111 			    len, "~/%.100s", _PATH_SSH_CLIENT_ID_DSA);
1112 		}
1113 	}
1114 	if (options->escape_char == -1)
1115 		options->escape_char = '~';
1116 	if (options->system_hostfile == NULL)
1117 		options->system_hostfile = _PATH_SSH_SYSTEM_HOSTFILE;
1118 	if (options->user_hostfile == NULL)
1119 		options->user_hostfile = _PATH_SSH_USER_HOSTFILE;
1120 	if (options->system_hostfile2 == NULL)
1121 		options->system_hostfile2 = _PATH_SSH_SYSTEM_HOSTFILE2;
1122 	if (options->user_hostfile2 == NULL)
1123 		options->user_hostfile2 = _PATH_SSH_USER_HOSTFILE2;
1124 	if (options->log_level == SYSLOG_LEVEL_NOT_SET)
1125 		options->log_level = SYSLOG_LEVEL_INFO;
1126 	if (options->clear_forwardings == 1)
1127 		clear_forwardings(options);
1128 	if (options->no_host_authentication_for_localhost == -1)
1129 		options->no_host_authentication_for_localhost = 0;
1130 	if (options->rekey_limit == -1)
1131 		options->rekey_limit = 0;
1132 	if (options->fallback_to_rsh == -1)
1133 		options->fallback_to_rsh = 0;
1134 	if (options->use_rsh == -1)
1135 		options->use_rsh = 0;
1136 	if (options->server_alive_interval == -1)
1137 		options->server_alive_interval = 0;
1138 	if (options->server_alive_count_max == -1)
1139 		options->server_alive_count_max = 3;
1140 	if (options->hash_known_hosts == -1)
1141 		options->hash_known_hosts = 0;
1142 	if (options->disable_banner == -1)
1143 		options->disable_banner = 0;
1144 	if (options->use_openssl_engine == -1)
1145 		options->use_openssl_engine = 1;
1146 	/* options->proxy_command should not be set by default */
1147 	/* options->user will be set in the main program if appropriate */
1148 	/* options->hostname will be set in the main program if appropriate */
1149 	/* options->host_key_alias should not be set by default */
1150 	/* options->preferred_authentications will be set in ssh */
1151 	/* options->ignore_if_unknown should not be set by default */
1152 }
1153 
1154 /*
1155  * Parses a string containing a port forwarding specification of one of the
1156  * two forms, short or long:
1157  *
1158  *	[listenhost:]listenport
1159  *	[listenhost:]listenport:connecthost:connectport
1160  *
1161  * short forwarding specification is used for dynamic port forwarding and for
1162  * port forwarding cancelation in process_cmdline(). The function returns number
1163  * of arguments parsed or zero on any error.
1164  */
1165 int
parse_forward(int long_form,Forward * fwd,const char * fwdspec)1166 parse_forward(int long_form, Forward *fwd, const char *fwdspec)
1167 {
1168 	int i;
1169 	char *p, *cp, *fwdarg[5];
1170 
1171 	memset(fwd, '\0', sizeof(*fwd));
1172 
1173 	cp = p = xstrdup(fwdspec);
1174 
1175 	/* skip leading spaces */
1176 	while (isspace(*cp))
1177 		cp++;
1178 
1179 	for (i = 0; i < 5; ++i)
1180 		if ((fwdarg[i] = hpdelim(&cp)) == NULL)
1181 			break;
1182 
1183 	if ((long_form == 0 && i > 2) || (long_form == 1 && i < 3) || (i == 5))
1184 		goto fail_free;
1185 
1186 	switch (i) {
1187 	case 0:
1188 		goto fail_free;
1189 
1190 	case 1:
1191 		fwd->listen_host = NULL;
1192 		fwd->listen_port = a2port(fwdarg[0]);
1193 		break;
1194 
1195 	case 2:
1196 		fwd->listen_host = xstrdup(cleanhostname(fwdarg[0]));
1197 		fwd->listen_port = a2port(fwdarg[1]);
1198 		break;
1199 
1200 	case 3:
1201 		fwd->listen_host = NULL;
1202 		fwd->listen_port = a2port(fwdarg[0]);
1203 		fwd->connect_host = xstrdup(cleanhostname(fwdarg[1]));
1204 		fwd->connect_port = a2port(fwdarg[2]);
1205 		break;
1206 
1207 	case 4:
1208 		fwd->listen_host = xstrdup(cleanhostname(fwdarg[0]));
1209 		fwd->listen_port = a2port(fwdarg[1]);
1210 		fwd->connect_host = xstrdup(cleanhostname(fwdarg[2]));
1211 		fwd->connect_port = a2port(fwdarg[3]);
1212 		break;
1213 	}
1214 
1215 	if (fwd->listen_port == 0 || (fwd->connect_port == 0 && i > 2))
1216 		goto fail_free;
1217 
1218 	xfree(p);
1219 	return (i);
1220 
1221 fail_free:
1222 	if (p != NULL)
1223 		xfree(p);
1224 	if (fwd->connect_host != NULL)
1225 		xfree(fwd->connect_host);
1226 	if (fwd->listen_host != NULL)
1227 		xfree(fwd->listen_host);
1228 	return (0);
1229 }
1230 
1231 /*
1232  * Process previously stored unknown options. When this function is called we
1233  * already have IgnoreIfUnknown set so finally we can decide whether each
1234  * unknown option is to be ignored or not.
1235  */
1236 void
process_unknown_options(Options * options)1237 process_unknown_options(Options *options)
1238 {
1239 	StoredOption *so;
1240 	int m, i, bad_options = 0;
1241 
1242 	/* if there is no unknown option we are done */
1243 	if (options->unknown_opts_num == 0)
1244 		return;
1245 
1246 	/*
1247 	 * Now go through the list of unknown options and report any one that
1248 	 * is not explicitly listed in IgnoreIfUnknown option. If at least one
1249 	 * such as that is found it's a show stopper.
1250 	 */
1251 	for (i = 0; i < options->unknown_opts_num; ++i) {
1252 		so = &options->unknown_opts[i];
1253 		if (options->ignore_if_unknown == NULL)
1254 			m = 0;
1255 		else
1256 			m = match_pattern_list(tolowercase(so->keyword),
1257 			    options->ignore_if_unknown,
1258 			    strlen(options->ignore_if_unknown), 1);
1259 		if (m == 1) {
1260 			debug("%s: line %d: ignoring unknown option: %s",
1261 			    so->filename, so->linenum, so->keyword);
1262 		}
1263 		else {
1264 			error("%s: line %d: unknown configuration option: %s",
1265 			    so->filename, so->linenum, so->keyword);
1266 			bad_options++;
1267 		}
1268 		xfree(so->keyword);
1269 		xfree(so->filename);
1270 	}
1271 
1272 	/* exit if we found at least one unignored unknown option */
1273 	if (bad_options > 0)
1274 		fatal("terminating, %d bad configuration option(s)",
1275 		    bad_options);
1276 }
1277