]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - crypto/openssh/readconf.c
MFH (r261320): upgrade openssh to 6.5p1
[FreeBSD/stable/10.git] / crypto / openssh / readconf.c
1 /* $OpenBSD: readconf.c,v 1.215 2013/12/06 13:39:49 markus Exp $ */
2 /* $FreeBSD$ */
3 /*
4  * Author: Tatu Ylonen <ylo@cs.hut.fi>
5  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
6  *                    All rights reserved
7  * Functions for reading the configuration files.
8  *
9  * As far as I am concerned, the code I have written for this software
10  * can be used freely for any purpose.  Any derived versions of this
11  * software must be clearly marked as such, and if the derived work is
12  * incompatible with the protocol description in the RFC file, it must be
13  * called by a name other than "ssh" or "Secure Shell".
14  */
15
16 #include "includes.h"
17 __RCSID("$FreeBSD$");
18
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <sys/socket.h>
22 #include <sys/sysctl.h>
23 #include <sys/wait.h>
24
25 #include <netinet/in.h>
26 #include <netinet/in_systm.h>
27 #include <netinet/ip.h>
28
29 #include <ctype.h>
30 #include <errno.h>
31 #include <fcntl.h>
32 #include <netdb.h>
33 #ifdef HAVE_PATHS_H
34 # include <paths.h>
35 #endif
36 #include <pwd.h>
37 #include <signal.h>
38 #include <stdarg.h>
39 #include <stdio.h>
40 #include <string.h>
41 #include <unistd.h>
42 #ifdef HAVE_UTIL_H
43 #include <util.h>
44 #endif
45
46 #include "xmalloc.h"
47 #include "ssh.h"
48 #include "compat.h"
49 #include "cipher.h"
50 #include "pathnames.h"
51 #include "log.h"
52 #include "key.h"
53 #include "readconf.h"
54 #include "match.h"
55 #include "misc.h"
56 #include "buffer.h"
57 #include "kex.h"
58 #include "mac.h"
59 #include "uidswap.h"
60 #include "version.h"
61
62 /* Format of the configuration file:
63
64    # Configuration data is parsed as follows:
65    #  1. command line options
66    #  2. user-specific file
67    #  3. system-wide file
68    # Any configuration value is only changed the first time it is set.
69    # Thus, host-specific definitions should be at the beginning of the
70    # configuration file, and defaults at the end.
71
72    # Host-specific declarations.  These may override anything above.  A single
73    # host may match multiple declarations; these are processed in the order
74    # that they are given in.
75
76    Host *.ngs.fi ngs.fi
77      User foo
78
79    Host fake.com
80      HostName another.host.name.real.org
81      User blaah
82      Port 34289
83      ForwardX11 no
84      ForwardAgent no
85
86    Host books.com
87      RemoteForward 9999 shadows.cs.hut.fi:9999
88      Cipher 3des
89
90    Host fascist.blob.com
91      Port 23123
92      User tylonen
93      PasswordAuthentication no
94
95    Host puukko.hut.fi
96      User t35124p
97      ProxyCommand ssh-proxy %h %p
98
99    Host *.fr
100      PublicKeyAuthentication no
101
102    Host *.su
103      Cipher none
104      PasswordAuthentication no
105
106    Host vpn.fake.com
107      Tunnel yes
108      TunnelDevice 3
109
110    # Defaults for various options
111    Host *
112      ForwardAgent no
113      ForwardX11 no
114      PasswordAuthentication yes
115      RSAAuthentication yes
116      RhostsRSAAuthentication yes
117      StrictHostKeyChecking yes
118      TcpKeepAlive no
119      IdentityFile ~/.ssh/identity
120      Port 22
121      EscapeChar ~
122
123 */
124
125 /* Keyword tokens. */
126
127 typedef enum {
128         oBadOption,
129         oHost, oMatch,
130         oForwardAgent, oForwardX11, oForwardX11Trusted, oForwardX11Timeout,
131         oGatewayPorts, oExitOnForwardFailure,
132         oPasswordAuthentication, oRSAAuthentication,
133         oChallengeResponseAuthentication, oXAuthLocation,
134         oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward,
135         oUser, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
136         oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
137         oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
138         oCompressionLevel, oTCPKeepAlive, oNumberOfPasswordPrompts,
139         oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oMacs,
140         oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication,
141         oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
142         oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
143         oHostKeyAlgorithms, oBindAddress, oPKCS11Provider,
144         oClearAllForwardings, oNoHostAuthenticationForLocalhost,
145         oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
146         oAddressFamily, oGssAuthentication, oGssDelegateCreds,
147         oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
148         oSendEnv, oControlPath, oControlMaster, oControlPersist,
149         oHashKnownHosts,
150         oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand,
151         oVisualHostKey, oUseRoaming, oZeroKnowledgePasswordAuthentication,
152         oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass,
153         oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots,
154         oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs,
155         oIgnoredUnknownOption,
156         oHPNDisabled, oHPNBufferSize, oTcpRcvBufPoll, oTcpRcvBuf,
157 #ifdef NONE_CIPHER_ENABLED
158         oNoneEnabled, oNoneSwitch,
159 #endif
160         oVersionAddendum, oDeprecated, oUnsupported
161 } OpCodes;
162
163 /* Textual representations of the tokens. */
164
165 static struct {
166         const char *name;
167         OpCodes opcode;
168 } keywords[] = {
169         { "forwardagent", oForwardAgent },
170         { "forwardx11", oForwardX11 },
171         { "forwardx11trusted", oForwardX11Trusted },
172         { "forwardx11timeout", oForwardX11Timeout },
173         { "exitonforwardfailure", oExitOnForwardFailure },
174         { "xauthlocation", oXAuthLocation },
175         { "gatewayports", oGatewayPorts },
176         { "useprivilegedport", oUsePrivilegedPort },
177         { "rhostsauthentication", oDeprecated },
178         { "passwordauthentication", oPasswordAuthentication },
179         { "kbdinteractiveauthentication", oKbdInteractiveAuthentication },
180         { "kbdinteractivedevices", oKbdInteractiveDevices },
181         { "rsaauthentication", oRSAAuthentication },
182         { "pubkeyauthentication", oPubkeyAuthentication },
183         { "dsaauthentication", oPubkeyAuthentication },             /* alias */
184         { "rhostsrsaauthentication", oRhostsRSAAuthentication },
185         { "hostbasedauthentication", oHostbasedAuthentication },
186         { "challengeresponseauthentication", oChallengeResponseAuthentication },
187         { "skeyauthentication", oChallengeResponseAuthentication }, /* alias */
188         { "tisauthentication", oChallengeResponseAuthentication },  /* alias */
189         { "kerberosauthentication", oUnsupported },
190         { "kerberostgtpassing", oUnsupported },
191         { "afstokenpassing", oUnsupported },
192 #if defined(GSSAPI)
193         { "gssapiauthentication", oGssAuthentication },
194         { "gssapidelegatecredentials", oGssDelegateCreds },
195 #else
196         { "gssapiauthentication", oUnsupported },
197         { "gssapidelegatecredentials", oUnsupported },
198 #endif
199         { "fallbacktorsh", oDeprecated },
200         { "usersh", oDeprecated },
201         { "identityfile", oIdentityFile },
202         { "identityfile2", oIdentityFile },                     /* obsolete */
203         { "identitiesonly", oIdentitiesOnly },
204         { "hostname", oHostName },
205         { "hostkeyalias", oHostKeyAlias },
206         { "proxycommand", oProxyCommand },
207         { "port", oPort },
208         { "cipher", oCipher },
209         { "ciphers", oCiphers },
210         { "macs", oMacs },
211         { "protocol", oProtocol },
212         { "remoteforward", oRemoteForward },
213         { "localforward", oLocalForward },
214         { "user", oUser },
215         { "host", oHost },
216         { "match", oMatch },
217         { "escapechar", oEscapeChar },
218         { "globalknownhostsfile", oGlobalKnownHostsFile },
219         { "globalknownhostsfile2", oDeprecated },
220         { "userknownhostsfile", oUserKnownHostsFile },
221         { "userknownhostsfile2", oDeprecated }, 
222         { "connectionattempts", oConnectionAttempts },
223         { "batchmode", oBatchMode },
224         { "checkhostip", oCheckHostIP },
225         { "stricthostkeychecking", oStrictHostKeyChecking },
226         { "compression", oCompression },
227         { "compressionlevel", oCompressionLevel },
228         { "tcpkeepalive", oTCPKeepAlive },
229         { "keepalive", oTCPKeepAlive },                         /* obsolete */
230         { "numberofpasswordprompts", oNumberOfPasswordPrompts },
231         { "loglevel", oLogLevel },
232         { "dynamicforward", oDynamicForward },
233         { "preferredauthentications", oPreferredAuthentications },
234         { "hostkeyalgorithms", oHostKeyAlgorithms },
235         { "bindaddress", oBindAddress },
236 #ifdef ENABLE_PKCS11
237         { "smartcarddevice", oPKCS11Provider },
238         { "pkcs11provider", oPKCS11Provider },
239 #else
240         { "smartcarddevice", oUnsupported },
241         { "pkcs11provider", oUnsupported },
242 #endif
243         { "clearallforwardings", oClearAllForwardings },
244         { "enablesshkeysign", oEnableSSHKeysign },
245         { "verifyhostkeydns", oVerifyHostKeyDNS },
246         { "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
247         { "rekeylimit", oRekeyLimit },
248         { "connecttimeout", oConnectTimeout },
249         { "addressfamily", oAddressFamily },
250         { "serveraliveinterval", oServerAliveInterval },
251         { "serveralivecountmax", oServerAliveCountMax },
252         { "sendenv", oSendEnv },
253         { "controlpath", oControlPath },
254         { "controlmaster", oControlMaster },
255         { "controlpersist", oControlPersist },
256         { "hashknownhosts", oHashKnownHosts },
257         { "tunnel", oTunnel },
258         { "tunneldevice", oTunnelDevice },
259         { "localcommand", oLocalCommand },
260         { "permitlocalcommand", oPermitLocalCommand },
261         { "visualhostkey", oVisualHostKey },
262         { "useroaming", oUseRoaming },
263 #ifdef JPAKE
264         { "zeroknowledgepasswordauthentication",
265             oZeroKnowledgePasswordAuthentication },
266 #else
267         { "zeroknowledgepasswordauthentication", oUnsupported },
268 #endif
269         { "kexalgorithms", oKexAlgorithms },
270         { "ipqos", oIPQoS },
271         { "requesttty", oRequestTTY },
272         { "proxyusefdpass", oProxyUseFdpass },
273         { "canonicaldomains", oCanonicalDomains },
274         { "canonicalizefallbacklocal", oCanonicalizeFallbackLocal },
275         { "canonicalizehostname", oCanonicalizeHostname },
276         { "canonicalizemaxdots", oCanonicalizeMaxDots },
277         { "canonicalizepermittedcnames", oCanonicalizePermittedCNAMEs },
278         { "ignoreunknown", oIgnoreUnknown },
279         { "hpndisabled", oHPNDisabled },
280         { "hpnbuffersize", oHPNBufferSize },
281         { "tcprcvbufpoll", oTcpRcvBufPoll },
282         { "tcprcvbuf", oTcpRcvBuf },
283 #ifdef  NONE_CIPHER_ENABLED
284         { "noneenabled", oNoneEnabled },
285         { "noneswitch", oNoneSwitch },
286 #endif
287         { "versionaddendum", oVersionAddendum },
288
289         { NULL, oBadOption }
290 };
291
292 /*
293  * Adds a local TCP/IP port forward to options.  Never returns if there is an
294  * error.
295  */
296
297 void
298 add_local_forward(Options *options, const Forward *newfwd)
299 {
300         Forward *fwd;
301 #ifndef NO_IPPORT_RESERVED_CONCEPT
302         extern uid_t original_real_uid;
303         int ipport_reserved;
304 #ifdef __FreeBSD__
305         size_t len_ipport_reserved = sizeof(ipport_reserved);
306
307         if (sysctlbyname("net.inet.ip.portrange.reservedhigh",
308             &ipport_reserved, &len_ipport_reserved, NULL, 0) != 0)
309                 ipport_reserved = IPPORT_RESERVED;
310         else
311                 ipport_reserved++;
312 #else
313         ipport_reserved = IPPORT_RESERVED;
314 #endif
315         if (newfwd->listen_port < ipport_reserved && original_real_uid != 0)
316                 fatal("Privileged ports can only be forwarded by root.");
317 #endif
318         options->local_forwards = xrealloc(options->local_forwards,
319             options->num_local_forwards + 1,
320             sizeof(*options->local_forwards));
321         fwd = &options->local_forwards[options->num_local_forwards++];
322
323         fwd->listen_host = newfwd->listen_host;
324         fwd->listen_port = newfwd->listen_port;
325         fwd->connect_host = newfwd->connect_host;
326         fwd->connect_port = newfwd->connect_port;
327 }
328
329 /*
330  * Adds a remote TCP/IP port forward to options.  Never returns if there is
331  * an error.
332  */
333
334 void
335 add_remote_forward(Options *options, const Forward *newfwd)
336 {
337         Forward *fwd;
338
339         options->remote_forwards = xrealloc(options->remote_forwards,
340             options->num_remote_forwards + 1,
341             sizeof(*options->remote_forwards));
342         fwd = &options->remote_forwards[options->num_remote_forwards++];
343
344         fwd->listen_host = newfwd->listen_host;
345         fwd->listen_port = newfwd->listen_port;
346         fwd->connect_host = newfwd->connect_host;
347         fwd->connect_port = newfwd->connect_port;
348         fwd->handle = newfwd->handle;
349         fwd->allocated_port = 0;
350 }
351
352 static void
353 clear_forwardings(Options *options)
354 {
355         int i;
356
357         for (i = 0; i < options->num_local_forwards; i++) {
358                 free(options->local_forwards[i].listen_host);
359                 free(options->local_forwards[i].connect_host);
360         }
361         if (options->num_local_forwards > 0) {
362                 free(options->local_forwards);
363                 options->local_forwards = NULL;
364         }
365         options->num_local_forwards = 0;
366         for (i = 0; i < options->num_remote_forwards; i++) {
367                 free(options->remote_forwards[i].listen_host);
368                 free(options->remote_forwards[i].connect_host);
369         }
370         if (options->num_remote_forwards > 0) {
371                 free(options->remote_forwards);
372                 options->remote_forwards = NULL;
373         }
374         options->num_remote_forwards = 0;
375         options->tun_open = SSH_TUNMODE_NO;
376 }
377
378 void
379 add_identity_file(Options *options, const char *dir, const char *filename,
380     int userprovided)
381 {
382         char *path;
383
384         if (options->num_identity_files >= SSH_MAX_IDENTITY_FILES)
385                 fatal("Too many identity files specified (max %d)",
386                     SSH_MAX_IDENTITY_FILES);
387
388         if (dir == NULL) /* no dir, filename is absolute */
389                 path = xstrdup(filename);
390         else
391                 (void)xasprintf(&path, "%.100s%.100s", dir, filename);
392
393         options->identity_file_userprovided[options->num_identity_files] =
394             userprovided;
395         options->identity_files[options->num_identity_files++] = path;
396 }
397
398 int
399 default_ssh_port(void)
400 {
401         static int port;
402         struct servent *sp;
403
404         if (port == 0) {
405                 sp = getservbyname(SSH_SERVICE_NAME, "tcp");
406                 port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT;
407         }
408         return port;
409 }
410
411 /*
412  * Execute a command in a shell.
413  * Return its exit status or -1 on abnormal exit.
414  */
415 static int
416 execute_in_shell(const char *cmd)
417 {
418         char *shell, *command_string;
419         pid_t pid;
420         int devnull, status;
421         extern uid_t original_real_uid;
422
423         if ((shell = getenv("SHELL")) == NULL)
424                 shell = _PATH_BSHELL;
425
426         /*
427          * Use "exec" to avoid "sh -c" processes on some platforms
428          * (e.g. Solaris)
429          */
430         xasprintf(&command_string, "exec %s", cmd);
431
432         /* Need this to redirect subprocess stdin/out */
433         if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1)
434                 fatal("open(/dev/null): %s", strerror(errno));
435
436         debug("Executing command: '%.500s'", cmd);
437
438         /* Fork and execute the command. */
439         if ((pid = fork()) == 0) {
440                 char *argv[4];
441
442                 /* Child.  Permanently give up superuser privileges. */
443                 permanently_drop_suid(original_real_uid);
444
445                 /* Redirect child stdin and stdout. Leave stderr */
446                 if (dup2(devnull, STDIN_FILENO) == -1)
447                         fatal("dup2: %s", strerror(errno));
448                 if (dup2(devnull, STDOUT_FILENO) == -1)
449                         fatal("dup2: %s", strerror(errno));
450                 if (devnull > STDERR_FILENO)
451                         close(devnull);
452                 closefrom(STDERR_FILENO + 1);
453
454                 argv[0] = shell;
455                 argv[1] = "-c";
456                 argv[2] = command_string;
457                 argv[3] = NULL;
458
459                 execv(argv[0], argv);
460                 error("Unable to execute '%.100s': %s", cmd, strerror(errno));
461                 /* Die with signal to make this error apparent to parent. */
462                 signal(SIGTERM, SIG_DFL);
463                 kill(getpid(), SIGTERM);
464                 _exit(1);
465         }
466         /* Parent. */
467         if (pid < 0)
468                 fatal("%s: fork: %.100s", __func__, strerror(errno));
469
470         close(devnull);
471         free(command_string);
472
473         while (waitpid(pid, &status, 0) == -1) {
474                 if (errno != EINTR && errno != EAGAIN)
475                         fatal("%s: waitpid: %s", __func__, strerror(errno));
476         }
477         if (!WIFEXITED(status)) {
478                 error("command '%.100s' exited abnormally", cmd);
479                 return -1;
480         } 
481         debug3("command returned status %d", WEXITSTATUS(status));
482         return WEXITSTATUS(status);
483 }
484
485 /*
486  * Parse and execute a Match directive.
487  */
488 static int
489 match_cfg_line(Options *options, char **condition, struct passwd *pw,
490     const char *host_arg, const char *filename, int linenum)
491 {
492         char *arg, *attrib, *cmd, *cp = *condition, *host;
493         const char *ruser;
494         int r, port, result = 1, attributes = 0;
495         size_t len;
496         char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV];
497
498         /*
499          * Configuration is likely to be incomplete at this point so we
500          * must be prepared to use default values.
501          */
502         port = options->port <= 0 ? default_ssh_port() : options->port;
503         ruser = options->user == NULL ? pw->pw_name : options->user;
504         if (options->hostname != NULL) {
505                 /* NB. Please keep in sync with ssh.c:main() */
506                 host = percent_expand(options->hostname,
507                     "h", host_arg, (char *)NULL);
508         } else
509                 host = xstrdup(host_arg);
510
511         debug3("checking match for '%s' host %s", cp, host);
512         while ((attrib = strdelim(&cp)) && *attrib != '\0') {
513                 attributes++;
514                 if (strcasecmp(attrib, "all") == 0) {
515                         if (attributes != 1 ||
516                             ((arg = strdelim(&cp)) != NULL && *arg != '\0')) {
517                                 error("'all' cannot be combined with other "
518                                     "Match attributes");
519                                 result = -1;
520                                 goto out;
521                         }
522                         *condition = cp;
523                         result = 1;
524                         goto out;
525                 }
526                 if ((arg = strdelim(&cp)) == NULL || *arg == '\0') {
527                         error("Missing Match criteria for %s", attrib);
528                         result = -1;
529                         goto out;
530                 }
531                 len = strlen(arg);
532                 if (strcasecmp(attrib, "host") == 0) {
533                         if (match_hostname(host, arg, len) != 1)
534                                 result = 0;
535                         else
536                                 debug("%.200s line %d: matched 'Host %.100s' ",
537                                     filename, linenum, host);
538                 } else if (strcasecmp(attrib, "originalhost") == 0) {
539                         if (match_hostname(host_arg, arg, len) != 1)
540                                 result = 0;
541                         else
542                                 debug("%.200s line %d: matched "
543                                     "'OriginalHost %.100s' ",
544                                     filename, linenum, host_arg);
545                 } else if (strcasecmp(attrib, "user") == 0) {
546                         if (match_pattern_list(ruser, arg, len, 0) != 1)
547                                 result = 0;
548                         else
549                                 debug("%.200s line %d: matched 'User %.100s' ",
550                                     filename, linenum, ruser);
551                 } else if (strcasecmp(attrib, "localuser") == 0) {
552                         if (match_pattern_list(pw->pw_name, arg, len, 0) != 1)
553                                 result = 0;
554                         else
555                                 debug("%.200s line %d: matched "
556                                     "'LocalUser %.100s' ",
557                                     filename, linenum, pw->pw_name);
558                 } else if (strcasecmp(attrib, "exec") == 0) {
559                         if (gethostname(thishost, sizeof(thishost)) == -1)
560                                 fatal("gethostname: %s", strerror(errno));
561                         strlcpy(shorthost, thishost, sizeof(shorthost));
562                         shorthost[strcspn(thishost, ".")] = '\0';
563                         snprintf(portstr, sizeof(portstr), "%d", port);
564
565                         cmd = percent_expand(arg,
566                             "L", shorthost,
567                             "d", pw->pw_dir,
568                             "h", host,
569                             "l", thishost,
570                             "n", host_arg,
571                             "p", portstr,
572                             "r", ruser,
573                             "u", pw->pw_name,
574                             (char *)NULL);
575                         r = execute_in_shell(cmd);
576                         if (r == -1) {
577                                 fatal("%.200s line %d: match exec '%.100s' "
578                                     "error", filename, linenum, cmd);
579                         } else if (r == 0) {
580                                 debug("%.200s line %d: matched "
581                                     "'exec \"%.100s\"' ",
582                                     filename, linenum, cmd);
583                         } else
584                                 result = 0;
585                         free(cmd);
586                 } else {
587                         error("Unsupported Match attribute %s", attrib);
588                         result = -1;
589                         goto out;
590                 }
591         }
592         if (attributes == 0) {
593                 error("One or more attributes required for Match");
594                 result = -1;
595                 goto out;
596         }
597         debug3("match %sfound", result ? "" : "not ");
598         *condition = cp;
599  out:
600         free(host);
601         return result;
602 }
603
604 /* Check and prepare a domain name: removes trailing '.' and lowercases */
605 static void
606 valid_domain(char *name, const char *filename, int linenum)
607 {
608         size_t i, l = strlen(name);
609         u_char c, last = '\0';
610
611         if (l == 0)
612                 fatal("%s line %d: empty hostname suffix", filename, linenum);
613         if (!isalpha((u_char)name[0]) && !isdigit((u_char)name[0]))
614                 fatal("%s line %d: hostname suffix \"%.100s\" "
615                     "starts with invalid character", filename, linenum, name);
616         for (i = 0; i < l; i++) {
617                 c = tolower((u_char)name[i]);
618                 name[i] = (char)c;
619                 if (last == '.' && c == '.')
620                         fatal("%s line %d: hostname suffix \"%.100s\" contains "
621                             "consecutive separators", filename, linenum, name);
622                 if (c != '.' && c != '-' && !isalnum(c) &&
623                     c != '_') /* technically invalid, but common */
624                         fatal("%s line %d: hostname suffix \"%.100s\" contains "
625                             "invalid characters", filename, linenum, name);
626                 last = c;
627         }
628         if (name[l - 1] == '.')
629                 name[l - 1] = '\0';
630 }
631
632 /*
633  * Returns the number of the token pointed to by cp or oBadOption.
634  */
635 static OpCodes
636 parse_token(const char *cp, const char *filename, int linenum,
637     const char *ignored_unknown)
638 {
639         int i;
640
641         for (i = 0; keywords[i].name; i++)
642                 if (strcmp(cp, keywords[i].name) == 0)
643                         return keywords[i].opcode;
644         if (ignored_unknown != NULL && match_pattern_list(cp, ignored_unknown,
645             strlen(ignored_unknown), 1) == 1)
646                 return oIgnoredUnknownOption;
647         error("%s: line %d: Bad configuration option: %s",
648             filename, linenum, cp);
649         return oBadOption;
650 }
651
652 /* Multistate option parsing */
653 struct multistate {
654         char *key;
655         int value;
656 };
657 static const struct multistate multistate_flag[] = {
658         { "true",                       1 },
659         { "false",                      0 },
660         { "yes",                        1 },
661         { "no",                         0 },
662         { NULL, -1 }
663 };
664 static const struct multistate multistate_yesnoask[] = {
665         { "true",                       1 },
666         { "false",                      0 },
667         { "yes",                        1 },
668         { "no",                         0 },
669         { "ask",                        2 },
670         { NULL, -1 }
671 };
672 static const struct multistate multistate_addressfamily[] = {
673         { "inet",                       AF_INET },
674         { "inet6",                      AF_INET6 },
675         { "any",                        AF_UNSPEC },
676         { NULL, -1 }
677 };
678 static const struct multistate multistate_controlmaster[] = {
679         { "true",                       SSHCTL_MASTER_YES },
680         { "yes",                        SSHCTL_MASTER_YES },
681         { "false",                      SSHCTL_MASTER_NO },
682         { "no",                         SSHCTL_MASTER_NO },
683         { "auto",                       SSHCTL_MASTER_AUTO },
684         { "ask",                        SSHCTL_MASTER_ASK },
685         { "autoask",                    SSHCTL_MASTER_AUTO_ASK },
686         { NULL, -1 }
687 };
688 static const struct multistate multistate_tunnel[] = {
689         { "ethernet",                   SSH_TUNMODE_ETHERNET },
690         { "point-to-point",             SSH_TUNMODE_POINTOPOINT },
691         { "true",                       SSH_TUNMODE_DEFAULT },
692         { "yes",                        SSH_TUNMODE_DEFAULT },
693         { "false",                      SSH_TUNMODE_NO },
694         { "no",                         SSH_TUNMODE_NO },
695         { NULL, -1 }
696 };
697 static const struct multistate multistate_requesttty[] = {
698         { "true",                       REQUEST_TTY_YES },
699         { "yes",                        REQUEST_TTY_YES },
700         { "false",                      REQUEST_TTY_NO },
701         { "no",                         REQUEST_TTY_NO },
702         { "force",                      REQUEST_TTY_FORCE },
703         { "auto",                       REQUEST_TTY_AUTO },
704         { NULL, -1 }
705 };
706 static const struct multistate multistate_canonicalizehostname[] = {
707         { "true",                       SSH_CANONICALISE_YES },
708         { "false",                      SSH_CANONICALISE_NO },
709         { "yes",                        SSH_CANONICALISE_YES },
710         { "no",                         SSH_CANONICALISE_NO },
711         { "always",                     SSH_CANONICALISE_ALWAYS },
712         { NULL, -1 }
713 };
714
715 /*
716  * Processes a single option line as used in the configuration files. This
717  * only sets those values that have not already been set.
718  */
719 #define WHITESPACE " \t\r\n"
720 int
721 process_config_line(Options *options, struct passwd *pw, const char *host,
722     char *line, const char *filename, int linenum, int *activep, int userconfig)
723 {
724         char *s, **charptr, *endofnumber, *keyword, *arg, *arg2;
725         char **cpptr, fwdarg[256];
726         u_int i, *uintptr, max_entries = 0;
727         int negated, opcode, *intptr, value, value2, cmdline = 0;
728         LogLevel *log_level_ptr;
729         long long val64;
730         size_t len;
731         Forward fwd;
732         const struct multistate *multistate_ptr;
733         struct allowed_cname *cname;
734
735         if (activep == NULL) { /* We are processing a command line directive */
736                 cmdline = 1;
737                 activep = &cmdline;
738         }
739
740         /* Strip trailing whitespace */
741         for (len = strlen(line) - 1; len > 0; len--) {
742                 if (strchr(WHITESPACE, line[len]) == NULL)
743                         break;
744                 line[len] = '\0';
745         }
746
747         s = line;
748         /* Get the keyword. (Each line is supposed to begin with a keyword). */
749         if ((keyword = strdelim(&s)) == NULL)
750                 return 0;
751         /* Ignore leading whitespace. */
752         if (*keyword == '\0')
753                 keyword = strdelim(&s);
754         if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#')
755                 return 0;
756         /* Match lowercase keyword */
757         lowercase(keyword);
758
759         opcode = parse_token(keyword, filename, linenum,
760             options->ignored_unknown);
761
762         switch (opcode) {
763         case oBadOption:
764                 /* don't panic, but count bad options */
765                 return -1;
766                 /* NOTREACHED */
767         case oIgnoredUnknownOption:
768                 debug("%s line %d: Ignored unknown option \"%s\"",
769                     filename, linenum, keyword);
770                 return 0;
771         case oConnectTimeout:
772                 intptr = &options->connection_timeout;
773 parse_time:
774                 arg = strdelim(&s);
775                 if (!arg || *arg == '\0')
776                         fatal("%s line %d: missing time value.",
777                             filename, linenum);
778                 if ((value = convtime(arg)) == -1)
779                         fatal("%s line %d: invalid time value.",
780                             filename, linenum);
781                 if (*activep && *intptr == -1)
782                         *intptr = value;
783                 break;
784
785         case oForwardAgent:
786                 intptr = &options->forward_agent;
787  parse_flag:
788                 multistate_ptr = multistate_flag;
789  parse_multistate:
790                 arg = strdelim(&s);
791                 if (!arg || *arg == '\0')
792                         fatal("%s line %d: missing argument.",
793                             filename, linenum);
794                 value = -1;
795                 for (i = 0; multistate_ptr[i].key != NULL; i++) {
796                         if (strcasecmp(arg, multistate_ptr[i].key) == 0) {
797                                 value = multistate_ptr[i].value;
798                                 break;
799                         }
800                 }
801                 if (value == -1)
802                         fatal("%s line %d: unsupported option \"%s\".",
803                             filename, linenum, arg);
804                 if (*activep && *intptr == -1)
805                         *intptr = value;
806                 break;
807
808         case oForwardX11:
809                 intptr = &options->forward_x11;
810                 goto parse_flag;
811
812         case oForwardX11Trusted:
813                 intptr = &options->forward_x11_trusted;
814                 goto parse_flag;
815         
816         case oForwardX11Timeout:
817                 intptr = &options->forward_x11_timeout;
818                 goto parse_time;
819
820         case oGatewayPorts:
821                 intptr = &options->gateway_ports;
822                 goto parse_flag;
823
824         case oExitOnForwardFailure:
825                 intptr = &options->exit_on_forward_failure;
826                 goto parse_flag;
827
828         case oUsePrivilegedPort:
829                 intptr = &options->use_privileged_port;
830                 goto parse_flag;
831
832         case oPasswordAuthentication:
833                 intptr = &options->password_authentication;
834                 goto parse_flag;
835
836         case oZeroKnowledgePasswordAuthentication:
837                 intptr = &options->zero_knowledge_password_authentication;
838                 goto parse_flag;
839
840         case oKbdInteractiveAuthentication:
841                 intptr = &options->kbd_interactive_authentication;
842                 goto parse_flag;
843
844         case oKbdInteractiveDevices:
845                 charptr = &options->kbd_interactive_devices;
846                 goto parse_string;
847
848         case oPubkeyAuthentication:
849                 intptr = &options->pubkey_authentication;
850                 goto parse_flag;
851
852         case oRSAAuthentication:
853                 intptr = &options->rsa_authentication;
854                 goto parse_flag;
855
856         case oRhostsRSAAuthentication:
857                 intptr = &options->rhosts_rsa_authentication;
858                 goto parse_flag;
859
860         case oHostbasedAuthentication:
861                 intptr = &options->hostbased_authentication;
862                 goto parse_flag;
863
864         case oChallengeResponseAuthentication:
865                 intptr = &options->challenge_response_authentication;
866                 goto parse_flag;
867
868         case oGssAuthentication:
869                 intptr = &options->gss_authentication;
870                 goto parse_flag;
871
872         case oGssDelegateCreds:
873                 intptr = &options->gss_deleg_creds;
874                 goto parse_flag;
875
876         case oBatchMode:
877                 intptr = &options->batch_mode;
878                 goto parse_flag;
879
880         case oCheckHostIP:
881                 intptr = &options->check_host_ip;
882                 goto parse_flag;
883
884         case oVerifyHostKeyDNS:
885                 intptr = &options->verify_host_key_dns;
886                 multistate_ptr = multistate_yesnoask;
887                 goto parse_multistate;
888
889         case oStrictHostKeyChecking:
890                 intptr = &options->strict_host_key_checking;
891                 multistate_ptr = multistate_yesnoask;
892                 goto parse_multistate;
893
894         case oCompression:
895                 intptr = &options->compression;
896                 goto parse_flag;
897
898         case oTCPKeepAlive:
899                 intptr = &options->tcp_keep_alive;
900                 goto parse_flag;
901
902         case oNoHostAuthenticationForLocalhost:
903                 intptr = &options->no_host_authentication_for_localhost;
904                 goto parse_flag;
905
906         case oNumberOfPasswordPrompts:
907                 intptr = &options->number_of_password_prompts;
908                 goto parse_int;
909
910         case oCompressionLevel:
911                 intptr = &options->compression_level;
912                 goto parse_int;
913
914         case oRekeyLimit:
915                 arg = strdelim(&s);
916                 if (!arg || *arg == '\0')
917                         fatal("%.200s line %d: Missing argument.", filename,
918                             linenum);
919                 if (strcmp(arg, "default") == 0) {
920                         val64 = 0;
921                 } else {
922                         if (scan_scaled(arg, &val64) == -1)
923                                 fatal("%.200s line %d: Bad number '%s': %s",
924                                     filename, linenum, arg, strerror(errno));
925                         /* check for too-large or too-small limits */
926                         if (val64 > UINT_MAX)
927                                 fatal("%.200s line %d: RekeyLimit too large",
928                                     filename, linenum);
929                         if (val64 != 0 && val64 < 16)
930                                 fatal("%.200s line %d: RekeyLimit too small",
931                                     filename, linenum);
932                 }
933                 if (*activep && options->rekey_limit == -1)
934                         options->rekey_limit = (u_int32_t)val64;
935                 if (s != NULL) { /* optional rekey interval present */
936                         if (strcmp(s, "none") == 0) {
937                                 (void)strdelim(&s);     /* discard */
938                                 break;
939                         }
940                         intptr = &options->rekey_interval;
941                         goto parse_time;
942                 }
943                 break;
944
945         case oIdentityFile:
946                 arg = strdelim(&s);
947                 if (!arg || *arg == '\0')
948                         fatal("%.200s line %d: Missing argument.", filename, linenum);
949                 if (*activep) {
950                         intptr = &options->num_identity_files;
951                         if (*intptr >= SSH_MAX_IDENTITY_FILES)
952                                 fatal("%.200s line %d: Too many identity files specified (max %d).",
953                                     filename, linenum, SSH_MAX_IDENTITY_FILES);
954                         add_identity_file(options, NULL, arg, userconfig);
955                 }
956                 break;
957
958         case oXAuthLocation:
959                 charptr=&options->xauth_location;
960                 goto parse_string;
961
962         case oUser:
963                 charptr = &options->user;
964 parse_string:
965                 arg = strdelim(&s);
966                 if (!arg || *arg == '\0')
967                         fatal("%.200s line %d: Missing argument.",
968                             filename, linenum);
969                 if (*activep && *charptr == NULL)
970                         *charptr = xstrdup(arg);
971                 break;
972
973         case oGlobalKnownHostsFile:
974                 cpptr = (char **)&options->system_hostfiles;
975                 uintptr = &options->num_system_hostfiles;
976                 max_entries = SSH_MAX_HOSTS_FILES;
977 parse_char_array:
978                 if (*activep && *uintptr == 0) {
979                         while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
980                                 if ((*uintptr) >= max_entries)
981                                         fatal("%s line %d: "
982                                             "too many authorized keys files.",
983                                             filename, linenum);
984                                 cpptr[(*uintptr)++] = xstrdup(arg);
985                         }
986                 }
987                 return 0;
988
989         case oUserKnownHostsFile:
990                 cpptr = (char **)&options->user_hostfiles;
991                 uintptr = &options->num_user_hostfiles;
992                 max_entries = SSH_MAX_HOSTS_FILES;
993                 goto parse_char_array;
994
995         case oHostName:
996                 charptr = &options->hostname;
997                 goto parse_string;
998
999         case oHostKeyAlias:
1000                 charptr = &options->host_key_alias;
1001                 goto parse_string;
1002
1003         case oPreferredAuthentications:
1004                 charptr = &options->preferred_authentications;
1005                 goto parse_string;
1006
1007         case oBindAddress:
1008                 charptr = &options->bind_address;
1009                 goto parse_string;
1010
1011         case oPKCS11Provider:
1012                 charptr = &options->pkcs11_provider;
1013                 goto parse_string;
1014
1015         case oProxyCommand:
1016                 charptr = &options->proxy_command;
1017 parse_command:
1018                 if (s == NULL)
1019                         fatal("%.200s line %d: Missing argument.", filename, linenum);
1020                 len = strspn(s, WHITESPACE "=");
1021                 if (*activep && *charptr == NULL)
1022                         *charptr = xstrdup(s + len);
1023                 return 0;
1024
1025         case oPort:
1026                 intptr = &options->port;
1027 parse_int:
1028                 arg = strdelim(&s);
1029                 if (!arg || *arg == '\0')
1030                         fatal("%.200s line %d: Missing argument.", filename, linenum);
1031                 if (arg[0] < '0' || arg[0] > '9')
1032                         fatal("%.200s line %d: Bad number.", filename, linenum);
1033
1034                 /* Octal, decimal, or hex format? */
1035                 value = strtol(arg, &endofnumber, 0);
1036                 if (arg == endofnumber)
1037                         fatal("%.200s line %d: Bad number.", filename, linenum);
1038                 if (*activep && *intptr == -1)
1039                         *intptr = value;
1040                 break;
1041
1042         case oConnectionAttempts:
1043                 intptr = &options->connection_attempts;
1044                 goto parse_int;
1045
1046         case oCipher:
1047                 intptr = &options->cipher;
1048                 arg = strdelim(&s);
1049                 if (!arg || *arg == '\0')
1050                         fatal("%.200s line %d: Missing argument.", filename, linenum);
1051                 value = cipher_number(arg);
1052                 if (value == -1)
1053                         fatal("%.200s line %d: Bad cipher '%s'.",
1054                             filename, linenum, arg ? arg : "<NONE>");
1055                 if (*activep && *intptr == -1)
1056                         *intptr = value;
1057                 break;
1058
1059         case oCiphers:
1060                 arg = strdelim(&s);
1061                 if (!arg || *arg == '\0')
1062                         fatal("%.200s line %d: Missing argument.", filename, linenum);
1063                 if (!ciphers_valid(arg))
1064                         fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.",
1065                             filename, linenum, arg ? arg : "<NONE>");
1066                 if (*activep && options->ciphers == NULL)
1067                         options->ciphers = xstrdup(arg);
1068                 break;
1069
1070         case oMacs:
1071                 arg = strdelim(&s);
1072                 if (!arg || *arg == '\0')
1073                         fatal("%.200s line %d: Missing argument.", filename, linenum);
1074                 if (!mac_valid(arg))
1075                         fatal("%.200s line %d: Bad SSH2 Mac spec '%s'.",
1076                             filename, linenum, arg ? arg : "<NONE>");
1077                 if (*activep && options->macs == NULL)
1078                         options->macs = xstrdup(arg);
1079                 break;
1080
1081         case oKexAlgorithms:
1082                 arg = strdelim(&s);
1083                 if (!arg || *arg == '\0')
1084                         fatal("%.200s line %d: Missing argument.",
1085                             filename, linenum);
1086                 if (!kex_names_valid(arg))
1087                         fatal("%.200s line %d: Bad SSH2 KexAlgorithms '%s'.",
1088                             filename, linenum, arg ? arg : "<NONE>");
1089                 if (*activep && options->kex_algorithms == NULL)
1090                         options->kex_algorithms = xstrdup(arg);
1091                 break;
1092
1093         case oHostKeyAlgorithms:
1094                 arg = strdelim(&s);
1095                 if (!arg || *arg == '\0')
1096                         fatal("%.200s line %d: Missing argument.", filename, linenum);
1097                 if (!key_names_valid2(arg))
1098                         fatal("%.200s line %d: Bad protocol 2 host key algorithms '%s'.",
1099                             filename, linenum, arg ? arg : "<NONE>");
1100                 if (*activep && options->hostkeyalgorithms == NULL)
1101                         options->hostkeyalgorithms = xstrdup(arg);
1102                 break;
1103
1104         case oProtocol:
1105                 intptr = &options->protocol;
1106                 arg = strdelim(&s);
1107                 if (!arg || *arg == '\0')
1108                         fatal("%.200s line %d: Missing argument.", filename, linenum);
1109                 value = proto_spec(arg);
1110                 if (value == SSH_PROTO_UNKNOWN)
1111                         fatal("%.200s line %d: Bad protocol spec '%s'.",
1112                             filename, linenum, arg ? arg : "<NONE>");
1113                 if (*activep && *intptr == SSH_PROTO_UNKNOWN)
1114                         *intptr = value;
1115                 break;
1116
1117         case oLogLevel:
1118                 log_level_ptr = &options->log_level;
1119                 arg = strdelim(&s);
1120                 value = log_level_number(arg);
1121                 if (value == SYSLOG_LEVEL_NOT_SET)
1122                         fatal("%.200s line %d: unsupported log level '%s'",
1123                             filename, linenum, arg ? arg : "<NONE>");
1124                 if (*activep && *log_level_ptr == SYSLOG_LEVEL_NOT_SET)
1125                         *log_level_ptr = (LogLevel) value;
1126                 break;
1127
1128         case oLocalForward:
1129         case oRemoteForward:
1130         case oDynamicForward:
1131                 arg = strdelim(&s);
1132                 if (arg == NULL || *arg == '\0')
1133                         fatal("%.200s line %d: Missing port argument.",
1134                             filename, linenum);
1135
1136                 if (opcode == oLocalForward ||
1137                     opcode == oRemoteForward) {
1138                         arg2 = strdelim(&s);
1139                         if (arg2 == NULL || *arg2 == '\0')
1140                                 fatal("%.200s line %d: Missing target argument.",
1141                                     filename, linenum);
1142
1143                         /* construct a string for parse_forward */
1144                         snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg, arg2);
1145                 } else if (opcode == oDynamicForward) {
1146                         strlcpy(fwdarg, arg, sizeof(fwdarg));
1147                 }
1148
1149                 if (parse_forward(&fwd, fwdarg,
1150                     opcode == oDynamicForward ? 1 : 0,
1151                     opcode == oRemoteForward ? 1 : 0) == 0)
1152                         fatal("%.200s line %d: Bad forwarding specification.",
1153                             filename, linenum);
1154
1155                 if (*activep) {
1156                         if (opcode == oLocalForward ||
1157                             opcode == oDynamicForward)
1158                                 add_local_forward(options, &fwd);
1159                         else if (opcode == oRemoteForward)
1160                                 add_remote_forward(options, &fwd);
1161                 }
1162                 break;
1163
1164         case oClearAllForwardings:
1165                 intptr = &options->clear_forwardings;
1166                 goto parse_flag;
1167
1168         case oHost:
1169                 if (cmdline)
1170                         fatal("Host directive not supported as a command-line "
1171                             "option");
1172                 *activep = 0;
1173                 arg2 = NULL;
1174                 while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1175                         negated = *arg == '!';
1176                         if (negated)
1177                                 arg++;
1178                         if (match_pattern(host, arg)) {
1179                                 if (negated) {
1180                                         debug("%.200s line %d: Skipping Host "
1181                                             "block because of negated match "
1182                                             "for %.100s", filename, linenum,
1183                                             arg);
1184                                         *activep = 0;
1185                                         break;
1186                                 }
1187                                 if (!*activep)
1188                                         arg2 = arg; /* logged below */
1189                                 *activep = 1;
1190                         }
1191                 }
1192                 if (*activep)
1193                         debug("%.200s line %d: Applying options for %.100s",
1194                             filename, linenum, arg2);
1195                 /* Avoid garbage check below, as strdelim is done. */
1196                 return 0;
1197
1198         case oMatch:
1199                 if (cmdline)
1200                         fatal("Host directive not supported as a command-line "
1201                             "option");
1202                 value = match_cfg_line(options, &s, pw, host,
1203                     filename, linenum);
1204                 if (value < 0)
1205                         fatal("%.200s line %d: Bad Match condition", filename,
1206                             linenum);
1207                 *activep = value;
1208                 break;
1209
1210         case oEscapeChar:
1211                 intptr = &options->escape_char;
1212                 arg = strdelim(&s);
1213                 if (!arg || *arg == '\0')
1214                         fatal("%.200s line %d: Missing argument.", filename, linenum);
1215                 if (arg[0] == '^' && arg[2] == 0 &&
1216                     (u_char) arg[1] >= 64 && (u_char) arg[1] < 128)
1217                         value = (u_char) arg[1] & 31;
1218                 else if (strlen(arg) == 1)
1219                         value = (u_char) arg[0];
1220                 else if (strcmp(arg, "none") == 0)
1221                         value = SSH_ESCAPECHAR_NONE;
1222                 else {
1223                         fatal("%.200s line %d: Bad escape character.",
1224                             filename, linenum);
1225                         /* NOTREACHED */
1226                         value = 0;      /* Avoid compiler warning. */
1227                 }
1228                 if (*activep && *intptr == -1)
1229                         *intptr = value;
1230                 break;
1231
1232         case oAddressFamily:
1233                 intptr = &options->address_family;
1234                 multistate_ptr = multistate_addressfamily;
1235                 goto parse_multistate;
1236
1237         case oEnableSSHKeysign:
1238                 intptr = &options->enable_ssh_keysign;
1239                 goto parse_flag;
1240
1241         case oIdentitiesOnly:
1242                 intptr = &options->identities_only;
1243                 goto parse_flag;
1244
1245         case oServerAliveInterval:
1246                 intptr = &options->server_alive_interval;
1247                 goto parse_time;
1248
1249         case oServerAliveCountMax:
1250                 intptr = &options->server_alive_count_max;
1251                 goto parse_int;
1252
1253         case oSendEnv:
1254                 while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1255                         if (strchr(arg, '=') != NULL)
1256                                 fatal("%s line %d: Invalid environment name.",
1257                                     filename, linenum);
1258                         if (!*activep)
1259                                 continue;
1260                         if (options->num_send_env >= MAX_SEND_ENV)
1261                                 fatal("%s line %d: too many send env.",
1262                                     filename, linenum);
1263                         options->send_env[options->num_send_env++] =
1264                             xstrdup(arg);
1265                 }
1266                 break;
1267
1268         case oControlPath:
1269                 charptr = &options->control_path;
1270                 goto parse_string;
1271
1272         case oControlMaster:
1273                 intptr = &options->control_master;
1274                 multistate_ptr = multistate_controlmaster;
1275                 goto parse_multistate;
1276
1277         case oControlPersist:
1278                 /* no/false/yes/true, or a time spec */
1279                 intptr = &options->control_persist;
1280                 arg = strdelim(&s);
1281                 if (!arg || *arg == '\0')
1282                         fatal("%.200s line %d: Missing ControlPersist"
1283                             " argument.", filename, linenum);
1284                 value = 0;
1285                 value2 = 0;     /* timeout */
1286                 if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
1287                         value = 0;
1288                 else if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
1289                         value = 1;
1290                 else if ((value2 = convtime(arg)) >= 0)
1291                         value = 1;
1292                 else
1293                         fatal("%.200s line %d: Bad ControlPersist argument.",
1294                             filename, linenum);
1295                 if (*activep && *intptr == -1) {
1296                         *intptr = value;
1297                         options->control_persist_timeout = value2;
1298                 }
1299                 break;
1300
1301         case oHashKnownHosts:
1302                 intptr = &options->hash_known_hosts;
1303                 goto parse_flag;
1304
1305         case oTunnel:
1306                 intptr = &options->tun_open;
1307                 multistate_ptr = multistate_tunnel;
1308                 goto parse_multistate;
1309
1310         case oTunnelDevice:
1311                 arg = strdelim(&s);
1312                 if (!arg || *arg == '\0')
1313                         fatal("%.200s line %d: Missing argument.", filename, linenum);
1314                 value = a2tun(arg, &value2);
1315                 if (value == SSH_TUNID_ERR)
1316                         fatal("%.200s line %d: Bad tun device.", filename, linenum);
1317                 if (*activep) {
1318                         options->tun_local = value;
1319                         options->tun_remote = value2;
1320                 }
1321                 break;
1322
1323         case oLocalCommand:
1324                 charptr = &options->local_command;
1325                 goto parse_command;
1326
1327         case oPermitLocalCommand:
1328                 intptr = &options->permit_local_command;
1329                 goto parse_flag;
1330
1331         case oVisualHostKey:
1332                 intptr = &options->visual_host_key;
1333                 goto parse_flag;
1334
1335         case oIPQoS:
1336                 arg = strdelim(&s);
1337                 if ((value = parse_ipqos(arg)) == -1)
1338                         fatal("%s line %d: Bad IPQoS value: %s",
1339                             filename, linenum, arg);
1340                 arg = strdelim(&s);
1341                 if (arg == NULL)
1342                         value2 = value;
1343                 else if ((value2 = parse_ipqos(arg)) == -1)
1344                         fatal("%s line %d: Bad IPQoS value: %s",
1345                             filename, linenum, arg);
1346                 if (*activep) {
1347                         options->ip_qos_interactive = value;
1348                         options->ip_qos_bulk = value2;
1349                 }
1350                 break;
1351
1352         case oUseRoaming:
1353                 intptr = &options->use_roaming;
1354                 goto parse_flag;
1355
1356         case oRequestTTY:
1357                 intptr = &options->request_tty;
1358                 multistate_ptr = multistate_requesttty;
1359                 goto parse_multistate;
1360
1361         case oHPNDisabled:
1362                 intptr = &options->hpn_disabled;
1363                 goto parse_flag;
1364
1365         case oHPNBufferSize:
1366                 intptr = &options->hpn_buffer_size;
1367                 goto parse_int;
1368
1369         case oTcpRcvBufPoll:
1370                 intptr = &options->tcp_rcv_buf_poll;
1371                 goto parse_flag;
1372
1373         case oTcpRcvBuf:
1374                 intptr = &options->tcp_rcv_buf;
1375                 goto parse_int;
1376
1377 #ifdef  NONE_CIPHER_ENABLED
1378         case oNoneEnabled:
1379                 intptr = &options->none_enabled;
1380                 goto parse_flag;
1381
1382         /*
1383          * We check to see if the command comes from the command line or not.
1384          * If it does then enable it otherwise fail.  NONE must never be a
1385          * default configuration.
1386          */
1387         case oNoneSwitch:
1388                 if (strcmp(filename,"command-line") == 0) {
1389                         intptr = &options->none_switch;
1390                         goto parse_flag;
1391                 } else {
1392                         debug("NoneSwitch directive found in %.200s.",
1393                             filename);
1394                         error("NoneSwitch is found in %.200s.\n"
1395                             "You may only use this configuration option "
1396                             "from the command line", filename);
1397                         error("Continuing...");
1398                         return 0;
1399                 }
1400 #endif
1401
1402         case oVersionAddendum:
1403                 if (s == NULL)
1404                         fatal("%.200s line %d: Missing argument.", filename,
1405                             linenum);
1406                 len = strspn(s, WHITESPACE);
1407                 if (*activep && options->version_addendum == NULL) {
1408                         if (strcasecmp(s + len, "none") == 0)
1409                                 options->version_addendum = xstrdup("");
1410                         else if (strchr(s + len, '\r') != NULL)
1411                                 fatal("%.200s line %d: Invalid argument",
1412                                     filename, linenum);
1413                         else
1414                                 options->version_addendum = xstrdup(s + len);
1415                 }
1416                 return 0;
1417
1418         case oIgnoreUnknown:
1419                 charptr = &options->ignored_unknown;
1420                 goto parse_string;
1421
1422         case oProxyUseFdpass:
1423                 intptr = &options->proxy_use_fdpass;
1424                 goto parse_flag;
1425
1426         case oCanonicalDomains:
1427                 value = options->num_canonical_domains != 0;
1428                 while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1429                         valid_domain(arg, filename, linenum);
1430                         if (!*activep || value)
1431                                 continue;
1432                         if (options->num_canonical_domains >= MAX_CANON_DOMAINS)
1433                                 fatal("%s line %d: too many hostname suffixes.",
1434                                     filename, linenum);
1435                         options->canonical_domains[
1436                             options->num_canonical_domains++] = xstrdup(arg);
1437                 }
1438                 break;
1439
1440         case oCanonicalizePermittedCNAMEs:
1441                 value = options->num_permitted_cnames != 0;
1442                 while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1443                         /* Either '*' for everything or 'list:list' */
1444                         if (strcmp(arg, "*") == 0)
1445                                 arg2 = arg;
1446                         else {
1447                                 lowercase(arg);
1448                                 if ((arg2 = strchr(arg, ':')) == NULL ||
1449                                     arg2[1] == '\0') {
1450                                         fatal("%s line %d: "
1451                                             "Invalid permitted CNAME \"%s\"",
1452                                             filename, linenum, arg);
1453                                 }
1454                                 *arg2 = '\0';
1455                                 arg2++;
1456                         }
1457                         if (!*activep || value)
1458                                 continue;
1459                         if (options->num_permitted_cnames >= MAX_CANON_DOMAINS)
1460                                 fatal("%s line %d: too many permitted CNAMEs.",
1461                                     filename, linenum);
1462                         cname = options->permitted_cnames +
1463                             options->num_permitted_cnames++;
1464                         cname->source_list = xstrdup(arg);
1465                         cname->target_list = xstrdup(arg2);
1466                 }
1467                 break;
1468
1469         case oCanonicalizeHostname:
1470                 intptr = &options->canonicalize_hostname;
1471                 multistate_ptr = multistate_canonicalizehostname;
1472                 goto parse_multistate;
1473
1474         case oCanonicalizeMaxDots:
1475                 intptr = &options->canonicalize_max_dots;
1476                 goto parse_int;
1477
1478         case oCanonicalizeFallbackLocal:
1479                 intptr = &options->canonicalize_fallback_local;
1480                 goto parse_flag;
1481
1482         case oDeprecated:
1483                 debug("%s line %d: Deprecated option \"%s\"",
1484                     filename, linenum, keyword);
1485                 return 0;
1486
1487         case oUnsupported:
1488                 error("%s line %d: Unsupported option \"%s\"",
1489                     filename, linenum, keyword);
1490                 return 0;
1491
1492         default:
1493                 fatal("process_config_line: Unimplemented opcode %d", opcode);
1494         }
1495
1496         /* Check that there is no garbage at end of line. */
1497         if ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1498                 fatal("%.200s line %d: garbage at end of line; \"%.200s\".",
1499                     filename, linenum, arg);
1500         }
1501         return 0;
1502 }
1503
1504
1505 /*
1506  * Reads the config file and modifies the options accordingly.  Options
1507  * should already be initialized before this call.  This never returns if
1508  * there is an error.  If the file does not exist, this returns 0.
1509  */
1510
1511 int
1512 read_config_file(const char *filename, struct passwd *pw, const char *host,
1513     Options *options, int flags)
1514 {
1515         FILE *f;
1516         char line[1024];
1517         int active, linenum;
1518         int bad_options = 0;
1519
1520         if ((f = fopen(filename, "r")) == NULL)
1521                 return 0;
1522
1523         if (flags & SSHCONF_CHECKPERM) {
1524                 struct stat sb;
1525
1526                 if (fstat(fileno(f), &sb) == -1)
1527                         fatal("fstat %s: %s", filename, strerror(errno));
1528                 if (((sb.st_uid != 0 && sb.st_uid != getuid()) ||
1529                     (sb.st_mode & 022) != 0))
1530                         fatal("Bad owner or permissions on %s", filename);
1531         }
1532
1533         debug("Reading configuration data %.200s", filename);
1534
1535         /*
1536          * Mark that we are now processing the options.  This flag is turned
1537          * on/off by Host specifications.
1538          */
1539         active = 1;
1540         linenum = 0;
1541         while (fgets(line, sizeof(line), f)) {
1542                 /* Update line number counter. */
1543                 linenum++;
1544                 if (process_config_line(options, pw, host, line, filename,
1545                     linenum, &active, flags & SSHCONF_USERCONF) != 0)
1546                         bad_options++;
1547         }
1548         fclose(f);
1549         if (bad_options > 0)
1550                 fatal("%s: terminating, %d bad configuration options",
1551                     filename, bad_options);
1552         return 1;
1553 }
1554
1555 /*
1556  * Initializes options to special values that indicate that they have not yet
1557  * been set.  Read_config_file will only set options with this value. Options
1558  * are processed in the following order: command line, user config file,
1559  * system config file.  Last, fill_default_options is called.
1560  */
1561
1562 void
1563 initialize_options(Options * options)
1564 {
1565         memset(options, 'X', sizeof(*options));
1566         options->forward_agent = -1;
1567         options->forward_x11 = -1;
1568         options->forward_x11_trusted = -1;
1569         options->forward_x11_timeout = -1;
1570         options->exit_on_forward_failure = -1;
1571         options->xauth_location = NULL;
1572         options->gateway_ports = -1;
1573         options->use_privileged_port = -1;
1574         options->rsa_authentication = -1;
1575         options->pubkey_authentication = -1;
1576         options->challenge_response_authentication = -1;
1577         options->gss_authentication = -1;
1578         options->gss_deleg_creds = -1;
1579         options->password_authentication = -1;
1580         options->kbd_interactive_authentication = -1;
1581         options->kbd_interactive_devices = NULL;
1582         options->rhosts_rsa_authentication = -1;
1583         options->hostbased_authentication = -1;
1584         options->batch_mode = -1;
1585         options->check_host_ip = -1;
1586         options->strict_host_key_checking = -1;
1587         options->compression = -1;
1588         options->tcp_keep_alive = -1;
1589         options->compression_level = -1;
1590         options->port = -1;
1591         options->address_family = -1;
1592         options->connection_attempts = -1;
1593         options->connection_timeout = -1;
1594         options->number_of_password_prompts = -1;
1595         options->cipher = -1;
1596         options->ciphers = NULL;
1597         options->macs = NULL;
1598         options->kex_algorithms = NULL;
1599         options->hostkeyalgorithms = NULL;
1600         options->protocol = SSH_PROTO_UNKNOWN;
1601         options->num_identity_files = 0;
1602         options->hostname = NULL;
1603         options->host_key_alias = NULL;
1604         options->proxy_command = NULL;
1605         options->user = NULL;
1606         options->escape_char = -1;
1607         options->num_system_hostfiles = 0;
1608         options->num_user_hostfiles = 0;
1609         options->local_forwards = NULL;
1610         options->num_local_forwards = 0;
1611         options->remote_forwards = NULL;
1612         options->num_remote_forwards = 0;
1613         options->clear_forwardings = -1;
1614         options->log_level = SYSLOG_LEVEL_NOT_SET;
1615         options->preferred_authentications = NULL;
1616         options->bind_address = NULL;
1617         options->pkcs11_provider = NULL;
1618         options->enable_ssh_keysign = - 1;
1619         options->no_host_authentication_for_localhost = - 1;
1620         options->identities_only = - 1;
1621         options->rekey_limit = - 1;
1622         options->rekey_interval = -1;
1623         options->verify_host_key_dns = -1;
1624         options->server_alive_interval = -1;
1625         options->server_alive_count_max = -1;
1626         options->num_send_env = 0;
1627         options->control_path = NULL;
1628         options->control_master = -1;
1629         options->control_persist = -1;
1630         options->control_persist_timeout = 0;
1631         options->hash_known_hosts = -1;
1632         options->tun_open = -1;
1633         options->tun_local = -1;
1634         options->tun_remote = -1;
1635         options->local_command = NULL;
1636         options->permit_local_command = -1;
1637         options->use_roaming = -1;
1638         options->visual_host_key = -1;
1639         options->zero_knowledge_password_authentication = -1;
1640         options->ip_qos_interactive = -1;
1641         options->ip_qos_bulk = -1;
1642         options->request_tty = -1;
1643         options->proxy_use_fdpass = -1;
1644         options->ignored_unknown = NULL;
1645         options->num_canonical_domains = 0;
1646         options->num_permitted_cnames = 0;
1647         options->canonicalize_max_dots = -1;
1648         options->canonicalize_fallback_local = -1;
1649         options->canonicalize_hostname = -1;
1650         options->version_addendum = NULL;
1651         options->hpn_disabled = -1;
1652         options->hpn_buffer_size = -1;
1653         options->tcp_rcv_buf_poll = -1;
1654         options->tcp_rcv_buf = -1;
1655 #ifdef NONE_CIPHER_ENABLED
1656         options->none_enabled = -1;
1657         options->none_switch = -1;
1658 #endif
1659 }
1660
1661 /*
1662  * Called after processing other sources of option data, this fills those
1663  * options for which no value has been specified with their default values.
1664  */
1665
1666 void
1667 fill_default_options(Options * options)
1668 {
1669         if (options->forward_agent == -1)
1670                 options->forward_agent = 0;
1671         if (options->forward_x11 == -1)
1672                 options->forward_x11 = 0;
1673         if (options->forward_x11_trusted == -1)
1674                 options->forward_x11_trusted = 0;
1675         if (options->forward_x11_timeout == -1)
1676                 options->forward_x11_timeout = 1200;
1677         if (options->exit_on_forward_failure == -1)
1678                 options->exit_on_forward_failure = 0;
1679         if (options->xauth_location == NULL)
1680                 options->xauth_location = _PATH_XAUTH;
1681         if (options->gateway_ports == -1)
1682                 options->gateway_ports = 0;
1683         if (options->use_privileged_port == -1)
1684                 options->use_privileged_port = 0;
1685         if (options->rsa_authentication == -1)
1686                 options->rsa_authentication = 1;
1687         if (options->pubkey_authentication == -1)
1688                 options->pubkey_authentication = 1;
1689         if (options->challenge_response_authentication == -1)
1690                 options->challenge_response_authentication = 1;
1691         if (options->gss_authentication == -1)
1692                 options->gss_authentication = 0;
1693         if (options->gss_deleg_creds == -1)
1694                 options->gss_deleg_creds = 0;
1695         if (options->password_authentication == -1)
1696                 options->password_authentication = 1;
1697         if (options->kbd_interactive_authentication == -1)
1698                 options->kbd_interactive_authentication = 1;
1699         if (options->rhosts_rsa_authentication == -1)
1700                 options->rhosts_rsa_authentication = 0;
1701         if (options->hostbased_authentication == -1)
1702                 options->hostbased_authentication = 0;
1703         if (options->batch_mode == -1)
1704                 options->batch_mode = 0;
1705         if (options->check_host_ip == -1)
1706                 options->check_host_ip = 0;
1707         if (options->strict_host_key_checking == -1)
1708                 options->strict_host_key_checking = 2;  /* 2 is default */
1709         if (options->compression == -1)
1710                 options->compression = 0;
1711         if (options->tcp_keep_alive == -1)
1712                 options->tcp_keep_alive = 1;
1713         if (options->compression_level == -1)
1714                 options->compression_level = 6;
1715         if (options->port == -1)
1716                 options->port = 0;      /* Filled in ssh_connect. */
1717         if (options->address_family == -1)
1718                 options->address_family = AF_UNSPEC;
1719         if (options->connection_attempts == -1)
1720                 options->connection_attempts = 1;
1721         if (options->number_of_password_prompts == -1)
1722                 options->number_of_password_prompts = 3;
1723         /* Selected in ssh_login(). */
1724         if (options->cipher == -1)
1725                 options->cipher = SSH_CIPHER_NOT_SET;
1726         /* options->ciphers, default set in myproposals.h */
1727         /* options->macs, default set in myproposals.h */
1728         /* options->kex_algorithms, default set in myproposals.h */
1729         /* options->hostkeyalgorithms, default set in myproposals.h */
1730         if (options->protocol == SSH_PROTO_UNKNOWN)
1731                 options->protocol = SSH_PROTO_2;
1732         if (options->num_identity_files == 0) {
1733                 if (options->protocol & SSH_PROTO_1) {
1734                         add_identity_file(options, "~/",
1735                             _PATH_SSH_CLIENT_IDENTITY, 0);
1736                 }
1737                 if (options->protocol & SSH_PROTO_2) {
1738                         add_identity_file(options, "~/",
1739                             _PATH_SSH_CLIENT_ID_RSA, 0);
1740                         add_identity_file(options, "~/",
1741                             _PATH_SSH_CLIENT_ID_DSA, 0);
1742 #ifdef OPENSSL_HAS_ECC
1743                         add_identity_file(options, "~/",
1744                             _PATH_SSH_CLIENT_ID_ECDSA, 0);
1745 #endif
1746                         add_identity_file(options, "~/",
1747                             _PATH_SSH_CLIENT_ID_ED25519, 0);
1748                 }
1749         }
1750         if (options->escape_char == -1)
1751                 options->escape_char = '~';
1752         if (options->num_system_hostfiles == 0) {
1753                 options->system_hostfiles[options->num_system_hostfiles++] =
1754                     xstrdup(_PATH_SSH_SYSTEM_HOSTFILE);
1755                 options->system_hostfiles[options->num_system_hostfiles++] =
1756                     xstrdup(_PATH_SSH_SYSTEM_HOSTFILE2);
1757         }
1758         if (options->num_user_hostfiles == 0) {
1759                 options->user_hostfiles[options->num_user_hostfiles++] =
1760                     xstrdup(_PATH_SSH_USER_HOSTFILE);
1761                 options->user_hostfiles[options->num_user_hostfiles++] =
1762                     xstrdup(_PATH_SSH_USER_HOSTFILE2);
1763         }
1764         if (options->log_level == SYSLOG_LEVEL_NOT_SET)
1765                 options->log_level = SYSLOG_LEVEL_INFO;
1766         if (options->clear_forwardings == 1)
1767                 clear_forwardings(options);
1768         if (options->no_host_authentication_for_localhost == - 1)
1769                 options->no_host_authentication_for_localhost = 0;
1770         if (options->identities_only == -1)
1771                 options->identities_only = 0;
1772         if (options->enable_ssh_keysign == -1)
1773                 options->enable_ssh_keysign = 0;
1774         if (options->rekey_limit == -1)
1775                 options->rekey_limit = 0;
1776         if (options->rekey_interval == -1)
1777                 options->rekey_interval = 0;
1778 #if HAVE_LDNS
1779         if (options->verify_host_key_dns == -1)
1780                 /* automatically trust a verified SSHFP record */
1781                 options->verify_host_key_dns = 1;
1782 #else
1783         if (options->verify_host_key_dns == -1)
1784                 options->verify_host_key_dns = 0;
1785 #endif
1786         if (options->server_alive_interval == -1)
1787                 options->server_alive_interval = 0;
1788         if (options->server_alive_count_max == -1)
1789                 options->server_alive_count_max = 3;
1790         if (options->control_master == -1)
1791                 options->control_master = 0;
1792         if (options->control_persist == -1) {
1793                 options->control_persist = 0;
1794                 options->control_persist_timeout = 0;
1795         }
1796         if (options->hash_known_hosts == -1)
1797                 options->hash_known_hosts = 0;
1798         if (options->tun_open == -1)
1799                 options->tun_open = SSH_TUNMODE_NO;
1800         if (options->tun_local == -1)
1801                 options->tun_local = SSH_TUNID_ANY;
1802         if (options->tun_remote == -1)
1803                 options->tun_remote = SSH_TUNID_ANY;
1804         if (options->permit_local_command == -1)
1805                 options->permit_local_command = 0;
1806         if (options->use_roaming == -1)
1807                 options->use_roaming = 1;
1808         if (options->visual_host_key == -1)
1809                 options->visual_host_key = 0;
1810         if (options->zero_knowledge_password_authentication == -1)
1811                 options->zero_knowledge_password_authentication = 0;
1812         if (options->ip_qos_interactive == -1)
1813                 options->ip_qos_interactive = IPTOS_LOWDELAY;
1814         if (options->ip_qos_bulk == -1)
1815                 options->ip_qos_bulk = IPTOS_THROUGHPUT;
1816         if (options->request_tty == -1)
1817                 options->request_tty = REQUEST_TTY_AUTO;
1818         if (options->proxy_use_fdpass == -1)
1819                 options->proxy_use_fdpass = 0;
1820         if (options->canonicalize_max_dots == -1)
1821                 options->canonicalize_max_dots = 1;
1822         if (options->canonicalize_fallback_local == -1)
1823                 options->canonicalize_fallback_local = 1;
1824         if (options->canonicalize_hostname == -1)
1825                 options->canonicalize_hostname = SSH_CANONICALISE_NO;
1826 #define CLEAR_ON_NONE(v) \
1827         do { \
1828                 if (v != NULL && strcasecmp(v, "none") == 0) { \
1829                         free(v); \
1830                         v = NULL; \
1831                 } \
1832         } while(0)
1833         CLEAR_ON_NONE(options->local_command);
1834         CLEAR_ON_NONE(options->proxy_command);
1835         CLEAR_ON_NONE(options->control_path);
1836         /* options->user will be set in the main program if appropriate */
1837         /* options->hostname will be set in the main program if appropriate */
1838         /* options->host_key_alias should not be set by default */
1839         /* options->preferred_authentications will be set in ssh */
1840         if (options->version_addendum == NULL)
1841                 options->version_addendum = xstrdup(SSH_VERSION_FREEBSD);
1842         if (options->hpn_disabled == -1)
1843                 options->hpn_disabled = 0;
1844         if (options->hpn_buffer_size > -1)
1845         {
1846                 u_int maxlen;
1847
1848                 /* If a user tries to set the size to 0 set it to 1KB. */
1849                 if (options->hpn_buffer_size == 0)
1850                         options->hpn_buffer_size = 1024;
1851                 /* Limit the buffer to BUFFER_MAX_LEN. */
1852                 maxlen = buffer_get_max_len();
1853                 if (options->hpn_buffer_size > (maxlen / 1024)) {
1854                         debug("User requested buffer larger than %ub: %ub. "
1855                             "Request reverted to %ub", maxlen,
1856                             options->hpn_buffer_size * 1024, maxlen);
1857                         options->hpn_buffer_size = maxlen;
1858                 }
1859                 debug("hpn_buffer_size set to %d", options->hpn_buffer_size);
1860         }
1861         if (options->tcp_rcv_buf == 0)
1862                 options->tcp_rcv_buf = 1;
1863         if (options->tcp_rcv_buf > -1)
1864                 options->tcp_rcv_buf *= 1024;
1865         if (options->tcp_rcv_buf_poll == -1)
1866                 options->tcp_rcv_buf_poll = 1;
1867 #ifdef  NONE_CIPHER_ENABLED
1868         /* options->none_enabled must not be set by default */
1869         if (options->none_switch == -1)
1870                 options->none_switch = 0;
1871 #endif
1872 }
1873
1874 /*
1875  * parse_forward
1876  * parses a string containing a port forwarding specification of the form:
1877  *   dynamicfwd == 0
1878  *      [listenhost:]listenport:connecthost:connectport
1879  *   dynamicfwd == 1
1880  *      [listenhost:]listenport
1881  * returns number of arguments parsed or zero on error
1882  */
1883 int
1884 parse_forward(Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
1885 {
1886         int i;
1887         char *p, *cp, *fwdarg[4];
1888
1889         memset(fwd, '\0', sizeof(*fwd));
1890
1891         cp = p = xstrdup(fwdspec);
1892
1893         /* skip leading spaces */
1894         while (isspace((u_char)*cp))
1895                 cp++;
1896
1897         for (i = 0; i < 4; ++i)
1898                 if ((fwdarg[i] = hpdelim(&cp)) == NULL)
1899                         break;
1900
1901         /* Check for trailing garbage */
1902         if (cp != NULL)
1903                 i = 0;  /* failure */
1904
1905         switch (i) {
1906         case 1:
1907                 fwd->listen_host = NULL;
1908                 fwd->listen_port = a2port(fwdarg[0]);
1909                 fwd->connect_host = xstrdup("socks");
1910                 break;
1911
1912         case 2:
1913                 fwd->listen_host = xstrdup(cleanhostname(fwdarg[0]));
1914                 fwd->listen_port = a2port(fwdarg[1]);
1915                 fwd->connect_host = xstrdup("socks");
1916                 break;
1917
1918         case 3:
1919                 fwd->listen_host = NULL;
1920                 fwd->listen_port = a2port(fwdarg[0]);
1921                 fwd->connect_host = xstrdup(cleanhostname(fwdarg[1]));
1922                 fwd->connect_port = a2port(fwdarg[2]);
1923                 break;
1924
1925         case 4:
1926                 fwd->listen_host = xstrdup(cleanhostname(fwdarg[0]));
1927                 fwd->listen_port = a2port(fwdarg[1]);
1928                 fwd->connect_host = xstrdup(cleanhostname(fwdarg[2]));
1929                 fwd->connect_port = a2port(fwdarg[3]);
1930                 break;
1931         default:
1932                 i = 0; /* failure */
1933         }
1934
1935         free(p);
1936
1937         if (dynamicfwd) {
1938                 if (!(i == 1 || i == 2))
1939                         goto fail_free;
1940         } else {
1941                 if (!(i == 3 || i == 4))
1942                         goto fail_free;
1943                 if (fwd->connect_port <= 0)
1944                         goto fail_free;
1945         }
1946
1947         if (fwd->listen_port < 0 || (!remotefwd && fwd->listen_port == 0))
1948                 goto fail_free;
1949
1950         if (fwd->connect_host != NULL &&
1951             strlen(fwd->connect_host) >= NI_MAXHOST)
1952                 goto fail_free;
1953         if (fwd->listen_host != NULL &&
1954             strlen(fwd->listen_host) >= NI_MAXHOST)
1955                 goto fail_free;
1956
1957
1958         return (i);
1959
1960  fail_free:
1961         free(fwd->connect_host);
1962         fwd->connect_host = NULL;
1963         free(fwd->listen_host);
1964         fwd->listen_host = NULL;
1965         return (0);
1966 }