Import OpenSSH-6.7p1.
[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
60 /* Format of the configuration file:
61
62    # Configuration data is parsed as follows:
63    #  1. command line options
64    #  2. user-specific file
65    #  3. system-wide file
66    # Any configuration value is only changed the first time it is set.
67    # Thus, host-specific definitions should be at the beginning of the
68    # configuration file, and defaults at the end.
69
70    # Host-specific declarations.  These may override anything above.  A single
71    # host may match multiple declarations; these are processed in the order
72    # that they are given in.
73
74    Host *.ngs.fi ngs.fi
75      User foo
76
77    Host fake.com
78      HostName another.host.name.real.org
79      User blaah
80      Port 34289
81      ForwardX11 no
82      ForwardAgent no
83
84    Host books.com
85      RemoteForward 9999 shadows.cs.hut.fi:9999
86      Cipher 3des
87
88    Host fascist.blob.com
89      Port 23123
90      User tylonen
91      PasswordAuthentication no
92
93    Host puukko.hut.fi
94      User t35124p
95      ProxyCommand ssh-proxy %h %p
96
97    Host *.fr
98      PublicKeyAuthentication no
99
100    Host *.su
101      Cipher none
102      PasswordAuthentication no
103
104    Host vpn.fake.com
105      Tunnel yes
106      TunnelDevice 3
107
108    # Defaults for various options
109    Host *
110      ForwardAgent no
111      ForwardX11 no
112      PasswordAuthentication yes
113      RSAAuthentication yes
114      RhostsRSAAuthentication yes
115      StrictHostKeyChecking yes
116      TcpKeepAlive no
117      IdentityFile ~/.ssh/identity
118      Port 22
119      EscapeChar ~
120
121 */
122
123 /* Keyword tokens. */
124
125 typedef enum {
126         oBadOption,
127         oHost, oMatch,
128         oForwardAgent, oForwardX11, oForwardX11Trusted, oForwardX11Timeout,
129         oGatewayPorts, oExitOnForwardFailure,
130         oPasswordAuthentication, oRSAAuthentication,
131         oChallengeResponseAuthentication, oXAuthLocation,
132         oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward,
133         oUser, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
134         oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
135         oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
136         oCompressionLevel, oTCPKeepAlive, oNumberOfPasswordPrompts,
137         oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oMacs,
138         oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication,
139         oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
140         oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
141         oHostKeyAlgorithms, oBindAddress, oPKCS11Provider,
142         oClearAllForwardings, oNoHostAuthenticationForLocalhost,
143         oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
144         oAddressFamily, oGssAuthentication, oGssDelegateCreds,
145         oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
146         oSendEnv, oControlPath, oControlMaster, oControlPersist,
147         oHashKnownHosts,
148         oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand,
149         oVisualHostKey, oUseRoaming,
150         oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass,
151         oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots,
152         oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs,
153         oStreamLocalBindMask, oStreamLocalBindUnlink,
154         oIgnoredUnknownOption, oDeprecated, oUnsupported
155 } OpCodes;
156
157 /* Textual representations of the tokens. */
158
159 static struct {
160         const char *name;
161         OpCodes opcode;
162 } keywords[] = {
163         { "forwardagent", oForwardAgent },
164         { "forwardx11", oForwardX11 },
165         { "forwardx11trusted", oForwardX11Trusted },
166         { "forwardx11timeout", oForwardX11Timeout },
167         { "exitonforwardfailure", oExitOnForwardFailure },
168         { "xauthlocation", oXAuthLocation },
169         { "gatewayports", oGatewayPorts },
170         { "useprivilegedport", oUsePrivilegedPort },
171         { "rhostsauthentication", oDeprecated },
172         { "passwordauthentication", oPasswordAuthentication },
173         { "kbdinteractiveauthentication", oKbdInteractiveAuthentication },
174         { "kbdinteractivedevices", oKbdInteractiveDevices },
175         { "rsaauthentication", oRSAAuthentication },
176         { "pubkeyauthentication", oPubkeyAuthentication },
177         { "dsaauthentication", oPubkeyAuthentication },             /* alias */
178         { "rhostsrsaauthentication", oRhostsRSAAuthentication },
179         { "hostbasedauthentication", oHostbasedAuthentication },
180         { "challengeresponseauthentication", oChallengeResponseAuthentication },
181         { "skeyauthentication", oChallengeResponseAuthentication }, /* alias */
182         { "tisauthentication", oChallengeResponseAuthentication },  /* alias */
183         { "kerberosauthentication", oUnsupported },
184         { "kerberostgtpassing", oUnsupported },
185         { "afstokenpassing", oUnsupported },
186 #if defined(GSSAPI)
187         { "gssapiauthentication", oGssAuthentication },
188         { "gssapidelegatecredentials", oGssDelegateCreds },
189 #else
190         { "gssapiauthentication", oUnsupported },
191         { "gssapidelegatecredentials", oUnsupported },
192 #endif
193         { "fallbacktorsh", oDeprecated },
194         { "usersh", oDeprecated },
195         { "identityfile", oIdentityFile },
196         { "identityfile2", oIdentityFile },                     /* obsolete */
197         { "identitiesonly", oIdentitiesOnly },
198         { "hostname", oHostName },
199         { "hostkeyalias", oHostKeyAlias },
200         { "proxycommand", oProxyCommand },
201         { "port", oPort },
202         { "cipher", oCipher },
203         { "ciphers", oCiphers },
204         { "macs", oMacs },
205         { "protocol", oProtocol },
206         { "remoteforward", oRemoteForward },
207         { "localforward", oLocalForward },
208         { "user", oUser },
209         { "host", oHost },
210         { "match", oMatch },
211         { "escapechar", oEscapeChar },
212         { "globalknownhostsfile", oGlobalKnownHostsFile },
213         { "globalknownhostsfile2", oDeprecated },
214         { "userknownhostsfile", oUserKnownHostsFile },
215         { "userknownhostsfile2", oDeprecated }, 
216         { "connectionattempts", oConnectionAttempts },
217         { "batchmode", oBatchMode },
218         { "checkhostip", oCheckHostIP },
219         { "stricthostkeychecking", oStrictHostKeyChecking },
220         { "compression", oCompression },
221         { "compressionlevel", oCompressionLevel },
222         { "tcpkeepalive", oTCPKeepAlive },
223         { "keepalive", oTCPKeepAlive },                         /* obsolete */
224         { "numberofpasswordprompts", oNumberOfPasswordPrompts },
225         { "loglevel", oLogLevel },
226         { "dynamicforward", oDynamicForward },
227         { "preferredauthentications", oPreferredAuthentications },
228         { "hostkeyalgorithms", oHostKeyAlgorithms },
229         { "bindaddress", oBindAddress },
230 #ifdef ENABLE_PKCS11
231         { "smartcarddevice", oPKCS11Provider },
232         { "pkcs11provider", oPKCS11Provider },
233 #else
234         { "smartcarddevice", oUnsupported },
235         { "pkcs11provider", oUnsupported },
236 #endif
237         { "clearallforwardings", oClearAllForwardings },
238         { "enablesshkeysign", oEnableSSHKeysign },
239         { "verifyhostkeydns", oVerifyHostKeyDNS },
240         { "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
241         { "rekeylimit", oRekeyLimit },
242         { "connecttimeout", oConnectTimeout },
243         { "addressfamily", oAddressFamily },
244         { "serveraliveinterval", oServerAliveInterval },
245         { "serveralivecountmax", oServerAliveCountMax },
246         { "sendenv", oSendEnv },
247         { "controlpath", oControlPath },
248         { "controlmaster", oControlMaster },
249         { "controlpersist", oControlPersist },
250         { "hashknownhosts", oHashKnownHosts },
251         { "tunnel", oTunnel },
252         { "tunneldevice", oTunnelDevice },
253         { "localcommand", oLocalCommand },
254         { "permitlocalcommand", oPermitLocalCommand },
255         { "visualhostkey", oVisualHostKey },
256         { "useroaming", oUseRoaming },
257         { "kexalgorithms", oKexAlgorithms },
258         { "ipqos", oIPQoS },
259         { "requesttty", oRequestTTY },
260         { "proxyusefdpass", oProxyUseFdpass },
261         { "canonicaldomains", oCanonicalDomains },
262         { "canonicalizefallbacklocal", oCanonicalizeFallbackLocal },
263         { "canonicalizehostname", oCanonicalizeHostname },
264         { "canonicalizemaxdots", oCanonicalizeMaxDots },
265         { "canonicalizepermittedcnames", oCanonicalizePermittedCNAMEs },
266         { "streamlocalbindmask", oStreamLocalBindMask },
267         { "streamlocalbindunlink", oStreamLocalBindUnlink },
268         { "ignoreunknown", oIgnoreUnknown },
269
270         { NULL, oBadOption }
271 };
272
273 /*
274  * Adds a local TCP/IP port forward to options.  Never returns if there is an
275  * error.
276  */
277
278 void
279 add_local_forward(Options *options, const struct Forward *newfwd)
280 {
281         struct Forward *fwd;
282 #ifndef NO_IPPORT_RESERVED_CONCEPT
283         extern uid_t original_real_uid;
284         if (newfwd->listen_port < IPPORT_RESERVED && original_real_uid != 0 &&
285             newfwd->listen_path == NULL)
286                 fatal("Privileged ports can only be forwarded by root.");
287 #endif
288         options->local_forwards = xrealloc(options->local_forwards,
289             options->num_local_forwards + 1,
290             sizeof(*options->local_forwards));
291         fwd = &options->local_forwards[options->num_local_forwards++];
292
293         fwd->listen_host = newfwd->listen_host;
294         fwd->listen_port = newfwd->listen_port;
295         fwd->listen_path = newfwd->listen_path;
296         fwd->connect_host = newfwd->connect_host;
297         fwd->connect_port = newfwd->connect_port;
298         fwd->connect_path = newfwd->connect_path;
299 }
300
301 /*
302  * Adds a remote TCP/IP port forward to options.  Never returns if there is
303  * an error.
304  */
305
306 void
307 add_remote_forward(Options *options, const struct Forward *newfwd)
308 {
309         struct Forward *fwd;
310
311         options->remote_forwards = xrealloc(options->remote_forwards,
312             options->num_remote_forwards + 1,
313             sizeof(*options->remote_forwards));
314         fwd = &options->remote_forwards[options->num_remote_forwards++];
315
316         fwd->listen_host = newfwd->listen_host;
317         fwd->listen_port = newfwd->listen_port;
318         fwd->listen_path = newfwd->listen_path;
319         fwd->connect_host = newfwd->connect_host;
320         fwd->connect_port = newfwd->connect_port;
321         fwd->connect_path = newfwd->connect_path;
322         fwd->handle = newfwd->handle;
323         fwd->allocated_port = 0;
324 }
325
326 static void
327 clear_forwardings(Options *options)
328 {
329         int i;
330
331         for (i = 0; i < options->num_local_forwards; i++) {
332                 free(options->local_forwards[i].listen_host);
333                 free(options->local_forwards[i].listen_path);
334                 free(options->local_forwards[i].connect_host);
335                 free(options->local_forwards[i].connect_path);
336         }
337         if (options->num_local_forwards > 0) {
338                 free(options->local_forwards);
339                 options->local_forwards = NULL;
340         }
341         options->num_local_forwards = 0;
342         for (i = 0; i < options->num_remote_forwards; i++) {
343                 free(options->remote_forwards[i].listen_host);
344                 free(options->remote_forwards[i].listen_path);
345                 free(options->remote_forwards[i].connect_host);
346                 free(options->remote_forwards[i].connect_path);
347         }
348         if (options->num_remote_forwards > 0) {
349                 free(options->remote_forwards);
350                 options->remote_forwards = NULL;
351         }
352         options->num_remote_forwards = 0;
353         options->tun_open = SSH_TUNMODE_NO;
354 }
355
356 void
357 add_identity_file(Options *options, const char *dir, const char *filename,
358     int userprovided)
359 {
360         char *path;
361         int i;
362
363         if (options->num_identity_files >= SSH_MAX_IDENTITY_FILES)
364                 fatal("Too many identity files specified (max %d)",
365                     SSH_MAX_IDENTITY_FILES);
366
367         if (dir == NULL) /* no dir, filename is absolute */
368                 path = xstrdup(filename);
369         else
370                 (void)xasprintf(&path, "%.100s%.100s", dir, filename);
371
372         /* Avoid registering duplicates */
373         for (i = 0; i < options->num_identity_files; i++) {
374                 if (options->identity_file_userprovided[i] == userprovided &&
375                     strcmp(options->identity_files[i], path) == 0) {
376                         debug2("%s: ignoring duplicate key %s", __func__, path);
377                         free(path);
378                         return;
379                 }
380         }
381
382         options->identity_file_userprovided[options->num_identity_files] =
383             userprovided;
384         options->identity_files[options->num_identity_files++] = path;
385 }
386
387 int
388 default_ssh_port(void)
389 {
390         static int port;
391         struct servent *sp;
392
393         if (port == 0) {
394                 sp = getservbyname(SSH_SERVICE_NAME, "tcp");
395                 port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT;
396         }
397         return port;
398 }
399
400 /*
401  * Execute a command in a shell.
402  * Return its exit status or -1 on abnormal exit.
403  */
404 static int
405 execute_in_shell(const char *cmd)
406 {
407         char *shell, *command_string;
408         pid_t pid;
409         int devnull, status;
410         extern uid_t original_real_uid;
411
412         if ((shell = getenv("SHELL")) == NULL)
413                 shell = _PATH_BSHELL;
414
415         /*
416          * Use "exec" to avoid "sh -c" processes on some platforms
417          * (e.g. Solaris)
418          */
419         xasprintf(&command_string, "exec %s", cmd);
420
421         /* Need this to redirect subprocess stdin/out */
422         if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1)
423                 fatal("open(/dev/null): %s", strerror(errno));
424
425         debug("Executing command: '%.500s'", cmd);
426
427         /* Fork and execute the command. */
428         if ((pid = fork()) == 0) {
429                 char *argv[4];
430
431                 /* Child.  Permanently give up superuser privileges. */
432                 permanently_drop_suid(original_real_uid);
433
434                 /* Redirect child stdin and stdout. Leave stderr */
435                 if (dup2(devnull, STDIN_FILENO) == -1)
436                         fatal("dup2: %s", strerror(errno));
437                 if (dup2(devnull, STDOUT_FILENO) == -1)
438                         fatal("dup2: %s", strerror(errno));
439                 if (devnull > STDERR_FILENO)
440                         close(devnull);
441                 closefrom(STDERR_FILENO + 1);
442
443                 argv[0] = shell;
444                 argv[1] = "-c";
445                 argv[2] = command_string;
446                 argv[3] = NULL;
447
448                 execv(argv[0], argv);
449                 error("Unable to execute '%.100s': %s", cmd, strerror(errno));
450                 /* Die with signal to make this error apparent to parent. */
451                 signal(SIGTERM, SIG_DFL);
452                 kill(getpid(), SIGTERM);
453                 _exit(1);
454         }
455         /* Parent. */
456         if (pid < 0)
457                 fatal("%s: fork: %.100s", __func__, strerror(errno));
458
459         close(devnull);
460         free(command_string);
461
462         while (waitpid(pid, &status, 0) == -1) {
463                 if (errno != EINTR && errno != EAGAIN)
464                         fatal("%s: waitpid: %s", __func__, strerror(errno));
465         }
466         if (!WIFEXITED(status)) {
467                 error("command '%.100s' exited abnormally", cmd);
468                 return -1;
469         } 
470         debug3("command returned status %d", WEXITSTATUS(status));
471         return WEXITSTATUS(status);
472 }
473
474 /*
475  * Parse and execute a Match directive.
476  */
477 static int
478 match_cfg_line(Options *options, char **condition, struct passwd *pw,
479     const char *host_arg, const char *filename, int linenum)
480 {
481         char *arg, *attrib, *cmd, *cp = *condition, *host;
482         const char *ruser;
483         int r, port, result = 1, attributes = 0;
484         size_t len;
485         char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV];
486
487         /*
488          * Configuration is likely to be incomplete at this point so we
489          * must be prepared to use default values.
490          */
491         port = options->port <= 0 ? default_ssh_port() : options->port;
492         ruser = options->user == NULL ? pw->pw_name : options->user;
493         if (options->hostname != NULL) {
494                 /* NB. Please keep in sync with ssh.c:main() */
495                 host = percent_expand(options->hostname,
496                     "h", host_arg, (char *)NULL);
497         } else
498                 host = xstrdup(host_arg);
499
500         debug3("checking match for '%s' host %s", cp, host);
501         while ((attrib = strdelim(&cp)) && *attrib != '\0') {
502                 attributes++;
503                 if (strcasecmp(attrib, "all") == 0) {
504                         if (attributes != 1 ||
505                             ((arg = strdelim(&cp)) != NULL && *arg != '\0')) {
506                                 error("'all' cannot be combined with other "
507                                     "Match attributes");
508                                 result = -1;
509                                 goto out;
510                         }
511                         *condition = cp;
512                         result = 1;
513                         goto out;
514                 }
515                 if ((arg = strdelim(&cp)) == NULL || *arg == '\0') {
516                         error("Missing Match criteria for %s", attrib);
517                         result = -1;
518                         goto out;
519                 }
520                 len = strlen(arg);
521                 if (strcasecmp(attrib, "host") == 0) {
522                         if (match_hostname(host, arg, len) != 1)
523                                 result = 0;
524                         else
525                                 debug("%.200s line %d: matched 'Host %.100s' ",
526                                     filename, linenum, host);
527                 } else if (strcasecmp(attrib, "originalhost") == 0) {
528                         if (match_hostname(host_arg, arg, len) != 1)
529                                 result = 0;
530                         else
531                                 debug("%.200s line %d: matched "
532                                     "'OriginalHost %.100s' ",
533                                     filename, linenum, host_arg);
534                 } else if (strcasecmp(attrib, "user") == 0) {
535                         if (match_pattern_list(ruser, arg, len, 0) != 1)
536                                 result = 0;
537                         else
538                                 debug("%.200s line %d: matched 'User %.100s' ",
539                                     filename, linenum, ruser);
540                 } else if (strcasecmp(attrib, "localuser") == 0) {
541                         if (match_pattern_list(pw->pw_name, arg, len, 0) != 1)
542                                 result = 0;
543                         else
544                                 debug("%.200s line %d: matched "
545                                     "'LocalUser %.100s' ",
546                                     filename, linenum, pw->pw_name);
547                 } else if (strcasecmp(attrib, "exec") == 0) {
548                         if (gethostname(thishost, sizeof(thishost)) == -1)
549                                 fatal("gethostname: %s", strerror(errno));
550                         strlcpy(shorthost, thishost, sizeof(shorthost));
551                         shorthost[strcspn(thishost, ".")] = '\0';
552                         snprintf(portstr, sizeof(portstr), "%d", port);
553
554                         cmd = percent_expand(arg,
555                             "L", shorthost,
556                             "d", pw->pw_dir,
557                             "h", host,
558                             "l", thishost,
559                             "n", host_arg,
560                             "p", portstr,
561                             "r", ruser,
562                             "u", pw->pw_name,
563                             (char *)NULL);
564                         if (result != 1) {
565                                 /* skip execution if prior predicate failed */
566                                 debug("%.200s line %d: skipped exec \"%.100s\"",
567                                     filename, linenum, cmd);
568                         } else {
569                                 r = execute_in_shell(cmd);
570                                 if (r == -1) {
571                                         fatal("%.200s line %d: match exec "
572                                             "'%.100s' error", filename,
573                                             linenum, cmd);
574                                 } else if (r == 0) {
575                                         debug("%.200s line %d: matched "
576                                             "'exec \"%.100s\"'", filename,
577                                             linenum, cmd);
578                                 } else {
579                                         debug("%.200s line %d: no match "
580                                             "'exec \"%.100s\"'", filename,
581                                             linenum, cmd);
582                                         result = 0;
583                                 }
584                         }
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         struct 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->fwd_opts.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 oKbdInteractiveAuthentication:
837                 intptr = &options->kbd_interactive_authentication;
838                 goto parse_flag;
839
840         case oKbdInteractiveDevices:
841                 charptr = &options->kbd_interactive_devices;
842                 goto parse_string;
843
844         case oPubkeyAuthentication:
845                 intptr = &options->pubkey_authentication;
846                 goto parse_flag;
847
848         case oRSAAuthentication:
849                 intptr = &options->rsa_authentication;
850                 goto parse_flag;
851
852         case oRhostsRSAAuthentication:
853                 intptr = &options->rhosts_rsa_authentication;
854                 goto parse_flag;
855
856         case oHostbasedAuthentication:
857                 intptr = &options->hostbased_authentication;
858                 goto parse_flag;
859
860         case oChallengeResponseAuthentication:
861                 intptr = &options->challenge_response_authentication;
862                 goto parse_flag;
863
864         case oGssAuthentication:
865                 intptr = &options->gss_authentication;
866                 goto parse_flag;
867
868         case oGssDelegateCreds:
869                 intptr = &options->gss_deleg_creds;
870                 goto parse_flag;
871
872         case oBatchMode:
873                 intptr = &options->batch_mode;
874                 goto parse_flag;
875
876         case oCheckHostIP:
877                 intptr = &options->check_host_ip;
878                 goto parse_flag;
879
880         case oVerifyHostKeyDNS:
881                 intptr = &options->verify_host_key_dns;
882                 multistate_ptr = multistate_yesnoask;
883                 goto parse_multistate;
884
885         case oStrictHostKeyChecking:
886                 intptr = &options->strict_host_key_checking;
887                 multistate_ptr = multistate_yesnoask;
888                 goto parse_multistate;
889
890         case oCompression:
891                 intptr = &options->compression;
892                 goto parse_flag;
893
894         case oTCPKeepAlive:
895                 intptr = &options->tcp_keep_alive;
896                 goto parse_flag;
897
898         case oNoHostAuthenticationForLocalhost:
899                 intptr = &options->no_host_authentication_for_localhost;
900                 goto parse_flag;
901
902         case oNumberOfPasswordPrompts:
903                 intptr = &options->number_of_password_prompts;
904                 goto parse_int;
905
906         case oCompressionLevel:
907                 intptr = &options->compression_level;
908                 goto parse_int;
909
910         case oRekeyLimit:
911                 arg = strdelim(&s);
912                 if (!arg || *arg == '\0')
913                         fatal("%.200s line %d: Missing argument.", filename,
914                             linenum);
915                 if (strcmp(arg, "default") == 0) {
916                         val64 = 0;
917                 } else {
918                         if (scan_scaled(arg, &val64) == -1)
919                                 fatal("%.200s line %d: Bad number '%s': %s",
920                                     filename, linenum, arg, strerror(errno));
921                         /* check for too-large or too-small limits */
922                         if (val64 > UINT_MAX)
923                                 fatal("%.200s line %d: RekeyLimit too large",
924                                     filename, linenum);
925                         if (val64 != 0 && val64 < 16)
926                                 fatal("%.200s line %d: RekeyLimit too small",
927                                     filename, linenum);
928                 }
929                 if (*activep && options->rekey_limit == -1)
930                         options->rekey_limit = (u_int32_t)val64;
931                 if (s != NULL) { /* optional rekey interval present */
932                         if (strcmp(s, "none") == 0) {
933                                 (void)strdelim(&s);     /* discard */
934                                 break;
935                         }
936                         intptr = &options->rekey_interval;
937                         goto parse_time;
938                 }
939                 break;
940
941         case oIdentityFile:
942                 arg = strdelim(&s);
943                 if (!arg || *arg == '\0')
944                         fatal("%.200s line %d: Missing argument.", filename, linenum);
945                 if (*activep) {
946                         intptr = &options->num_identity_files;
947                         if (*intptr >= SSH_MAX_IDENTITY_FILES)
948                                 fatal("%.200s line %d: Too many identity files specified (max %d).",
949                                     filename, linenum, SSH_MAX_IDENTITY_FILES);
950                         add_identity_file(options, NULL, arg, userconfig);
951                 }
952                 break;
953
954         case oXAuthLocation:
955                 charptr=&options->xauth_location;
956                 goto parse_string;
957
958         case oUser:
959                 charptr = &options->user;
960 parse_string:
961                 arg = strdelim(&s);
962                 if (!arg || *arg == '\0')
963                         fatal("%.200s line %d: Missing argument.",
964                             filename, linenum);
965                 if (*activep && *charptr == NULL)
966                         *charptr = xstrdup(arg);
967                 break;
968
969         case oGlobalKnownHostsFile:
970                 cpptr = (char **)&options->system_hostfiles;
971                 uintptr = &options->num_system_hostfiles;
972                 max_entries = SSH_MAX_HOSTS_FILES;
973 parse_char_array:
974                 if (*activep && *uintptr == 0) {
975                         while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
976                                 if ((*uintptr) >= max_entries)
977                                         fatal("%s line %d: "
978                                             "too many authorized keys files.",
979                                             filename, linenum);
980                                 cpptr[(*uintptr)++] = xstrdup(arg);
981                         }
982                 }
983                 return 0;
984
985         case oUserKnownHostsFile:
986                 cpptr = (char **)&options->user_hostfiles;
987                 uintptr = &options->num_user_hostfiles;
988                 max_entries = SSH_MAX_HOSTS_FILES;
989                 goto parse_char_array;
990
991         case oHostName:
992                 charptr = &options->hostname;
993                 goto parse_string;
994
995         case oHostKeyAlias:
996                 charptr = &options->host_key_alias;
997                 goto parse_string;
998
999         case oPreferredAuthentications:
1000                 charptr = &options->preferred_authentications;
1001                 goto parse_string;
1002
1003         case oBindAddress:
1004                 charptr = &options->bind_address;
1005                 goto parse_string;
1006
1007         case oPKCS11Provider:
1008                 charptr = &options->pkcs11_provider;
1009                 goto parse_string;
1010
1011         case oProxyCommand:
1012                 charptr = &options->proxy_command;
1013 parse_command:
1014                 if (s == NULL)
1015                         fatal("%.200s line %d: Missing argument.", filename, linenum);
1016                 len = strspn(s, WHITESPACE "=");
1017                 if (*activep && *charptr == NULL)
1018                         *charptr = xstrdup(s + len);
1019                 return 0;
1020
1021         case oPort:
1022                 intptr = &options->port;
1023 parse_int:
1024                 arg = strdelim(&s);
1025                 if (!arg || *arg == '\0')
1026                         fatal("%.200s line %d: Missing argument.", filename, linenum);
1027                 if (arg[0] < '0' || arg[0] > '9')
1028                         fatal("%.200s line %d: Bad number.", filename, linenum);
1029
1030                 /* Octal, decimal, or hex format? */
1031                 value = strtol(arg, &endofnumber, 0);
1032                 if (arg == endofnumber)
1033                         fatal("%.200s line %d: Bad number.", filename, linenum);
1034                 if (*activep && *intptr == -1)
1035                         *intptr = value;
1036                 break;
1037
1038         case oConnectionAttempts:
1039                 intptr = &options->connection_attempts;
1040                 goto parse_int;
1041
1042         case oCipher:
1043                 intptr = &options->cipher;
1044                 arg = strdelim(&s);
1045                 if (!arg || *arg == '\0')
1046                         fatal("%.200s line %d: Missing argument.", filename, linenum);
1047                 value = cipher_number(arg);
1048                 if (value == -1)
1049                         fatal("%.200s line %d: Bad cipher '%s'.",
1050                             filename, linenum, arg ? arg : "<NONE>");
1051                 if (*activep && *intptr == -1)
1052                         *intptr = value;
1053                 break;
1054
1055         case oCiphers:
1056                 arg = strdelim(&s);
1057                 if (!arg || *arg == '\0')
1058                         fatal("%.200s line %d: Missing argument.", filename, linenum);
1059                 if (!ciphers_valid(arg))
1060                         fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.",
1061                             filename, linenum, arg ? arg : "<NONE>");
1062                 if (*activep && options->ciphers == NULL)
1063                         options->ciphers = xstrdup(arg);
1064                 break;
1065
1066         case oMacs:
1067                 arg = strdelim(&s);
1068                 if (!arg || *arg == '\0')
1069                         fatal("%.200s line %d: Missing argument.", filename, linenum);
1070                 if (!mac_valid(arg))
1071                         fatal("%.200s line %d: Bad SSH2 Mac spec '%s'.",
1072                             filename, linenum, arg ? arg : "<NONE>");
1073                 if (*activep && options->macs == NULL)
1074                         options->macs = xstrdup(arg);
1075                 break;
1076
1077         case oKexAlgorithms:
1078                 arg = strdelim(&s);
1079                 if (!arg || *arg == '\0')
1080                         fatal("%.200s line %d: Missing argument.",
1081                             filename, linenum);
1082                 if (!kex_names_valid(arg))
1083                         fatal("%.200s line %d: Bad SSH2 KexAlgorithms '%s'.",
1084                             filename, linenum, arg ? arg : "<NONE>");
1085                 if (*activep && options->kex_algorithms == NULL)
1086                         options->kex_algorithms = xstrdup(arg);
1087                 break;
1088
1089         case oHostKeyAlgorithms:
1090                 arg = strdelim(&s);
1091                 if (!arg || *arg == '\0')
1092                         fatal("%.200s line %d: Missing argument.", filename, linenum);
1093                 if (!key_names_valid2(arg))
1094                         fatal("%.200s line %d: Bad protocol 2 host key algorithms '%s'.",
1095                             filename, linenum, arg ? arg : "<NONE>");
1096                 if (*activep && options->hostkeyalgorithms == NULL)
1097                         options->hostkeyalgorithms = xstrdup(arg);
1098                 break;
1099
1100         case oProtocol:
1101                 intptr = &options->protocol;
1102                 arg = strdelim(&s);
1103                 if (!arg || *arg == '\0')
1104                         fatal("%.200s line %d: Missing argument.", filename, linenum);
1105                 value = proto_spec(arg);
1106                 if (value == SSH_PROTO_UNKNOWN)
1107                         fatal("%.200s line %d: Bad protocol spec '%s'.",
1108                             filename, linenum, arg ? arg : "<NONE>");
1109                 if (*activep && *intptr == SSH_PROTO_UNKNOWN)
1110                         *intptr = value;
1111                 break;
1112
1113         case oLogLevel:
1114                 log_level_ptr = &options->log_level;
1115                 arg = strdelim(&s);
1116                 value = log_level_number(arg);
1117                 if (value == SYSLOG_LEVEL_NOT_SET)
1118                         fatal("%.200s line %d: unsupported log level '%s'",
1119                             filename, linenum, arg ? arg : "<NONE>");
1120                 if (*activep && *log_level_ptr == SYSLOG_LEVEL_NOT_SET)
1121                         *log_level_ptr = (LogLevel) value;
1122                 break;
1123
1124         case oLocalForward:
1125         case oRemoteForward:
1126         case oDynamicForward:
1127                 arg = strdelim(&s);
1128                 if (arg == NULL || *arg == '\0')
1129                         fatal("%.200s line %d: Missing port argument.",
1130                             filename, linenum);
1131
1132                 if (opcode == oLocalForward ||
1133                     opcode == oRemoteForward) {
1134                         arg2 = strdelim(&s);
1135                         if (arg2 == NULL || *arg2 == '\0')
1136                                 fatal("%.200s line %d: Missing target argument.",
1137                                     filename, linenum);
1138
1139                         /* construct a string for parse_forward */
1140                         snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg, arg2);
1141                 } else if (opcode == oDynamicForward) {
1142                         strlcpy(fwdarg, arg, sizeof(fwdarg));
1143                 }
1144
1145                 if (parse_forward(&fwd, fwdarg,
1146                     opcode == oDynamicForward ? 1 : 0,
1147                     opcode == oRemoteForward ? 1 : 0) == 0)
1148                         fatal("%.200s line %d: Bad forwarding specification.",
1149                             filename, linenum);
1150
1151                 if (*activep) {
1152                         if (opcode == oLocalForward ||
1153                             opcode == oDynamicForward)
1154                                 add_local_forward(options, &fwd);
1155                         else if (opcode == oRemoteForward)
1156                                 add_remote_forward(options, &fwd);
1157                 }
1158                 break;
1159
1160         case oClearAllForwardings:
1161                 intptr = &options->clear_forwardings;
1162                 goto parse_flag;
1163
1164         case oHost:
1165                 if (cmdline)
1166                         fatal("Host directive not supported as a command-line "
1167                             "option");
1168                 *activep = 0;
1169                 arg2 = NULL;
1170                 while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1171                         negated = *arg == '!';
1172                         if (negated)
1173                                 arg++;
1174                         if (match_pattern(host, arg)) {
1175                                 if (negated) {
1176                                         debug("%.200s line %d: Skipping Host "
1177                                             "block because of negated match "
1178                                             "for %.100s", filename, linenum,
1179                                             arg);
1180                                         *activep = 0;
1181                                         break;
1182                                 }
1183                                 if (!*activep)
1184                                         arg2 = arg; /* logged below */
1185                                 *activep = 1;
1186                         }
1187                 }
1188                 if (*activep)
1189                         debug("%.200s line %d: Applying options for %.100s",
1190                             filename, linenum, arg2);
1191                 /* Avoid garbage check below, as strdelim is done. */
1192                 return 0;
1193
1194         case oMatch:
1195                 if (cmdline)
1196                         fatal("Host directive not supported as a command-line "
1197                             "option");
1198                 value = match_cfg_line(options, &s, pw, host,
1199                     filename, linenum);
1200                 if (value < 0)
1201                         fatal("%.200s line %d: Bad Match condition", filename,
1202                             linenum);
1203                 *activep = value;
1204                 break;
1205
1206         case oEscapeChar:
1207                 intptr = &options->escape_char;
1208                 arg = strdelim(&s);
1209                 if (!arg || *arg == '\0')
1210                         fatal("%.200s line %d: Missing argument.", filename, linenum);
1211                 if (arg[0] == '^' && arg[2] == 0 &&
1212                     (u_char) arg[1] >= 64 && (u_char) arg[1] < 128)
1213                         value = (u_char) arg[1] & 31;
1214                 else if (strlen(arg) == 1)
1215                         value = (u_char) arg[0];
1216                 else if (strcmp(arg, "none") == 0)
1217                         value = SSH_ESCAPECHAR_NONE;
1218                 else {
1219                         fatal("%.200s line %d: Bad escape character.",
1220                             filename, linenum);
1221                         /* NOTREACHED */
1222                         value = 0;      /* Avoid compiler warning. */
1223                 }
1224                 if (*activep && *intptr == -1)
1225                         *intptr = value;
1226                 break;
1227
1228         case oAddressFamily:
1229                 intptr = &options->address_family;
1230                 multistate_ptr = multistate_addressfamily;
1231                 goto parse_multistate;
1232
1233         case oEnableSSHKeysign:
1234                 intptr = &options->enable_ssh_keysign;
1235                 goto parse_flag;
1236
1237         case oIdentitiesOnly:
1238                 intptr = &options->identities_only;
1239                 goto parse_flag;
1240
1241         case oServerAliveInterval:
1242                 intptr = &options->server_alive_interval;
1243                 goto parse_time;
1244
1245         case oServerAliveCountMax:
1246                 intptr = &options->server_alive_count_max;
1247                 goto parse_int;
1248
1249         case oSendEnv:
1250                 while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1251                         if (strchr(arg, '=') != NULL)
1252                                 fatal("%s line %d: Invalid environment name.",
1253                                     filename, linenum);
1254                         if (!*activep)
1255                                 continue;
1256                         if (options->num_send_env >= MAX_SEND_ENV)
1257                                 fatal("%s line %d: too many send env.",
1258                                     filename, linenum);
1259                         options->send_env[options->num_send_env++] =
1260                             xstrdup(arg);
1261                 }
1262                 break;
1263
1264         case oControlPath:
1265                 charptr = &options->control_path;
1266                 goto parse_string;
1267
1268         case oControlMaster:
1269                 intptr = &options->control_master;
1270                 multistate_ptr = multistate_controlmaster;
1271                 goto parse_multistate;
1272
1273         case oControlPersist:
1274                 /* no/false/yes/true, or a time spec */
1275                 intptr = &options->control_persist;
1276                 arg = strdelim(&s);
1277                 if (!arg || *arg == '\0')
1278                         fatal("%.200s line %d: Missing ControlPersist"
1279                             " argument.", filename, linenum);
1280                 value = 0;
1281                 value2 = 0;     /* timeout */
1282                 if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
1283                         value = 0;
1284                 else if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
1285                         value = 1;
1286                 else if ((value2 = convtime(arg)) >= 0)
1287                         value = 1;
1288                 else
1289                         fatal("%.200s line %d: Bad ControlPersist argument.",
1290                             filename, linenum);
1291                 if (*activep && *intptr == -1) {
1292                         *intptr = value;
1293                         options->control_persist_timeout = value2;
1294                 }
1295                 break;
1296
1297         case oHashKnownHosts:
1298                 intptr = &options->hash_known_hosts;
1299                 goto parse_flag;
1300
1301         case oTunnel:
1302                 intptr = &options->tun_open;
1303                 multistate_ptr = multistate_tunnel;
1304                 goto parse_multistate;
1305
1306         case oTunnelDevice:
1307                 arg = strdelim(&s);
1308                 if (!arg || *arg == '\0')
1309                         fatal("%.200s line %d: Missing argument.", filename, linenum);
1310                 value = a2tun(arg, &value2);
1311                 if (value == SSH_TUNID_ERR)
1312                         fatal("%.200s line %d: Bad tun device.", filename, linenum);
1313                 if (*activep) {
1314                         options->tun_local = value;
1315                         options->tun_remote = value2;
1316                 }
1317                 break;
1318
1319         case oLocalCommand:
1320                 charptr = &options->local_command;
1321                 goto parse_command;
1322
1323         case oPermitLocalCommand:
1324                 intptr = &options->permit_local_command;
1325                 goto parse_flag;
1326
1327         case oVisualHostKey:
1328                 intptr = &options->visual_host_key;
1329                 goto parse_flag;
1330
1331         case oIPQoS:
1332                 arg = strdelim(&s);
1333                 if ((value = parse_ipqos(arg)) == -1)
1334                         fatal("%s line %d: Bad IPQoS value: %s",
1335                             filename, linenum, arg);
1336                 arg = strdelim(&s);
1337                 if (arg == NULL)
1338                         value2 = value;
1339                 else if ((value2 = parse_ipqos(arg)) == -1)
1340                         fatal("%s line %d: Bad IPQoS value: %s",
1341                             filename, linenum, arg);
1342                 if (*activep) {
1343                         options->ip_qos_interactive = value;
1344                         options->ip_qos_bulk = value2;
1345                 }
1346                 break;
1347
1348         case oUseRoaming:
1349                 intptr = &options->use_roaming;
1350                 goto parse_flag;
1351
1352         case oRequestTTY:
1353                 intptr = &options->request_tty;
1354                 multistate_ptr = multistate_requesttty;
1355                 goto parse_multistate;
1356
1357         case oIgnoreUnknown:
1358                 charptr = &options->ignored_unknown;
1359                 goto parse_string;
1360
1361         case oProxyUseFdpass:
1362                 intptr = &options->proxy_use_fdpass;
1363                 goto parse_flag;
1364
1365         case oCanonicalDomains:
1366                 value = options->num_canonical_domains != 0;
1367                 while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1368                         valid_domain(arg, filename, linenum);
1369                         if (!*activep || value)
1370                                 continue;
1371                         if (options->num_canonical_domains >= MAX_CANON_DOMAINS)
1372                                 fatal("%s line %d: too many hostname suffixes.",
1373                                     filename, linenum);
1374                         options->canonical_domains[
1375                             options->num_canonical_domains++] = xstrdup(arg);
1376                 }
1377                 break;
1378
1379         case oCanonicalizePermittedCNAMEs:
1380                 value = options->num_permitted_cnames != 0;
1381                 while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1382                         /* Either '*' for everything or 'list:list' */
1383                         if (strcmp(arg, "*") == 0)
1384                                 arg2 = arg;
1385                         else {
1386                                 lowercase(arg);
1387                                 if ((arg2 = strchr(arg, ':')) == NULL ||
1388                                     arg2[1] == '\0') {
1389                                         fatal("%s line %d: "
1390                                             "Invalid permitted CNAME \"%s\"",
1391                                             filename, linenum, arg);
1392                                 }
1393                                 *arg2 = '\0';
1394                                 arg2++;
1395                         }
1396                         if (!*activep || value)
1397                                 continue;
1398                         if (options->num_permitted_cnames >= MAX_CANON_DOMAINS)
1399                                 fatal("%s line %d: too many permitted CNAMEs.",
1400                                     filename, linenum);
1401                         cname = options->permitted_cnames +
1402                             options->num_permitted_cnames++;
1403                         cname->source_list = xstrdup(arg);
1404                         cname->target_list = xstrdup(arg2);
1405                 }
1406                 break;
1407
1408         case oCanonicalizeHostname:
1409                 intptr = &options->canonicalize_hostname;
1410                 multistate_ptr = multistate_canonicalizehostname;
1411                 goto parse_multistate;
1412
1413         case oCanonicalizeMaxDots:
1414                 intptr = &options->canonicalize_max_dots;
1415                 goto parse_int;
1416
1417         case oCanonicalizeFallbackLocal:
1418                 intptr = &options->canonicalize_fallback_local;
1419                 goto parse_flag;
1420
1421         case oStreamLocalBindMask:
1422                 arg = strdelim(&s);
1423                 if (!arg || *arg == '\0')
1424                         fatal("%.200s line %d: Missing StreamLocalBindMask argument.", filename, linenum);
1425                 /* Parse mode in octal format */
1426                 value = strtol(arg, &endofnumber, 8);
1427                 if (arg == endofnumber || value < 0 || value > 0777)
1428                         fatal("%.200s line %d: Bad mask.", filename, linenum);
1429                 options->fwd_opts.streamlocal_bind_mask = (mode_t)value;
1430                 break;
1431
1432         case oStreamLocalBindUnlink:
1433                 intptr = &options->fwd_opts.streamlocal_bind_unlink;
1434                 goto parse_flag;
1435
1436         case oDeprecated:
1437                 debug("%s line %d: Deprecated option \"%s\"",
1438                     filename, linenum, keyword);
1439                 return 0;
1440
1441         case oUnsupported:
1442                 error("%s line %d: Unsupported option \"%s\"",
1443                     filename, linenum, keyword);
1444                 return 0;
1445
1446         default:
1447                 fatal("process_config_line: Unimplemented opcode %d", opcode);
1448         }
1449
1450         /* Check that there is no garbage at end of line. */
1451         if ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1452                 fatal("%.200s line %d: garbage at end of line; \"%.200s\".",
1453                     filename, linenum, arg);
1454         }
1455         return 0;
1456 }
1457
1458
1459 /*
1460  * Reads the config file and modifies the options accordingly.  Options
1461  * should already be initialized before this call.  This never returns if
1462  * there is an error.  If the file does not exist, this returns 0.
1463  */
1464
1465 int
1466 read_config_file(const char *filename, struct passwd *pw, const char *host,
1467     Options *options, int flags)
1468 {
1469         FILE *f;
1470         char line[1024];
1471         int active, linenum;
1472         int bad_options = 0;
1473
1474         if ((f = fopen(filename, "r")) == NULL)
1475                 return 0;
1476
1477         if (flags & SSHCONF_CHECKPERM) {
1478                 struct stat sb;
1479
1480                 if (fstat(fileno(f), &sb) == -1)
1481                         fatal("fstat %s: %s", filename, strerror(errno));
1482                 if (((sb.st_uid != 0 && sb.st_uid != getuid()) ||
1483                     (sb.st_mode & 022) != 0))
1484                         fatal("Bad owner or permissions on %s", filename);
1485         }
1486
1487         debug("Reading configuration data %.200s", filename);
1488
1489         /*
1490          * Mark that we are now processing the options.  This flag is turned
1491          * on/off by Host specifications.
1492          */
1493         active = 1;
1494         linenum = 0;
1495         while (fgets(line, sizeof(line), f)) {
1496                 /* Update line number counter. */
1497                 linenum++;
1498                 if (process_config_line(options, pw, host, line, filename,
1499                     linenum, &active, flags & SSHCONF_USERCONF) != 0)
1500                         bad_options++;
1501         }
1502         fclose(f);
1503         if (bad_options > 0)
1504                 fatal("%s: terminating, %d bad configuration options",
1505                     filename, bad_options);
1506         return 1;
1507 }
1508
1509 /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */
1510 int
1511 option_clear_or_none(const char *o)
1512 {
1513         return o == NULL || strcasecmp(o, "none") == 0;
1514 }
1515
1516 /*
1517  * Initializes options to special values that indicate that they have not yet
1518  * been set.  Read_config_file will only set options with this value. Options
1519  * are processed in the following order: command line, user config file,
1520  * system config file.  Last, fill_default_options is called.
1521  */
1522
1523 void
1524 initialize_options(Options * options)
1525 {
1526         memset(options, 'X', sizeof(*options));
1527         options->forward_agent = -1;
1528         options->forward_x11 = -1;
1529         options->forward_x11_trusted = -1;
1530         options->forward_x11_timeout = -1;
1531         options->exit_on_forward_failure = -1;
1532         options->xauth_location = NULL;
1533         options->fwd_opts.gateway_ports = -1;
1534         options->fwd_opts.streamlocal_bind_mask = (mode_t)-1;
1535         options->fwd_opts.streamlocal_bind_unlink = -1;
1536         options->use_privileged_port = -1;
1537         options->rsa_authentication = -1;
1538         options->pubkey_authentication = -1;
1539         options->challenge_response_authentication = -1;
1540         options->gss_authentication = -1;
1541         options->gss_deleg_creds = -1;
1542         options->password_authentication = -1;
1543         options->kbd_interactive_authentication = -1;
1544         options->kbd_interactive_devices = NULL;
1545         options->rhosts_rsa_authentication = -1;
1546         options->hostbased_authentication = -1;
1547         options->batch_mode = -1;
1548         options->check_host_ip = -1;
1549         options->strict_host_key_checking = -1;
1550         options->compression = -1;
1551         options->tcp_keep_alive = -1;
1552         options->compression_level = -1;
1553         options->port = -1;
1554         options->address_family = -1;
1555         options->connection_attempts = -1;
1556         options->connection_timeout = -1;
1557         options->number_of_password_prompts = -1;
1558         options->cipher = -1;
1559         options->ciphers = NULL;
1560         options->macs = NULL;
1561         options->kex_algorithms = NULL;
1562         options->hostkeyalgorithms = NULL;
1563         options->protocol = SSH_PROTO_UNKNOWN;
1564         options->num_identity_files = 0;
1565         options->hostname = NULL;
1566         options->host_key_alias = NULL;
1567         options->proxy_command = NULL;
1568         options->user = NULL;
1569         options->escape_char = -1;
1570         options->num_system_hostfiles = 0;
1571         options->num_user_hostfiles = 0;
1572         options->local_forwards = NULL;
1573         options->num_local_forwards = 0;
1574         options->remote_forwards = NULL;
1575         options->num_remote_forwards = 0;
1576         options->clear_forwardings = -1;
1577         options->log_level = SYSLOG_LEVEL_NOT_SET;
1578         options->preferred_authentications = NULL;
1579         options->bind_address = NULL;
1580         options->pkcs11_provider = NULL;
1581         options->enable_ssh_keysign = - 1;
1582         options->no_host_authentication_for_localhost = - 1;
1583         options->identities_only = - 1;
1584         options->rekey_limit = - 1;
1585         options->rekey_interval = -1;
1586         options->verify_host_key_dns = -1;
1587         options->server_alive_interval = -1;
1588         options->server_alive_count_max = -1;
1589         options->num_send_env = 0;
1590         options->control_path = NULL;
1591         options->control_master = -1;
1592         options->control_persist = -1;
1593         options->control_persist_timeout = 0;
1594         options->hash_known_hosts = -1;
1595         options->tun_open = -1;
1596         options->tun_local = -1;
1597         options->tun_remote = -1;
1598         options->local_command = NULL;
1599         options->permit_local_command = -1;
1600         options->use_roaming = -1;
1601         options->visual_host_key = -1;
1602         options->ip_qos_interactive = -1;
1603         options->ip_qos_bulk = -1;
1604         options->request_tty = -1;
1605         options->proxy_use_fdpass = -1;
1606         options->ignored_unknown = NULL;
1607         options->num_canonical_domains = 0;
1608         options->num_permitted_cnames = 0;
1609         options->canonicalize_max_dots = -1;
1610         options->canonicalize_fallback_local = -1;
1611         options->canonicalize_hostname = -1;
1612 }
1613
1614 /*
1615  * A petite version of fill_default_options() that just fills the options
1616  * needed for hostname canonicalization to proceed.
1617  */
1618 void
1619 fill_default_options_for_canonicalization(Options *options)
1620 {
1621         if (options->canonicalize_max_dots == -1)
1622                 options->canonicalize_max_dots = 1;
1623         if (options->canonicalize_fallback_local == -1)
1624                 options->canonicalize_fallback_local = 1;
1625         if (options->canonicalize_hostname == -1)
1626                 options->canonicalize_hostname = SSH_CANONICALISE_NO;
1627 }
1628
1629 /*
1630  * Called after processing other sources of option data, this fills those
1631  * options for which no value has been specified with their default values.
1632  */
1633 void
1634 fill_default_options(Options * options)
1635 {
1636         if (options->forward_agent == -1)
1637                 options->forward_agent = 0;
1638         if (options->forward_x11 == -1)
1639                 options->forward_x11 = 0;
1640         if (options->forward_x11_trusted == -1)
1641                 options->forward_x11_trusted = 0;
1642         if (options->forward_x11_timeout == -1)
1643                 options->forward_x11_timeout = 1200;
1644         if (options->exit_on_forward_failure == -1)
1645                 options->exit_on_forward_failure = 0;
1646         if (options->xauth_location == NULL)
1647                 options->xauth_location = _PATH_XAUTH;
1648         if (options->fwd_opts.gateway_ports == -1)
1649                 options->fwd_opts.gateway_ports = 0;
1650         if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1)
1651                 options->fwd_opts.streamlocal_bind_mask = 0177;
1652         if (options->fwd_opts.streamlocal_bind_unlink == -1)
1653                 options->fwd_opts.streamlocal_bind_unlink = 0;
1654         if (options->use_privileged_port == -1)
1655                 options->use_privileged_port = 0;
1656         if (options->rsa_authentication == -1)
1657                 options->rsa_authentication = 1;
1658         if (options->pubkey_authentication == -1)
1659                 options->pubkey_authentication = 1;
1660         if (options->challenge_response_authentication == -1)
1661                 options->challenge_response_authentication = 1;
1662         if (options->gss_authentication == -1)
1663                 options->gss_authentication = 0;
1664         if (options->gss_deleg_creds == -1)
1665                 options->gss_deleg_creds = 0;
1666         if (options->password_authentication == -1)
1667                 options->password_authentication = 1;
1668         if (options->kbd_interactive_authentication == -1)
1669                 options->kbd_interactive_authentication = 1;
1670         if (options->rhosts_rsa_authentication == -1)
1671                 options->rhosts_rsa_authentication = 0;
1672         if (options->hostbased_authentication == -1)
1673                 options->hostbased_authentication = 0;
1674         if (options->batch_mode == -1)
1675                 options->batch_mode = 0;
1676         if (options->check_host_ip == -1)
1677                 options->check_host_ip = 1;
1678         if (options->strict_host_key_checking == -1)
1679                 options->strict_host_key_checking = 2;  /* 2 is default */
1680         if (options->compression == -1)
1681                 options->compression = 0;
1682         if (options->tcp_keep_alive == -1)
1683                 options->tcp_keep_alive = 1;
1684         if (options->compression_level == -1)
1685                 options->compression_level = 6;
1686         if (options->port == -1)
1687                 options->port = 0;      /* Filled in ssh_connect. */
1688         if (options->address_family == -1)
1689                 options->address_family = AF_UNSPEC;
1690         if (options->connection_attempts == -1)
1691                 options->connection_attempts = 1;
1692         if (options->number_of_password_prompts == -1)
1693                 options->number_of_password_prompts = 3;
1694         /* Selected in ssh_login(). */
1695         if (options->cipher == -1)
1696                 options->cipher = SSH_CIPHER_NOT_SET;
1697         /* options->ciphers, default set in myproposals.h */
1698         /* options->macs, default set in myproposals.h */
1699         /* options->kex_algorithms, default set in myproposals.h */
1700         /* options->hostkeyalgorithms, default set in myproposals.h */
1701         if (options->protocol == SSH_PROTO_UNKNOWN)
1702                 options->protocol = SSH_PROTO_2;
1703         if (options->num_identity_files == 0) {
1704                 if (options->protocol & SSH_PROTO_1) {
1705                         add_identity_file(options, "~/",
1706                             _PATH_SSH_CLIENT_IDENTITY, 0);
1707                 }
1708                 if (options->protocol & SSH_PROTO_2) {
1709                         add_identity_file(options, "~/",
1710                             _PATH_SSH_CLIENT_ID_RSA, 0);
1711                         add_identity_file(options, "~/",
1712                             _PATH_SSH_CLIENT_ID_DSA, 0);
1713 #ifdef OPENSSL_HAS_ECC
1714                         add_identity_file(options, "~/",
1715                             _PATH_SSH_CLIENT_ID_ECDSA, 0);
1716 #endif
1717                         add_identity_file(options, "~/",
1718                             _PATH_SSH_CLIENT_ID_ED25519, 0);
1719                 }
1720         }
1721         if (options->escape_char == -1)
1722                 options->escape_char = '~';
1723         if (options->num_system_hostfiles == 0) {
1724                 options->system_hostfiles[options->num_system_hostfiles++] =
1725                     xstrdup(_PATH_SSH_SYSTEM_HOSTFILE);
1726                 options->system_hostfiles[options->num_system_hostfiles++] =
1727                     xstrdup(_PATH_SSH_SYSTEM_HOSTFILE2);
1728         }
1729         if (options->num_user_hostfiles == 0) {
1730                 options->user_hostfiles[options->num_user_hostfiles++] =
1731                     xstrdup(_PATH_SSH_USER_HOSTFILE);
1732                 options->user_hostfiles[options->num_user_hostfiles++] =
1733                     xstrdup(_PATH_SSH_USER_HOSTFILE2);
1734         }
1735         if (options->log_level == SYSLOG_LEVEL_NOT_SET)
1736                 options->log_level = SYSLOG_LEVEL_INFO;
1737         if (options->clear_forwardings == 1)
1738                 clear_forwardings(options);
1739         if (options->no_host_authentication_for_localhost == - 1)
1740                 options->no_host_authentication_for_localhost = 0;
1741         if (options->identities_only == -1)
1742                 options->identities_only = 0;
1743         if (options->enable_ssh_keysign == -1)
1744                 options->enable_ssh_keysign = 0;
1745         if (options->rekey_limit == -1)
1746                 options->rekey_limit = 0;
1747         if (options->rekey_interval == -1)
1748                 options->rekey_interval = 0;
1749         if (options->verify_host_key_dns == -1)
1750                 options->verify_host_key_dns = 0;
1751         if (options->server_alive_interval == -1)
1752                 options->server_alive_interval = 0;
1753         if (options->server_alive_count_max == -1)
1754                 options->server_alive_count_max = 3;
1755         if (options->control_master == -1)
1756                 options->control_master = 0;
1757         if (options->control_persist == -1) {
1758                 options->control_persist = 0;
1759                 options->control_persist_timeout = 0;
1760         }
1761         if (options->hash_known_hosts == -1)
1762                 options->hash_known_hosts = 0;
1763         if (options->tun_open == -1)
1764                 options->tun_open = SSH_TUNMODE_NO;
1765         if (options->tun_local == -1)
1766                 options->tun_local = SSH_TUNID_ANY;
1767         if (options->tun_remote == -1)
1768                 options->tun_remote = SSH_TUNID_ANY;
1769         if (options->permit_local_command == -1)
1770                 options->permit_local_command = 0;
1771         if (options->use_roaming == -1)
1772                 options->use_roaming = 1;
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 }