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