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