jcs's openbsd hax
openbsd
at jcs 3890 lines 113 kB view raw
1/* $OpenBSD: readconf.c,v 1.410 2026/02/14 00:18:34 jsg 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#include <sys/wait.h> 19#include <sys/un.h> 20 21#include <net/if.h> 22#include <netinet/in.h> 23#include <netinet/ip.h> 24 25#include <ctype.h> 26#include <errno.h> 27#include <glob.h> 28#include <ifaddrs.h> 29#include <limits.h> 30#include <netdb.h> 31#include <paths.h> 32#include <pwd.h> 33#include <signal.h> 34#include <stdio.h> 35#include <string.h> 36#include <stdarg.h> 37#include <unistd.h> 38#include <util.h> 39#include <vis.h> 40 41#include "xmalloc.h" 42#include "ssh.h" 43#include "cipher.h" 44#include "pathnames.h" 45#include "log.h" 46#include "sshkey.h" 47#include "misc.h" 48#include "readconf.h" 49#include "match.h" 50#include "kex.h" 51#include "mac.h" 52#include "myproposal.h" 53#include "digest.h" 54#include "version.h" 55 56/* Format of the configuration file: 57 58 # Configuration data is parsed as follows: 59 # 1. command line options 60 # 2. user-specific file 61 # 3. system-wide file 62 # Any configuration value is only changed the first time it is set. 63 # Thus, host-specific definitions should be at the beginning of the 64 # configuration file, and defaults at the end. 65 66 # Host-specific declarations. These may override anything above. A single 67 # host may match multiple declarations; these are processed in the order 68 # that they are given in. 69 70 Host *.ngs.fi ngs.fi 71 User foo 72 73 Host fake.com 74 Hostname another.host.name.real.org 75 User blaah 76 Port 34289 77 ForwardX11 no 78 ForwardAgent no 79 80 Host books.com 81 RemoteForward 9999 shadows.cs.hut.fi:9999 82 Ciphers 3des-cbc 83 84 Host fascist.blob.com 85 Port 23123 86 User tylonen 87 PasswordAuthentication no 88 89 Host puukko.hut.fi 90 User t35124p 91 ProxyCommand ssh-proxy %h %p 92 93 Host *.fr 94 PublicKeyAuthentication no 95 96 Host *.su 97 Ciphers aes128-ctr 98 PasswordAuthentication no 99 100 Host vpn.fake.com 101 Tunnel yes 102 TunnelDevice 3 103 104 # Defaults for various options 105 Host * 106 ForwardAgent no 107 ForwardX11 no 108 PasswordAuthentication yes 109 StrictHostKeyChecking yes 110 TcpKeepAlive no 111 IdentityFile ~/.ssh/identity 112 Port 22 113 EscapeChar ~ 114 115*/ 116 117static int read_config_file_depth(const char *filename, struct passwd *pw, 118 const char *host, const char *original_host, const char *remote_command, 119 Options *options, int flags, int *activep, int *want_final_pass, int depth); 120static int process_config_line_depth(Options *options, struct passwd *pw, 121 const char *host, const char *original_host, const char *remote_command, 122 char *line, const char *filename, int linenum, int *activep, int flags, 123 int *want_final_pass, int depth); 124 125/* Keyword tokens. */ 126 127typedef enum { 128 oBadOption, 129 oHost, oMatch, oInclude, oTag, 130 oForwardAgent, oForwardX11, oForwardX11Trusted, oForwardX11Timeout, 131 oGatewayPorts, oExitOnForwardFailure, 132 oPasswordAuthentication, 133 oXAuthLocation, 134 oIdentityFile, oHostname, oPort, oRemoteForward, oLocalForward, 135 oPermitRemoteOpen, 136 oCertificateFile, oAddKeysToAgent, oIdentityAgent, 137 oUser, oEscapeChar, oProxyCommand, 138 oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts, 139 oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression, 140 oTCPKeepAlive, oNumberOfPasswordPrompts, 141 oLogFacility, oLogLevel, oLogVerbose, oCiphers, oMacs, 142 oPubkeyAuthentication, 143 oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias, 144 oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication, 145 oHostKeyAlgorithms, oBindAddress, oBindInterface, oPKCS11Provider, 146 oClearAllForwardings, oNoHostAuthenticationForLocalhost, 147 oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, 148 oAddressFamily, oGssAuthentication, oGssDelegateCreds, 149 oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, 150 oSendEnv, oSetEnv, oControlPath, oControlMaster, oControlPersist, 151 oHashKnownHosts, 152 oTunnel, oTunnelDevice, 153 oLocalCommand, oPermitLocalCommand, oRemoteCommand, 154 oVisualHostKey, 155 oKexAlgorithms, oIPQoS, oRequestTTY, oSessionType, oStdinNull, 156 oForkAfterAuthentication, oIgnoreUnknown, oProxyUseFdpass, 157 oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots, 158 oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs, 159 oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys, 160 oFingerprintHash, oUpdateHostkeys, oHostbasedAcceptedAlgorithms, 161 oPubkeyAcceptedAlgorithms, oCASignatureAlgorithms, oProxyJump, 162 oSecurityKeyProvider, oKnownHostsCommand, oRequiredRSASize, 163 oEnableEscapeCommandline, oObscureKeystrokeTiming, oChannelTimeout, 164 oVersionAddendum, oRefuseConnection, oWarnWeakCrypto, 165 oIgnore, oIgnoredUnknownOption, oDeprecated, oUnsupported 166} OpCodes; 167 168/* Textual representations of the tokens. */ 169 170static struct { 171 const char *name; 172 OpCodes opcode; 173} keywords[] = { 174 /* Deprecated options */ 175 { "protocol", oIgnore }, /* NB. silently ignored */ 176 { "cipher", oDeprecated }, 177 { "fallbacktorsh", oDeprecated }, 178 { "globalknownhostsfile2", oDeprecated }, 179 { "rhostsauthentication", oDeprecated }, 180 { "userknownhostsfile2", oDeprecated }, 181 { "useroaming", oDeprecated }, 182 { "usersh", oDeprecated }, 183 { "useprivilegedport", oDeprecated }, 184 185 /* Unsupported options */ 186 { "afstokenpassing", oUnsupported }, 187 { "kerberosauthentication", oUnsupported }, 188 { "kerberostgtpassing", oUnsupported }, 189 { "rsaauthentication", oUnsupported }, 190 { "rhostsrsaauthentication", oUnsupported }, 191 { "compressionlevel", oUnsupported }, 192 193 /* Sometimes-unsupported options */ 194#if defined(GSSAPI) 195 { "gssapiauthentication", oGssAuthentication }, 196 { "gssapidelegatecredentials", oGssDelegateCreds }, 197# else 198 { "gssapiauthentication", oUnsupported }, 199 { "gssapidelegatecredentials", oUnsupported }, 200#endif 201#ifdef ENABLE_PKCS11 202 { "pkcs11provider", oPKCS11Provider }, 203 { "smartcarddevice", oPKCS11Provider }, 204# else 205 { "smartcarddevice", oUnsupported }, 206 { "pkcs11provider", oUnsupported }, 207#endif 208 209 { "forwardagent", oForwardAgent }, 210 { "forwardx11", oForwardX11 }, 211 { "forwardx11trusted", oForwardX11Trusted }, 212 { "forwardx11timeout", oForwardX11Timeout }, 213 { "exitonforwardfailure", oExitOnForwardFailure }, 214 { "xauthlocation", oXAuthLocation }, 215 { "gatewayports", oGatewayPorts }, 216 { "passwordauthentication", oPasswordAuthentication }, 217 { "kbdinteractiveauthentication", oKbdInteractiveAuthentication }, 218 { "kbdinteractivedevices", oKbdInteractiveDevices }, 219 { "challengeresponseauthentication", oKbdInteractiveAuthentication }, /* alias */ 220 { "skeyauthentication", oKbdInteractiveAuthentication }, /* alias */ 221 { "tisauthentication", oKbdInteractiveAuthentication }, /* alias */ 222 { "pubkeyauthentication", oPubkeyAuthentication }, 223 { "dsaauthentication", oPubkeyAuthentication }, /* alias */ 224 { "hostbasedauthentication", oHostbasedAuthentication }, 225 { "identityfile", oIdentityFile }, 226 { "identityfile2", oIdentityFile }, /* obsolete */ 227 { "identitiesonly", oIdentitiesOnly }, 228 { "certificatefile", oCertificateFile }, 229 { "addkeystoagent", oAddKeysToAgent }, 230 { "identityagent", oIdentityAgent }, 231 { "hostname", oHostname }, 232 { "hostkeyalias", oHostKeyAlias }, 233 { "proxycommand", oProxyCommand }, 234 { "port", oPort }, 235 { "ciphers", oCiphers }, 236 { "macs", oMacs }, 237 { "remoteforward", oRemoteForward }, 238 { "localforward", oLocalForward }, 239 { "permitremoteopen", oPermitRemoteOpen }, 240 { "user", oUser }, 241 { "host", oHost }, 242 { "match", oMatch }, 243 { "tag", oTag }, 244 { "escapechar", oEscapeChar }, 245 { "globalknownhostsfile", oGlobalKnownHostsFile }, 246 { "userknownhostsfile", oUserKnownHostsFile }, 247 { "connectionattempts", oConnectionAttempts }, 248 { "batchmode", oBatchMode }, 249 { "checkhostip", oCheckHostIP }, 250 { "stricthostkeychecking", oStrictHostKeyChecking }, 251 { "compression", oCompression }, 252 { "tcpkeepalive", oTCPKeepAlive }, 253 { "keepalive", oTCPKeepAlive }, /* obsolete */ 254 { "numberofpasswordprompts", oNumberOfPasswordPrompts }, 255 { "syslogfacility", oLogFacility }, 256 { "loglevel", oLogLevel }, 257 { "logverbose", oLogVerbose }, 258 { "dynamicforward", oDynamicForward }, 259 { "preferredauthentications", oPreferredAuthentications }, 260 { "hostkeyalgorithms", oHostKeyAlgorithms }, 261 { "casignaturealgorithms", oCASignatureAlgorithms }, 262 { "bindaddress", oBindAddress }, 263 { "bindinterface", oBindInterface }, 264 { "clearallforwardings", oClearAllForwardings }, 265 { "enablesshkeysign", oEnableSSHKeysign }, 266 { "verifyhostkeydns", oVerifyHostKeyDNS }, 267 { "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost }, 268 { "rekeylimit", oRekeyLimit }, 269 { "connecttimeout", oConnectTimeout }, 270 { "addressfamily", oAddressFamily }, 271 { "serveraliveinterval", oServerAliveInterval }, 272 { "serveralivecountmax", oServerAliveCountMax }, 273 { "sendenv", oSendEnv }, 274 { "setenv", oSetEnv }, 275 { "controlpath", oControlPath }, 276 { "controlmaster", oControlMaster }, 277 { "controlpersist", oControlPersist }, 278 { "hashknownhosts", oHashKnownHosts }, 279 { "include", oInclude }, 280 { "tunnel", oTunnel }, 281 { "tunneldevice", oTunnelDevice }, 282 { "localcommand", oLocalCommand }, 283 { "permitlocalcommand", oPermitLocalCommand }, 284 { "remotecommand", oRemoteCommand }, 285 { "visualhostkey", oVisualHostKey }, 286 { "kexalgorithms", oKexAlgorithms }, 287 { "ipqos", oIPQoS }, 288 { "requesttty", oRequestTTY }, 289 { "sessiontype", oSessionType }, 290 { "stdinnull", oStdinNull }, 291 { "forkafterauthentication", oForkAfterAuthentication }, 292 { "proxyusefdpass", oProxyUseFdpass }, 293 { "canonicaldomains", oCanonicalDomains }, 294 { "canonicalizefallbacklocal", oCanonicalizeFallbackLocal }, 295 { "canonicalizehostname", oCanonicalizeHostname }, 296 { "canonicalizemaxdots", oCanonicalizeMaxDots }, 297 { "canonicalizepermittedcnames", oCanonicalizePermittedCNAMEs }, 298 { "streamlocalbindmask", oStreamLocalBindMask }, 299 { "streamlocalbindunlink", oStreamLocalBindUnlink }, 300 { "revokedhostkeys", oRevokedHostKeys }, 301 { "fingerprinthash", oFingerprintHash }, 302 { "updatehostkeys", oUpdateHostkeys }, 303 { "hostbasedacceptedalgorithms", oHostbasedAcceptedAlgorithms }, 304 { "hostbasedkeytypes", oHostbasedAcceptedAlgorithms }, /* obsolete */ 305 { "pubkeyacceptedalgorithms", oPubkeyAcceptedAlgorithms }, 306 { "pubkeyacceptedkeytypes", oPubkeyAcceptedAlgorithms }, /* obsolete */ 307 { "ignoreunknown", oIgnoreUnknown }, 308 { "proxyjump", oProxyJump }, 309 { "securitykeyprovider", oSecurityKeyProvider }, 310 { "knownhostscommand", oKnownHostsCommand }, 311 { "requiredrsasize", oRequiredRSASize }, 312 { "enableescapecommandline", oEnableEscapeCommandline }, 313 { "obscurekeystroketiming", oObscureKeystrokeTiming }, 314 { "channeltimeout", oChannelTimeout }, 315 { "versionaddendum", oVersionAddendum }, 316 { "refuseconnection", oRefuseConnection }, 317 { "warnweakcrypto", oWarnWeakCrypto }, 318 319 { NULL, oBadOption } 320}; 321 322static const char *lookup_opcode_name(OpCodes code); 323 324const char * 325kex_default_pk_alg(void) 326{ 327 static char *pkalgs; 328 329 if (pkalgs == NULL) { 330 char *all_key; 331 332 all_key = sshkey_alg_list(0, 0, 1, ','); 333 pkalgs = match_filter_allowlist(KEX_DEFAULT_PK_ALG, all_key); 334 free(all_key); 335 } 336 return pkalgs; 337} 338 339char * 340ssh_connection_hash(const char *thishost, const char *host, const char *portstr, 341 const char *user, const char *jumphost) 342{ 343 struct ssh_digest_ctx *md; 344 u_char conn_hash[SSH_DIGEST_MAX_LENGTH]; 345 346 if ((md = ssh_digest_start(SSH_DIGEST_SHA1)) == NULL || 347 ssh_digest_update(md, thishost, strlen(thishost)) < 0 || 348 ssh_digest_update(md, host, strlen(host)) < 0 || 349 ssh_digest_update(md, portstr, strlen(portstr)) < 0 || 350 ssh_digest_update(md, user, strlen(user)) < 0 || 351 ssh_digest_update(md, jumphost, strlen(jumphost)) < 0 || 352 ssh_digest_final(md, conn_hash, sizeof(conn_hash)) < 0) 353 fatal_f("mux digest failed"); 354 ssh_digest_free(md); 355 return tohex(conn_hash, ssh_digest_bytes(SSH_DIGEST_SHA1)); 356} 357 358/* 359 * Adds a local TCP/IP port forward to options. Never returns if there is an 360 * error. 361 */ 362 363void 364add_local_forward(Options *options, const struct Forward *newfwd) 365{ 366 struct Forward *fwd; 367 int i; 368 369 /* Don't add duplicates */ 370 for (i = 0; i < options->num_local_forwards; i++) { 371 if (forward_equals(newfwd, options->local_forwards + i)) 372 return; 373 } 374 options->local_forwards = xreallocarray(options->local_forwards, 375 options->num_local_forwards + 1, 376 sizeof(*options->local_forwards)); 377 fwd = &options->local_forwards[options->num_local_forwards++]; 378 379 fwd->listen_host = newfwd->listen_host; 380 fwd->listen_port = newfwd->listen_port; 381 fwd->listen_path = newfwd->listen_path; 382 fwd->connect_host = newfwd->connect_host; 383 fwd->connect_port = newfwd->connect_port; 384 fwd->connect_path = newfwd->connect_path; 385} 386 387/* 388 * Adds a remote TCP/IP port forward to options. Never returns if there is 389 * an error. 390 */ 391 392void 393add_remote_forward(Options *options, const struct Forward *newfwd) 394{ 395 struct Forward *fwd; 396 int i; 397 398 /* Don't add duplicates */ 399 for (i = 0; i < options->num_remote_forwards; i++) { 400 if (forward_equals(newfwd, options->remote_forwards + i)) 401 return; 402 } 403 options->remote_forwards = xreallocarray(options->remote_forwards, 404 options->num_remote_forwards + 1, 405 sizeof(*options->remote_forwards)); 406 fwd = &options->remote_forwards[options->num_remote_forwards++]; 407 408 fwd->listen_host = newfwd->listen_host; 409 fwd->listen_port = newfwd->listen_port; 410 fwd->listen_path = newfwd->listen_path; 411 fwd->connect_host = newfwd->connect_host; 412 fwd->connect_port = newfwd->connect_port; 413 fwd->connect_path = newfwd->connect_path; 414 fwd->handle = newfwd->handle; 415 fwd->allocated_port = 0; 416} 417 418static void 419clear_forwardings(Options *options) 420{ 421 int i; 422 423 for (i = 0; i < options->num_local_forwards; i++) { 424 free(options->local_forwards[i].listen_host); 425 free(options->local_forwards[i].listen_path); 426 free(options->local_forwards[i].connect_host); 427 free(options->local_forwards[i].connect_path); 428 } 429 if (options->num_local_forwards > 0) { 430 free(options->local_forwards); 431 options->local_forwards = NULL; 432 } 433 options->num_local_forwards = 0; 434 for (i = 0; i < options->num_remote_forwards; i++) { 435 free(options->remote_forwards[i].listen_host); 436 free(options->remote_forwards[i].listen_path); 437 free(options->remote_forwards[i].connect_host); 438 free(options->remote_forwards[i].connect_path); 439 } 440 if (options->num_remote_forwards > 0) { 441 free(options->remote_forwards); 442 options->remote_forwards = NULL; 443 } 444 options->num_remote_forwards = 0; 445 options->tun_open = SSH_TUNMODE_NO; 446} 447 448void 449add_certificate_file(Options *options, const char *path, int userprovided) 450{ 451 int i; 452 453 if (options->num_certificate_files >= SSH_MAX_CERTIFICATE_FILES) 454 fatal("Too many certificate files specified (max %d)", 455 SSH_MAX_CERTIFICATE_FILES); 456 457 /* Avoid registering duplicates */ 458 for (i = 0; i < options->num_certificate_files; i++) { 459 if (options->certificate_file_userprovided[i] == userprovided && 460 strcmp(options->certificate_files[i], path) == 0) { 461 debug2_f("ignoring duplicate key %s", path); 462 return; 463 } 464 } 465 466 options->certificate_file_userprovided[options->num_certificate_files] = 467 userprovided; 468 options->certificate_files[options->num_certificate_files++] = 469 xstrdup(path); 470} 471 472void 473add_identity_file(Options *options, const char *dir, const char *filename, 474 int userprovided) 475{ 476 char *path; 477 int i; 478 479 if (options->num_identity_files >= SSH_MAX_IDENTITY_FILES) 480 fatal("Too many identity files specified (max %d)", 481 SSH_MAX_IDENTITY_FILES); 482 483 if (dir == NULL) /* no dir, filename is absolute */ 484 path = xstrdup(filename); 485 else if (xasprintf(&path, "%s%s", dir, filename) >= PATH_MAX) 486 fatal("Identity file path %s too long", path); 487 488 /* Avoid registering duplicates */ 489 for (i = 0; i < options->num_identity_files; i++) { 490 if (options->identity_file_userprovided[i] == userprovided && 491 strcmp(options->identity_files[i], path) == 0) { 492 debug2_f("ignoring duplicate key %s", path); 493 free(path); 494 return; 495 } 496 } 497 498 options->identity_file_userprovided[options->num_identity_files] = 499 userprovided; 500 options->identity_files[options->num_identity_files++] = path; 501} 502 503int 504default_ssh_port(void) 505{ 506 static int port; 507 struct servent *sp; 508 509 if (port == 0) { 510 sp = getservbyname(SSH_SERVICE_NAME, "tcp"); 511 port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT; 512 } 513 return port; 514} 515 516/* 517 * Execute a command in a shell. 518 * Return its exit status or -1 on abnormal exit. 519 */ 520static int 521execute_in_shell(const char *cmd) 522{ 523 char *shell; 524 pid_t pid; 525 int status; 526 527 if ((shell = getenv("SHELL")) == NULL) 528 shell = _PATH_BSHELL; 529 530 if (access(shell, X_OK) == -1) { 531 fatal("Shell \"%s\" is not executable: %s", 532 shell, strerror(errno)); 533 } 534 535 debug("Executing command: '%.500s'", cmd); 536 537 /* Fork and execute the command. */ 538 if ((pid = fork()) == 0) { 539 char *argv[4]; 540 541 if (stdfd_devnull(1, 1, 0) == -1) 542 fatal_f("stdfd_devnull failed"); 543 closefrom(STDERR_FILENO + 1); 544 545 argv[0] = shell; 546 argv[1] = "-c"; 547 argv[2] = xstrdup(cmd); 548 argv[3] = NULL; 549 550 execv(argv[0], argv); 551 error("Unable to execute '%.100s': %s", cmd, strerror(errno)); 552 /* Die with signal to make this error apparent to parent. */ 553 ssh_signal(SIGTERM, SIG_DFL); 554 kill(getpid(), SIGTERM); 555 _exit(1); 556 } 557 /* Parent. */ 558 if (pid == -1) 559 fatal_f("fork: %.100s", strerror(errno)); 560 561 while (waitpid(pid, &status, 0) == -1) { 562 if (errno != EINTR && errno != EAGAIN) 563 fatal_f("waitpid: %s", strerror(errno)); 564 } 565 if (!WIFEXITED(status)) { 566 error("command '%.100s' exited abnormally", cmd); 567 return -1; 568 } 569 debug3("command returned status %d", WEXITSTATUS(status)); 570 return WEXITSTATUS(status); 571} 572 573/* 574 * Check whether a local network interface address appears in CIDR pattern- 575 * list 'addrlist'. Returns 1 if matched or 0 otherwise. 576 */ 577static int 578check_match_ifaddrs(const char *addrlist) 579{ 580 struct ifaddrs *ifa, *ifaddrs = NULL; 581 int r, found = 0; 582 char addr[NI_MAXHOST]; 583 socklen_t salen; 584 585 if (getifaddrs(&ifaddrs) != 0) { 586 error("match localnetwork: getifaddrs failed: %s", 587 strerror(errno)); 588 return 0; 589 } 590 for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) { 591 if (ifa->ifa_addr == NULL || ifa->ifa_name == NULL || 592 (ifa->ifa_flags & IFF_UP) == 0) 593 continue; 594 switch (ifa->ifa_addr->sa_family) { 595 case AF_INET: 596 salen = sizeof(struct sockaddr_in); 597 break; 598 case AF_INET6: 599 salen = sizeof(struct sockaddr_in6); 600 break; 601 case AF_LINK: 602 /* ignore */ 603 continue; 604 default: 605 debug2_f("interface %s: unsupported address family %d", 606 ifa->ifa_name, ifa->ifa_addr->sa_family); 607 continue; 608 } 609 if ((r = getnameinfo(ifa->ifa_addr, salen, addr, sizeof(addr), 610 NULL, 0, NI_NUMERICHOST)) != 0) { 611 debug2_f("interface %s getnameinfo failed: %s", 612 ifa->ifa_name, gai_strerror(r)); 613 continue; 614 } 615 debug3_f("interface %s addr %s", ifa->ifa_name, addr); 616 if (addr_match_cidr_list(addr, addrlist) == 1) { 617 debug3_f("matched interface %s: address %s in %s", 618 ifa->ifa_name, addr, addrlist); 619 found = 1; 620 break; 621 } 622 } 623 freeifaddrs(ifaddrs); 624 return found; 625} 626 627/* 628 * Expand a "match exec" command or an Include path, caller must free returned 629 * value. 630 */ 631static char * 632expand_match_exec_or_include_path(const char *path, Options *options, 633 struct passwd *pw, const char *host_arg, const char *original_host, 634 int final_pass, int is_include_path) 635{ 636 char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV]; 637 char uidstr[32], *conn_hash_hex, *keyalias, *jmphost, *ruser; 638 char *host, *ret; 639 int port; 640 641 port = options->port <= 0 ? default_ssh_port() : options->port; 642 ruser = options->user == NULL ? pw->pw_name : options->user; 643 if (final_pass) { 644 host = xstrdup(options->hostname); 645 } else if (options->hostname != NULL) { 646 /* NB. Please keep in sync with ssh.c:main() */ 647 host = percent_expand(options->hostname, 648 "h", host_arg, (char *)NULL); 649 } else { 650 host = xstrdup(host_arg); 651 } 652 if (gethostname(thishost, sizeof(thishost)) == -1) 653 fatal("gethostname: %s", strerror(errno)); 654 jmphost = option_clear_or_none(options->jump_host) ? 655 "" : options->jump_host; 656 strlcpy(shorthost, thishost, sizeof(shorthost)); 657 shorthost[strcspn(thishost, ".")] = '\0'; 658 snprintf(portstr, sizeof(portstr), "%d", port); 659 snprintf(uidstr, sizeof(uidstr), "%llu", 660 (unsigned long long)pw->pw_uid); 661 conn_hash_hex = ssh_connection_hash(thishost, host, 662 portstr, ruser, jmphost); 663 keyalias = options->host_key_alias ? options->host_key_alias : host; 664 665 ret = (is_include_path ? percent_dollar_expand : percent_expand)(path, 666 "C", conn_hash_hex, 667 "L", shorthost, 668 "d", pw->pw_dir, 669 "h", host, 670 "k", keyalias, 671 "l", thishost, 672 "n", original_host, 673 "p", portstr, 674 "r", ruser, 675 "u", pw->pw_name, 676 "i", uidstr, 677 "j", jmphost, 678 (char *)NULL); 679 free(host); 680 free(conn_hash_hex); 681 return ret; 682} 683 684/* 685 * Parse and execute a Match directive. 686 */ 687static int 688match_cfg_line(Options *options, const char *full_line, int *acp, char ***avp, 689 struct passwd *pw, const char *host_arg, const char *original_host, 690 const char *remote_command, int final_pass, int *want_final_pass, 691 const char *filename, int linenum) 692{ 693 char *arg, *oattrib = NULL, *attrib = NULL, *cmd, *host, *criteria; 694 const char *ruser; 695 int r, this_result, result = 1, attributes = 0, negate; 696 697 /* 698 * Configuration is likely to be incomplete at this point so we 699 * must be prepared to use default values. 700 */ 701 ruser = options->user == NULL ? pw->pw_name : options->user; 702 if (final_pass) { 703 host = xstrdup(options->hostname); 704 } else if (options->hostname != NULL) { 705 /* NB. Please keep in sync with ssh.c:main() */ 706 host = percent_expand(options->hostname, 707 "h", host_arg, (char *)NULL); 708 } else { 709 host = xstrdup(host_arg); 710 } 711 712 debug2("checking match for '%s' host %s originally %s", 713 full_line, host, original_host); 714 while ((attrib = argv_next(acp, avp)) != NULL) { 715 /* Terminate on comment */ 716 if (*attrib == '#') { 717 argv_consume(acp); 718 break; 719 } 720 attrib = oattrib = xstrdup(attrib); 721 arg = criteria = NULL; 722 this_result = 1; 723 if ((negate = (attrib[0] == '!'))) 724 attrib++; 725 /* Criterion "all" has no argument and must appear alone */ 726 if (strcasecmp(attrib, "all") == 0) { 727 if (attributes > 1 || 728 ((arg = argv_next(acp, avp)) != NULL && 729 *arg != '\0' && *arg != '#')) { 730 error("%.200s line %d: '%s' cannot be combined " 731 "with other Match attributes", 732 filename, linenum, oattrib); 733 result = -1; 734 goto out; 735 } 736 if (arg != NULL && *arg == '#') 737 argv_consume(acp); /* consume remaining args */ 738 if (result) 739 result = negate ? 0 : 1; 740 goto out; 741 } 742 attributes++; 743 /* criteria "final" and "canonical" have no argument */ 744 if (strcasecmp(attrib, "canonical") == 0 || 745 strcasecmp(attrib, "final") == 0) { 746 /* 747 * If the config requests "Match final" without 748 * negation then remember this so we can perform a 749 * second pass later. 750 */ 751 if (strcasecmp(attrib, "final") == 0 && 752 want_final_pass != NULL) 753 *want_final_pass |= !negate; 754 r = !!final_pass; /* force bitmask member to boolean */ 755 if (r == (negate ? 1 : 0)) 756 this_result = result = 0; 757 debug3("%.200s line %d: %smatched '%s'", 758 filename, linenum, 759 this_result ? "" : "not ", oattrib); 760 goto next; 761 } 762 763 /* Keep this list in sync with below */ 764 if (strprefix(attrib, "host=", 1) != NULL || 765 strprefix(attrib, "originalhost=", 1) != NULL || 766 strprefix(attrib, "user=", 1) != NULL || 767 strprefix(attrib, "localuser=", 1) != NULL || 768 strprefix(attrib, "localnetwork=", 1) != NULL || 769 strprefix(attrib, "version=", 1) != NULL || 770 strprefix(attrib, "tagged=", 1) != NULL || 771 strprefix(attrib, "command=", 1) != NULL || 772 strprefix(attrib, "exec=", 1) != NULL) { 773 arg = strchr(attrib, '='); 774 *(arg++) = '\0'; 775 } else if ((arg = argv_next(acp, avp)) == NULL) { 776 error("%.200s line %d: missing argument for Match '%s'", 777 filename, linenum, oattrib); 778 result = -1; 779 goto out; 780 } 781 782 /* 783 * All other criteria require an argument, though it may 784 * be the empty string for the "tagged" and "command" 785 * options. 786 */ 787 if (*arg == '\0' && 788 strcasecmp(attrib, "tagged") != 0 && 789 strcasecmp(attrib, "command") != 0) 790 arg = NULL; 791 if (arg == NULL || *arg == '#') { 792 error("Missing Match criteria for %s", attrib); 793 result = -1; 794 goto out; 795 } 796 if (strcasecmp(attrib, "host") == 0) { 797 criteria = xstrdup(host); 798 r = match_hostname(host, arg) == 1; 799 if (r == (negate ? 1 : 0)) 800 this_result = result = 0; 801 } else if (strcasecmp(attrib, "originalhost") == 0) { 802 criteria = xstrdup(original_host); 803 r = match_hostname(original_host, arg) == 1; 804 if (r == (negate ? 1 : 0)) 805 this_result = result = 0; 806 } else if (strcasecmp(attrib, "user") == 0) { 807 criteria = xstrdup(ruser); 808 r = match_pattern_list(ruser, arg, 0) == 1; 809 if (r == (negate ? 1 : 0)) 810 this_result = result = 0; 811 } else if (strcasecmp(attrib, "localuser") == 0) { 812 criteria = xstrdup(pw->pw_name); 813 r = match_pattern_list(pw->pw_name, arg, 0) == 1; 814 if (r == (negate ? 1 : 0)) 815 this_result = result = 0; 816 } else if (strcasecmp(attrib, "localnetwork") == 0) { 817 if (addr_match_cidr_list(NULL, arg) == -1) { 818 /* Error already printed */ 819 result = -1; 820 goto out; 821 } 822 r = check_match_ifaddrs(arg) == 1; 823 if (r == (negate ? 1 : 0)) 824 this_result = result = 0; 825 } else if (strcasecmp(attrib, "version") == 0) { 826 criteria = xstrdup(SSH_RELEASE); 827 r = match_pattern_list(SSH_RELEASE, arg, 0) == 1; 828 if (r == (negate ? 1 : 0)) 829 this_result = result = 0; 830 } else if (strcasecmp(attrib, "tagged") == 0) { 831 criteria = xstrdup(options->tag == NULL ? "" : 832 options->tag); 833 /* Special case: empty criteria matches empty arg */ 834 r = (*criteria == '\0') ? *arg == '\0' : 835 match_pattern_list(criteria, arg, 0) == 1; 836 if (r == (negate ? 1 : 0)) 837 this_result = result = 0; 838 } else if (strcasecmp(attrib, "command") == 0) { 839 criteria = xstrdup(remote_command == NULL ? 840 "" : remote_command); 841 /* Special case: empty criteria matches empty arg */ 842 r = (*criteria == '\0') ? *arg == '\0' : 843 match_pattern_list(criteria, arg, 0) == 1; 844 if (r == (negate ? 1 : 0)) 845 this_result = result = 0; 846 } else if (strcasecmp(attrib, "sessiontype") == 0) { 847 if (options->session_type == SESSION_TYPE_SUBSYSTEM) 848 criteria = xstrdup("subsystem"); 849 else if (options->session_type == SESSION_TYPE_NONE) 850 criteria = xstrdup("none"); 851 else if (remote_command != NULL && 852 *remote_command != '\0') 853 criteria = xstrdup("exec"); 854 else 855 criteria = xstrdup("shell"); 856 r = match_pattern_list(criteria, arg, 0) == 1; 857 if (r == (negate ? 1 : 0)) 858 this_result = result = 0; 859 } else if (strcasecmp(attrib, "exec") == 0) { 860 if ((cmd = expand_match_exec_or_include_path(arg, 861 options, pw, host_arg, original_host, 862 final_pass, 0)) == NULL) { 863 fatal("%.200s line %d: failed to expand match " 864 "exec '%.100s'", filename, linenum, arg); 865 } 866 if (result != 1) { 867 /* skip execution if prior predicate failed */ 868 debug3("%.200s line %d: skipped exec " 869 "\"%.100s\"", filename, linenum, cmd); 870 free(cmd); 871 goto next; 872 } 873 r = execute_in_shell(cmd); 874 if (r == -1) { 875 fatal("%.200s line %d: match exec " 876 "'%.100s' error", filename, 877 linenum, cmd); 878 } 879 criteria = xstrdup(cmd); 880 free(cmd); 881 /* Force exit status to boolean */ 882 r = r == 0; 883 if (r == (negate ? 1 : 0)) 884 this_result = result = 0; 885 } else { 886 error("Unsupported Match attribute %s", attrib); 887 result = -1; 888 goto out; 889 } 890 debug3("%.200s line %d: %smatched '%s%s%.100s%s' ", 891 filename, linenum, this_result ? "": "not ", oattrib, 892 criteria == NULL ? "" : " \"", 893 criteria == NULL ? "" : criteria, 894 criteria == NULL ? "" : "\""); 895 next: 896 free(criteria); 897 free(oattrib); 898 oattrib = attrib = NULL; 899 } 900 if (attributes == 0) { 901 error("One or more attributes required for Match"); 902 result = -1; 903 goto out; 904 } 905 out: 906 if (result != -1) 907 debug2("match %sfound", result ? "" : "not "); 908 free(oattrib); 909 free(host); 910 return result; 911} 912 913/* Remove environment variable by pattern */ 914static void 915rm_env(Options *options, const char *arg, const char *filename, int linenum) 916{ 917 u_int i, j, onum_send_env = options->num_send_env; 918 919 /* Remove an environment variable */ 920 for (i = 0; i < options->num_send_env; ) { 921 if (!match_pattern(options->send_env[i], arg + 1)) { 922 i++; 923 continue; 924 } 925 debug3("%s line %d: removing environment %s", 926 filename, linenum, options->send_env[i]); 927 free(options->send_env[i]); 928 options->send_env[i] = NULL; 929 for (j = i; j < options->num_send_env - 1; j++) { 930 options->send_env[j] = options->send_env[j + 1]; 931 options->send_env[j + 1] = NULL; 932 } 933 options->num_send_env--; 934 /* NB. don't increment i */ 935 } 936 if (onum_send_env != options->num_send_env) { 937 options->send_env = xrecallocarray(options->send_env, 938 onum_send_env, options->num_send_env, 939 sizeof(*options->send_env)); 940 } 941} 942 943/* 944 * Returns the number of the token pointed to by cp or oBadOption. 945 */ 946static OpCodes 947parse_token(const char *cp, const char *filename, int linenum, 948 const char *ignored_unknown) 949{ 950 int i; 951 952 for (i = 0; keywords[i].name; i++) 953 if (strcmp(cp, keywords[i].name) == 0) 954 return keywords[i].opcode; 955 if (ignored_unknown != NULL && 956 match_pattern_list(cp, ignored_unknown, 1) == 1) 957 return oIgnoredUnknownOption; 958 error("%s: line %d: Bad configuration option: %s", 959 filename, linenum, cp); 960 return oBadOption; 961} 962 963static void 964free_canon_cnames(struct allowed_cname *cnames, u_int n) 965{ 966 u_int i; 967 968 if (cnames == NULL || n == 0) 969 return; 970 for (i = 0; i < n; i++) { 971 free(cnames[i].source_list); 972 free(cnames[i].target_list); 973 } 974 free(cnames); 975} 976 977/* Multistate option parsing */ 978struct multistate { 979 char *key; 980 int value; 981}; 982static const struct multistate multistate_flag[] = { 983 { "true", 1 }, 984 { "false", 0 }, 985 { "yes", 1 }, 986 { "no", 0 }, 987 { NULL, -1 } 988}; 989static const struct multistate multistate_yesnoask[] = { 990 { "true", 1 }, 991 { "false", 0 }, 992 { "yes", 1 }, 993 { "no", 0 }, 994 { "ask", 2 }, 995 { NULL, -1 } 996}; 997static const struct multistate multistate_strict_hostkey[] = { 998 { "true", SSH_STRICT_HOSTKEY_YES }, 999 { "false", SSH_STRICT_HOSTKEY_OFF }, 1000 { "yes", SSH_STRICT_HOSTKEY_YES }, 1001 { "no", SSH_STRICT_HOSTKEY_OFF }, 1002 { "ask", SSH_STRICT_HOSTKEY_ASK }, 1003 { "off", SSH_STRICT_HOSTKEY_OFF }, 1004 { "accept-new", SSH_STRICT_HOSTKEY_NEW }, 1005 { NULL, -1 } 1006}; 1007static const struct multistate multistate_yesnoaskconfirm[] = { 1008 { "true", 1 }, 1009 { "false", 0 }, 1010 { "yes", 1 }, 1011 { "no", 0 }, 1012 { "ask", 2 }, 1013 { "confirm", 3 }, 1014 { NULL, -1 } 1015}; 1016static const struct multistate multistate_addressfamily[] = { 1017 { "inet", AF_INET }, 1018 { "inet6", AF_INET6 }, 1019 { "any", AF_UNSPEC }, 1020 { NULL, -1 } 1021}; 1022static const struct multistate multistate_controlmaster[] = { 1023 { "true", SSHCTL_MASTER_YES }, 1024 { "yes", SSHCTL_MASTER_YES }, 1025 { "false", SSHCTL_MASTER_NO }, 1026 { "no", SSHCTL_MASTER_NO }, 1027 { "auto", SSHCTL_MASTER_AUTO }, 1028 { "ask", SSHCTL_MASTER_ASK }, 1029 { "autoask", SSHCTL_MASTER_AUTO_ASK }, 1030 { NULL, -1 } 1031}; 1032static const struct multistate multistate_tunnel[] = { 1033 { "ethernet", SSH_TUNMODE_ETHERNET }, 1034 { "point-to-point", SSH_TUNMODE_POINTOPOINT }, 1035 { "true", SSH_TUNMODE_DEFAULT }, 1036 { "yes", SSH_TUNMODE_DEFAULT }, 1037 { "false", SSH_TUNMODE_NO }, 1038 { "no", SSH_TUNMODE_NO }, 1039 { NULL, -1 } 1040}; 1041static const struct multistate multistate_requesttty[] = { 1042 { "true", REQUEST_TTY_YES }, 1043 { "yes", REQUEST_TTY_YES }, 1044 { "false", REQUEST_TTY_NO }, 1045 { "no", REQUEST_TTY_NO }, 1046 { "force", REQUEST_TTY_FORCE }, 1047 { "auto", REQUEST_TTY_AUTO }, 1048 { NULL, -1 } 1049}; 1050static const struct multistate multistate_sessiontype[] = { 1051 { "none", SESSION_TYPE_NONE }, 1052 { "subsystem", SESSION_TYPE_SUBSYSTEM }, 1053 { "default", SESSION_TYPE_DEFAULT }, 1054 { NULL, -1 } 1055}; 1056static const struct multistate multistate_canonicalizehostname[] = { 1057 { "true", SSH_CANONICALISE_YES }, 1058 { "false", SSH_CANONICALISE_NO }, 1059 { "yes", SSH_CANONICALISE_YES }, 1060 { "no", SSH_CANONICALISE_NO }, 1061 { "always", SSH_CANONICALISE_ALWAYS }, 1062 { NULL, -1 } 1063}; 1064static const struct multistate multistate_pubkey_auth[] = { 1065 { "true", SSH_PUBKEY_AUTH_ALL }, 1066 { "false", SSH_PUBKEY_AUTH_NO }, 1067 { "yes", SSH_PUBKEY_AUTH_ALL }, 1068 { "no", SSH_PUBKEY_AUTH_NO }, 1069 { "unbound", SSH_PUBKEY_AUTH_UNBOUND }, 1070 { "host-bound", SSH_PUBKEY_AUTH_HBOUND }, 1071 { NULL, -1 } 1072}; 1073static const struct multistate multistate_compression[] = { 1074#ifdef WITH_ZLIB 1075 { "yes", COMP_DELAYED }, 1076#endif 1077 { "no", COMP_NONE }, 1078 { NULL, -1 } 1079}; 1080/* XXX this will need to be replaced with a bitmask if we add more flags */ 1081static const struct multistate multistate_warnweakcrypto[] = { 1082 { "true", 1 }, 1083 { "false", 0 }, 1084 { "yes", 1 }, 1085 { "no", 0 }, 1086 { "no-pq-kex", 0 }, 1087 { NULL, -1 } 1088}; 1089 1090static int 1091parse_multistate_value(const char *arg, const char *filename, int linenum, 1092 const struct multistate *multistate_ptr) 1093{ 1094 int i; 1095 1096 if (!arg || *arg == '\0') { 1097 error("%s line %d: missing argument.", filename, linenum); 1098 return -1; 1099 } 1100 for (i = 0; multistate_ptr[i].key != NULL; i++) { 1101 if (strcasecmp(arg, multistate_ptr[i].key) == 0) 1102 return multistate_ptr[i].value; 1103 } 1104 return -1; 1105} 1106 1107/* 1108 * Processes a single option line as used in the configuration files. This 1109 * only sets those values that have not already been set. 1110 */ 1111int 1112process_config_line(Options *options, struct passwd *pw, const char *host, 1113 const char *original_host, const char *remote_command, char *line, 1114 const char *filename, int linenum, int *activep, int flags) 1115{ 1116 return process_config_line_depth(options, pw, host, original_host, 1117 remote_command, line, filename, linenum, activep, flags, NULL, 0); 1118} 1119 1120#define WHITESPACE " \t\r\n" 1121static int 1122process_config_line_depth(Options *options, struct passwd *pw, const char *host, 1123 const char *original_host, const char *remote_command, char *line, 1124 const char *filename, int linenum, int *activep, int flags, 1125 int *want_final_pass, int depth) 1126{ 1127 char *str, **charptr, *endofnumber, *keyword, *arg, *arg2, *p; 1128 char **cpptr, ***cppptr, fwdarg[256]; 1129 u_int i, *uintptr, max_entries = 0; 1130 int r, oactive, negated, opcode, *intptr, value, value2, cmdline = 0; 1131 int remotefwd, dynamicfwd, ca_only = 0, found = 0; 1132 LogLevel *log_level_ptr; 1133 SyslogFacility *log_facility_ptr; 1134 long long val64; 1135 size_t len; 1136 struct Forward fwd; 1137 const struct multistate *multistate_ptr; 1138 glob_t gl; 1139 const char *errstr; 1140 char **oav = NULL, **av; 1141 int oac = 0, ac; 1142 int ret = -1; 1143 struct allowed_cname *cnames = NULL; 1144 u_int ncnames = 0; 1145 char **strs = NULL; /* string array arguments; freed implicitly */ 1146 u_int nstrs = 0; 1147 1148 if (activep == NULL) { /* We are processing a command line directive */ 1149 cmdline = 1; 1150 activep = &cmdline; 1151 } 1152 1153 /* Strip trailing whitespace. Allow \f (form feed) at EOL only */ 1154 if ((len = strlen(line)) == 0) 1155 return 0; 1156 for (len--; len > 0; len--) { 1157 if (strchr(WHITESPACE "\f", line[len]) == NULL) 1158 break; 1159 line[len] = '\0'; 1160 } 1161 1162 str = line; 1163 /* Get the keyword. (Each line is supposed to begin with a keyword). */ 1164 if ((keyword = strdelim(&str)) == NULL) 1165 return 0; 1166 /* Ignore leading whitespace. */ 1167 if (*keyword == '\0') 1168 keyword = strdelim(&str); 1169 if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#') 1170 return 0; 1171 /* Match lowercase keyword */ 1172 lowercase(keyword); 1173 1174 /* Prepare to parse remainder of line */ 1175 if (str != NULL) 1176 str += strspn(str, WHITESPACE); 1177 if (str == NULL || *str == '\0') { 1178 error("%s line %d: no argument after keyword \"%s\"", 1179 filename, linenum, keyword); 1180 return -1; 1181 } 1182 opcode = parse_token(keyword, filename, linenum, 1183 options->ignored_unknown); 1184 if (argv_split(str, &oac, &oav, 1) != 0) { 1185 error("%s line %d: invalid quotes", filename, linenum); 1186 return -1; 1187 } 1188 ac = oac; 1189 av = oav; 1190 1191 switch (opcode) { 1192 case oBadOption: 1193 /* don't panic, but count bad options */ 1194 goto out; 1195 case oIgnore: 1196 argv_consume(&ac); 1197 break; 1198 case oIgnoredUnknownOption: 1199 debug("%s line %d: Ignored unknown option \"%s\"", 1200 filename, linenum, keyword); 1201 argv_consume(&ac); 1202 break; 1203 case oConnectTimeout: 1204 intptr = &options->connection_timeout; 1205parse_time: 1206 arg = argv_next(&ac, &av); 1207 if (!arg || *arg == '\0') { 1208 error("%s line %d: missing time value.", 1209 filename, linenum); 1210 goto out; 1211 } 1212 if (strcmp(arg, "none") == 0) 1213 value = -1; 1214 else if ((value = convtime(arg)) == -1) { 1215 error("%s line %d: invalid time value.", 1216 filename, linenum); 1217 goto out; 1218 } 1219 if (*activep && *intptr == -1) 1220 *intptr = value; 1221 break; 1222 1223 case oForwardAgent: 1224 intptr = &options->forward_agent; 1225 1226 arg = argv_next(&ac, &av); 1227 if (!arg || *arg == '\0') { 1228 error("%s line %d: missing argument.", 1229 filename, linenum); 1230 goto out; 1231 } 1232 1233 value = -1; 1234 multistate_ptr = multistate_flag; 1235 for (i = 0; multistate_ptr[i].key != NULL; i++) { 1236 if (strcasecmp(arg, multistate_ptr[i].key) == 0) { 1237 value = multistate_ptr[i].value; 1238 break; 1239 } 1240 } 1241 if (value != -1) { 1242 if (*activep && *intptr == -1) 1243 *intptr = value; 1244 break; 1245 } 1246 /* ForwardAgent wasn't 'yes' or 'no', assume a path */ 1247 if (*activep && *intptr == -1) 1248 *intptr = 1; 1249 1250 charptr = &options->forward_agent_sock_path; 1251 goto parse_agent_path; 1252 1253 case oForwardX11: 1254 intptr = &options->forward_x11; 1255 parse_flag: 1256 multistate_ptr = multistate_flag; 1257 parse_multistate: 1258 arg = argv_next(&ac, &av); 1259 if ((value = parse_multistate_value(arg, filename, linenum, 1260 multistate_ptr)) == -1) { 1261 error("%s line %d: unsupported option \"%s\".", 1262 filename, linenum, arg); 1263 goto out; 1264 } 1265 if (*activep && *intptr == -1) 1266 *intptr = value; 1267 break; 1268 1269 case oForwardX11Trusted: 1270 intptr = &options->forward_x11_trusted; 1271 goto parse_flag; 1272 1273 case oForwardX11Timeout: 1274 intptr = &options->forward_x11_timeout; 1275 goto parse_time; 1276 1277 case oGatewayPorts: 1278 intptr = &options->fwd_opts.gateway_ports; 1279 goto parse_flag; 1280 1281 case oExitOnForwardFailure: 1282 intptr = &options->exit_on_forward_failure; 1283 goto parse_flag; 1284 1285 case oPasswordAuthentication: 1286 intptr = &options->password_authentication; 1287 goto parse_flag; 1288 1289 case oKbdInteractiveAuthentication: 1290 intptr = &options->kbd_interactive_authentication; 1291 goto parse_flag; 1292 1293 case oKbdInteractiveDevices: 1294 charptr = &options->kbd_interactive_devices; 1295 goto parse_string; 1296 1297 case oPubkeyAuthentication: 1298 multistate_ptr = multistate_pubkey_auth; 1299 intptr = &options->pubkey_authentication; 1300 goto parse_multistate; 1301 1302 case oHostbasedAuthentication: 1303 intptr = &options->hostbased_authentication; 1304 goto parse_flag; 1305 1306 case oGssAuthentication: 1307 intptr = &options->gss_authentication; 1308 goto parse_flag; 1309 1310 case oGssDelegateCreds: 1311 intptr = &options->gss_deleg_creds; 1312 goto parse_flag; 1313 1314 case oBatchMode: 1315 intptr = &options->batch_mode; 1316 goto parse_flag; 1317 1318 case oCheckHostIP: 1319 intptr = &options->check_host_ip; 1320 goto parse_flag; 1321 1322 case oVerifyHostKeyDNS: 1323 intptr = &options->verify_host_key_dns; 1324 multistate_ptr = multistate_yesnoask; 1325 goto parse_multistate; 1326 1327 case oStrictHostKeyChecking: 1328 intptr = &options->strict_host_key_checking; 1329 multistate_ptr = multistate_strict_hostkey; 1330 goto parse_multistate; 1331 1332 case oCompression: 1333 intptr = &options->compression; 1334 multistate_ptr = multistate_compression; 1335 goto parse_multistate; 1336 1337 case oTCPKeepAlive: 1338 intptr = &options->tcp_keep_alive; 1339 goto parse_flag; 1340 1341 case oNoHostAuthenticationForLocalhost: 1342 intptr = &options->no_host_authentication_for_localhost; 1343 goto parse_flag; 1344 1345 case oNumberOfPasswordPrompts: 1346 intptr = &options->number_of_password_prompts; 1347 goto parse_int; 1348 1349 case oRekeyLimit: 1350 arg = argv_next(&ac, &av); 1351 if (!arg || *arg == '\0') { 1352 error("%.200s line %d: Missing argument.", filename, 1353 linenum); 1354 goto out; 1355 } 1356 if (strcmp(arg, "default") == 0) { 1357 val64 = 0; 1358 } else { 1359 if (scan_scaled(arg, &val64) == -1) { 1360 error("%.200s line %d: Bad number '%s': %s", 1361 filename, linenum, arg, strerror(errno)); 1362 goto out; 1363 } 1364 if (val64 != 0 && val64 < 16) { 1365 error("%.200s line %d: RekeyLimit too small", 1366 filename, linenum); 1367 goto out; 1368 } 1369 } 1370 if (*activep && options->rekey_limit == -1) 1371 options->rekey_limit = val64; 1372 if (ac != 0) { /* optional rekey interval present */ 1373 if (strcmp(av[0], "none") == 0) { 1374 (void)argv_next(&ac, &av); /* discard */ 1375 break; 1376 } 1377 intptr = &options->rekey_interval; 1378 goto parse_time; 1379 } 1380 break; 1381 1382 case oIdentityFile: 1383 arg = argv_next(&ac, &av); 1384 if (!arg || *arg == '\0') { 1385 error("%.200s line %d: Missing argument.", 1386 filename, linenum); 1387 goto out; 1388 } 1389 if (*activep) { 1390 intptr = &options->num_identity_files; 1391 if (*intptr >= SSH_MAX_IDENTITY_FILES) { 1392 error("%.200s line %d: Too many identity files " 1393 "specified (max %d).", filename, linenum, 1394 SSH_MAX_IDENTITY_FILES); 1395 goto out; 1396 } 1397 add_identity_file(options, NULL, 1398 arg, flags & SSHCONF_USERCONF); 1399 } 1400 break; 1401 1402 case oCertificateFile: 1403 arg = argv_next(&ac, &av); 1404 if (!arg || *arg == '\0') { 1405 error("%.200s line %d: Missing argument.", 1406 filename, linenum); 1407 goto out; 1408 } 1409 if (*activep) { 1410 intptr = &options->num_certificate_files; 1411 if (*intptr >= SSH_MAX_CERTIFICATE_FILES) { 1412 error("%.200s line %d: Too many certificate " 1413 "files specified (max %d).", 1414 filename, linenum, 1415 SSH_MAX_CERTIFICATE_FILES); 1416 goto out; 1417 } 1418 add_certificate_file(options, arg, 1419 flags & SSHCONF_USERCONF); 1420 } 1421 break; 1422 1423 case oXAuthLocation: 1424 charptr=&options->xauth_location; 1425 goto parse_string; 1426 1427 case oUser: 1428 charptr = &options->user; 1429parse_string: 1430 arg = argv_next(&ac, &av); 1431 if (!arg || *arg == '\0') { 1432 error("%.200s line %d: Missing argument.", 1433 filename, linenum); 1434 goto out; 1435 } 1436 if (*activep && *charptr == NULL) 1437 *charptr = xstrdup(arg); 1438 break; 1439 1440 case oGlobalKnownHostsFile: 1441 cpptr = (char **)&options->system_hostfiles; 1442 uintptr = &options->num_system_hostfiles; 1443 max_entries = SSH_MAX_HOSTS_FILES; 1444parse_char_array: 1445 i = 0; 1446 value = *uintptr == 0; /* was array empty when we started? */ 1447 while ((arg = argv_next(&ac, &av)) != NULL) { 1448 if (*arg == '\0') { 1449 error("%s line %d: keyword %s empty argument", 1450 filename, linenum, keyword); 1451 goto out; 1452 } 1453 /* Allow "none" only in first position */ 1454 if (strcasecmp(arg, "none") == 0) { 1455 if (i > 0 || ac > 0) { 1456 error("%s line %d: keyword %s \"none\" " 1457 "argument must appear alone.", 1458 filename, linenum, keyword); 1459 goto out; 1460 } 1461 } 1462 i++; 1463 if (*activep && value) { 1464 if ((*uintptr) >= max_entries) { 1465 error("%s line %d: too many %s " 1466 "entries.", filename, linenum, 1467 keyword); 1468 goto out; 1469 } 1470 cpptr[(*uintptr)++] = xstrdup(arg); 1471 } 1472 } 1473 break; 1474 1475 case oUserKnownHostsFile: 1476 cpptr = (char **)&options->user_hostfiles; 1477 uintptr = &options->num_user_hostfiles; 1478 max_entries = SSH_MAX_HOSTS_FILES; 1479 goto parse_char_array; 1480 1481 case oHostname: 1482 charptr = &options->hostname; 1483 goto parse_string; 1484 1485 case oTag: 1486 charptr = &options->tag; 1487 goto parse_string; 1488 1489 case oHostKeyAlias: 1490 charptr = &options->host_key_alias; 1491 goto parse_string; 1492 1493 case oPreferredAuthentications: 1494 charptr = &options->preferred_authentications; 1495 goto parse_string; 1496 1497 case oBindAddress: 1498 charptr = &options->bind_address; 1499 goto parse_string; 1500 1501 case oBindInterface: 1502 charptr = &options->bind_interface; 1503 goto parse_string; 1504 1505 case oPKCS11Provider: 1506 charptr = &options->pkcs11_provider; 1507 goto parse_string; 1508 1509 case oSecurityKeyProvider: 1510 charptr = &options->sk_provider; 1511 goto parse_string; 1512 1513 case oKnownHostsCommand: 1514 charptr = &options->known_hosts_command; 1515 goto parse_command; 1516 1517 case oProxyCommand: 1518 charptr = &options->proxy_command; 1519 /* Ignore ProxyCommand if ProxyJump already specified */ 1520 if (options->jump_host != NULL) 1521 charptr = &options->jump_host; /* Skip below */ 1522parse_command: 1523 if (str == NULL) { 1524 error("%.200s line %d: Missing argument.", 1525 filename, linenum); 1526 goto out; 1527 } 1528 len = strspn(str, WHITESPACE "="); 1529 if (*activep && *charptr == NULL) 1530 *charptr = xstrdup(str + len); 1531 argv_consume(&ac); 1532 break; 1533 1534 case oProxyJump: 1535 if (str == NULL) { 1536 error("%.200s line %d: Missing argument.", 1537 filename, linenum); 1538 goto out; 1539 } 1540 len = strspn(str, WHITESPACE "="); 1541 /* XXX use argv? */ 1542 if (parse_jump(str + len, options, *activep) == -1) { 1543 error("%.200s line %d: Invalid ProxyJump \"%s\"", 1544 filename, linenum, str + len); 1545 goto out; 1546 } 1547 argv_consume(&ac); 1548 break; 1549 1550 case oPort: 1551 arg = argv_next(&ac, &av); 1552 if (!arg || *arg == '\0') { 1553 error("%.200s line %d: Missing argument.", 1554 filename, linenum); 1555 goto out; 1556 } 1557 value = a2port(arg); 1558 if (value <= 0) { 1559 error("%.200s line %d: Bad port '%s'.", 1560 filename, linenum, arg); 1561 goto out; 1562 } 1563 if (*activep && options->port == -1) 1564 options->port = value; 1565 break; 1566 1567 case oConnectionAttempts: 1568 intptr = &options->connection_attempts; 1569parse_int: 1570 arg = argv_next(&ac, &av); 1571 if ((errstr = atoi_err(arg, &value)) != NULL) { 1572 error("%s line %d: integer value %s.", 1573 filename, linenum, errstr); 1574 goto out; 1575 } 1576 if (*activep && *intptr == -1) 1577 *intptr = value; 1578 break; 1579 1580 case oCiphers: 1581 arg = argv_next(&ac, &av); 1582 if (!arg || *arg == '\0') { 1583 error("%.200s line %d: Missing argument.", 1584 filename, linenum); 1585 goto out; 1586 } 1587 if (*arg != '-' && 1588 !ciphers_valid(*arg == '+' || *arg == '^' ? arg + 1 : arg)){ 1589 error("%.200s line %d: Bad SSH2 cipher spec '%s'.", 1590 filename, linenum, arg ? arg : "<NONE>"); 1591 goto out; 1592 } 1593 if (*activep && options->ciphers == NULL) 1594 options->ciphers = xstrdup(arg); 1595 break; 1596 1597 case oMacs: 1598 arg = argv_next(&ac, &av); 1599 if (!arg || *arg == '\0') { 1600 error("%.200s line %d: Missing argument.", 1601 filename, linenum); 1602 goto out; 1603 } 1604 if (*arg != '-' && 1605 !mac_valid(*arg == '+' || *arg == '^' ? arg + 1 : arg)) { 1606 error("%.200s line %d: Bad SSH2 MAC spec '%s'.", 1607 filename, linenum, arg ? arg : "<NONE>"); 1608 goto out; 1609 } 1610 if (*activep && options->macs == NULL) 1611 options->macs = xstrdup(arg); 1612 break; 1613 1614 case oKexAlgorithms: 1615 arg = argv_next(&ac, &av); 1616 if (!arg || *arg == '\0') { 1617 error("%.200s line %d: Missing argument.", 1618 filename, linenum); 1619 goto out; 1620 } 1621 if (*arg != '-' && 1622 !kex_names_valid(*arg == '+' || *arg == '^' ? 1623 arg + 1 : arg)) { 1624 error("%.200s line %d: Bad SSH2 KexAlgorithms '%s'.", 1625 filename, linenum, arg ? arg : "<NONE>"); 1626 goto out; 1627 } 1628 if (*activep && options->kex_algorithms == NULL) 1629 options->kex_algorithms = xstrdup(arg); 1630 break; 1631 1632 case oHostKeyAlgorithms: 1633 charptr = &options->hostkeyalgorithms; 1634 ca_only = 0; 1635parse_pubkey_algos: 1636 arg = argv_next(&ac, &av); 1637 if (!arg || *arg == '\0') { 1638 error("%.200s line %d: Missing argument.", 1639 filename, linenum); 1640 goto out; 1641 } 1642 if (*arg != '-' && 1643 !sshkey_names_valid2(*arg == '+' || *arg == '^' ? 1644 arg + 1 : arg, 1, ca_only)) { 1645 error("%s line %d: Bad key types '%s'.", 1646 filename, linenum, arg ? arg : "<NONE>"); 1647 goto out; 1648 } 1649 if (*activep && *charptr == NULL) 1650 *charptr = xstrdup(arg); 1651 break; 1652 1653 case oCASignatureAlgorithms: 1654 charptr = &options->ca_sign_algorithms; 1655 ca_only = 1; 1656 goto parse_pubkey_algos; 1657 1658 case oLogLevel: 1659 log_level_ptr = &options->log_level; 1660 arg = argv_next(&ac, &av); 1661 value = log_level_number(arg); 1662 if (value == SYSLOG_LEVEL_NOT_SET) { 1663 error("%.200s line %d: unsupported log level '%s'", 1664 filename, linenum, arg ? arg : "<NONE>"); 1665 goto out; 1666 } 1667 if (*activep && *log_level_ptr == SYSLOG_LEVEL_NOT_SET) 1668 *log_level_ptr = (LogLevel) value; 1669 break; 1670 1671 case oLogFacility: 1672 log_facility_ptr = &options->log_facility; 1673 arg = argv_next(&ac, &av); 1674 value = log_facility_number(arg); 1675 if (value == SYSLOG_FACILITY_NOT_SET) { 1676 error("%.200s line %d: unsupported log facility '%s'", 1677 filename, linenum, arg ? arg : "<NONE>"); 1678 goto out; 1679 } 1680 if (*log_facility_ptr == -1) 1681 *log_facility_ptr = (SyslogFacility) value; 1682 break; 1683 1684 case oLogVerbose: 1685 cppptr = &options->log_verbose; 1686 uintptr = &options->num_log_verbose; 1687 i = 0; 1688 while ((arg = argv_next(&ac, &av)) != NULL) { 1689 if (*arg == '\0') { 1690 error("%s line %d: keyword %s empty argument", 1691 filename, linenum, keyword); 1692 goto out; 1693 } 1694 /* Allow "none" only in first position */ 1695 if (strcasecmp(arg, "none") == 0) { 1696 if (i > 0 || ac > 0) { 1697 error("%s line %d: keyword %s \"none\" " 1698 "argument must appear alone.", 1699 filename, linenum, keyword); 1700 goto out; 1701 } 1702 } 1703 i++; 1704 if (*activep && *uintptr == 0) { 1705 *cppptr = xrecallocarray(*cppptr, *uintptr, 1706 *uintptr + 1, sizeof(**cppptr)); 1707 (*cppptr)[(*uintptr)++] = xstrdup(arg); 1708 } 1709 } 1710 break; 1711 1712 case oLocalForward: 1713 case oRemoteForward: 1714 case oDynamicForward: 1715 arg = argv_next(&ac, &av); 1716 if (!arg || *arg == '\0') { 1717 error("%.200s line %d: Missing argument.", 1718 filename, linenum); 1719 goto out; 1720 } 1721 1722 remotefwd = (opcode == oRemoteForward); 1723 dynamicfwd = (opcode == oDynamicForward); 1724 1725 if (!dynamicfwd) { 1726 arg2 = argv_next(&ac, &av); 1727 if (arg2 == NULL || *arg2 == '\0') { 1728 if (remotefwd) 1729 dynamicfwd = 1; 1730 else { 1731 error("%.200s line %d: Missing target " 1732 "argument.", filename, linenum); 1733 goto out; 1734 } 1735 } else { 1736 /* construct a string for parse_forward */ 1737 snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg, 1738 arg2); 1739 } 1740 } 1741 if (dynamicfwd) 1742 strlcpy(fwdarg, arg, sizeof(fwdarg)); 1743 1744 if (parse_forward(&fwd, fwdarg, dynamicfwd, remotefwd) == 0) { 1745 error("%.200s line %d: Bad forwarding specification.", 1746 filename, linenum); 1747 goto out; 1748 } 1749 1750 if (*activep) { 1751 if (remotefwd) { 1752 add_remote_forward(options, &fwd); 1753 } else { 1754 add_local_forward(options, &fwd); 1755 } 1756 } 1757 break; 1758 1759 case oPermitRemoteOpen: 1760 uintptr = &options->num_permitted_remote_opens; 1761 cppptr = &options->permitted_remote_opens; 1762 found = *uintptr == 0; 1763 while ((arg = argv_next(&ac, &av)) != NULL) { 1764 arg2 = xstrdup(arg); 1765 /* Allow any/none only in first position */ 1766 if (strcasecmp(arg, "none") == 0 || 1767 strcasecmp(arg, "any") == 0) { 1768 if (nstrs > 0 || ac > 0) { 1769 error("%s line %d: keyword %s \"%s\" " 1770 "argument must appear alone.", 1771 filename, linenum, keyword, arg); 1772 free(arg2); 1773 goto out; 1774 } 1775 } else { 1776 p = hpdelim(&arg); 1777 if (p == NULL) { 1778 fatal("%s line %d: missing host in %s", 1779 filename, linenum, 1780 lookup_opcode_name(opcode)); 1781 } 1782 p = cleanhostname(p); 1783 /* 1784 * don't want to use permitopen_port to avoid 1785 * dependency on channels.[ch] here. 1786 */ 1787 if (arg == NULL || (strcmp(arg, "*") != 0 && 1788 a2port(arg) <= 0)) { 1789 fatal("%s line %d: bad port number " 1790 "in %s", filename, linenum, 1791 lookup_opcode_name(opcode)); 1792 } 1793 } 1794 opt_array_append(filename, linenum, 1795 lookup_opcode_name(opcode), 1796 &strs, &nstrs, arg2); 1797 free(arg2); 1798 } 1799 if (nstrs == 0) 1800 fatal("%s line %d: missing %s specification", 1801 filename, linenum, lookup_opcode_name(opcode)); 1802 if (found && *activep) { 1803 *cppptr = strs; 1804 *uintptr = nstrs; 1805 strs = NULL; /* transferred */ 1806 nstrs = 0; 1807 } 1808 break; 1809 1810 case oClearAllForwardings: 1811 intptr = &options->clear_forwardings; 1812 goto parse_flag; 1813 1814 case oHost: 1815 if (cmdline) { 1816 error("Host directive not supported as a command-line " 1817 "option"); 1818 goto out; 1819 } 1820 *activep = 0; 1821 arg2 = NULL; 1822 while ((arg = argv_next(&ac, &av)) != NULL) { 1823 if (*arg == '\0') { 1824 error("%s line %d: keyword %s empty argument", 1825 filename, linenum, keyword); 1826 goto out; 1827 } 1828 if ((flags & SSHCONF_NEVERMATCH) != 0) { 1829 argv_consume(&ac); 1830 break; 1831 } 1832 negated = *arg == '!'; 1833 if (negated) 1834 arg++; 1835 if (match_pattern(host, arg)) { 1836 if (negated) { 1837 debug("%.200s line %d: Skipping Host " 1838 "block because of negated match " 1839 "for %.100s", filename, linenum, 1840 arg); 1841 *activep = 0; 1842 argv_consume(&ac); 1843 break; 1844 } 1845 if (!*activep) 1846 arg2 = arg; /* logged below */ 1847 *activep = 1; 1848 } 1849 } 1850 if (*activep) 1851 debug("%.200s line %d: Applying options for %.100s", 1852 filename, linenum, arg2); 1853 break; 1854 1855 case oMatch: 1856 if (cmdline) { 1857 error("Host directive not supported as a command-line " 1858 "option"); 1859 goto out; 1860 } 1861 value = match_cfg_line(options, str, &ac, &av, pw, host, 1862 original_host, remote_command, flags & SSHCONF_FINAL, 1863 want_final_pass, filename, linenum); 1864 if (value < 0) { 1865 error("%.200s line %d: Bad Match condition", filename, 1866 linenum); 1867 goto out; 1868 } 1869 *activep = (flags & SSHCONF_NEVERMATCH) ? 0 : value; 1870 break; 1871 1872 case oEscapeChar: 1873 intptr = &options->escape_char; 1874 arg = argv_next(&ac, &av); 1875 if (!arg || *arg == '\0') { 1876 error("%.200s line %d: Missing argument.", 1877 filename, linenum); 1878 goto out; 1879 } 1880 if (strcmp(arg, "none") == 0) 1881 value = SSH_ESCAPECHAR_NONE; 1882 else if (arg[1] == '\0') 1883 value = (u_char) arg[0]; 1884 else if (arg[0] == '^' && arg[2] == 0 && 1885 (u_char) arg[1] >= 64 && (u_char) arg[1] < 128) 1886 value = (u_char) arg[1] & 31; 1887 else { 1888 error("%.200s line %d: Bad escape character.", 1889 filename, linenum); 1890 goto out; 1891 } 1892 if (*activep && *intptr == -1) 1893 *intptr = value; 1894 break; 1895 1896 case oAddressFamily: 1897 intptr = &options->address_family; 1898 multistate_ptr = multistate_addressfamily; 1899 goto parse_multistate; 1900 1901 case oEnableSSHKeysign: 1902 intptr = &options->enable_ssh_keysign; 1903 goto parse_flag; 1904 1905 case oIdentitiesOnly: 1906 intptr = &options->identities_only; 1907 goto parse_flag; 1908 1909 case oServerAliveInterval: 1910 intptr = &options->server_alive_interval; 1911 goto parse_time; 1912 1913 case oServerAliveCountMax: 1914 intptr = &options->server_alive_count_max; 1915 goto parse_int; 1916 1917 case oSendEnv: 1918 /* XXX appends to list; doesn't respect first-match-wins */ 1919 while ((arg = argv_next(&ac, &av)) != NULL) { 1920 if (*arg == '\0' || strchr(arg, '=') != NULL) { 1921 error("%s line %d: Invalid environment name.", 1922 filename, linenum); 1923 goto out; 1924 } 1925 found = 1; 1926 if (!*activep) 1927 continue; 1928 if (*arg == '-') { 1929 /* Removing an env var */ 1930 rm_env(options, arg, filename, linenum); 1931 continue; 1932 } 1933 opt_array_append(filename, linenum, 1934 lookup_opcode_name(opcode), 1935 &options->send_env, &options->num_send_env, arg); 1936 } 1937 if (!found) { 1938 fatal("%s line %d: no %s specified", 1939 filename, linenum, keyword); 1940 } 1941 break; 1942 1943 case oSetEnv: 1944 found = options->num_setenv == 0; 1945 while ((arg = argv_next(&ac, &av)) != NULL) { 1946 if (strchr(arg, '=') == NULL) { 1947 error("%s line %d: Invalid SetEnv.", 1948 filename, linenum); 1949 goto out; 1950 } 1951 if (lookup_setenv_in_list(arg, strs, nstrs) != NULL) { 1952 debug2("%s line %d: ignoring duplicate env " 1953 "name \"%.64s\"", filename, linenum, arg); 1954 continue; 1955 } 1956 opt_array_append(filename, linenum, 1957 lookup_opcode_name(opcode), 1958 &strs, &nstrs, arg); 1959 } 1960 if (nstrs == 0) { 1961 fatal("%s line %d: no %s specified", 1962 filename, linenum, keyword); 1963 } 1964 if (found && *activep) { 1965 options->setenv = strs; 1966 options->num_setenv = nstrs; 1967 strs = NULL; /* transferred */ 1968 nstrs = 0; 1969 } 1970 break; 1971 1972 case oControlPath: 1973 charptr = &options->control_path; 1974 goto parse_string; 1975 1976 case oControlMaster: 1977 intptr = &options->control_master; 1978 multistate_ptr = multistate_controlmaster; 1979 goto parse_multistate; 1980 1981 case oControlPersist: 1982 /* no/false/yes/true, or a time spec */ 1983 intptr = &options->control_persist; 1984 arg = argv_next(&ac, &av); 1985 if (!arg || *arg == '\0') { 1986 error("%.200s line %d: Missing ControlPersist" 1987 " argument.", filename, linenum); 1988 goto out; 1989 } 1990 value = 0; 1991 value2 = 0; /* timeout */ 1992 if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0) 1993 value = 0; 1994 else if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0) 1995 value = 1; 1996 else if ((value2 = convtime(arg)) >= 0) 1997 value = 1; 1998 else { 1999 error("%.200s line %d: Bad ControlPersist argument.", 2000 filename, linenum); 2001 goto out; 2002 } 2003 if (*activep && *intptr == -1) { 2004 *intptr = value; 2005 options->control_persist_timeout = value2; 2006 } 2007 break; 2008 2009 case oHashKnownHosts: 2010 intptr = &options->hash_known_hosts; 2011 goto parse_flag; 2012 2013 case oTunnel: 2014 intptr = &options->tun_open; 2015 multistate_ptr = multistate_tunnel; 2016 goto parse_multistate; 2017 2018 case oTunnelDevice: 2019 arg = argv_next(&ac, &av); 2020 if (!arg || *arg == '\0') { 2021 error("%.200s line %d: Missing argument.", 2022 filename, linenum); 2023 goto out; 2024 } 2025 value = a2tun(arg, &value2); 2026 if (value == SSH_TUNID_ERR) { 2027 error("%.200s line %d: Bad tun device.", 2028 filename, linenum); 2029 goto out; 2030 } 2031 if (*activep && options->tun_local == -1) { 2032 options->tun_local = value; 2033 options->tun_remote = value2; 2034 } 2035 break; 2036 2037 case oLocalCommand: 2038 charptr = &options->local_command; 2039 goto parse_command; 2040 2041 case oPermitLocalCommand: 2042 intptr = &options->permit_local_command; 2043 goto parse_flag; 2044 2045 case oRemoteCommand: 2046 charptr = &options->remote_command; 2047 goto parse_command; 2048 2049 case oVisualHostKey: 2050 intptr = &options->visual_host_key; 2051 goto parse_flag; 2052 2053 case oInclude: 2054 if (cmdline) { 2055 error("Include directive not supported as a " 2056 "command-line option"); 2057 goto out; 2058 } 2059 value = 0; 2060 while ((arg = argv_next(&ac, &av)) != NULL) { 2061 if (*arg == '\0') { 2062 error("%s line %d: keyword %s empty argument", 2063 filename, linenum, keyword); 2064 goto out; 2065 } 2066 /* Expand %tokens and environment variables */ 2067 if ((p = expand_match_exec_or_include_path(arg, 2068 options, pw, host, original_host, 2069 flags & SSHCONF_FINAL, 1)) == NULL) { 2070 error("%.200s line %d: Unable to expand user " 2071 "config file '%.100s'", 2072 filename, linenum, arg); 2073 continue; 2074 } 2075 /* 2076 * Ensure all paths are anchored. User configuration 2077 * files may begin with '~/' but system configurations 2078 * must not. If the path is relative, then treat it 2079 * as living in ~/.ssh for user configurations or 2080 * /etc/ssh for system ones. 2081 */ 2082 if (*p == '~' && (flags & SSHCONF_USERCONF) == 0) { 2083 error("%.200s line %d: bad include path %s.", 2084 filename, linenum, p); 2085 goto out; 2086 } 2087 if (!path_absolute(p) && *p != '~') { 2088 xasprintf(&arg2, "%s/%s", 2089 (flags & SSHCONF_USERCONF) ? 2090 "~/" _PATH_SSH_USER_DIR : SSHDIR, p); 2091 } else { 2092 arg2 = xstrdup(p); 2093 } 2094 free(p); 2095 memset(&gl, 0, sizeof(gl)); 2096 r = glob(arg2, GLOB_TILDE, NULL, &gl); 2097 if (r == GLOB_NOMATCH) { 2098 debug("%.200s line %d: include %s matched no " 2099 "files",filename, linenum, arg2); 2100 free(arg2); 2101 continue; 2102 } else if (r != 0) { 2103 error("%.200s line %d: glob failed for %s.", 2104 filename, linenum, arg2); 2105 goto out; 2106 } 2107 free(arg2); 2108 oactive = *activep; 2109 for (i = 0; i < gl.gl_pathc; i++) { 2110 debug3("%.200s line %d: Including file %s " 2111 "depth %d%s", filename, linenum, 2112 gl.gl_pathv[i], depth, 2113 oactive ? "" : " (parse only)"); 2114 r = read_config_file_depth(gl.gl_pathv[i], 2115 pw, host, original_host, remote_command, 2116 options, flags | SSHCONF_CHECKPERM | 2117 (oactive ? 0 : SSHCONF_NEVERMATCH), 2118 activep, want_final_pass, depth + 1); 2119 if (r != 1 && errno != ENOENT) { 2120 error("%.200s line %d: Can't open user " 2121 "config file %.100s: %.100s", 2122 filename, linenum, gl.gl_pathv[i], 2123 strerror(errno)); 2124 globfree(&gl); 2125 goto out; 2126 } 2127 /* 2128 * don't let Match in includes clobber the 2129 * containing file's Match state. 2130 */ 2131 *activep = oactive; 2132 if (r != 1) 2133 value = -1; 2134 } 2135 globfree(&gl); 2136 } 2137 if (value != 0) 2138 ret = value; 2139 break; 2140 2141 case oIPQoS: 2142 arg = argv_next(&ac, &av); 2143 if ((value = parse_ipqos(arg)) == -1) { 2144 error("%s line %d: Bad IPQoS value: %s", 2145 filename, linenum, arg); 2146 goto out; 2147 } 2148 if (value == INT_MIN) { 2149 debug("%s line %d: Deprecated IPQoS value \"%s\" " 2150 "ignored - using system default instead. Consider" 2151 " using DSCP values.", filename, linenum, arg); 2152 value = INT_MAX; 2153 } 2154 arg = argv_next(&ac, &av); 2155 if (arg == NULL) 2156 value2 = value; 2157 else if ((value2 = parse_ipqos(arg)) == -1) { 2158 error("%s line %d: Bad IPQoS value: %s", 2159 filename, linenum, arg); 2160 goto out; 2161 } 2162 if (value2 == INT_MIN) { 2163 debug("%s line %d: Deprecated IPQoS value \"%s\" " 2164 "ignored - using system default instead. Consider" 2165 " using DSCP values.", filename, linenum, arg); 2166 value2 = INT_MAX; 2167 } 2168 if (*activep && options->ip_qos_interactive == -1) { 2169 options->ip_qos_interactive = value; 2170 options->ip_qos_bulk = value2; 2171 } 2172 break; 2173 2174 case oRequestTTY: 2175 intptr = &options->request_tty; 2176 multistate_ptr = multistate_requesttty; 2177 goto parse_multistate; 2178 2179 case oSessionType: 2180 intptr = &options->session_type; 2181 multistate_ptr = multistate_sessiontype; 2182 goto parse_multistate; 2183 2184 case oStdinNull: 2185 intptr = &options->stdin_null; 2186 goto parse_flag; 2187 2188 case oForkAfterAuthentication: 2189 intptr = &options->fork_after_authentication; 2190 goto parse_flag; 2191 2192 case oIgnoreUnknown: 2193 charptr = &options->ignored_unknown; 2194 goto parse_string; 2195 2196 case oProxyUseFdpass: 2197 intptr = &options->proxy_use_fdpass; 2198 goto parse_flag; 2199 2200 case oCanonicalDomains: 2201 found = options->num_canonical_domains == 0; 2202 while ((arg = argv_next(&ac, &av)) != NULL) { 2203 /* Allow "none" only in first position */ 2204 if (strcasecmp(arg, "none") == 0) { 2205 if (nstrs > 0 || ac > 0) { 2206 error("%s line %d: keyword %s \"none\" " 2207 "argument must appear alone.", 2208 filename, linenum, keyword); 2209 goto out; 2210 } 2211 } 2212 if (!valid_domain(arg, 1, &errstr)) { 2213 error("%s line %d: %s", filename, linenum, 2214 errstr); 2215 goto out; 2216 } 2217 opt_array_append(filename, linenum, keyword, 2218 &strs, &nstrs, arg); 2219 } 2220 if (nstrs == 0) { 2221 fatal("%s line %d: no %s specified", 2222 filename, linenum, keyword); 2223 } 2224 if (found && *activep) { 2225 options->canonical_domains = strs; 2226 options->num_canonical_domains = nstrs; 2227 strs = NULL; /* transferred */ 2228 nstrs = 0; 2229 } 2230 break; 2231 2232 case oCanonicalizePermittedCNAMEs: 2233 found = options->num_permitted_cnames == 0; 2234 while ((arg = argv_next(&ac, &av)) != NULL) { 2235 /* 2236 * Either 'none' (only in first position), '*' for 2237 * everything or 'list:list' 2238 */ 2239 if (strcasecmp(arg, "none") == 0) { 2240 if (ncnames > 0 || ac > 0) { 2241 error("%s line %d: keyword %s \"none\" " 2242 "argument must appear alone.", 2243 filename, linenum, keyword); 2244 goto out; 2245 } 2246 arg2 = ""; 2247 } else if (strcmp(arg, "*") == 0) { 2248 arg2 = arg; 2249 } else { 2250 lowercase(arg); 2251 if ((arg2 = strchr(arg, ':')) == NULL || 2252 arg2[1] == '\0') { 2253 error("%s line %d: " 2254 "Invalid permitted CNAME \"%s\"", 2255 filename, linenum, arg); 2256 goto out; 2257 } 2258 *arg2 = '\0'; 2259 arg2++; 2260 } 2261 cnames = xrecallocarray(cnames, ncnames, ncnames + 1, 2262 sizeof(*cnames)); 2263 cnames[ncnames].source_list = xstrdup(arg); 2264 cnames[ncnames].target_list = xstrdup(arg2); 2265 ncnames++; 2266 } 2267 if (ncnames == 0) { 2268 fatal("%s line %d: no %s specified", 2269 filename, linenum, keyword); 2270 } 2271 if (found && *activep) { 2272 options->permitted_cnames = cnames; 2273 options->num_permitted_cnames = ncnames; 2274 cnames = NULL; /* transferred */ 2275 ncnames = 0; 2276 } 2277 /* un-transferred cnames is cleaned up before exit */ 2278 break; 2279 2280 case oCanonicalizeHostname: 2281 intptr = &options->canonicalize_hostname; 2282 multistate_ptr = multistate_canonicalizehostname; 2283 goto parse_multistate; 2284 2285 case oCanonicalizeMaxDots: 2286 intptr = &options->canonicalize_max_dots; 2287 goto parse_int; 2288 2289 case oCanonicalizeFallbackLocal: 2290 intptr = &options->canonicalize_fallback_local; 2291 goto parse_flag; 2292 2293 case oStreamLocalBindMask: 2294 arg = argv_next(&ac, &av); 2295 if (!arg || *arg == '\0') { 2296 error("%.200s line %d: Missing StreamLocalBindMask " 2297 "argument.", filename, linenum); 2298 goto out; 2299 } 2300 /* Parse mode in octal format */ 2301 value = strtol(arg, &endofnumber, 8); 2302 if (arg == endofnumber || value < 0 || value > 0777) { 2303 error("%.200s line %d: Bad mask.", filename, linenum); 2304 goto out; 2305 } 2306 options->fwd_opts.streamlocal_bind_mask = (mode_t)value; 2307 break; 2308 2309 case oStreamLocalBindUnlink: 2310 intptr = &options->fwd_opts.streamlocal_bind_unlink; 2311 goto parse_flag; 2312 2313 case oRevokedHostKeys: 2314 uintptr = &options->num_revoked_host_keys; 2315 cppptr = &options->revoked_host_keys; 2316 found = *uintptr == 0; 2317 while ((arg = argv_next(&ac, &av)) != NULL) { 2318 if (*arg == '\0') { 2319 error("%s line %d: keyword %s empty argument", 2320 filename, linenum, keyword); 2321 goto out; 2322 } 2323 /* Allow "none" only in first position */ 2324 if (strcasecmp(arg, "none") == 0) { 2325 if (nstrs > 0 || ac > 0) { 2326 error("%s line %d: keyword %s \"none\" " 2327 "argument must appear alone.", 2328 filename, linenum, keyword); 2329 goto out; 2330 } 2331 } 2332 opt_array_append(filename, linenum, keyword, 2333 &strs, &nstrs, arg); 2334 } 2335 if (nstrs == 0) { 2336 fatal("%s line %d: no %s specified", 2337 filename, linenum, keyword); 2338 } 2339 if (found && *activep) { 2340 *cppptr = strs; 2341 *uintptr = nstrs; 2342 strs = NULL; /* transferred */ 2343 nstrs = 0; 2344 } 2345 break; 2346 2347 case oFingerprintHash: 2348 intptr = &options->fingerprint_hash; 2349 arg = argv_next(&ac, &av); 2350 if (!arg || *arg == '\0') { 2351 error("%.200s line %d: Missing argument.", 2352 filename, linenum); 2353 goto out; 2354 } 2355 if ((value = ssh_digest_alg_by_name(arg)) == -1) { 2356 error("%.200s line %d: Invalid hash algorithm \"%s\".", 2357 filename, linenum, arg); 2358 goto out; 2359 } 2360 if (*activep && *intptr == -1) 2361 *intptr = value; 2362 break; 2363 2364 case oUpdateHostkeys: 2365 intptr = &options->update_hostkeys; 2366 multistate_ptr = multistate_yesnoask; 2367 goto parse_multistate; 2368 2369 case oHostbasedAcceptedAlgorithms: 2370 charptr = &options->hostbased_accepted_algos; 2371 ca_only = 0; 2372 goto parse_pubkey_algos; 2373 2374 case oPubkeyAcceptedAlgorithms: 2375 charptr = &options->pubkey_accepted_algos; 2376 ca_only = 0; 2377 goto parse_pubkey_algos; 2378 2379 case oAddKeysToAgent: 2380 arg = argv_next(&ac, &av); 2381 arg2 = argv_next(&ac, &av); 2382 value = parse_multistate_value(arg, filename, linenum, 2383 multistate_yesnoaskconfirm); 2384 value2 = 0; /* unlimited lifespan by default */ 2385 if (value == 3 && arg2 != NULL) { 2386 /* allow "AddKeysToAgent confirm 5m" */ 2387 if ((value2 = convtime(arg2)) == -1) { 2388 error("%s line %d: invalid time value.", 2389 filename, linenum); 2390 goto out; 2391 } 2392 } else if (value == -1 && arg2 == NULL) { 2393 if ((value2 = convtime(arg)) == -1) { 2394 error("%s line %d: unsupported option", 2395 filename, linenum); 2396 goto out; 2397 } 2398 value = 1; /* yes */ 2399 } else if (value == -1 || arg2 != NULL) { 2400 error("%s line %d: unsupported option", 2401 filename, linenum); 2402 goto out; 2403 } 2404 if (*activep && options->add_keys_to_agent == -1) { 2405 options->add_keys_to_agent = value; 2406 options->add_keys_to_agent_lifespan = value2; 2407 } 2408 break; 2409 2410 case oIdentityAgent: 2411 charptr = &options->identity_agent; 2412 arg = argv_next(&ac, &av); 2413 if (!arg || *arg == '\0') { 2414 error("%.200s line %d: Missing argument.", 2415 filename, linenum); 2416 goto out; 2417 } 2418 parse_agent_path: 2419 /* Extra validation if the string represents an env var. */ 2420 if ((arg2 = dollar_expand(&r, arg)) == NULL || r) { 2421 error("%.200s line %d: Invalid environment expansion " 2422 "%s.", filename, linenum, arg); 2423 goto out; 2424 } 2425 free(arg2); 2426 /* check for legacy environment format */ 2427 if (arg[0] == '$' && arg[1] != '{' && 2428 !valid_env_name(arg + 1)) { 2429 error("%.200s line %d: Invalid environment name %s.", 2430 filename, linenum, arg); 2431 goto out; 2432 } 2433 if (*activep && *charptr == NULL) 2434 *charptr = xstrdup(arg); 2435 break; 2436 2437 case oEnableEscapeCommandline: 2438 intptr = &options->enable_escape_commandline; 2439 goto parse_flag; 2440 2441 case oRequiredRSASize: 2442 intptr = &options->required_rsa_size; 2443 goto parse_int; 2444 2445 case oWarnWeakCrypto: 2446 intptr = &options->warn_weak_crypto; 2447 multistate_ptr = multistate_warnweakcrypto; 2448 goto parse_multistate; 2449 2450 case oObscureKeystrokeTiming: 2451 value = -1; 2452 while ((arg = argv_next(&ac, &av)) != NULL) { 2453 if (value != -1) { 2454 error("%s line %d: invalid arguments", 2455 filename, linenum); 2456 goto out; 2457 } 2458 if (strcmp(arg, "yes") == 0 || 2459 strcmp(arg, "true") == 0) 2460 value = SSH_KEYSTROKE_DEFAULT_INTERVAL_MS; 2461 else if (strcmp(arg, "no") == 0 || 2462 strcmp(arg, "false") == 0) 2463 value = 0; 2464 else if (strncmp(arg, "interval:", 9) == 0) { 2465 if ((errstr = atoi_err(arg + 9, 2466 &value)) != NULL) { 2467 error("%s line %d: integer value %s.", 2468 filename, linenum, errstr); 2469 goto out; 2470 } 2471 if (value <= 0 || value > 1000) { 2472 error("%s line %d: value out of range.", 2473 filename, linenum); 2474 goto out; 2475 } 2476 } else { 2477 error("%s line %d: unsupported argument \"%s\"", 2478 filename, linenum, arg); 2479 goto out; 2480 } 2481 } 2482 if (value == -1) { 2483 error("%s line %d: missing argument", 2484 filename, linenum); 2485 goto out; 2486 } 2487 intptr = &options->obscure_keystroke_timing_interval; 2488 if (*activep && *intptr == -1) 2489 *intptr = value; 2490 break; 2491 2492 case oChannelTimeout: 2493 found = options->num_channel_timeouts == 0; 2494 while ((arg = argv_next(&ac, &av)) != NULL) { 2495 /* Allow "none" only in first position */ 2496 if (strcasecmp(arg, "none") == 0) { 2497 if (nstrs > 0 || ac > 0) { 2498 error("%s line %d: keyword %s \"none\" " 2499 "argument must appear alone.", 2500 filename, linenum, keyword); 2501 goto out; 2502 } 2503 } else if (parse_pattern_interval(arg, 2504 NULL, NULL) != 0) { 2505 fatal("%s line %d: invalid channel timeout %s", 2506 filename, linenum, arg); 2507 } 2508 opt_array_append(filename, linenum, keyword, 2509 &strs, &nstrs, arg); 2510 } 2511 if (nstrs == 0) { 2512 fatal("%s line %d: no %s specified", 2513 filename, linenum, keyword); 2514 } 2515 if (found && *activep) { 2516 options->channel_timeouts = strs; 2517 options->num_channel_timeouts = nstrs; 2518 strs = NULL; /* transferred */ 2519 nstrs = 0; 2520 } 2521 break; 2522 2523 case oVersionAddendum: 2524 if (str == NULL || *str == '\0') 2525 fatal("%s line %d: %s missing argument.", 2526 filename, linenum, keyword); 2527 len = strspn(str, WHITESPACE); 2528 if (strchr(str + len, '\r') != NULL) { 2529 fatal("%.200s line %d: Invalid %s argument", 2530 filename, linenum, keyword); 2531 } 2532 if ((arg = strchr(line, '#')) != NULL) { 2533 *arg = '\0'; 2534 rtrim(line); 2535 } 2536 if (*activep && options->version_addendum == NULL) { 2537 if (strcasecmp(str + len, "none") == 0) 2538 options->version_addendum = xstrdup(""); 2539 else 2540 options->version_addendum = xstrdup(str + len); 2541 } 2542 argv_consume(&ac); 2543 break; 2544 2545 case oRefuseConnection: 2546 arg = argv_next(&ac, &av); 2547 if (!arg || *arg == '\0') { 2548 error("%.200s line %d: Missing argument.", 2549 filename, linenum); 2550 goto out; 2551 } 2552 if (*activep) { 2553 fatal("%.200s line %d: RefuseConnection: %s", 2554 filename, linenum, arg); 2555 } 2556 break; 2557 2558 case oDeprecated: 2559 debug("%s line %d: Deprecated option \"%s\"", 2560 filename, linenum, keyword); 2561 argv_consume(&ac); 2562 break; 2563 2564 case oUnsupported: 2565 error("%s line %d: Unsupported option \"%s\"", 2566 filename, linenum, keyword); 2567 argv_consume(&ac); 2568 break; 2569 2570 default: 2571 error("%s line %d: Unimplemented opcode %d", 2572 filename, linenum, opcode); 2573 goto out; 2574 } 2575 2576 /* Check that there is no garbage at end of line. */ 2577 if (ac > 0) { 2578 error("%.200s line %d: keyword %s extra arguments " 2579 "at end of line", filename, linenum, keyword); 2580 goto out; 2581 } 2582 2583 /* success */ 2584 ret = 0; 2585 out: 2586 free_canon_cnames(cnames, ncnames); 2587 opt_array_free2(strs, NULL, nstrs); 2588 argv_free(oav, oac); 2589 return ret; 2590} 2591 2592/* 2593 * Reads the config file and modifies the options accordingly. Options 2594 * should already be initialized before this call. This never returns if 2595 * there is an error. If the file does not exist, this returns 0. 2596 */ 2597int 2598read_config_file(const char *filename, struct passwd *pw, const char *host, 2599 const char *original_host, const char *remote_command, Options *options, int flags, 2600 int *want_final_pass) 2601{ 2602 int active = 1; 2603 2604 return read_config_file_depth(filename, pw, host, original_host, 2605 remote_command, options, flags, &active, want_final_pass, 0); 2606} 2607 2608#define READCONF_MAX_DEPTH 16 2609static int 2610read_config_file_depth(const char *filename, struct passwd *pw, 2611 const char *host, const char *original_host, const char *remote_command, 2612 Options *options, int flags, int *activep, int *want_final_pass, int depth) 2613{ 2614 FILE *f; 2615 char *line = NULL; 2616 size_t linesize = 0; 2617 int linenum; 2618 int bad_options = 0; 2619 2620 if (depth < 0 || depth > READCONF_MAX_DEPTH) 2621 fatal("Too many recursive configuration includes"); 2622 2623 if ((f = fopen(filename, "r")) == NULL) 2624 return 0; 2625 2626 if (flags & SSHCONF_CHECKPERM) { 2627 struct stat sb; 2628 2629 if (fstat(fileno(f), &sb) == -1) 2630 fatal("fstat %s: %s", filename, strerror(errno)); 2631 if (((sb.st_uid != 0 && sb.st_uid != getuid()) || 2632 (sb.st_mode & 022) != 0)) 2633 fatal("Bad owner or permissions on %s", filename); 2634 } 2635 2636 debug("Reading configuration data %.200s", filename); 2637 2638 /* 2639 * Mark that we are now processing the options. This flag is turned 2640 * on/off by Host specifications. 2641 */ 2642 linenum = 0; 2643 while (getline(&line, &linesize, f) != -1) { 2644 /* Update line number counter. */ 2645 linenum++; 2646 /* 2647 * Trim out comments and strip whitespace. 2648 * NB - preserve newlines, they are needed to reproduce 2649 * line numbers later for error messages. 2650 */ 2651 if (process_config_line_depth(options, pw, host, original_host, 2652 remote_command, line, filename, linenum, activep, flags, 2653 want_final_pass, depth) != 0) 2654 bad_options++; 2655 } 2656 free(line); 2657 fclose(f); 2658 if (bad_options > 0) 2659 fatal("%s: terminating, %d bad configuration options", 2660 filename, bad_options); 2661 return 1; 2662} 2663 2664/* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */ 2665int 2666option_clear_or_none(const char *o) 2667{ 2668 return o == NULL || strcasecmp(o, "none") == 0; 2669} 2670 2671/* 2672 * Returns 1 if CanonicalizePermittedCNAMEs have been specified, 0 otherwise. 2673 * Allowed to be called on non-final configuration. 2674 */ 2675int 2676config_has_permitted_cnames(Options *options) 2677{ 2678 if (options->num_permitted_cnames == 1 && 2679 strcasecmp(options->permitted_cnames[0].source_list, "none") == 0 && 2680 strcmp(options->permitted_cnames[0].target_list, "") == 0) 2681 return 0; 2682 return options->num_permitted_cnames > 0; 2683} 2684 2685/* 2686 * Initializes options to special values that indicate that they have not yet 2687 * been set. Read_config_file will only set options with this value. Options 2688 * are processed in the following order: command line, user config file, 2689 * system config file. Last, fill_default_options is called. 2690 */ 2691 2692void 2693initialize_options(Options * options) 2694{ 2695 memset(options, 'X', sizeof(*options)); 2696 options->host_arg = NULL; 2697 options->forward_agent = -1; 2698 options->forward_agent_sock_path = NULL; 2699 options->forward_x11 = -1; 2700 options->forward_x11_trusted = -1; 2701 options->forward_x11_timeout = -1; 2702 options->stdio_forward_host = NULL; 2703 options->stdio_forward_port = 0; 2704 options->clear_forwardings = -1; 2705 options->exit_on_forward_failure = -1; 2706 options->xauth_location = NULL; 2707 options->fwd_opts.gateway_ports = -1; 2708 options->fwd_opts.streamlocal_bind_mask = (mode_t)-1; 2709 options->fwd_opts.streamlocal_bind_unlink = -1; 2710 options->pubkey_authentication = -1; 2711 options->gss_authentication = -1; 2712 options->gss_deleg_creds = -1; 2713 options->password_authentication = -1; 2714 options->kbd_interactive_authentication = -1; 2715 options->kbd_interactive_devices = NULL; 2716 options->hostbased_authentication = -1; 2717 options->batch_mode = -1; 2718 options->check_host_ip = -1; 2719 options->strict_host_key_checking = -1; 2720 options->compression = -1; 2721 options->tcp_keep_alive = -1; 2722 options->port = -1; 2723 options->address_family = -1; 2724 options->connection_attempts = -1; 2725 options->connection_timeout = -1; 2726 options->number_of_password_prompts = -1; 2727 options->ciphers = NULL; 2728 options->macs = NULL; 2729 options->kex_algorithms = NULL; 2730 options->hostkeyalgorithms = NULL; 2731 options->ca_sign_algorithms = NULL; 2732 options->num_identity_files = 0; 2733 memset(options->identity_keys, 0, sizeof(options->identity_keys)); 2734 options->num_certificate_files = 0; 2735 memset(options->certificates, 0, sizeof(options->certificates)); 2736 options->hostname = NULL; 2737 options->host_key_alias = NULL; 2738 options->proxy_command = NULL; 2739 options->jump_user = NULL; 2740 options->jump_host = NULL; 2741 options->jump_port = -1; 2742 options->jump_extra = NULL; 2743 options->user = NULL; 2744 options->escape_char = -1; 2745 options->num_system_hostfiles = 0; 2746 options->num_user_hostfiles = 0; 2747 options->local_forwards = NULL; 2748 options->num_local_forwards = 0; 2749 options->remote_forwards = NULL; 2750 options->num_remote_forwards = 0; 2751 options->permitted_remote_opens = NULL; 2752 options->num_permitted_remote_opens = 0; 2753 options->log_facility = SYSLOG_FACILITY_NOT_SET; 2754 options->log_level = SYSLOG_LEVEL_NOT_SET; 2755 options->num_log_verbose = 0; 2756 options->log_verbose = NULL; 2757 options->preferred_authentications = NULL; 2758 options->bind_address = NULL; 2759 options->bind_interface = NULL; 2760 options->pkcs11_provider = NULL; 2761 options->sk_provider = NULL; 2762 options->enable_ssh_keysign = - 1; 2763 options->no_host_authentication_for_localhost = - 1; 2764 options->identities_only = - 1; 2765 options->rekey_limit = - 1; 2766 options->rekey_interval = -1; 2767 options->verify_host_key_dns = -1; 2768 options->server_alive_interval = -1; 2769 options->server_alive_count_max = -1; 2770 options->send_env = NULL; 2771 options->num_send_env = 0; 2772 options->setenv = NULL; 2773 options->num_setenv = 0; 2774 options->control_path = NULL; 2775 options->control_master = -1; 2776 options->control_persist = -1; 2777 options->control_persist_timeout = 0; 2778 options->hash_known_hosts = -1; 2779 options->tun_open = -1; 2780 options->tun_local = -1; 2781 options->tun_remote = -1; 2782 options->local_command = NULL; 2783 options->permit_local_command = -1; 2784 options->remote_command = NULL; 2785 options->add_keys_to_agent = -1; 2786 options->add_keys_to_agent_lifespan = -1; 2787 options->identity_agent = NULL; 2788 options->visual_host_key = -1; 2789 options->ip_qos_interactive = -1; 2790 options->ip_qos_bulk = -1; 2791 options->request_tty = -1; 2792 options->session_type = -1; 2793 options->stdin_null = -1; 2794 options->fork_after_authentication = -1; 2795 options->proxy_use_fdpass = -1; 2796 options->ignored_unknown = NULL; 2797 options->num_canonical_domains = 0; 2798 options->num_permitted_cnames = 0; 2799 options->canonicalize_max_dots = -1; 2800 options->canonicalize_fallback_local = -1; 2801 options->canonicalize_hostname = -1; 2802 options->revoked_host_keys = NULL; 2803 options->num_revoked_host_keys = 0; 2804 options->fingerprint_hash = -1; 2805 options->update_hostkeys = -1; 2806 options->hostbased_accepted_algos = NULL; 2807 options->pubkey_accepted_algos = NULL; 2808 options->known_hosts_command = NULL; 2809 options->required_rsa_size = -1; 2810 options->warn_weak_crypto = -1; 2811 options->enable_escape_commandline = -1; 2812 options->obscure_keystroke_timing_interval = -1; 2813 options->tag = NULL; 2814 options->channel_timeouts = NULL; 2815 options->num_channel_timeouts = 0; 2816 options->version_addendum = NULL; 2817} 2818 2819/* 2820 * A petite version of fill_default_options() that just fills the options 2821 * needed for hostname canonicalization to proceed. 2822 */ 2823void 2824fill_default_options_for_canonicalization(Options *options) 2825{ 2826 if (options->canonicalize_max_dots == -1) 2827 options->canonicalize_max_dots = 1; 2828 if (options->canonicalize_fallback_local == -1) 2829 options->canonicalize_fallback_local = 1; 2830 if (options->canonicalize_hostname == -1) 2831 options->canonicalize_hostname = SSH_CANONICALISE_NO; 2832} 2833 2834/* 2835 * Called after processing other sources of option data, this fills those 2836 * options for which no value has been specified with their default values. 2837 */ 2838int 2839fill_default_options(Options * options) 2840{ 2841 char *all_cipher, *all_mac, *all_kex, *all_key, *all_sig; 2842 char *def_cipher, *def_mac, *def_kex, *def_key, *def_sig; 2843 int ret = 0, r; 2844 2845 if (options->forward_agent == -1) 2846 options->forward_agent = 0; 2847 if (options->forward_x11 == -1) 2848 options->forward_x11 = 0; 2849 if (options->forward_x11_trusted == -1) 2850 options->forward_x11_trusted = 0; 2851 if (options->forward_x11_timeout == -1) 2852 options->forward_x11_timeout = 1200; 2853 /* 2854 * stdio forwarding (-W) changes the default for these but we defer 2855 * setting the values so they can be overridden. 2856 */ 2857 if (options->exit_on_forward_failure == -1) 2858 options->exit_on_forward_failure = 2859 options->stdio_forward_host != NULL ? 1 : 0; 2860 if (options->clear_forwardings == -1) 2861 options->clear_forwardings = 2862 options->stdio_forward_host != NULL ? 1 : 0; 2863 if (options->clear_forwardings == 1) 2864 clear_forwardings(options); 2865 2866 if (options->xauth_location == NULL) 2867 options->xauth_location = xstrdup(_PATH_XAUTH); 2868 if (options->fwd_opts.gateway_ports == -1) 2869 options->fwd_opts.gateway_ports = 0; 2870 if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1) 2871 options->fwd_opts.streamlocal_bind_mask = 0177; 2872 if (options->fwd_opts.streamlocal_bind_unlink == -1) 2873 options->fwd_opts.streamlocal_bind_unlink = 0; 2874 if (options->pubkey_authentication == -1) 2875 options->pubkey_authentication = SSH_PUBKEY_AUTH_ALL; 2876 if (options->gss_authentication == -1) 2877 options->gss_authentication = 0; 2878 if (options->gss_deleg_creds == -1) 2879 options->gss_deleg_creds = 0; 2880 if (options->password_authentication == -1) 2881 options->password_authentication = 1; 2882 if (options->kbd_interactive_authentication == -1) 2883 options->kbd_interactive_authentication = 1; 2884 if (options->hostbased_authentication == -1) 2885 options->hostbased_authentication = 0; 2886 if (options->batch_mode == -1) 2887 options->batch_mode = 0; 2888 if (options->check_host_ip == -1) 2889 options->check_host_ip = 0; 2890 if (options->strict_host_key_checking == -1) 2891 options->strict_host_key_checking = SSH_STRICT_HOSTKEY_ASK; 2892 if (options->compression == -1) 2893 options->compression = 0; 2894 if (options->tcp_keep_alive == -1) 2895 options->tcp_keep_alive = 1; 2896 if (options->port == -1) 2897 options->port = 0; /* Filled in ssh_connect. */ 2898 if (options->address_family == -1) 2899 options->address_family = AF_UNSPEC; 2900 if (options->connection_attempts == -1) 2901 options->connection_attempts = 1; 2902 if (options->number_of_password_prompts == -1) 2903 options->number_of_password_prompts = 3; 2904 /* options->hostkeyalgorithms, default set in myproposals.h */ 2905 if (options->add_keys_to_agent == -1) { 2906 options->add_keys_to_agent = 0; 2907 options->add_keys_to_agent_lifespan = 0; 2908 } 2909 if (options->num_identity_files == 0) { 2910 add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_RSA, 0); 2911 add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_ECDSA, 0); 2912 add_identity_file(options, "~/", 2913 _PATH_SSH_CLIENT_ID_ECDSA_SK, 0); 2914 add_identity_file(options, "~/", 2915 _PATH_SSH_CLIENT_ID_ED25519, 0); 2916 add_identity_file(options, "~/", 2917 _PATH_SSH_CLIENT_ID_ED25519_SK, 0); 2918 } 2919 if (options->escape_char == -1) 2920 options->escape_char = '~'; 2921 if (options->num_system_hostfiles == 0) { 2922 options->system_hostfiles[options->num_system_hostfiles++] = 2923 xstrdup(_PATH_SSH_SYSTEM_HOSTFILE); 2924 options->system_hostfiles[options->num_system_hostfiles++] = 2925 xstrdup(_PATH_SSH_SYSTEM_HOSTFILE2); 2926 } 2927 if (options->update_hostkeys == -1) { 2928 if (options->verify_host_key_dns <= 0 && 2929 (options->num_user_hostfiles == 0 || 2930 (options->num_user_hostfiles == 1 && strcmp(options-> 2931 user_hostfiles[0], _PATH_SSH_USER_HOSTFILE) == 0))) 2932 options->update_hostkeys = SSH_UPDATE_HOSTKEYS_YES; 2933 else 2934 options->update_hostkeys = SSH_UPDATE_HOSTKEYS_NO; 2935 } 2936 if (options->num_user_hostfiles == 0) { 2937 options->user_hostfiles[options->num_user_hostfiles++] = 2938 xstrdup(_PATH_SSH_USER_HOSTFILE); 2939 options->user_hostfiles[options->num_user_hostfiles++] = 2940 xstrdup(_PATH_SSH_USER_HOSTFILE2); 2941 } 2942 if (options->log_level == SYSLOG_LEVEL_NOT_SET) 2943 options->log_level = SYSLOG_LEVEL_INFO; 2944 if (options->log_facility == SYSLOG_FACILITY_NOT_SET) 2945 options->log_facility = SYSLOG_FACILITY_USER; 2946 if (options->no_host_authentication_for_localhost == - 1) 2947 options->no_host_authentication_for_localhost = 0; 2948 if (options->identities_only == -1) 2949 options->identities_only = 0; 2950 if (options->enable_ssh_keysign == -1) 2951 options->enable_ssh_keysign = 0; 2952 if (options->rekey_limit == -1) 2953 options->rekey_limit = 0; 2954 if (options->rekey_interval == -1) 2955 options->rekey_interval = 0; 2956 if (options->verify_host_key_dns == -1) 2957 options->verify_host_key_dns = 0; 2958 if (options->server_alive_interval == -1) 2959 options->server_alive_interval = 0; 2960 if (options->server_alive_count_max == -1) 2961 options->server_alive_count_max = 3; 2962 if (options->control_master == -1) 2963 options->control_master = 0; 2964 if (options->control_persist == -1) { 2965 options->control_persist = 0; 2966 options->control_persist_timeout = 0; 2967 } 2968 if (options->hash_known_hosts == -1) 2969 options->hash_known_hosts = 0; 2970 if (options->tun_open == -1) 2971 options->tun_open = SSH_TUNMODE_NO; 2972 if (options->tun_local == -1) 2973 options->tun_local = SSH_TUNID_ANY; 2974 if (options->tun_remote == -1) 2975 options->tun_remote = SSH_TUNID_ANY; 2976 if (options->permit_local_command == -1) 2977 options->permit_local_command = 0; 2978 if (options->visual_host_key == -1) 2979 options->visual_host_key = 0; 2980 if (options->ip_qos_interactive == -1) 2981 options->ip_qos_interactive = IPTOS_DSCP_EF; 2982 if (options->ip_qos_bulk == -1) 2983 options->ip_qos_bulk = IPTOS_DSCP_CS0; 2984 if (options->request_tty == -1) 2985 options->request_tty = REQUEST_TTY_AUTO; 2986 if (options->session_type == -1) 2987 options->session_type = SESSION_TYPE_DEFAULT; 2988 if (options->stdin_null == -1) 2989 options->stdin_null = 0; 2990 if (options->fork_after_authentication == -1) 2991 options->fork_after_authentication = 0; 2992 if (options->proxy_use_fdpass == -1) 2993 options->proxy_use_fdpass = 0; 2994 if (options->canonicalize_max_dots == -1) 2995 options->canonicalize_max_dots = 1; 2996 if (options->canonicalize_fallback_local == -1) 2997 options->canonicalize_fallback_local = 1; 2998 if (options->canonicalize_hostname == -1) 2999 options->canonicalize_hostname = SSH_CANONICALISE_NO; 3000 if (options->fingerprint_hash == -1) 3001 options->fingerprint_hash = SSH_FP_HASH_DEFAULT; 3002 if (options->sk_provider == NULL) 3003 options->sk_provider = xstrdup("internal"); 3004 if (options->required_rsa_size == -1) 3005 options->required_rsa_size = SSH_RSA_MINIMUM_MODULUS_SIZE; 3006 if (options->warn_weak_crypto == -1) 3007 options->warn_weak_crypto = 1; 3008 if (options->enable_escape_commandline == -1) 3009 options->enable_escape_commandline = 0; 3010 if (options->obscure_keystroke_timing_interval == -1) { 3011 options->obscure_keystroke_timing_interval = 3012 SSH_KEYSTROKE_DEFAULT_INTERVAL_MS; 3013 } 3014 3015 /* Expand KEX name lists */ 3016 all_cipher = cipher_alg_list(',', 0); 3017 all_mac = mac_alg_list(','); 3018 all_kex = kex_alg_list(','); 3019 all_key = sshkey_alg_list(0, 0, 1, ','); 3020 all_sig = sshkey_alg_list(0, 1, 1, ','); 3021 /* remove unsupported algos from default lists */ 3022 def_cipher = match_filter_allowlist(KEX_CLIENT_ENCRYPT, all_cipher); 3023 def_mac = match_filter_allowlist(KEX_CLIENT_MAC, all_mac); 3024 def_kex = match_filter_allowlist(KEX_CLIENT_KEX, all_kex); 3025 def_key = match_filter_allowlist(KEX_DEFAULT_PK_ALG, all_key); 3026 def_sig = match_filter_allowlist(SSH_ALLOWED_CA_SIGALGS, all_sig); 3027#define ASSEMBLE(what, defaults, all) \ 3028 do { \ 3029 if ((r = kex_assemble_names(&options->what, \ 3030 defaults, all)) != 0) { \ 3031 error_fr(r, "%s", #what); \ 3032 goto fail; \ 3033 } \ 3034 } while (0) 3035 options->kex_algorithms_set = options->kex_algorithms != NULL; 3036 ASSEMBLE(ciphers, def_cipher, all_cipher); 3037 ASSEMBLE(macs, def_mac, all_mac); 3038 ASSEMBLE(kex_algorithms, def_kex, all_kex); 3039 ASSEMBLE(hostbased_accepted_algos, def_key, all_key); 3040 ASSEMBLE(pubkey_accepted_algos, def_key, all_key); 3041 ASSEMBLE(ca_sign_algorithms, def_sig, all_sig); 3042#undef ASSEMBLE 3043 3044#define CLEAR_ON_NONE(v) \ 3045 do { \ 3046 if (option_clear_or_none(v)) { \ 3047 free(v); \ 3048 v = NULL; \ 3049 } \ 3050 } while(0) 3051#define CLEAR_ON_NONE_ARRAY(v, nv, none) \ 3052 do { \ 3053 if (options->nv == 1 && \ 3054 strcasecmp(options->v[0], none) == 0) { \ 3055 free(options->v[0]); \ 3056 free(options->v); \ 3057 options->v = NULL; \ 3058 options->nv = 0; \ 3059 } \ 3060 } while (0) 3061 CLEAR_ON_NONE(options->local_command); 3062 CLEAR_ON_NONE(options->remote_command); 3063 CLEAR_ON_NONE(options->proxy_command); 3064 CLEAR_ON_NONE(options->control_path); 3065 CLEAR_ON_NONE(options->pkcs11_provider); 3066 CLEAR_ON_NONE(options->sk_provider); 3067 CLEAR_ON_NONE(options->known_hosts_command); 3068 CLEAR_ON_NONE_ARRAY(channel_timeouts, num_channel_timeouts, "none"); 3069 CLEAR_ON_NONE_ARRAY(revoked_host_keys, num_revoked_host_keys, "none"); 3070#undef CLEAR_ON_NONE 3071#undef CLEAR_ON_NONE_ARRAY 3072 if (options->jump_host != NULL && 3073 strcmp(options->jump_host, "none") == 0 && 3074 options->jump_port == 0 && options->jump_user == NULL) { 3075 free(options->jump_host); 3076 options->jump_host = NULL; 3077 } 3078 if (options->num_permitted_cnames == 1 && 3079 !config_has_permitted_cnames(options)) { 3080 /* clean up CanonicalizePermittedCNAMEs=none */ 3081 free(options->permitted_cnames[0].source_list); 3082 free(options->permitted_cnames[0].target_list); 3083 memset(options->permitted_cnames, '\0', 3084 sizeof(*options->permitted_cnames)); 3085 options->num_permitted_cnames = 0; 3086 } 3087 /* options->identity_agent distinguishes NULL from 'none' */ 3088 /* options->user will be set in the main program if appropriate */ 3089 /* options->hostname will be set in the main program if appropriate */ 3090 /* options->host_key_alias should not be set by default */ 3091 /* options->preferred_authentications will be set in ssh */ 3092 3093 /* success */ 3094 ret = 0; 3095 fail: 3096 free(all_cipher); 3097 free(all_mac); 3098 free(all_kex); 3099 free(all_key); 3100 free(all_sig); 3101 free(def_cipher); 3102 free(def_mac); 3103 free(def_kex); 3104 free(def_key); 3105 free(def_sig); 3106 return ret; 3107} 3108 3109void 3110free_options(Options *o) 3111{ 3112 int i; 3113 3114 if (o == NULL) 3115 return; 3116 3117#define FREE_ARRAY(type, n, a) \ 3118 do { \ 3119 type _i; \ 3120 for (_i = 0; _i < (n); _i++) \ 3121 free((a)[_i]); \ 3122 } while (0) 3123 3124 free(o->forward_agent_sock_path); 3125 free(o->xauth_location); 3126 FREE_ARRAY(u_int, o->num_log_verbose, o->log_verbose); 3127 free(o->log_verbose); 3128 free(o->ciphers); 3129 free(o->macs); 3130 free(o->hostkeyalgorithms); 3131 free(o->kex_algorithms); 3132 free(o->ca_sign_algorithms); 3133 free(o->hostname); 3134 free(o->host_key_alias); 3135 free(o->proxy_command); 3136 free(o->user); 3137 FREE_ARRAY(u_int, o->num_system_hostfiles, o->system_hostfiles); 3138 FREE_ARRAY(u_int, o->num_user_hostfiles, o->user_hostfiles); 3139 free(o->preferred_authentications); 3140 free(o->bind_address); 3141 free(o->bind_interface); 3142 free(o->pkcs11_provider); 3143 free(o->sk_provider); 3144 for (i = 0; i < o->num_identity_files; i++) { 3145 free(o->identity_files[i]); 3146 sshkey_free(o->identity_keys[i]); 3147 } 3148 for (i = 0; i < o->num_certificate_files; i++) { 3149 free(o->certificate_files[i]); 3150 sshkey_free(o->certificates[i]); 3151 } 3152 free(o->identity_agent); 3153 for (i = 0; i < o->num_local_forwards; i++) { 3154 free(o->local_forwards[i].listen_host); 3155 free(o->local_forwards[i].listen_path); 3156 free(o->local_forwards[i].connect_host); 3157 free(o->local_forwards[i].connect_path); 3158 } 3159 free(o->local_forwards); 3160 for (i = 0; i < o->num_remote_forwards; i++) { 3161 free(o->remote_forwards[i].listen_host); 3162 free(o->remote_forwards[i].listen_path); 3163 free(o->remote_forwards[i].connect_host); 3164 free(o->remote_forwards[i].connect_path); 3165 } 3166 free(o->remote_forwards); 3167 free(o->stdio_forward_host); 3168 FREE_ARRAY(u_int, o->num_send_env, o->send_env); 3169 free(o->send_env); 3170 FREE_ARRAY(u_int, o->num_setenv, o->setenv); 3171 free(o->setenv); 3172 free(o->control_path); 3173 free(o->local_command); 3174 free(o->remote_command); 3175 FREE_ARRAY(int, o->num_canonical_domains, o->canonical_domains); 3176 for (i = 0; i < o->num_permitted_cnames; i++) { 3177 free(o->permitted_cnames[i].source_list); 3178 free(o->permitted_cnames[i].target_list); 3179 } 3180 FREE_ARRAY(u_int, o->num_revoked_host_keys, o->revoked_host_keys); 3181 free(o->revoked_host_keys); 3182 free(o->hostbased_accepted_algos); 3183 free(o->pubkey_accepted_algos); 3184 free(o->jump_user); 3185 free(o->jump_host); 3186 free(o->jump_extra); 3187 free(o->ignored_unknown); 3188 explicit_bzero(o, sizeof(*o)); 3189#undef FREE_ARRAY 3190} 3191 3192struct fwdarg { 3193 char *arg; 3194 int ispath; 3195}; 3196 3197/* 3198 * parse_fwd_field 3199 * parses the next field in a port forwarding specification. 3200 * sets fwd to the parsed field and advances p past the colon 3201 * or sets it to NULL at end of string. 3202 * returns 0 on success, else non-zero. 3203 */ 3204static int 3205parse_fwd_field(char **p, struct fwdarg *fwd) 3206{ 3207 char *ep, *cp = *p; 3208 int ispath = 0; 3209 3210 if (*cp == '\0') { 3211 *p = NULL; 3212 return -1; /* end of string */ 3213 } 3214 3215 /* 3216 * A field escaped with square brackets is used literally. 3217 * XXX - allow ']' to be escaped via backslash? 3218 */ 3219 if (*cp == '[') { 3220 /* find matching ']' */ 3221 for (ep = cp + 1; *ep != ']' && *ep != '\0'; ep++) { 3222 if (*ep == '/') 3223 ispath = 1; 3224 } 3225 /* no matching ']' or not at end of field. */ 3226 if (ep[0] != ']' || (ep[1] != ':' && ep[1] != '\0')) 3227 return -1; 3228 /* NUL terminate the field and advance p past the colon */ 3229 *ep++ = '\0'; 3230 if (*ep != '\0') 3231 *ep++ = '\0'; 3232 fwd->arg = cp + 1; 3233 fwd->ispath = ispath; 3234 *p = ep; 3235 return 0; 3236 } 3237 3238 for (cp = *p; *cp != '\0'; cp++) { 3239 switch (*cp) { 3240 case '\\': 3241 memmove(cp, cp + 1, strlen(cp + 1) + 1); 3242 if (*cp == '\0') 3243 return -1; 3244 break; 3245 case '/': 3246 ispath = 1; 3247 break; 3248 case ':': 3249 *cp++ = '\0'; 3250 goto done; 3251 } 3252 } 3253done: 3254 fwd->arg = *p; 3255 fwd->ispath = ispath; 3256 *p = cp; 3257 return 0; 3258} 3259 3260/* 3261 * parse_forward 3262 * parses a string containing a port forwarding specification of the form: 3263 * dynamicfwd == 0 3264 * [listenhost:]listenport|listenpath:connecthost:connectport|connectpath 3265 * listenpath:connectpath 3266 * dynamicfwd == 1 3267 * [listenhost:]listenport 3268 * returns number of arguments parsed or zero on error 3269 */ 3270int 3271parse_forward(struct Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd) 3272{ 3273 struct fwdarg fwdargs[4]; 3274 char *p, *cp; 3275 int i, err; 3276 3277 memset(fwd, 0, sizeof(*fwd)); 3278 memset(fwdargs, 0, sizeof(fwdargs)); 3279 3280 /* 3281 * We expand environment variables before checking if we think they're 3282 * paths so that if ${VAR} expands to a fully qualified path it is 3283 * treated as a path. 3284 */ 3285 cp = p = dollar_expand(&err, fwdspec); 3286 if (p == NULL || err) 3287 return 0; 3288 3289 /* skip leading spaces */ 3290 while (isspace((u_char)*cp)) 3291 cp++; 3292 3293 for (i = 0; i < 4; ++i) { 3294 if (parse_fwd_field(&cp, &fwdargs[i]) != 0) 3295 break; 3296 } 3297 3298 /* Check for trailing garbage */ 3299 if (cp != NULL && *cp != '\0') { 3300 i = 0; /* failure */ 3301 } 3302 3303 switch (i) { 3304 case 1: 3305 if (fwdargs[0].ispath) { 3306 fwd->listen_path = xstrdup(fwdargs[0].arg); 3307 fwd->listen_port = PORT_STREAMLOCAL; 3308 } else { 3309 fwd->listen_host = NULL; 3310 fwd->listen_port = a2port(fwdargs[0].arg); 3311 } 3312 fwd->connect_host = xstrdup("socks"); 3313 break; 3314 3315 case 2: 3316 if (fwdargs[0].ispath && fwdargs[1].ispath) { 3317 fwd->listen_path = xstrdup(fwdargs[0].arg); 3318 fwd->listen_port = PORT_STREAMLOCAL; 3319 fwd->connect_path = xstrdup(fwdargs[1].arg); 3320 fwd->connect_port = PORT_STREAMLOCAL; 3321 } else if (fwdargs[1].ispath) { 3322 fwd->listen_host = NULL; 3323 fwd->listen_port = a2port(fwdargs[0].arg); 3324 fwd->connect_path = xstrdup(fwdargs[1].arg); 3325 fwd->connect_port = PORT_STREAMLOCAL; 3326 } else { 3327 fwd->listen_host = xstrdup(fwdargs[0].arg); 3328 fwd->listen_port = a2port(fwdargs[1].arg); 3329 fwd->connect_host = xstrdup("socks"); 3330 } 3331 break; 3332 3333 case 3: 3334 if (fwdargs[0].ispath) { 3335 fwd->listen_path = xstrdup(fwdargs[0].arg); 3336 fwd->listen_port = PORT_STREAMLOCAL; 3337 fwd->connect_host = xstrdup(fwdargs[1].arg); 3338 fwd->connect_port = a2port(fwdargs[2].arg); 3339 } else if (fwdargs[2].ispath) { 3340 fwd->listen_host = xstrdup(fwdargs[0].arg); 3341 fwd->listen_port = a2port(fwdargs[1].arg); 3342 fwd->connect_path = xstrdup(fwdargs[2].arg); 3343 fwd->connect_port = PORT_STREAMLOCAL; 3344 } else { 3345 fwd->listen_host = NULL; 3346 fwd->listen_port = a2port(fwdargs[0].arg); 3347 fwd->connect_host = xstrdup(fwdargs[1].arg); 3348 fwd->connect_port = a2port(fwdargs[2].arg); 3349 } 3350 break; 3351 3352 case 4: 3353 fwd->listen_host = xstrdup(fwdargs[0].arg); 3354 fwd->listen_port = a2port(fwdargs[1].arg); 3355 fwd->connect_host = xstrdup(fwdargs[2].arg); 3356 fwd->connect_port = a2port(fwdargs[3].arg); 3357 break; 3358 default: 3359 i = 0; /* failure */ 3360 } 3361 3362 free(p); 3363 3364 if (dynamicfwd) { 3365 if (!(i == 1 || i == 2)) 3366 goto fail_free; 3367 } else { 3368 if (!(i == 3 || i == 4)) { 3369 if (fwd->connect_path == NULL && 3370 fwd->listen_path == NULL) 3371 goto fail_free; 3372 } 3373 if (fwd->connect_port <= 0 && fwd->connect_path == NULL) 3374 goto fail_free; 3375 } 3376 3377 if ((fwd->listen_port < 0 && fwd->listen_path == NULL) || 3378 (!remotefwd && fwd->listen_port == 0)) 3379 goto fail_free; 3380 if (fwd->connect_host != NULL && 3381 strlen(fwd->connect_host) >= NI_MAXHOST) 3382 goto fail_free; 3383 /* 3384 * XXX - if connecting to a remote socket, max sun len may not 3385 * match this host 3386 */ 3387 if (fwd->connect_path != NULL && 3388 strlen(fwd->connect_path) >= PATH_MAX_SUN) 3389 goto fail_free; 3390 if (fwd->listen_host != NULL && 3391 strlen(fwd->listen_host) >= NI_MAXHOST) 3392 goto fail_free; 3393 if (fwd->listen_path != NULL && 3394 strlen(fwd->listen_path) >= PATH_MAX_SUN) 3395 goto fail_free; 3396 3397 return (i); 3398 3399 fail_free: 3400 free(fwd->connect_host); 3401 fwd->connect_host = NULL; 3402 free(fwd->connect_path); 3403 fwd->connect_path = NULL; 3404 free(fwd->listen_host); 3405 fwd->listen_host = NULL; 3406 free(fwd->listen_path); 3407 fwd->listen_path = NULL; 3408 return (0); 3409} 3410 3411int 3412parse_jump(const char *s, Options *o, int active) 3413{ 3414 char *orig, *sdup, *cp; 3415 char *host = NULL, *user = NULL; 3416 int r, ret = -1, port = -1, first; 3417 3418 active &= o->proxy_command == NULL && o->jump_host == NULL; 3419 3420 orig = sdup = xstrdup(s); 3421 3422 /* Remove comment and trailing whitespace */ 3423 if ((cp = strchr(orig, '#')) != NULL) 3424 *cp = '\0'; 3425 rtrim(orig); 3426 3427 first = active; 3428 do { 3429 if (strcasecmp(s, "none") == 0) 3430 break; 3431 if ((cp = strrchr(sdup, ',')) == NULL) 3432 cp = sdup; /* last */ 3433 else 3434 *cp++ = '\0'; 3435 3436 if (first) { 3437 /* First argument and configuration is active */ 3438 r = parse_ssh_uri(cp, &user, &host, &port); 3439 if (r == -1 || (r == 1 && 3440 parse_user_host_port(cp, &user, &host, &port) != 0)) 3441 goto out; 3442 } else { 3443 /* Subsequent argument or inactive configuration */ 3444 r = parse_ssh_uri(cp, NULL, NULL, NULL); 3445 if (r == -1 || (r == 1 && 3446 parse_user_host_port(cp, NULL, NULL, NULL) != 0)) 3447 goto out; 3448 } 3449 first = 0; /* only check syntax for subsequent hosts */ 3450 } while (cp != sdup); 3451 /* success */ 3452 if (active) { 3453 if (strcasecmp(s, "none") == 0) { 3454 o->jump_host = xstrdup("none"); 3455 o->jump_port = 0; 3456 } else { 3457 o->jump_user = user; 3458 o->jump_host = host; 3459 o->jump_port = port; 3460 o->proxy_command = xstrdup("none"); 3461 user = host = NULL; 3462 if ((cp = strrchr(s, ',')) != NULL && cp != s) { 3463 o->jump_extra = xstrdup(s); 3464 o->jump_extra[cp - s] = '\0'; 3465 } 3466 } 3467 } 3468 ret = 0; 3469 out: 3470 free(orig); 3471 free(user); 3472 free(host); 3473 return ret; 3474} 3475 3476int 3477parse_ssh_uri(const char *uri, char **userp, char **hostp, int *portp) 3478{ 3479 char *user = NULL, *host = NULL, *path = NULL; 3480 int r, port; 3481 3482 r = parse_uri("ssh", uri, &user, &host, &port, &path); 3483 if (r == 0 && path != NULL) 3484 r = -1; /* path not allowed */ 3485 if (r == 0) { 3486 if (userp != NULL) { 3487 *userp = user; 3488 user = NULL; 3489 } 3490 if (hostp != NULL) { 3491 *hostp = host; 3492 host = NULL; 3493 } 3494 if (portp != NULL) 3495 *portp = port; 3496 } 3497 free(user); 3498 free(host); 3499 free(path); 3500 return r; 3501} 3502 3503/* XXX the following is a near-verbatim copy from servconf.c; refactor */ 3504static const char * 3505fmt_multistate_int(int val, const struct multistate *m) 3506{ 3507 u_int i; 3508 3509 for (i = 0; m[i].key != NULL; i++) { 3510 if (m[i].value == val) 3511 return m[i].key; 3512 } 3513 return "UNKNOWN"; 3514} 3515 3516static const char * 3517fmt_intarg(OpCodes code, int val) 3518{ 3519 if (val == -1) 3520 return "unset"; 3521 switch (code) { 3522 case oAddressFamily: 3523 return fmt_multistate_int(val, multistate_addressfamily); 3524 case oCompression: 3525 return fmt_multistate_int(val, multistate_compression); 3526 case oVerifyHostKeyDNS: 3527 case oUpdateHostkeys: 3528 return fmt_multistate_int(val, multistate_yesnoask); 3529 case oStrictHostKeyChecking: 3530 return fmt_multistate_int(val, multistate_strict_hostkey); 3531 case oControlMaster: 3532 return fmt_multistate_int(val, multistate_controlmaster); 3533 case oTunnel: 3534 return fmt_multistate_int(val, multistate_tunnel); 3535 case oRequestTTY: 3536 return fmt_multistate_int(val, multistate_requesttty); 3537 case oSessionType: 3538 return fmt_multistate_int(val, multistate_sessiontype); 3539 case oCanonicalizeHostname: 3540 return fmt_multistate_int(val, multistate_canonicalizehostname); 3541 case oAddKeysToAgent: 3542 return fmt_multistate_int(val, multistate_yesnoaskconfirm); 3543 case oPubkeyAuthentication: 3544 return fmt_multistate_int(val, multistate_pubkey_auth); 3545 case oFingerprintHash: 3546 return ssh_digest_alg_name(val); 3547 default: 3548 switch (val) { 3549 case 0: 3550 return "no"; 3551 case 1: 3552 return "yes"; 3553 default: 3554 return "UNKNOWN"; 3555 } 3556 } 3557} 3558 3559static const char * 3560lookup_opcode_name(OpCodes code) 3561{ 3562 u_int i; 3563 3564 for (i = 0; keywords[i].name != NULL; i++) 3565 if (keywords[i].opcode == code) 3566 return(keywords[i].name); 3567 return "UNKNOWN"; 3568} 3569 3570static void 3571dump_cfg_int(OpCodes code, int val) 3572{ 3573 if (code == oObscureKeystrokeTiming) { 3574 if (val == 0) { 3575 printf("%s no\n", lookup_opcode_name(code)); 3576 return; 3577 } else if (val == SSH_KEYSTROKE_DEFAULT_INTERVAL_MS) { 3578 printf("%s yes\n", lookup_opcode_name(code)); 3579 return; 3580 } 3581 /* FALLTHROUGH */ 3582 } 3583 printf("%s %d\n", lookup_opcode_name(code), val); 3584} 3585 3586static void 3587dump_cfg_fmtint(OpCodes code, int val) 3588{ 3589 printf("%s %s\n", lookup_opcode_name(code), fmt_intarg(code, val)); 3590} 3591 3592static void 3593dump_cfg_string(OpCodes code, const char *val) 3594{ 3595 if (val == NULL) 3596 return; 3597 printf("%s %s\n", lookup_opcode_name(code), val); 3598} 3599 3600static void 3601dump_cfg_strarray(OpCodes code, u_int count, char **vals) 3602{ 3603 u_int i; 3604 3605 for (i = 0; i < count; i++) 3606 printf("%s %s\n", lookup_opcode_name(code), vals[i]); 3607} 3608 3609static void 3610dump_cfg_strarray_oneline(OpCodes code, u_int count, char **vals) 3611{ 3612 u_int i; 3613 3614 printf("%s", lookup_opcode_name(code)); 3615 if (count == 0) 3616 printf(" none"); 3617 for (i = 0; i < count; i++) 3618 printf(" %s", vals[i]); 3619 printf("\n"); 3620} 3621 3622static void 3623dump_cfg_forwards(OpCodes code, u_int count, const struct Forward *fwds) 3624{ 3625 const struct Forward *fwd; 3626 u_int i; 3627 3628 /* oDynamicForward */ 3629 for (i = 0; i < count; i++) { 3630 fwd = &fwds[i]; 3631 if (code == oDynamicForward && fwd->connect_host != NULL && 3632 strcmp(fwd->connect_host, "socks") != 0) 3633 continue; 3634 if (code == oLocalForward && fwd->connect_host != NULL && 3635 strcmp(fwd->connect_host, "socks") == 0) 3636 continue; 3637 printf("%s", lookup_opcode_name(code)); 3638 if (fwd->listen_port == PORT_STREAMLOCAL) 3639 printf(" %s", fwd->listen_path); 3640 else if (fwd->listen_host == NULL) 3641 printf(" %d", fwd->listen_port); 3642 else { 3643 printf(" [%s]:%d", 3644 fwd->listen_host, fwd->listen_port); 3645 } 3646 if (code != oDynamicForward) { 3647 if (fwd->connect_port == PORT_STREAMLOCAL) 3648 printf(" %s", fwd->connect_path); 3649 else if (fwd->connect_host == NULL) 3650 printf(" %d", fwd->connect_port); 3651 else { 3652 printf(" [%s]:%d", 3653 fwd->connect_host, fwd->connect_port); 3654 } 3655 } 3656 printf("\n"); 3657 } 3658} 3659 3660void 3661dump_client_config(Options *o, const char *host) 3662{ 3663 int i, r; 3664 char buf[8], *all_key; 3665 3666 /* 3667 * Expand HostKeyAlgorithms name lists. This isn't handled in 3668 * fill_default_options() like the other algorithm lists because 3669 * the host key algorithms are by default dynamically chosen based 3670 * on the host's keys found in known_hosts. 3671 */ 3672 all_key = sshkey_alg_list(0, 0, 1, ','); 3673 if ((r = kex_assemble_names(&o->hostkeyalgorithms, kex_default_pk_alg(), 3674 all_key)) != 0) 3675 fatal_fr(r, "expand HostKeyAlgorithms"); 3676 free(all_key); 3677 3678 /* Most interesting options first: user, host, port */ 3679 dump_cfg_string(oHost, o->host_arg); 3680 dump_cfg_string(oUser, o->user); 3681 dump_cfg_string(oHostname, host); 3682 dump_cfg_int(oPort, o->port); 3683 3684 /* Flag options */ 3685 dump_cfg_fmtint(oAddressFamily, o->address_family); 3686 dump_cfg_fmtint(oBatchMode, o->batch_mode); 3687 dump_cfg_fmtint(oCanonicalizeFallbackLocal, o->canonicalize_fallback_local); 3688 dump_cfg_fmtint(oCanonicalizeHostname, o->canonicalize_hostname); 3689 dump_cfg_fmtint(oCheckHostIP, o->check_host_ip); 3690 dump_cfg_fmtint(oCompression, o->compression); 3691 dump_cfg_fmtint(oControlMaster, o->control_master); 3692 dump_cfg_fmtint(oEnableSSHKeysign, o->enable_ssh_keysign); 3693 dump_cfg_fmtint(oClearAllForwardings, o->clear_forwardings); 3694 dump_cfg_fmtint(oExitOnForwardFailure, o->exit_on_forward_failure); 3695 dump_cfg_fmtint(oFingerprintHash, o->fingerprint_hash); 3696 dump_cfg_fmtint(oForwardX11, o->forward_x11); 3697 dump_cfg_fmtint(oForwardX11Trusted, o->forward_x11_trusted); 3698 dump_cfg_fmtint(oGatewayPorts, o->fwd_opts.gateway_ports); 3699#ifdef GSSAPI 3700 dump_cfg_fmtint(oGssAuthentication, o->gss_authentication); 3701 dump_cfg_fmtint(oGssDelegateCreds, o->gss_deleg_creds); 3702#endif /* GSSAPI */ 3703 dump_cfg_fmtint(oHashKnownHosts, o->hash_known_hosts); 3704 dump_cfg_fmtint(oHostbasedAuthentication, o->hostbased_authentication); 3705 dump_cfg_fmtint(oIdentitiesOnly, o->identities_only); 3706 dump_cfg_fmtint(oKbdInteractiveAuthentication, o->kbd_interactive_authentication); 3707 dump_cfg_fmtint(oNoHostAuthenticationForLocalhost, o->no_host_authentication_for_localhost); 3708 dump_cfg_fmtint(oPasswordAuthentication, o->password_authentication); 3709 dump_cfg_fmtint(oPermitLocalCommand, o->permit_local_command); 3710 dump_cfg_fmtint(oProxyUseFdpass, o->proxy_use_fdpass); 3711 dump_cfg_fmtint(oPubkeyAuthentication, o->pubkey_authentication); 3712 dump_cfg_fmtint(oRequestTTY, o->request_tty); 3713 dump_cfg_fmtint(oSessionType, o->session_type); 3714 dump_cfg_fmtint(oStdinNull, o->stdin_null); 3715 dump_cfg_fmtint(oForkAfterAuthentication, o->fork_after_authentication); 3716 dump_cfg_fmtint(oStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink); 3717 dump_cfg_fmtint(oStrictHostKeyChecking, o->strict_host_key_checking); 3718 dump_cfg_fmtint(oTCPKeepAlive, o->tcp_keep_alive); 3719 dump_cfg_fmtint(oTunnel, o->tun_open); 3720 dump_cfg_fmtint(oVerifyHostKeyDNS, o->verify_host_key_dns); 3721 dump_cfg_fmtint(oVisualHostKey, o->visual_host_key); 3722 dump_cfg_fmtint(oUpdateHostkeys, o->update_hostkeys); 3723 dump_cfg_fmtint(oEnableEscapeCommandline, o->enable_escape_commandline); 3724 dump_cfg_fmtint(oWarnWeakCrypto, o->warn_weak_crypto); 3725 3726 /* Integer options */ 3727 dump_cfg_int(oCanonicalizeMaxDots, o->canonicalize_max_dots); 3728 dump_cfg_int(oConnectionAttempts, o->connection_attempts); 3729 dump_cfg_int(oForwardX11Timeout, o->forward_x11_timeout); 3730 dump_cfg_int(oNumberOfPasswordPrompts, o->number_of_password_prompts); 3731 dump_cfg_int(oServerAliveCountMax, o->server_alive_count_max); 3732 dump_cfg_int(oServerAliveInterval, o->server_alive_interval); 3733 dump_cfg_int(oRequiredRSASize, o->required_rsa_size); 3734 dump_cfg_int(oObscureKeystrokeTiming, 3735 o->obscure_keystroke_timing_interval); 3736 3737 /* String options */ 3738 dump_cfg_string(oBindAddress, o->bind_address); 3739 dump_cfg_string(oBindInterface, o->bind_interface); 3740 dump_cfg_string(oCiphers, o->ciphers); 3741 dump_cfg_string(oControlPath, o->control_path); 3742 dump_cfg_string(oHostKeyAlgorithms, o->hostkeyalgorithms); 3743 dump_cfg_string(oHostKeyAlias, o->host_key_alias); 3744 dump_cfg_string(oHostbasedAcceptedAlgorithms, o->hostbased_accepted_algos); 3745 dump_cfg_string(oIdentityAgent, o->identity_agent); 3746 dump_cfg_string(oIgnoreUnknown, o->ignored_unknown); 3747 dump_cfg_string(oKbdInteractiveDevices, o->kbd_interactive_devices); 3748 dump_cfg_string(oKexAlgorithms, o->kex_algorithms); 3749 dump_cfg_string(oCASignatureAlgorithms, o->ca_sign_algorithms); 3750 dump_cfg_string(oLocalCommand, o->local_command); 3751 dump_cfg_string(oRemoteCommand, o->remote_command); 3752 dump_cfg_string(oLogLevel, log_level_name(o->log_level)); 3753 dump_cfg_string(oMacs, o->macs); 3754#ifdef ENABLE_PKCS11 3755 dump_cfg_string(oPKCS11Provider, o->pkcs11_provider); 3756#endif 3757 dump_cfg_string(oSecurityKeyProvider, o->sk_provider); 3758 dump_cfg_string(oPreferredAuthentications, o->preferred_authentications); 3759 dump_cfg_string(oPubkeyAcceptedAlgorithms, o->pubkey_accepted_algos); 3760 dump_cfg_string(oXAuthLocation, o->xauth_location); 3761 dump_cfg_string(oKnownHostsCommand, o->known_hosts_command); 3762 dump_cfg_string(oTag, o->tag); 3763 dump_cfg_string(oVersionAddendum, o->version_addendum); 3764 3765 /* Forwards */ 3766 dump_cfg_forwards(oDynamicForward, o->num_local_forwards, o->local_forwards); 3767 dump_cfg_forwards(oLocalForward, o->num_local_forwards, o->local_forwards); 3768 dump_cfg_forwards(oRemoteForward, o->num_remote_forwards, o->remote_forwards); 3769 3770 /* String array options */ 3771 dump_cfg_strarray(oIdentityFile, o->num_identity_files, o->identity_files); 3772 dump_cfg_strarray_oneline(oCanonicalDomains, o->num_canonical_domains, o->canonical_domains); 3773 dump_cfg_strarray(oCertificateFile, o->num_certificate_files, o->certificate_files); 3774 dump_cfg_strarray_oneline(oGlobalKnownHostsFile, o->num_system_hostfiles, o->system_hostfiles); 3775 dump_cfg_strarray_oneline(oUserKnownHostsFile, o->num_user_hostfiles, o->user_hostfiles); 3776 dump_cfg_strarray_oneline(oRevokedHostKeys, o->num_revoked_host_keys, o->revoked_host_keys); 3777 dump_cfg_strarray(oSendEnv, o->num_send_env, o->send_env); 3778 dump_cfg_strarray(oSetEnv, o->num_setenv, o->setenv); 3779 dump_cfg_strarray_oneline(oLogVerbose, 3780 o->num_log_verbose, o->log_verbose); 3781 dump_cfg_strarray_oneline(oChannelTimeout, 3782 o->num_channel_timeouts, o->channel_timeouts); 3783 3784 /* Special cases */ 3785 3786 /* PermitRemoteOpen */ 3787 if (o->num_permitted_remote_opens == 0) 3788 printf("%s any\n", lookup_opcode_name(oPermitRemoteOpen)); 3789 else 3790 dump_cfg_strarray_oneline(oPermitRemoteOpen, 3791 o->num_permitted_remote_opens, o->permitted_remote_opens); 3792 3793 /* AddKeysToAgent */ 3794 if (o->add_keys_to_agent_lifespan <= 0) 3795 dump_cfg_fmtint(oAddKeysToAgent, o->add_keys_to_agent); 3796 else { 3797 printf("addkeystoagent%s %d\n", 3798 o->add_keys_to_agent == 3 ? " confirm" : "", 3799 o->add_keys_to_agent_lifespan); 3800 } 3801 3802 /* oForwardAgent */ 3803 if (o->forward_agent_sock_path == NULL) 3804 dump_cfg_fmtint(oForwardAgent, o->forward_agent); 3805 else 3806 dump_cfg_string(oForwardAgent, o->forward_agent_sock_path); 3807 3808 /* oConnectTimeout */ 3809 if (o->connection_timeout == -1) 3810 printf("connecttimeout none\n"); 3811 else 3812 dump_cfg_int(oConnectTimeout, o->connection_timeout); 3813 3814 /* oTunnelDevice */ 3815 printf("tunneldevice"); 3816 if (o->tun_local == SSH_TUNID_ANY) 3817 printf(" any"); 3818 else 3819 printf(" %d", o->tun_local); 3820 if (o->tun_remote == SSH_TUNID_ANY) 3821 printf(":any"); 3822 else 3823 printf(":%d", o->tun_remote); 3824 printf("\n"); 3825 3826 /* oCanonicalizePermittedCNAMEs */ 3827 printf("canonicalizePermittedcnames"); 3828 if (o->num_permitted_cnames == 0) 3829 printf(" none"); 3830 for (i = 0; i < o->num_permitted_cnames; i++) { 3831 printf(" %s:%s", o->permitted_cnames[i].source_list, 3832 o->permitted_cnames[i].target_list); 3833 } 3834 printf("\n"); 3835 3836 /* oControlPersist */ 3837 if (o->control_persist == 0 || o->control_persist_timeout == 0) 3838 dump_cfg_fmtint(oControlPersist, o->control_persist); 3839 else 3840 dump_cfg_int(oControlPersist, o->control_persist_timeout); 3841 3842 /* oEscapeChar */ 3843 if (o->escape_char == SSH_ESCAPECHAR_NONE) 3844 printf("escapechar none\n"); 3845 else { 3846 vis(buf, o->escape_char, VIS_WHITE, 0); 3847 printf("escapechar %s\n", buf); 3848 } 3849 3850 /* oIPQoS */ 3851 printf("ipqos %s ", iptos2str(o->ip_qos_interactive)); 3852 printf("%s\n", iptos2str(o->ip_qos_bulk)); 3853 3854 /* oRekeyLimit */ 3855 printf("rekeylimit %llu %d\n", 3856 (unsigned long long)o->rekey_limit, o->rekey_interval); 3857 3858 /* oStreamLocalBindMask */ 3859 printf("streamlocalbindmask 0%o\n", 3860 o->fwd_opts.streamlocal_bind_mask); 3861 3862 /* oLogFacility */ 3863 printf("syslogfacility %s\n", log_facility_name(o->log_facility)); 3864 3865 /* oProxyCommand / oProxyJump */ 3866 if (o->jump_host == NULL) 3867 dump_cfg_string(oProxyCommand, o->proxy_command); 3868 else { 3869 /* Check for numeric addresses */ 3870 i = strchr(o->jump_host, ':') != NULL || 3871 strspn(o->jump_host, "1234567890.") == strlen(o->jump_host); 3872 snprintf(buf, sizeof(buf), "%d", o->jump_port); 3873 printf("proxyjump %s%s%s%s%s%s%s%s%s\n", 3874 /* optional additional jump spec */ 3875 o->jump_extra == NULL ? "" : o->jump_extra, 3876 o->jump_extra == NULL ? "" : ",", 3877 /* optional user */ 3878 o->jump_user == NULL ? "" : o->jump_user, 3879 o->jump_user == NULL ? "" : "@", 3880 /* opening [ if hostname is numeric */ 3881 i ? "[" : "", 3882 /* mandatory hostname */ 3883 o->jump_host, 3884 /* closing ] if hostname is numeric */ 3885 i ? "]" : "", 3886 /* optional port number */ 3887 o->jump_port <= 0 ? "" : ":", 3888 o->jump_port <= 0 ? "" : buf); 3889 } 3890}