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