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