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