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