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