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