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