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