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