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