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