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