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