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