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