1 /* $OpenBSD: readconf.c,v 1.187 2010/07/19 09:15:12 djm Exp $ */ 2 /* 3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 5 * All rights reserved 6 * Functions for reading the configuration files. 7 * 8 * As far as I am concerned, the code I have written for this software 9 * can be used freely for any purpose. Any derived versions of this 10 * software must be clearly marked as such, and if the derived work is 11 * incompatible with the protocol description in the RFC file, it must be 12 * called by a name other than "ssh" or "Secure Shell". 13 */ 14 15 #include "includes.h" 16 __RCSID("$FreeBSD$"); 17 18 #include <sys/types.h> 19 #include <sys/stat.h> 20 #include <sys/socket.h> 21 #include <sys/sysctl.h> 22 23 #include <netinet/in.h> 24 25 #include <ctype.h> 26 #include <errno.h> 27 #include <netdb.h> 28 #include <signal.h> 29 #include <stdarg.h> 30 #include <stdio.h> 31 #include <string.h> 32 #include <unistd.h> 33 34 #include "xmalloc.h" 35 #include "ssh.h" 36 #include "compat.h" 37 #include "cipher.h" 38 #include "pathnames.h" 39 #include "log.h" 40 #include "key.h" 41 #include "readconf.h" 42 #include "match.h" 43 #include "misc.h" 44 #include "buffer.h" 45 #include "kex.h" 46 #include "mac.h" 47 #include "version.h" 48 49 /* Format of the configuration file: 50 51 # Configuration data is parsed as follows: 52 # 1. command line options 53 # 2. user-specific file 54 # 3. system-wide file 55 # Any configuration value is only changed the first time it is set. 56 # Thus, host-specific definitions should be at the beginning of the 57 # configuration file, and defaults at the end. 58 59 # Host-specific declarations. These may override anything above. A single 60 # host may match multiple declarations; these are processed in the order 61 # that they are given in. 62 63 Host *.ngs.fi ngs.fi 64 User foo 65 66 Host fake.com 67 HostName another.host.name.real.org 68 User blaah 69 Port 34289 70 ForwardX11 no 71 ForwardAgent no 72 73 Host books.com 74 RemoteForward 9999 shadows.cs.hut.fi:9999 75 Cipher 3des 76 77 Host fascist.blob.com 78 Port 23123 79 User tylonen 80 PasswordAuthentication no 81 82 Host puukko.hut.fi 83 User t35124p 84 ProxyCommand ssh-proxy %h %p 85 86 Host *.fr 87 PublicKeyAuthentication no 88 89 Host *.su 90 Cipher none 91 PasswordAuthentication no 92 93 Host vpn.fake.com 94 Tunnel yes 95 TunnelDevice 3 96 97 # Defaults for various options 98 Host * 99 ForwardAgent no 100 ForwardX11 no 101 PasswordAuthentication yes 102 RSAAuthentication yes 103 RhostsRSAAuthentication yes 104 StrictHostKeyChecking yes 105 TcpKeepAlive no 106 IdentityFile ~/.ssh/identity 107 Port 22 108 EscapeChar ~ 109 110 */ 111 112 /* Keyword tokens. */ 113 114 typedef enum { 115 oBadOption, 116 oForwardAgent, oForwardX11, oForwardX11Trusted, oForwardX11Timeout, 117 oGatewayPorts, oExitOnForwardFailure, 118 oPasswordAuthentication, oRSAAuthentication, 119 oChallengeResponseAuthentication, oXAuthLocation, 120 oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward, 121 oUser, oHost, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand, 122 oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts, 123 oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression, 124 oCompressionLevel, oTCPKeepAlive, oNumberOfPasswordPrompts, 125 oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oMacs, 126 oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication, 127 oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias, 128 oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication, 129 oHostKeyAlgorithms, oBindAddress, oPKCS11Provider, 130 oClearAllForwardings, oNoHostAuthenticationForLocalhost, 131 oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, 132 oAddressFamily, oGssAuthentication, oGssDelegateCreds, 133 oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, 134 oSendEnv, oControlPath, oControlMaster, oControlPersist, 135 oHashKnownHosts, 136 oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand, 137 oVisualHostKey, oUseRoaming, oZeroKnowledgePasswordAuthentication, 138 oVersionAddendum, 139 oDeprecated, oUnsupported 140 } OpCodes; 141 142 /* Textual representations of the tokens. */ 143 144 static struct { 145 const char *name; 146 OpCodes opcode; 147 } keywords[] = { 148 { "forwardagent", oForwardAgent }, 149 { "forwardx11", oForwardX11 }, 150 { "forwardx11trusted", oForwardX11Trusted }, 151 { "forwardx11timeout", oForwardX11Timeout }, 152 { "exitonforwardfailure", oExitOnForwardFailure }, 153 { "xauthlocation", oXAuthLocation }, 154 { "gatewayports", oGatewayPorts }, 155 { "useprivilegedport", oUsePrivilegedPort }, 156 { "rhostsauthentication", oDeprecated }, 157 { "passwordauthentication", oPasswordAuthentication }, 158 { "kbdinteractiveauthentication", oKbdInteractiveAuthentication }, 159 { "kbdinteractivedevices", oKbdInteractiveDevices }, 160 { "rsaauthentication", oRSAAuthentication }, 161 { "pubkeyauthentication", oPubkeyAuthentication }, 162 { "dsaauthentication", oPubkeyAuthentication }, /* alias */ 163 { "rhostsrsaauthentication", oRhostsRSAAuthentication }, 164 { "hostbasedauthentication", oHostbasedAuthentication }, 165 { "challengeresponseauthentication", oChallengeResponseAuthentication }, 166 { "skeyauthentication", oChallengeResponseAuthentication }, /* alias */ 167 { "tisauthentication", oChallengeResponseAuthentication }, /* alias */ 168 { "kerberosauthentication", oUnsupported }, 169 { "kerberostgtpassing", oUnsupported }, 170 { "afstokenpassing", oUnsupported }, 171 #if defined(GSSAPI) 172 { "gssapiauthentication", oGssAuthentication }, 173 { "gssapidelegatecredentials", oGssDelegateCreds }, 174 #else 175 { "gssapiauthentication", oUnsupported }, 176 { "gssapidelegatecredentials", oUnsupported }, 177 #endif 178 { "fallbacktorsh", oDeprecated }, 179 { "usersh", oDeprecated }, 180 { "identityfile", oIdentityFile }, 181 { "identityfile2", oIdentityFile }, /* obsolete */ 182 { "identitiesonly", oIdentitiesOnly }, 183 { "hostname", oHostName }, 184 { "hostkeyalias", oHostKeyAlias }, 185 { "proxycommand", oProxyCommand }, 186 { "port", oPort }, 187 { "cipher", oCipher }, 188 { "ciphers", oCiphers }, 189 { "macs", oMacs }, 190 { "protocol", oProtocol }, 191 { "remoteforward", oRemoteForward }, 192 { "localforward", oLocalForward }, 193 { "user", oUser }, 194 { "host", oHost }, 195 { "escapechar", oEscapeChar }, 196 { "globalknownhostsfile", oGlobalKnownHostsFile }, 197 { "globalknownhostsfile2", oGlobalKnownHostsFile2 }, /* obsolete */ 198 { "userknownhostsfile", oUserKnownHostsFile }, 199 { "userknownhostsfile2", oUserKnownHostsFile2 }, /* obsolete */ 200 { "connectionattempts", oConnectionAttempts }, 201 { "batchmode", oBatchMode }, 202 { "checkhostip", oCheckHostIP }, 203 { "stricthostkeychecking", oStrictHostKeyChecking }, 204 { "compression", oCompression }, 205 { "compressionlevel", oCompressionLevel }, 206 { "tcpkeepalive", oTCPKeepAlive }, 207 { "keepalive", oTCPKeepAlive }, /* obsolete */ 208 { "numberofpasswordprompts", oNumberOfPasswordPrompts }, 209 { "loglevel", oLogLevel }, 210 { "dynamicforward", oDynamicForward }, 211 { "preferredauthentications", oPreferredAuthentications }, 212 { "hostkeyalgorithms", oHostKeyAlgorithms }, 213 { "bindaddress", oBindAddress }, 214 #ifdef ENABLE_PKCS11 215 { "smartcarddevice", oPKCS11Provider }, 216 { "pkcs11provider", oPKCS11Provider }, 217 #else 218 { "smartcarddevice", oUnsupported }, 219 { "pkcs11provider", oUnsupported }, 220 #endif 221 { "clearallforwardings", oClearAllForwardings }, 222 { "enablesshkeysign", oEnableSSHKeysign }, 223 { "verifyhostkeydns", oVerifyHostKeyDNS }, 224 { "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost }, 225 { "rekeylimit", oRekeyLimit }, 226 { "connecttimeout", oConnectTimeout }, 227 { "addressfamily", oAddressFamily }, 228 { "serveraliveinterval", oServerAliveInterval }, 229 { "serveralivecountmax", oServerAliveCountMax }, 230 { "sendenv", oSendEnv }, 231 { "controlpath", oControlPath }, 232 { "controlmaster", oControlMaster }, 233 { "controlpersist", oControlPersist }, 234 { "hashknownhosts", oHashKnownHosts }, 235 { "tunnel", oTunnel }, 236 { "tunneldevice", oTunnelDevice }, 237 { "localcommand", oLocalCommand }, 238 { "permitlocalcommand", oPermitLocalCommand }, 239 { "visualhostkey", oVisualHostKey }, 240 { "useroaming", oUseRoaming }, 241 #ifdef JPAKE 242 { "zeroknowledgepasswordauthentication", 243 oZeroKnowledgePasswordAuthentication }, 244 #else 245 { "zeroknowledgepasswordauthentication", oUnsupported }, 246 #endif 247 248 { "versionaddendum", oVersionAddendum }, 249 { NULL, oBadOption } 250 }; 251 252 /* 253 * Adds a local TCP/IP port forward to options. Never returns if there is an 254 * error. 255 */ 256 257 void 258 add_local_forward(Options *options, const Forward *newfwd) 259 { 260 Forward *fwd; 261 #ifndef NO_IPPORT_RESERVED_CONCEPT 262 extern uid_t original_real_uid; 263 int ipport_reserved; 264 #ifdef __FreeBSD__ 265 size_t len_ipport_reserved = sizeof(ipport_reserved); 266 267 if (sysctlbyname("net.inet.ip.portrange.reservedhigh", 268 &ipport_reserved, &len_ipport_reserved, NULL, 0) != 0) 269 ipport_reserved = IPPORT_RESERVED; 270 else 271 ipport_reserved++; 272 #else 273 ipport_reserved = IPPORT_RESERVED; 274 #endif 275 if (newfwd->listen_port < ipport_reserved && original_real_uid != 0) 276 fatal("Privileged ports can only be forwarded by root."); 277 #endif 278 options->local_forwards = xrealloc(options->local_forwards, 279 options->num_local_forwards + 1, 280 sizeof(*options->local_forwards)); 281 fwd = &options->local_forwards[options->num_local_forwards++]; 282 283 fwd->listen_host = newfwd->listen_host; 284 fwd->listen_port = newfwd->listen_port; 285 fwd->connect_host = newfwd->connect_host; 286 fwd->connect_port = newfwd->connect_port; 287 } 288 289 /* 290 * Adds a remote TCP/IP port forward to options. Never returns if there is 291 * an error. 292 */ 293 294 void 295 add_remote_forward(Options *options, const Forward *newfwd) 296 { 297 Forward *fwd; 298 299 options->remote_forwards = xrealloc(options->remote_forwards, 300 options->num_remote_forwards + 1, 301 sizeof(*options->remote_forwards)); 302 fwd = &options->remote_forwards[options->num_remote_forwards++]; 303 304 fwd->listen_host = newfwd->listen_host; 305 fwd->listen_port = newfwd->listen_port; 306 fwd->connect_host = newfwd->connect_host; 307 fwd->connect_port = newfwd->connect_port; 308 fwd->allocated_port = 0; 309 } 310 311 static void 312 clear_forwardings(Options *options) 313 { 314 int i; 315 316 for (i = 0; i < options->num_local_forwards; i++) { 317 if (options->local_forwards[i].listen_host != NULL) 318 xfree(options->local_forwards[i].listen_host); 319 xfree(options->local_forwards[i].connect_host); 320 } 321 if (options->num_local_forwards > 0) { 322 xfree(options->local_forwards); 323 options->local_forwards = NULL; 324 } 325 options->num_local_forwards = 0; 326 for (i = 0; i < options->num_remote_forwards; i++) { 327 if (options->remote_forwards[i].listen_host != NULL) 328 xfree(options->remote_forwards[i].listen_host); 329 xfree(options->remote_forwards[i].connect_host); 330 } 331 if (options->num_remote_forwards > 0) { 332 xfree(options->remote_forwards); 333 options->remote_forwards = NULL; 334 } 335 options->num_remote_forwards = 0; 336 options->tun_open = SSH_TUNMODE_NO; 337 } 338 339 /* 340 * Returns the number of the token pointed to by cp or oBadOption. 341 */ 342 343 static OpCodes 344 parse_token(const char *cp, const char *filename, int linenum) 345 { 346 u_int i; 347 348 for (i = 0; keywords[i].name; i++) 349 if (strcasecmp(cp, keywords[i].name) == 0) 350 return keywords[i].opcode; 351 352 error("%s: line %d: Bad configuration option: %s", 353 filename, linenum, cp); 354 return oBadOption; 355 } 356 357 /* 358 * Processes a single option line as used in the configuration files. This 359 * only sets those values that have not already been set. 360 */ 361 #define WHITESPACE " \t\r\n" 362 363 int 364 process_config_line(Options *options, const char *host, 365 char *line, const char *filename, int linenum, 366 int *activep) 367 { 368 char *s, **charptr, *endofnumber, *keyword, *arg, *arg2, fwdarg[256]; 369 int opcode, *intptr, value, value2, scale; 370 LogLevel *log_level_ptr; 371 long long orig, val64; 372 size_t len; 373 Forward fwd; 374 375 /* Strip trailing whitespace */ 376 for (len = strlen(line) - 1; len > 0; len--) { 377 if (strchr(WHITESPACE, line[len]) == NULL) 378 break; 379 line[len] = '\0'; 380 } 381 382 s = line; 383 /* Get the keyword. (Each line is supposed to begin with a keyword). */ 384 if ((keyword = strdelim(&s)) == NULL) 385 return 0; 386 /* Ignore leading whitespace. */ 387 if (*keyword == '\0') 388 keyword = strdelim(&s); 389 if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#') 390 return 0; 391 392 opcode = parse_token(keyword, filename, linenum); 393 394 switch (opcode) { 395 case oBadOption: 396 /* don't panic, but count bad options */ 397 return -1; 398 /* NOTREACHED */ 399 case oConnectTimeout: 400 intptr = &options->connection_timeout; 401 parse_time: 402 arg = strdelim(&s); 403 if (!arg || *arg == '\0') 404 fatal("%s line %d: missing time value.", 405 filename, linenum); 406 if ((value = convtime(arg)) == -1) 407 fatal("%s line %d: invalid time value.", 408 filename, linenum); 409 if (*activep && *intptr == -1) 410 *intptr = value; 411 break; 412 413 case oForwardAgent: 414 intptr = &options->forward_agent; 415 parse_flag: 416 arg = strdelim(&s); 417 if (!arg || *arg == '\0') 418 fatal("%.200s line %d: Missing yes/no argument.", filename, linenum); 419 value = 0; /* To avoid compiler warning... */ 420 if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0) 421 value = 1; 422 else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0) 423 value = 0; 424 else 425 fatal("%.200s line %d: Bad yes/no argument.", filename, linenum); 426 if (*activep && *intptr == -1) 427 *intptr = value; 428 break; 429 430 case oForwardX11: 431 intptr = &options->forward_x11; 432 goto parse_flag; 433 434 case oForwardX11Trusted: 435 intptr = &options->forward_x11_trusted; 436 goto parse_flag; 437 438 case oForwardX11Timeout: 439 intptr = &options->forward_x11_timeout; 440 goto parse_time; 441 442 case oGatewayPorts: 443 intptr = &options->gateway_ports; 444 goto parse_flag; 445 446 case oExitOnForwardFailure: 447 intptr = &options->exit_on_forward_failure; 448 goto parse_flag; 449 450 case oUsePrivilegedPort: 451 intptr = &options->use_privileged_port; 452 goto parse_flag; 453 454 case oPasswordAuthentication: 455 intptr = &options->password_authentication; 456 goto parse_flag; 457 458 case oZeroKnowledgePasswordAuthentication: 459 intptr = &options->zero_knowledge_password_authentication; 460 goto parse_flag; 461 462 case oKbdInteractiveAuthentication: 463 intptr = &options->kbd_interactive_authentication; 464 goto parse_flag; 465 466 case oKbdInteractiveDevices: 467 charptr = &options->kbd_interactive_devices; 468 goto parse_string; 469 470 case oPubkeyAuthentication: 471 intptr = &options->pubkey_authentication; 472 goto parse_flag; 473 474 case oRSAAuthentication: 475 intptr = &options->rsa_authentication; 476 goto parse_flag; 477 478 case oRhostsRSAAuthentication: 479 intptr = &options->rhosts_rsa_authentication; 480 goto parse_flag; 481 482 case oHostbasedAuthentication: 483 intptr = &options->hostbased_authentication; 484 goto parse_flag; 485 486 case oChallengeResponseAuthentication: 487 intptr = &options->challenge_response_authentication; 488 goto parse_flag; 489 490 case oGssAuthentication: 491 intptr = &options->gss_authentication; 492 goto parse_flag; 493 494 case oGssDelegateCreds: 495 intptr = &options->gss_deleg_creds; 496 goto parse_flag; 497 498 case oBatchMode: 499 intptr = &options->batch_mode; 500 goto parse_flag; 501 502 case oCheckHostIP: 503 intptr = &options->check_host_ip; 504 goto parse_flag; 505 506 case oVerifyHostKeyDNS: 507 intptr = &options->verify_host_key_dns; 508 goto parse_yesnoask; 509 510 case oStrictHostKeyChecking: 511 intptr = &options->strict_host_key_checking; 512 parse_yesnoask: 513 arg = strdelim(&s); 514 if (!arg || *arg == '\0') 515 fatal("%.200s line %d: Missing yes/no/ask argument.", 516 filename, linenum); 517 value = 0; /* To avoid compiler warning... */ 518 if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0) 519 value = 1; 520 else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0) 521 value = 0; 522 else if (strcmp(arg, "ask") == 0) 523 value = 2; 524 else 525 fatal("%.200s line %d: Bad yes/no/ask argument.", filename, linenum); 526 if (*activep && *intptr == -1) 527 *intptr = value; 528 break; 529 530 case oCompression: 531 intptr = &options->compression; 532 goto parse_flag; 533 534 case oTCPKeepAlive: 535 intptr = &options->tcp_keep_alive; 536 goto parse_flag; 537 538 case oNoHostAuthenticationForLocalhost: 539 intptr = &options->no_host_authentication_for_localhost; 540 goto parse_flag; 541 542 case oNumberOfPasswordPrompts: 543 intptr = &options->number_of_password_prompts; 544 goto parse_int; 545 546 case oCompressionLevel: 547 intptr = &options->compression_level; 548 goto parse_int; 549 550 case oRekeyLimit: 551 arg = strdelim(&s); 552 if (!arg || *arg == '\0') 553 fatal("%.200s line %d: Missing argument.", filename, linenum); 554 if (arg[0] < '0' || arg[0] > '9') 555 fatal("%.200s line %d: Bad number.", filename, linenum); 556 orig = val64 = strtoll(arg, &endofnumber, 10); 557 if (arg == endofnumber) 558 fatal("%.200s line %d: Bad number.", filename, linenum); 559 switch (toupper(*endofnumber)) { 560 case '\0': 561 scale = 1; 562 break; 563 case 'K': 564 scale = 1<<10; 565 break; 566 case 'M': 567 scale = 1<<20; 568 break; 569 case 'G': 570 scale = 1<<30; 571 break; 572 default: 573 fatal("%.200s line %d: Invalid RekeyLimit suffix", 574 filename, linenum); 575 } 576 val64 *= scale; 577 /* detect integer wrap and too-large limits */ 578 if ((val64 / scale) != orig || val64 > UINT_MAX) 579 fatal("%.200s line %d: RekeyLimit too large", 580 filename, linenum); 581 if (val64 < 16) 582 fatal("%.200s line %d: RekeyLimit too small", 583 filename, linenum); 584 if (*activep && options->rekey_limit == -1) 585 options->rekey_limit = (u_int32_t)val64; 586 break; 587 588 case oIdentityFile: 589 arg = strdelim(&s); 590 if (!arg || *arg == '\0') 591 fatal("%.200s line %d: Missing argument.", filename, linenum); 592 if (*activep) { 593 intptr = &options->num_identity_files; 594 if (*intptr >= SSH_MAX_IDENTITY_FILES) 595 fatal("%.200s line %d: Too many identity files specified (max %d).", 596 filename, linenum, SSH_MAX_IDENTITY_FILES); 597 charptr = &options->identity_files[*intptr]; 598 *charptr = xstrdup(arg); 599 *intptr = *intptr + 1; 600 } 601 break; 602 603 case oXAuthLocation: 604 charptr=&options->xauth_location; 605 goto parse_string; 606 607 case oUser: 608 charptr = &options->user; 609 parse_string: 610 arg = strdelim(&s); 611 if (!arg || *arg == '\0') 612 fatal("%.200s line %d: Missing argument.", filename, linenum); 613 if (*activep && *charptr == NULL) 614 *charptr = xstrdup(arg); 615 break; 616 617 case oGlobalKnownHostsFile: 618 charptr = &options->system_hostfile; 619 goto parse_string; 620 621 case oUserKnownHostsFile: 622 charptr = &options->user_hostfile; 623 goto parse_string; 624 625 case oGlobalKnownHostsFile2: 626 charptr = &options->system_hostfile2; 627 goto parse_string; 628 629 case oUserKnownHostsFile2: 630 charptr = &options->user_hostfile2; 631 goto parse_string; 632 633 case oHostName: 634 charptr = &options->hostname; 635 goto parse_string; 636 637 case oHostKeyAlias: 638 charptr = &options->host_key_alias; 639 goto parse_string; 640 641 case oPreferredAuthentications: 642 charptr = &options->preferred_authentications; 643 goto parse_string; 644 645 case oBindAddress: 646 charptr = &options->bind_address; 647 goto parse_string; 648 649 case oPKCS11Provider: 650 charptr = &options->pkcs11_provider; 651 goto parse_string; 652 653 case oProxyCommand: 654 charptr = &options->proxy_command; 655 parse_command: 656 if (s == NULL) 657 fatal("%.200s line %d: Missing argument.", filename, linenum); 658 len = strspn(s, WHITESPACE "="); 659 if (*activep && *charptr == NULL) 660 *charptr = xstrdup(s + len); 661 return 0; 662 663 case oPort: 664 intptr = &options->port; 665 parse_int: 666 arg = strdelim(&s); 667 if (!arg || *arg == '\0') 668 fatal("%.200s line %d: Missing argument.", filename, linenum); 669 if (arg[0] < '0' || arg[0] > '9') 670 fatal("%.200s line %d: Bad number.", filename, linenum); 671 672 /* Octal, decimal, or hex format? */ 673 value = strtol(arg, &endofnumber, 0); 674 if (arg == endofnumber) 675 fatal("%.200s line %d: Bad number.", filename, linenum); 676 if (*activep && *intptr == -1) 677 *intptr = value; 678 break; 679 680 case oConnectionAttempts: 681 intptr = &options->connection_attempts; 682 goto parse_int; 683 684 case oCipher: 685 intptr = &options->cipher; 686 arg = strdelim(&s); 687 if (!arg || *arg == '\0') 688 fatal("%.200s line %d: Missing argument.", filename, linenum); 689 value = cipher_number(arg); 690 if (value == -1) 691 fatal("%.200s line %d: Bad cipher '%s'.", 692 filename, linenum, arg ? arg : "<NONE>"); 693 if (*activep && *intptr == -1) 694 *intptr = value; 695 break; 696 697 case oCiphers: 698 arg = strdelim(&s); 699 if (!arg || *arg == '\0') 700 fatal("%.200s line %d: Missing argument.", filename, linenum); 701 if (!ciphers_valid(arg)) 702 fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.", 703 filename, linenum, arg ? arg : "<NONE>"); 704 if (*activep && options->ciphers == NULL) 705 options->ciphers = xstrdup(arg); 706 break; 707 708 case oMacs: 709 arg = strdelim(&s); 710 if (!arg || *arg == '\0') 711 fatal("%.200s line %d: Missing argument.", filename, linenum); 712 if (!mac_valid(arg)) 713 fatal("%.200s line %d: Bad SSH2 Mac spec '%s'.", 714 filename, linenum, arg ? arg : "<NONE>"); 715 if (*activep && options->macs == NULL) 716 options->macs = xstrdup(arg); 717 break; 718 719 case oHostKeyAlgorithms: 720 arg = strdelim(&s); 721 if (!arg || *arg == '\0') 722 fatal("%.200s line %d: Missing argument.", filename, linenum); 723 if (!key_names_valid2(arg)) 724 fatal("%.200s line %d: Bad protocol 2 host key algorithms '%s'.", 725 filename, linenum, arg ? arg : "<NONE>"); 726 if (*activep && options->hostkeyalgorithms == NULL) 727 options->hostkeyalgorithms = xstrdup(arg); 728 break; 729 730 case oProtocol: 731 intptr = &options->protocol; 732 arg = strdelim(&s); 733 if (!arg || *arg == '\0') 734 fatal("%.200s line %d: Missing argument.", filename, linenum); 735 value = proto_spec(arg); 736 if (value == SSH_PROTO_UNKNOWN) 737 fatal("%.200s line %d: Bad protocol spec '%s'.", 738 filename, linenum, arg ? arg : "<NONE>"); 739 if (*activep && *intptr == SSH_PROTO_UNKNOWN) 740 *intptr = value; 741 break; 742 743 case oLogLevel: 744 log_level_ptr = &options->log_level; 745 arg = strdelim(&s); 746 value = log_level_number(arg); 747 if (value == SYSLOG_LEVEL_NOT_SET) 748 fatal("%.200s line %d: unsupported log level '%s'", 749 filename, linenum, arg ? arg : "<NONE>"); 750 if (*activep && *log_level_ptr == SYSLOG_LEVEL_NOT_SET) 751 *log_level_ptr = (LogLevel) value; 752 break; 753 754 case oLocalForward: 755 case oRemoteForward: 756 case oDynamicForward: 757 arg = strdelim(&s); 758 if (arg == NULL || *arg == '\0') 759 fatal("%.200s line %d: Missing port argument.", 760 filename, linenum); 761 762 if (opcode == oLocalForward || 763 opcode == oRemoteForward) { 764 arg2 = strdelim(&s); 765 if (arg2 == NULL || *arg2 == '\0') 766 fatal("%.200s line %d: Missing target argument.", 767 filename, linenum); 768 769 /* construct a string for parse_forward */ 770 snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg, arg2); 771 } else if (opcode == oDynamicForward) { 772 strlcpy(fwdarg, arg, sizeof(fwdarg)); 773 } 774 775 if (parse_forward(&fwd, fwdarg, 776 opcode == oDynamicForward ? 1 : 0, 777 opcode == oRemoteForward ? 1 : 0) == 0) 778 fatal("%.200s line %d: Bad forwarding specification.", 779 filename, linenum); 780 781 if (*activep) { 782 if (opcode == oLocalForward || 783 opcode == oDynamicForward) 784 add_local_forward(options, &fwd); 785 else if (opcode == oRemoteForward) 786 add_remote_forward(options, &fwd); 787 } 788 break; 789 790 case oClearAllForwardings: 791 intptr = &options->clear_forwardings; 792 goto parse_flag; 793 794 case oHost: 795 *activep = 0; 796 while ((arg = strdelim(&s)) != NULL && *arg != '\0') 797 if (match_pattern(host, arg)) { 798 debug("Applying options for %.100s", arg); 799 *activep = 1; 800 break; 801 } 802 /* Avoid garbage check below, as strdelim is done. */ 803 return 0; 804 805 case oEscapeChar: 806 intptr = &options->escape_char; 807 arg = strdelim(&s); 808 if (!arg || *arg == '\0') 809 fatal("%.200s line %d: Missing argument.", filename, linenum); 810 if (arg[0] == '^' && arg[2] == 0 && 811 (u_char) arg[1] >= 64 && (u_char) arg[1] < 128) 812 value = (u_char) arg[1] & 31; 813 else if (strlen(arg) == 1) 814 value = (u_char) arg[0]; 815 else if (strcmp(arg, "none") == 0) 816 value = SSH_ESCAPECHAR_NONE; 817 else { 818 fatal("%.200s line %d: Bad escape character.", 819 filename, linenum); 820 /* NOTREACHED */ 821 value = 0; /* Avoid compiler warning. */ 822 } 823 if (*activep && *intptr == -1) 824 *intptr = value; 825 break; 826 827 case oAddressFamily: 828 arg = strdelim(&s); 829 if (!arg || *arg == '\0') 830 fatal("%s line %d: missing address family.", 831 filename, linenum); 832 intptr = &options->address_family; 833 if (strcasecmp(arg, "inet") == 0) 834 value = AF_INET; 835 else if (strcasecmp(arg, "inet6") == 0) 836 value = AF_INET6; 837 else if (strcasecmp(arg, "any") == 0) 838 value = AF_UNSPEC; 839 else 840 fatal("Unsupported AddressFamily \"%s\"", arg); 841 if (*activep && *intptr == -1) 842 *intptr = value; 843 break; 844 845 case oEnableSSHKeysign: 846 intptr = &options->enable_ssh_keysign; 847 goto parse_flag; 848 849 case oIdentitiesOnly: 850 intptr = &options->identities_only; 851 goto parse_flag; 852 853 case oServerAliveInterval: 854 intptr = &options->server_alive_interval; 855 goto parse_time; 856 857 case oServerAliveCountMax: 858 intptr = &options->server_alive_count_max; 859 goto parse_int; 860 861 case oSendEnv: 862 while ((arg = strdelim(&s)) != NULL && *arg != '\0') { 863 if (strchr(arg, '=') != NULL) 864 fatal("%s line %d: Invalid environment name.", 865 filename, linenum); 866 if (!*activep) 867 continue; 868 if (options->num_send_env >= MAX_SEND_ENV) 869 fatal("%s line %d: too many send env.", 870 filename, linenum); 871 options->send_env[options->num_send_env++] = 872 xstrdup(arg); 873 } 874 break; 875 876 case oControlPath: 877 charptr = &options->control_path; 878 goto parse_string; 879 880 case oControlMaster: 881 intptr = &options->control_master; 882 arg = strdelim(&s); 883 if (!arg || *arg == '\0') 884 fatal("%.200s line %d: Missing ControlMaster argument.", 885 filename, linenum); 886 value = 0; /* To avoid compiler warning... */ 887 if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0) 888 value = SSHCTL_MASTER_YES; 889 else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0) 890 value = SSHCTL_MASTER_NO; 891 else if (strcmp(arg, "auto") == 0) 892 value = SSHCTL_MASTER_AUTO; 893 else if (strcmp(arg, "ask") == 0) 894 value = SSHCTL_MASTER_ASK; 895 else if (strcmp(arg, "autoask") == 0) 896 value = SSHCTL_MASTER_AUTO_ASK; 897 else 898 fatal("%.200s line %d: Bad ControlMaster argument.", 899 filename, linenum); 900 if (*activep && *intptr == -1) 901 *intptr = value; 902 break; 903 904 case oControlPersist: 905 /* no/false/yes/true, or a time spec */ 906 intptr = &options->control_persist; 907 arg = strdelim(&s); 908 if (!arg || *arg == '\0') 909 fatal("%.200s line %d: Missing ControlPersist" 910 " argument.", filename, linenum); 911 value = 0; 912 value2 = 0; /* timeout */ 913 if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0) 914 value = 0; 915 else if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0) 916 value = 1; 917 else if ((value2 = convtime(arg)) >= 0) 918 value = 1; 919 else 920 fatal("%.200s line %d: Bad ControlPersist argument.", 921 filename, linenum); 922 if (*activep && *intptr == -1) { 923 *intptr = value; 924 options->control_persist_timeout = value2; 925 } 926 break; 927 928 case oHashKnownHosts: 929 intptr = &options->hash_known_hosts; 930 goto parse_flag; 931 932 case oTunnel: 933 intptr = &options->tun_open; 934 arg = strdelim(&s); 935 if (!arg || *arg == '\0') 936 fatal("%s line %d: Missing yes/point-to-point/" 937 "ethernet/no argument.", filename, linenum); 938 value = 0; /* silence compiler */ 939 if (strcasecmp(arg, "ethernet") == 0) 940 value = SSH_TUNMODE_ETHERNET; 941 else if (strcasecmp(arg, "point-to-point") == 0) 942 value = SSH_TUNMODE_POINTOPOINT; 943 else if (strcasecmp(arg, "yes") == 0) 944 value = SSH_TUNMODE_DEFAULT; 945 else if (strcasecmp(arg, "no") == 0) 946 value = SSH_TUNMODE_NO; 947 else 948 fatal("%s line %d: Bad yes/point-to-point/ethernet/" 949 "no argument: %s", filename, linenum, arg); 950 if (*activep) 951 *intptr = value; 952 break; 953 954 case oTunnelDevice: 955 arg = strdelim(&s); 956 if (!arg || *arg == '\0') 957 fatal("%.200s line %d: Missing argument.", filename, linenum); 958 value = a2tun(arg, &value2); 959 if (value == SSH_TUNID_ERR) 960 fatal("%.200s line %d: Bad tun device.", filename, linenum); 961 if (*activep) { 962 options->tun_local = value; 963 options->tun_remote = value2; 964 } 965 break; 966 967 case oLocalCommand: 968 charptr = &options->local_command; 969 goto parse_command; 970 971 case oPermitLocalCommand: 972 intptr = &options->permit_local_command; 973 goto parse_flag; 974 975 case oVisualHostKey: 976 intptr = &options->visual_host_key; 977 goto parse_flag; 978 979 case oUseRoaming: 980 intptr = &options->use_roaming; 981 goto parse_flag; 982 983 case oVersionAddendum: 984 ssh_version_set_addendum(strtok(s, "\n")); 985 do { 986 arg = strdelim(&s); 987 } while (arg != NULL && *arg != '\0'); 988 break; 989 990 case oDeprecated: 991 debug("%s line %d: Deprecated option \"%s\"", 992 filename, linenum, keyword); 993 return 0; 994 995 case oUnsupported: 996 error("%s line %d: Unsupported option \"%s\"", 997 filename, linenum, keyword); 998 return 0; 999 1000 default: 1001 fatal("process_config_line: Unimplemented opcode %d", opcode); 1002 } 1003 1004 /* Check that there is no garbage at end of line. */ 1005 if ((arg = strdelim(&s)) != NULL && *arg != '\0') { 1006 fatal("%.200s line %d: garbage at end of line; \"%.200s\".", 1007 filename, linenum, arg); 1008 } 1009 return 0; 1010 } 1011 1012 1013 /* 1014 * Reads the config file and modifies the options accordingly. Options 1015 * should already be initialized before this call. This never returns if 1016 * there is an error. If the file does not exist, this returns 0. 1017 */ 1018 1019 int 1020 read_config_file(const char *filename, const char *host, Options *options, 1021 int checkperm) 1022 { 1023 FILE *f; 1024 char line[1024]; 1025 int active, linenum; 1026 int bad_options = 0; 1027 1028 if ((f = fopen(filename, "r")) == NULL) 1029 return 0; 1030 1031 if (checkperm) { 1032 struct stat sb; 1033 1034 if (fstat(fileno(f), &sb) == -1) 1035 fatal("fstat %s: %s", filename, strerror(errno)); 1036 if (((sb.st_uid != 0 && sb.st_uid != getuid()) || 1037 (sb.st_mode & 022) != 0)) 1038 fatal("Bad owner or permissions on %s", filename); 1039 } 1040 1041 debug("Reading configuration data %.200s", filename); 1042 1043 /* 1044 * Mark that we are now processing the options. This flag is turned 1045 * on/off by Host specifications. 1046 */ 1047 active = 1; 1048 linenum = 0; 1049 while (fgets(line, sizeof(line), f)) { 1050 /* Update line number counter. */ 1051 linenum++; 1052 if (process_config_line(options, host, line, filename, linenum, &active) != 0) 1053 bad_options++; 1054 } 1055 fclose(f); 1056 if (bad_options > 0) 1057 fatal("%s: terminating, %d bad configuration options", 1058 filename, bad_options); 1059 return 1; 1060 } 1061 1062 /* 1063 * Initializes options to special values that indicate that they have not yet 1064 * been set. Read_config_file will only set options with this value. Options 1065 * are processed in the following order: command line, user config file, 1066 * system config file. Last, fill_default_options is called. 1067 */ 1068 1069 void 1070 initialize_options(Options * options) 1071 { 1072 memset(options, 'X', sizeof(*options)); 1073 options->forward_agent = -1; 1074 options->forward_x11 = -1; 1075 options->forward_x11_trusted = -1; 1076 options->forward_x11_timeout = -1; 1077 options->exit_on_forward_failure = -1; 1078 options->xauth_location = NULL; 1079 options->gateway_ports = -1; 1080 options->use_privileged_port = -1; 1081 options->rsa_authentication = -1; 1082 options->pubkey_authentication = -1; 1083 options->challenge_response_authentication = -1; 1084 options->gss_authentication = -1; 1085 options->gss_deleg_creds = -1; 1086 options->password_authentication = -1; 1087 options->kbd_interactive_authentication = -1; 1088 options->kbd_interactive_devices = NULL; 1089 options->rhosts_rsa_authentication = -1; 1090 options->hostbased_authentication = -1; 1091 options->batch_mode = -1; 1092 options->check_host_ip = -1; 1093 options->strict_host_key_checking = -1; 1094 options->compression = -1; 1095 options->tcp_keep_alive = -1; 1096 options->compression_level = -1; 1097 options->port = -1; 1098 options->address_family = -1; 1099 options->connection_attempts = -1; 1100 options->connection_timeout = -1; 1101 options->number_of_password_prompts = -1; 1102 options->cipher = -1; 1103 options->ciphers = NULL; 1104 options->macs = NULL; 1105 options->hostkeyalgorithms = NULL; 1106 options->protocol = SSH_PROTO_UNKNOWN; 1107 options->num_identity_files = 0; 1108 options->hostname = NULL; 1109 options->host_key_alias = NULL; 1110 options->proxy_command = NULL; 1111 options->user = NULL; 1112 options->escape_char = -1; 1113 options->system_hostfile = NULL; 1114 options->user_hostfile = NULL; 1115 options->system_hostfile2 = NULL; 1116 options->user_hostfile2 = NULL; 1117 options->local_forwards = NULL; 1118 options->num_local_forwards = 0; 1119 options->remote_forwards = NULL; 1120 options->num_remote_forwards = 0; 1121 options->clear_forwardings = -1; 1122 options->log_level = SYSLOG_LEVEL_NOT_SET; 1123 options->preferred_authentications = NULL; 1124 options->bind_address = NULL; 1125 options->pkcs11_provider = NULL; 1126 options->enable_ssh_keysign = - 1; 1127 options->no_host_authentication_for_localhost = - 1; 1128 options->identities_only = - 1; 1129 options->rekey_limit = - 1; 1130 options->verify_host_key_dns = -1; 1131 options->server_alive_interval = -1; 1132 options->server_alive_count_max = -1; 1133 options->num_send_env = 0; 1134 options->control_path = NULL; 1135 options->control_master = -1; 1136 options->control_persist = -1; 1137 options->control_persist_timeout = 0; 1138 options->hash_known_hosts = -1; 1139 options->tun_open = -1; 1140 options->tun_local = -1; 1141 options->tun_remote = -1; 1142 options->local_command = NULL; 1143 options->permit_local_command = -1; 1144 options->use_roaming = -1; 1145 options->visual_host_key = -1; 1146 options->zero_knowledge_password_authentication = -1; 1147 } 1148 1149 /* 1150 * Called after processing other sources of option data, this fills those 1151 * options for which no value has been specified with their default values. 1152 */ 1153 1154 void 1155 fill_default_options(Options * options) 1156 { 1157 int len; 1158 1159 if (options->forward_agent == -1) 1160 options->forward_agent = 0; 1161 if (options->forward_x11 == -1) 1162 options->forward_x11 = 0; 1163 if (options->forward_x11_trusted == -1) 1164 options->forward_x11_trusted = 0; 1165 if (options->forward_x11_timeout == -1) 1166 options->forward_x11_timeout = 1200; 1167 if (options->exit_on_forward_failure == -1) 1168 options->exit_on_forward_failure = 0; 1169 if (options->xauth_location == NULL) 1170 options->xauth_location = _PATH_XAUTH; 1171 if (options->gateway_ports == -1) 1172 options->gateway_ports = 0; 1173 if (options->use_privileged_port == -1) 1174 options->use_privileged_port = 0; 1175 if (options->rsa_authentication == -1) 1176 options->rsa_authentication = 1; 1177 if (options->pubkey_authentication == -1) 1178 options->pubkey_authentication = 1; 1179 if (options->challenge_response_authentication == -1) 1180 options->challenge_response_authentication = 1; 1181 if (options->gss_authentication == -1) 1182 options->gss_authentication = 0; 1183 if (options->gss_deleg_creds == -1) 1184 options->gss_deleg_creds = 0; 1185 if (options->password_authentication == -1) 1186 options->password_authentication = 1; 1187 if (options->kbd_interactive_authentication == -1) 1188 options->kbd_interactive_authentication = 1; 1189 if (options->rhosts_rsa_authentication == -1) 1190 options->rhosts_rsa_authentication = 0; 1191 if (options->hostbased_authentication == -1) 1192 options->hostbased_authentication = 0; 1193 if (options->batch_mode == -1) 1194 options->batch_mode = 0; 1195 if (options->check_host_ip == -1) 1196 options->check_host_ip = 0; 1197 if (options->strict_host_key_checking == -1) 1198 options->strict_host_key_checking = 2; /* 2 is default */ 1199 if (options->compression == -1) 1200 options->compression = 0; 1201 if (options->tcp_keep_alive == -1) 1202 options->tcp_keep_alive = 1; 1203 if (options->compression_level == -1) 1204 options->compression_level = 6; 1205 if (options->port == -1) 1206 options->port = 0; /* Filled in ssh_connect. */ 1207 if (options->address_family == -1) 1208 options->address_family = AF_UNSPEC; 1209 if (options->connection_attempts == -1) 1210 options->connection_attempts = 1; 1211 if (options->number_of_password_prompts == -1) 1212 options->number_of_password_prompts = 3; 1213 /* Selected in ssh_login(). */ 1214 if (options->cipher == -1) 1215 options->cipher = SSH_CIPHER_NOT_SET; 1216 /* options->ciphers, default set in myproposals.h */ 1217 /* options->macs, default set in myproposals.h */ 1218 /* options->hostkeyalgorithms, default set in myproposals.h */ 1219 if (options->protocol == SSH_PROTO_UNKNOWN) 1220 options->protocol = SSH_PROTO_2; 1221 if (options->num_identity_files == 0) { 1222 if (options->protocol & SSH_PROTO_1) { 1223 len = 2 + strlen(_PATH_SSH_CLIENT_IDENTITY) + 1; 1224 options->identity_files[options->num_identity_files] = 1225 xmalloc(len); 1226 snprintf(options->identity_files[options->num_identity_files++], 1227 len, "~/%.100s", _PATH_SSH_CLIENT_IDENTITY); 1228 } 1229 if (options->protocol & SSH_PROTO_2) { 1230 len = 2 + strlen(_PATH_SSH_CLIENT_ID_RSA) + 1; 1231 options->identity_files[options->num_identity_files] = 1232 xmalloc(len); 1233 snprintf(options->identity_files[options->num_identity_files++], 1234 len, "~/%.100s", _PATH_SSH_CLIENT_ID_RSA); 1235 1236 len = 2 + strlen(_PATH_SSH_CLIENT_ID_DSA) + 1; 1237 options->identity_files[options->num_identity_files] = 1238 xmalloc(len); 1239 snprintf(options->identity_files[options->num_identity_files++], 1240 len, "~/%.100s", _PATH_SSH_CLIENT_ID_DSA); 1241 } 1242 } 1243 if (options->escape_char == -1) 1244 options->escape_char = '~'; 1245 if (options->system_hostfile == NULL) 1246 options->system_hostfile = _PATH_SSH_SYSTEM_HOSTFILE; 1247 if (options->user_hostfile == NULL) 1248 options->user_hostfile = _PATH_SSH_USER_HOSTFILE; 1249 if (options->system_hostfile2 == NULL) 1250 options->system_hostfile2 = _PATH_SSH_SYSTEM_HOSTFILE2; 1251 if (options->user_hostfile2 == NULL) 1252 options->user_hostfile2 = _PATH_SSH_USER_HOSTFILE2; 1253 if (options->log_level == SYSLOG_LEVEL_NOT_SET) 1254 options->log_level = SYSLOG_LEVEL_INFO; 1255 if (options->clear_forwardings == 1) 1256 clear_forwardings(options); 1257 if (options->no_host_authentication_for_localhost == - 1) 1258 options->no_host_authentication_for_localhost = 0; 1259 if (options->identities_only == -1) 1260 options->identities_only = 0; 1261 if (options->enable_ssh_keysign == -1) 1262 options->enable_ssh_keysign = 0; 1263 if (options->rekey_limit == -1) 1264 options->rekey_limit = 0; 1265 if (options->verify_host_key_dns == -1) 1266 options->verify_host_key_dns = 0; 1267 if (options->server_alive_interval == -1) 1268 options->server_alive_interval = 0; 1269 if (options->server_alive_count_max == -1) 1270 options->server_alive_count_max = 3; 1271 if (options->control_master == -1) 1272 options->control_master = 0; 1273 if (options->control_persist == -1) { 1274 options->control_persist = 0; 1275 options->control_persist_timeout = 0; 1276 } 1277 if (options->hash_known_hosts == -1) 1278 options->hash_known_hosts = 0; 1279 if (options->tun_open == -1) 1280 options->tun_open = SSH_TUNMODE_NO; 1281 if (options->tun_local == -1) 1282 options->tun_local = SSH_TUNID_ANY; 1283 if (options->tun_remote == -1) 1284 options->tun_remote = SSH_TUNID_ANY; 1285 if (options->permit_local_command == -1) 1286 options->permit_local_command = 0; 1287 if (options->use_roaming == -1) 1288 options->use_roaming = 1; 1289 if (options->visual_host_key == -1) 1290 options->visual_host_key = 0; 1291 if (options->zero_knowledge_password_authentication == -1) 1292 options->zero_knowledge_password_authentication = 0; 1293 /* options->local_command should not be set by default */ 1294 /* options->proxy_command should not be set by default */ 1295 /* options->user will be set in the main program if appropriate */ 1296 /* options->hostname will be set in the main program if appropriate */ 1297 /* options->host_key_alias should not be set by default */ 1298 /* options->preferred_authentications will be set in ssh */ 1299 } 1300 1301 /* 1302 * parse_forward 1303 * parses a string containing a port forwarding specification of the form: 1304 * dynamicfwd == 0 1305 * [listenhost:]listenport:connecthost:connectport 1306 * dynamicfwd == 1 1307 * [listenhost:]listenport 1308 * returns number of arguments parsed or zero on error 1309 */ 1310 int 1311 parse_forward(Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd) 1312 { 1313 int i; 1314 char *p, *cp, *fwdarg[4]; 1315 1316 memset(fwd, '\0', sizeof(*fwd)); 1317 1318 cp = p = xstrdup(fwdspec); 1319 1320 /* skip leading spaces */ 1321 while (isspace(*cp)) 1322 cp++; 1323 1324 for (i = 0; i < 4; ++i) 1325 if ((fwdarg[i] = hpdelim(&cp)) == NULL) 1326 break; 1327 1328 /* Check for trailing garbage */ 1329 if (cp != NULL) 1330 i = 0; /* failure */ 1331 1332 switch (i) { 1333 case 1: 1334 fwd->listen_host = NULL; 1335 fwd->listen_port = a2port(fwdarg[0]); 1336 fwd->connect_host = xstrdup("socks"); 1337 break; 1338 1339 case 2: 1340 fwd->listen_host = xstrdup(cleanhostname(fwdarg[0])); 1341 fwd->listen_port = a2port(fwdarg[1]); 1342 fwd->connect_host = xstrdup("socks"); 1343 break; 1344 1345 case 3: 1346 fwd->listen_host = NULL; 1347 fwd->listen_port = a2port(fwdarg[0]); 1348 fwd->connect_host = xstrdup(cleanhostname(fwdarg[1])); 1349 fwd->connect_port = a2port(fwdarg[2]); 1350 break; 1351 1352 case 4: 1353 fwd->listen_host = xstrdup(cleanhostname(fwdarg[0])); 1354 fwd->listen_port = a2port(fwdarg[1]); 1355 fwd->connect_host = xstrdup(cleanhostname(fwdarg[2])); 1356 fwd->connect_port = a2port(fwdarg[3]); 1357 break; 1358 default: 1359 i = 0; /* failure */ 1360 } 1361 1362 xfree(p); 1363 1364 if (dynamicfwd) { 1365 if (!(i == 1 || i == 2)) 1366 goto fail_free; 1367 } else { 1368 if (!(i == 3 || i == 4)) 1369 goto fail_free; 1370 if (fwd->connect_port <= 0) 1371 goto fail_free; 1372 } 1373 1374 if (fwd->listen_port < 0 || (!remotefwd && fwd->listen_port == 0)) 1375 goto fail_free; 1376 1377 if (fwd->connect_host != NULL && 1378 strlen(fwd->connect_host) >= NI_MAXHOST) 1379 goto fail_free; 1380 if (fwd->listen_host != NULL && 1381 strlen(fwd->listen_host) >= NI_MAXHOST) 1382 goto fail_free; 1383 1384 1385 return (i); 1386 1387 fail_free: 1388 if (fwd->connect_host != NULL) { 1389 xfree(fwd->connect_host); 1390 fwd->connect_host = NULL; 1391 } 1392 if (fwd->listen_host != NULL) { 1393 xfree(fwd->listen_host); 1394 fwd->listen_host = NULL; 1395 } 1396 return (0); 1397 } 1398