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