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