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