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