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