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