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