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