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