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