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