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