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